DynamicContainer.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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_DYNAMICCONTAINER_CPP
  13. #define SE_INCL_DYNAMICCONTAINER_CPP
  14. #ifdef PRAGMA_ONCE
  15. #pragma once
  16. #endif
  17. #include <Engine/Templates/DynamicContainer.h>
  18. #include <Engine/Base/Memory.h>
  19. #include <Engine/Templates/StaticStackArray.cpp>
  20. /*
  21. * Default constructor.
  22. */
  23. template<class Type>
  24. CDynamicContainer<Type>::CDynamicContainer(void) {
  25. #if CHECKARRAYLOCKING
  26. // not locked
  27. dc_LockCt = 0;
  28. #endif
  29. }
  30. /*
  31. * Copy constructor.
  32. */
  33. template<class Type>
  34. CDynamicContainer<Type>::CDynamicContainer(CDynamicContainer<Type> &dcOriginal)
  35. {
  36. #if CHECKARRAYLOCKING
  37. // not locked
  38. dc_LockCt = 0;
  39. #endif
  40. // call assignment operator
  41. (*this) = dcOriginal;
  42. }
  43. /*
  44. * Destructor -- removes all objects.
  45. */
  46. template<class Type>
  47. CDynamicContainer<Type>::~CDynamicContainer(void) {
  48. Clear();
  49. }
  50. /*
  51. * Remove all objects, and reset the array to initial (empty) state.
  52. */
  53. template<class Type>
  54. void CDynamicContainer<Type>::Clear(void) {
  55. ASSERT(this!=NULL);
  56. CStaticStackArray<Type *>::Clear();
  57. }
  58. /*
  59. * Add a given object to container.
  60. */
  61. template<class Type>
  62. void CDynamicContainer<Type>::Add(Type *ptNewObject)
  63. {
  64. // set the new pointer
  65. Push() = ptNewObject;
  66. }
  67. /*
  68. * Insert a given object to container at specified index.
  69. */
  70. template<class Type>
  71. void CDynamicContainer<Type>::Insert(Type *ptNewObject, const INDEX iPos/*=0*/)
  72. {
  73. // get number of member that need moving and add new one
  74. const INDEX ctMovees = CStaticStackArray<Type*>::Count() - iPos;
  75. CStaticStackArray<Type*>::Push();
  76. // move all members after insert position one place up
  77. Type **pptInsertAt = this->sa_Array+iPos;
  78. Type **pptMoveTo = pptInsertAt +1;
  79. memmove( pptMoveTo, pptInsertAt, sizeof(Type*)*ctMovees);
  80. // store pointer to newly inserted member at specified position
  81. *pptInsertAt = ptNewObject;
  82. }
  83. /*
  84. * Remove a given object from container.
  85. */
  86. template<class Type>
  87. void CDynamicContainer<Type>::Remove(Type *ptOldObject)
  88. {
  89. ASSERT(this!=NULL);
  90. #if CHECKARRAYLOCKING
  91. // check that not locked for indices
  92. ASSERT(dc_LockCt == 0);
  93. #endif
  94. // find its index
  95. INDEX iMember=GetIndex(ptOldObject);
  96. // move last pointer here
  97. sa_Array[iMember]=sa_Array[Count()-1];
  98. Pop();
  99. }
  100. /* Test if a given object is in the container. */
  101. template<class Type>
  102. BOOL CDynamicContainer<Type>::IsMember(Type *ptOldObject)
  103. {
  104. ASSERT(this!=NULL);
  105. // slow !!!!
  106. // check all members
  107. for (INDEX iMember=0; iMember<Count(); iMember++) {
  108. if(sa_Array[iMember]==ptOldObject) {
  109. return TRUE;
  110. }
  111. }
  112. return FALSE;
  113. }
  114. /*
  115. * Get pointer to a member from it's index.
  116. */
  117. template<class Type>
  118. Type *CDynamicContainer<Type>::Pointer(INDEX iMember) {
  119. ASSERT(this!=NULL);
  120. // check that index is currently valid
  121. ASSERT(iMember>=0 && iMember<Count());
  122. #if CHECKARRAYLOCKING
  123. // check that locked for indices
  124. ASSERT(dc_LockCt>0);
  125. #endif
  126. return sa_Array[iMember];
  127. }
  128. template<class Type>
  129. const Type *CDynamicContainer<Type>::Pointer(INDEX iMember) const {
  130. ASSERT(this!=NULL);
  131. // check that index is currently valid
  132. ASSERT(iMember>=0 && iMember<Count());
  133. #if CHECKARRAYLOCKING
  134. // check that locked for indices
  135. ASSERT(dc_LockCt>0);
  136. #endif
  137. return sa_Array[iMember];
  138. }
  139. /*
  140. * Lock for getting indices.
  141. */
  142. template<class Type>
  143. void CDynamicContainer<Type>::Lock(void) {
  144. ASSERT(this!=NULL);
  145. #if CHECKARRAYLOCKING
  146. ASSERT(dc_LockCt>=0);
  147. // increment lock counter
  148. dc_LockCt++;
  149. #endif
  150. }
  151. /*
  152. * Unlock after getting indices.
  153. */
  154. template<class Type>
  155. void CDynamicContainer<Type>::Unlock(void) {
  156. ASSERT(this!=NULL);
  157. #if CHECKARRAYLOCKING
  158. dc_LockCt--;
  159. ASSERT(dc_LockCt>=0);
  160. #endif
  161. }
  162. /*
  163. * Get index of a member from it's pointer.
  164. */
  165. template<class Type>
  166. INDEX CDynamicContainer<Type>::Index(Type *ptMember) {
  167. ASSERT(this!=NULL);
  168. // check that locked for indices
  169. #if CHECKARRAYLOCKING
  170. ASSERT(dc_LockCt>0);
  171. #endif
  172. return GetIndex(ptMember);
  173. }
  174. /*
  175. * Get index of a member from it's pointer without locking.
  176. */
  177. template<class Type>
  178. INDEX CDynamicContainer<Type>::GetIndex(Type *ptMember) {
  179. ASSERT(this!=NULL);
  180. // slow !!!!
  181. // check all members
  182. for (INDEX iMember=0; iMember<Count(); iMember++) {
  183. if(sa_Array[iMember]==ptMember) {
  184. return iMember;
  185. }
  186. }
  187. ASSERTALWAYS("CDynamicContainer<Type><>::Index(): Not a member of this container!");
  188. return 0;
  189. }
  190. /* Get first object in container (there must be at least one when calling this). */
  191. template<class Type>
  192. Type &CDynamicContainer<Type>::GetFirst(void)
  193. {
  194. ASSERT(Count()>=1);
  195. return *sa_Array[0];
  196. }
  197. /*
  198. * Assignment operator.
  199. */
  200. template<class Type>
  201. CDynamicContainer<Type> &CDynamicContainer<Type>::operator=(CDynamicContainer<Type> &coOriginal)
  202. {
  203. CStaticStackArray<Type *>::operator=(coOriginal);
  204. return *this;
  205. }
  206. /*
  207. * Move all elements of another array into this one.
  208. */
  209. template<class Type>
  210. void CDynamicContainer<Type>::MoveContainer(CDynamicContainer<Type> &coOther)
  211. {
  212. ASSERT(this!=NULL && &coOther!=NULL);
  213. // check that not locked for indices
  214. #if CHECKARRAYLOCKING
  215. ASSERT(dc_LockCt==0 && coOther.dc_LockCt==0);
  216. #endif
  217. CStaticStackArray<Type*>::MoveArray(coOther);
  218. }
  219. /////////////////////////////////////////////////////////////////////
  220. // CDynamicContainerIterator<Type>
  221. /*
  222. * Template class for iterating dynamic array.
  223. */
  224. template<class Type>
  225. class CDynamicContainerIterator {
  226. private:
  227. INDEX dci_Index; // index of current element
  228. CDynamicContainer<Type> &dci_Array; // reference to array
  229. public:
  230. /* Constructor for given array. */
  231. inline CDynamicContainerIterator(CDynamicContainer<Type> &da);
  232. /* Destructor. */
  233. inline ~CDynamicContainerIterator(void);
  234. /* Move to next object. */
  235. inline void MoveToNext(void);
  236. /* Check if finished. */
  237. inline BOOL IsPastEnd(void);
  238. /* Get current element. */
  239. Type &Current(void) { return *dci_Array.Pointer(dci_Index); }
  240. Type &operator*(void) { return *dci_Array.Pointer(dci_Index); }
  241. operator Type *(void) { return dci_Array.Pointer(dci_Index); }
  242. Type *operator->(void) { return dci_Array.Pointer(dci_Index); }
  243. };
  244. /*
  245. * Constructor for given array.
  246. */
  247. template<class Type>
  248. inline CDynamicContainerIterator<Type>::CDynamicContainerIterator(CDynamicContainer<Type> &da) : dci_Array(da) {
  249. // lock indices
  250. dci_Array.Lock();
  251. dci_Index = 0;
  252. }
  253. /*
  254. * Destructor.
  255. */
  256. template<class Type>
  257. inline CDynamicContainerIterator<Type>::~CDynamicContainerIterator(void) {
  258. // unlock indices
  259. dci_Array.Unlock();
  260. dci_Index = -1;
  261. }
  262. /*
  263. * Move to next object.
  264. */
  265. template<class Type>
  266. inline void CDynamicContainerIterator<Type>::MoveToNext(void) {
  267. ASSERT(this!=NULL);
  268. dci_Index++;
  269. }
  270. /*
  271. * Check if finished.
  272. */
  273. template<class Type>
  274. inline BOOL CDynamicContainerIterator<Type>::IsPastEnd(void) {
  275. ASSERT(this!=NULL);
  276. return dci_Index>=dci_Array.Count();
  277. }
  278. // iterate whole dynamic container
  279. /* NOTE: The iterator defined by this macro must be destroyed before adding/removing
  280. * elements in the container. To do so, embed the for loop in additional curly braces.
  281. */
  282. #define FOREACHINDYNAMICCONTAINER(container, type, iter) \
  283. for(CDynamicContainerIterator<type> iter(container); !iter.IsPastEnd(); iter.MoveToNext() )
  284. #endif /* include-once check. */