DynamicArray.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #ifndef SE_INCL_DYNAMICARRAY_CPP
  13. #define SE_INCL_DYNAMICARRAY_CPP
  14. #ifdef PRAGMA_ONCE
  15. #pragma once
  16. #endif
  17. #include <Engine/Base/Memory.h>
  18. #include <Engine/Base/ListIterator.inl>
  19. #include <Engine/Templates/DynamicArray.h>
  20. // iterate whole dynamic array
  21. /* NOTE: The iterator defined by this macro must be destroyed before adding/removing
  22. * elements in the array. To do so, embed the for loop in additional curly braces.
  23. */
  24. #define FOREACHINDYNAMICARRAY(array, type, iter) \
  25. for(CDynamicArrayIterator<type> iter(array); !iter.IsPastEnd(); iter.MoveToNext() )
  26. class CDABlockInfo {
  27. public:
  28. CListNode bi_ListNode;
  29. void *bi_Memory;
  30. };
  31. /*
  32. * Default constructor.
  33. */
  34. template<class Type>
  35. CDynamicArray<Type>::CDynamicArray(void) {
  36. #if CHECKARRAYLOCKING
  37. // not locked
  38. da_LockCt = 0;
  39. #endif
  40. // set to empty array of pointers
  41. da_Pointers = NULL;
  42. da_Count = 0;
  43. }
  44. /*
  45. * Copy constructor.
  46. */
  47. template<class Type>
  48. CDynamicArray<Type>::CDynamicArray(CDynamicArray<Type> &daOriginal)
  49. {
  50. #if CHECKARRAYLOCKING
  51. // not locked
  52. da_LockCt = 0;
  53. #endif
  54. // set to empty array of pointers
  55. da_Pointers = NULL;
  56. da_Count = 0;
  57. // call assignment operator
  58. (*this) = daOriginal;
  59. }
  60. /*
  61. * Destructor -- frees all memory.
  62. */
  63. template<class Type>
  64. CDynamicArray<Type>::~CDynamicArray(void) {
  65. Clear();
  66. }
  67. /*
  68. * Destroy all objects, and reset the array to initial (empty) state.
  69. */
  70. template<class Type>
  71. void CDynamicArray<Type>::Clear(void) {
  72. ASSERT(this!=NULL);
  73. // if any pointers are allocated
  74. if (da_Count!=0) {
  75. /* NOTE: We must explicitly clear objects here, because array deleting
  76. * does not call object destructors!
  77. */
  78. // for all pointers
  79. for (INDEX iPointer=0; iPointer<da_Count; iPointer++) {
  80. // destroy the object that it points to
  81. ::Clear(*da_Pointers[iPointer]);
  82. }
  83. // free the pointers
  84. FreeMemory(da_Pointers);
  85. // mark as freed
  86. da_Pointers = NULL;
  87. da_Count = 0;
  88. // otherwise
  89. } else {
  90. // check that the pointers are really not allocated
  91. ASSERT(da_Pointers==NULL);
  92. // nothing to free
  93. }
  94. // for all memory blocks
  95. FORDELETELIST(CDABlockInfo, bi_ListNode, da_BlocksList, itBlock) {
  96. // free memory used by block (this doesn't call destructors - see note above!)
  97. delete[] (Type *)itBlock->bi_Memory;
  98. // free memory used by block info
  99. delete &itBlock.Current();
  100. }
  101. }
  102. /* Random access operator. */
  103. template<class Type>
  104. Type &CDynamicArray<Type>::operator[](INDEX iObject) {
  105. return *Pointer(iObject);
  106. };
  107. template<class Type>
  108. const Type &CDynamicArray<Type>::operator[](INDEX iObject) const {
  109. return *Pointer(iObject);
  110. };
  111. /*
  112. * Grow pointer array by a given number of members.
  113. */
  114. template<class Type>
  115. void CDynamicArray<Type>::GrowPointers(INDEX iCount) {
  116. ASSERT(this!=NULL && iCount>0);
  117. // if not yet allocated
  118. if (da_Count==0) {
  119. // check that the pointers are really not allocated
  120. ASSERT(da_Pointers==NULL);
  121. // allocate
  122. da_Count=iCount;
  123. da_Pointers = (Type **)AllocMemory(da_Count*sizeof(Type*));
  124. // if allocated
  125. } else {
  126. // grow to new size
  127. da_Count+=iCount;
  128. GrowMemory((void **)&da_Pointers, da_Count*sizeof(Type*));
  129. }
  130. }
  131. /*
  132. * Shrink pointer array by a given number of members.
  133. */
  134. template<class Type>
  135. void CDynamicArray<Type>::ShrinkPointers(INDEX iCount) {
  136. ASSERT(this!=NULL && iCount>0);
  137. // check that the pointers are allocated
  138. ASSERT(da_Pointers!=NULL);
  139. // decrement count
  140. da_Count-=iCount;
  141. // checked that it has not dropped below zero
  142. ASSERT(da_Count>=0);
  143. // if all pointers are freed by this
  144. if (da_Count==0) {
  145. // free the array
  146. FreeMemory(da_Pointers);
  147. da_Pointers = NULL;
  148. // if some remain
  149. } else {
  150. // shrink to new size
  151. ShrinkMemory((void **)&da_Pointers, da_Count*sizeof(Type*));
  152. }
  153. }
  154. /*
  155. * Allocate a new memory block.
  156. */
  157. template<class Type>
  158. Type *CDynamicArray<Type>::AllocBlock(INDEX iCount) {
  159. ASSERT(this!=NULL && iCount>0);
  160. Type *ptBlock;
  161. CDABlockInfo *pbi;
  162. // allocate the memory and call constructors for all members (+1 for cache-prefetch opt)
  163. ptBlock = new Type[iCount+1]; // call vector constructor, for better performance
  164. // allocate the block info
  165. pbi = new CDABlockInfo;
  166. // add the block to list
  167. da_BlocksList.AddTail(pbi->bi_ListNode);
  168. // remember block memory
  169. pbi->bi_Memory = ptBlock;
  170. return ptBlock;
  171. }
  172. /*
  173. * Create a given number of new members.
  174. */
  175. template<class Type>
  176. Type *CDynamicArray<Type>::New(INDEX iCount /*= 1*/) {
  177. ASSERT(this!=NULL && iCount>=0);
  178. // if no new members are needed in fact
  179. if (iCount==0) {
  180. // do nothing
  181. return NULL;
  182. }
  183. Type *ptBlock;
  184. INDEX iOldCount = da_Count;
  185. // grow the pointer table
  186. GrowPointers(iCount);
  187. // allocate the memory block
  188. ptBlock = AllocBlock(iCount);
  189. // set pointers
  190. for(INDEX iNewMember=0; iNewMember<iCount; iNewMember++) {
  191. da_Pointers[iOldCount+iNewMember] = ptBlock+iNewMember;
  192. }
  193. return ptBlock;
  194. }
  195. /*
  196. * Delete a given member.
  197. */
  198. template<class Type>
  199. void CDynamicArray<Type>::Delete(Type *ptMember) {
  200. ASSERT(this!=NULL);
  201. #if CHECKARRAYLOCKING
  202. // check that not locked for indices
  203. ASSERT(da_LockCt == 0);
  204. #endif
  205. // clear the object
  206. ::Clear(*ptMember);
  207. INDEX iMember=GetIndex(ptMember);
  208. // move last pointer here
  209. da_Pointers[iMember]=da_Pointers[da_Count-1];
  210. // shrink pointers by one
  211. ShrinkPointers(1);
  212. // do nothing to free memory
  213. //!!!!
  214. }
  215. /*
  216. * Get pointer to a member from it's index.
  217. */
  218. template<class Type>
  219. Type *CDynamicArray<Type>::Pointer(INDEX iMember) {
  220. ASSERT(this!=NULL);
  221. // check that index is currently valid
  222. ASSERT(iMember>=0 && iMember<da_Count);
  223. #if CHECKARRAYLOCKING
  224. // check that locked for indices
  225. ASSERT(da_LockCt>0);
  226. #endif
  227. return da_Pointers[iMember];
  228. }
  229. template<class Type>
  230. const Type *CDynamicArray<Type>::Pointer(INDEX iMember) const {
  231. ASSERT(this!=NULL);
  232. // check that index is currently valid
  233. ASSERT(iMember>=0 && iMember<da_Count);
  234. #if CHECKARRAYLOCKING
  235. // check that locked for indices
  236. ASSERT(da_LockCt>0);
  237. #endif
  238. return da_Pointers[iMember];
  239. }
  240. /*
  241. * Lock for getting indices.
  242. */
  243. template<class Type>
  244. void CDynamicArray<Type>::Lock(void) {
  245. ASSERT(this!=NULL);
  246. #if CHECKARRAYLOCKING
  247. ASSERT(da_LockCt>=0);
  248. // increment lock counter
  249. da_LockCt++;
  250. #endif
  251. }
  252. /*
  253. * Unlock after getting indices.
  254. */
  255. template<class Type>
  256. void CDynamicArray<Type>::Unlock(void) {
  257. ASSERT(this!=NULL);
  258. #if CHECKARRAYLOCKING
  259. da_LockCt--;
  260. ASSERT(da_LockCt>=0);
  261. #endif
  262. }
  263. /*
  264. * Get index of a member from it's pointer.
  265. */
  266. template<class Type>
  267. INDEX CDynamicArray<Type>::Index(Type *ptMember) {
  268. ASSERT(this!=NULL);
  269. #if CHECKARRAYLOCKING
  270. // check that locked for indices
  271. ASSERT(da_LockCt>0);
  272. #endif
  273. return GetIndex(ptMember);
  274. }
  275. /*
  276. * Get index of a member from it's pointer without locking.
  277. */
  278. template<class Type>
  279. INDEX CDynamicArray<Type>::GetIndex(Type *ptMember) {
  280. ASSERT(this!=NULL);
  281. // slow !!!!
  282. // check all members
  283. for (INDEX iMember=0; iMember<da_Count; iMember++) {
  284. if(da_Pointers[iMember]==ptMember) {
  285. return iMember;
  286. }
  287. }
  288. ASSERTALWAYS("CDynamicArray<>::Index(): Not a member of this array!");
  289. return 0;
  290. }
  291. /*
  292. * Get number of elements in array.
  293. */
  294. template<class Type>
  295. INDEX CDynamicArray<Type>::Count(void) const {
  296. ASSERT(this!=NULL);
  297. return da_Count;
  298. }
  299. /*
  300. * Assignment operator.
  301. */
  302. template<class Type>
  303. CDynamicArray<Type> &CDynamicArray<Type>::operator=(CDynamicArray<Type> &arOriginal)
  304. {
  305. ASSERT(this!=NULL);
  306. ASSERT(&arOriginal!=NULL);
  307. ASSERT(this!=&arOriginal);
  308. // clear previous contents
  309. Clear();
  310. // get count of elements in original array
  311. INDEX ctOriginal = arOriginal.Count();
  312. // if the other array has no elements
  313. if (ctOriginal ==0) {
  314. // no assignment
  315. return*this;
  316. }
  317. // create that much elements
  318. Type *atNew = New(ctOriginal);
  319. // copy them all
  320. arOriginal.Lock();
  321. for (INDEX iNew=0; iNew<ctOriginal; iNew++) {
  322. atNew[iNew] = arOriginal[iNew];
  323. }
  324. arOriginal.Unlock();
  325. return *this;
  326. }
  327. /*
  328. * Move all elements of another array into this one.
  329. */
  330. template<class Type>
  331. void CDynamicArray<Type>::MoveArray(CDynamicArray<Type> &arOther)
  332. {
  333. ASSERT(this!=NULL && &arOther!=NULL);
  334. #if CHECKARRAYLOCKING
  335. // check that not locked for indices
  336. ASSERT(da_LockCt==0 && arOther.da_LockCt==0);
  337. #endif
  338. // if the other array has no elements
  339. if (arOther.da_Count==0) {
  340. // no moving
  341. return;
  342. }
  343. // remember number of elements
  344. INDEX iOldCount = da_Count;
  345. // grow pointer array to add the pointers to elements of other array
  346. GrowPointers(arOther.da_Count);
  347. // for each pointer in other array
  348. for (INDEX iOtherPointer=0; iOtherPointer<arOther.da_Count; iOtherPointer++) {
  349. // copy it at the end of this array
  350. da_Pointers[iOldCount+iOtherPointer] = arOther.da_Pointers[iOtherPointer];
  351. }
  352. // remove array of pointers in other array
  353. arOther.ShrinkPointers(arOther.da_Count);
  354. // move list of allocated blocks from the other array to the end of this one
  355. da_BlocksList.MoveList(arOther.da_BlocksList);
  356. }
  357. /////////////////////////////////////////////////////////////////////
  358. // CDynamicArrayIterator
  359. /*
  360. * Template class for iterating dynamic array.
  361. */
  362. template<class Type>
  363. class CDynamicArrayIterator {
  364. private:
  365. INDEX dai_Index; // index of current element
  366. CDynamicArray<Type> &dai_Array; // reference to array
  367. public:
  368. /* Constructor for given array. */
  369. inline CDynamicArrayIterator(CDynamicArray<Type> &da);
  370. /* Destructor. */
  371. inline ~CDynamicArrayIterator(void);
  372. /* Move to next object. */
  373. inline void MoveToNext(void);
  374. /* Check if finished. */
  375. inline BOOL IsPastEnd(void);
  376. /* Get current element. */
  377. Type &Current(void) { return *dai_Array.Pointer(dai_Index); }
  378. Type &operator*(void) { return *dai_Array.Pointer(dai_Index); }
  379. operator Type *(void) { return dai_Array.Pointer(dai_Index); }
  380. Type *operator->(void) { return dai_Array.Pointer(dai_Index); }
  381. };
  382. /*
  383. * Constructor for given array.
  384. */
  385. template<class Type>
  386. inline CDynamicArrayIterator<Type>::CDynamicArrayIterator(CDynamicArray<Type> &da) : dai_Array(da) {
  387. // lock indices
  388. dai_Array.Lock();
  389. dai_Index = 0;
  390. }
  391. /*
  392. * Destructor.
  393. */
  394. template<class Type>
  395. inline CDynamicArrayIterator<Type>::~CDynamicArrayIterator(void) {
  396. // unlock indices
  397. dai_Array.Unlock();
  398. dai_Index = -1;
  399. }
  400. /*
  401. * Move to next object.
  402. */
  403. template<class Type>
  404. inline void CDynamicArrayIterator<Type>::MoveToNext(void) {
  405. ASSERT(this!=NULL);
  406. dai_Index++;
  407. }
  408. /*
  409. * Check if finished.
  410. */
  411. template<class Type>
  412. inline BOOL CDynamicArrayIterator<Type>::IsPastEnd(void) {
  413. ASSERT(this!=NULL);
  414. return dai_Index>=dai_Array.Count();
  415. }
  416. #endif /* include-once check. */