IceContainer.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2. /**
  3. * Contains a simple container class.
  4. * \file IceContainer.cpp
  5. * \author Pierre Terdiman
  6. * \date February, 5, 2000
  7. */
  8. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  9. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  10. /**
  11. * Contains a list of 32-bits values.
  12. * Use this class when you need to store an unknown number of values. The list is automatically
  13. * resized and can contains 32-bits entities (dwords or floats)
  14. *
  15. * \class Container
  16. * \author Pierre Terdiman
  17. * \version 1.0
  18. * \date 08.15.98
  19. */
  20. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  21. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  22. // Precompiled Header
  23. #include "Stdafx.h"
  24. using namespace IceCore;
  25. #define MAX_RESERVE_GROWTH_SIZE 65536U
  26. // Static members
  27. #ifdef CONTAINER_STATS
  28. udword Container::mNbContainers = 0;
  29. udword Container::mUsedRam = 0;
  30. #endif
  31. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  32. /**
  33. * Constructor. No entries allocated there.
  34. */
  35. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  36. Container::Container() : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2)
  37. {
  38. #ifdef CONTAINER_STATS
  39. mNbContainers++;
  40. mUsedRam+=sizeof(Container);
  41. #endif
  42. }
  43. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  44. /**
  45. * Constructor. Also allocates a given number of entries.
  46. */
  47. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  48. Container::Container(udword size, float growth_factor) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(growth_factor)
  49. {
  50. #ifdef CONTAINER_STATS
  51. mNbContainers++;
  52. mUsedRam+=sizeof(Container);
  53. #endif
  54. SetSize(size);
  55. }
  56. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  57. /**
  58. * Copy constructor.
  59. */
  60. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  61. Container::Container(const Container& object) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2)
  62. {
  63. #ifdef CONTAINER_STATS
  64. mNbContainers++;
  65. mUsedRam+=sizeof(Container);
  66. #endif
  67. *this = object;
  68. }
  69. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  70. /**
  71. * Destructor. Frees everything and leaves.
  72. */
  73. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  74. Container::~Container()
  75. {
  76. Empty();
  77. #ifdef CONTAINER_STATS
  78. mNbContainers--;
  79. mUsedRam-=GetUsedRam();
  80. #endif
  81. }
  82. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  83. /**
  84. * Clears the container. All stored values are deleted, and it frees used ram.
  85. * \see Reset()
  86. * \return Self-Reference
  87. */
  88. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  89. Container& Container::Empty()
  90. {
  91. #ifdef CONTAINER_STATS
  92. mUsedRam-=mMaxNbEntries*sizeof(udword);
  93. #endif
  94. DELETEARRAY(mEntries);
  95. mCurNbEntries = mMaxNbEntries = 0;
  96. return *this;
  97. }
  98. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  99. /**
  100. * Resizes the container.
  101. * \param needed [in] assume the container can be added at least "needed" values
  102. * \return true if success.
  103. */
  104. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  105. bool Container::Resize(udword needed)
  106. {
  107. #ifdef CONTAINER_STATS
  108. // Subtract previous amount of bytes
  109. mUsedRam-=mMaxNbEntries*sizeof(udword);
  110. #endif
  111. if (MAX_UDWORD - mCurNbEntries < needed)
  112. {
  113. CHECKALLOC(null);
  114. }
  115. // Get more entries
  116. udword NewMaxNbEntries = mMaxNbEntries ? udword(mMaxNbEntries * mGrowthFactor) : 2; // Default nb Entries = 2
  117. if (NewMaxNbEntries <= mMaxNbEntries) NewMaxNbEntries = MAX_UDWORD - mMaxNbEntries < MAX_RESERVE_GROWTH_SIZE ? MAX_UDWORD : mMaxNbEntries + MAX_RESERVE_GROWTH_SIZE;
  118. else if (NewMaxNbEntries - mMaxNbEntries > MAX_RESERVE_GROWTH_SIZE) NewMaxNbEntries = mMaxNbEntries + MAX_RESERVE_GROWTH_SIZE;
  119. if (NewMaxNbEntries < mCurNbEntries + needed) NewMaxNbEntries = mCurNbEntries + needed;
  120. // Get some bytes for new entries
  121. udword* NewEntries = new udword[NewMaxNbEntries];
  122. CHECKALLOC(NewEntries);
  123. // Copy old data if needed
  124. if(mCurNbEntries) CopyMemory(NewEntries, mEntries, mCurNbEntries*sizeof(udword));
  125. // Delete old data
  126. DELETEARRAY(mEntries);
  127. // Assign new pointer
  128. mEntries = NewEntries;
  129. mMaxNbEntries = NewMaxNbEntries;
  130. #ifdef CONTAINER_STATS
  131. // Add current amount of bytes
  132. mUsedRam+=mMaxNbEntries*sizeof(udword);
  133. #endif
  134. return true;
  135. }
  136. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  137. /**
  138. * Sets the initial size of the container. If it already contains something, it's discarded.
  139. * \param nb [in] Number of entries
  140. * \return true if success
  141. */
  142. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  143. bool Container::SetSize(udword nb)
  144. {
  145. // Make sure it's empty
  146. Empty();
  147. // Checkings
  148. if(!nb) return false;
  149. // Initialize for nb entries
  150. mMaxNbEntries = nb;
  151. // Get some bytes for new entries
  152. mEntries = new udword[mMaxNbEntries];
  153. CHECKALLOC(mEntries);
  154. #ifdef CONTAINER_STATS
  155. // Add current amount of bytes
  156. mUsedRam+=mMaxNbEntries*sizeof(udword);
  157. #endif
  158. return true;
  159. }
  160. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  161. /**
  162. * Refits the container and get rid of unused bytes.
  163. * \return true if success
  164. */
  165. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  166. bool Container::Refit()
  167. {
  168. #ifdef CONTAINER_STATS
  169. // Subtract previous amount of bytes
  170. mUsedRam-=mMaxNbEntries*sizeof(udword);
  171. #endif
  172. // Get just enough entries
  173. mMaxNbEntries = mCurNbEntries;
  174. if(!mMaxNbEntries) return false;
  175. // Get just enough bytes
  176. udword* NewEntries = new udword[mMaxNbEntries];
  177. CHECKALLOC(NewEntries);
  178. #ifdef CONTAINER_STATS
  179. // Add current amount of bytes
  180. mUsedRam+=mMaxNbEntries*sizeof(udword);
  181. #endif
  182. // Copy old data
  183. CopyMemory(NewEntries, mEntries, mCurNbEntries*sizeof(udword));
  184. // Delete old data
  185. DELETEARRAY(mEntries);
  186. // Assign new pointer
  187. mEntries = NewEntries;
  188. return true;
  189. }
  190. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  191. /**
  192. * Checks whether the container already contains a given value.
  193. * \param entry [in] the value to look for in the container
  194. * \param location [out] a possible pointer to store the entry location
  195. * \see Add(udword entry)
  196. * \see Add(float entry)
  197. * \see Empty()
  198. * \return true if the value has been found in the container, else false.
  199. */
  200. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  201. bool Container::Contains(udword entry, udword* location) const
  202. {
  203. // Look for the entry
  204. for(udword i=0;i<mCurNbEntries;i++)
  205. {
  206. if(mEntries[i]==entry)
  207. {
  208. if(location) *location = i;
  209. return true;
  210. }
  211. }
  212. return false;
  213. }
  214. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  215. /**
  216. * Deletes an entry. If the container contains such an entry, it's removed.
  217. * \param entry [in] the value to delete.
  218. * \return true if the value has been found in the container, else false.
  219. * \warning This method is arbitrary slow (O(n)) and should be used carefully. Insertion order is not preserved.
  220. */
  221. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  222. bool Container::Delete(udword entry)
  223. {
  224. // Look for the entry
  225. for(udword i=0;i<mCurNbEntries;i++)
  226. {
  227. if(mEntries[i]==entry)
  228. {
  229. // Entry has been found at index i. The strategy is to copy the last current entry at index i, and decrement the current number of entries.
  230. DeleteIndex(i);
  231. return true;
  232. }
  233. }
  234. return false;
  235. }
  236. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  237. /**
  238. * Deletes an entry, preserving the insertion order. If the container contains such an entry, it's removed.
  239. * \param entry [in] the value to delete.
  240. * \return true if the value has been found in the container, else false.
  241. * \warning This method is arbitrary slow (O(n)) and should be used carefully.
  242. */
  243. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  244. bool Container::DeleteKeepingOrder(udword entry)
  245. {
  246. // Look for the entry
  247. for(udword i=0;i<mCurNbEntries;i++)
  248. {
  249. if(mEntries[i]==entry)
  250. {
  251. // Entry has been found at index i.
  252. // Shift entries to preserve order. You really should use a linked list instead.
  253. mCurNbEntries--;
  254. for(udword j=i;j<mCurNbEntries;j++)
  255. {
  256. mEntries[j] = mEntries[j+1];
  257. }
  258. return true;
  259. }
  260. }
  261. return false;
  262. }
  263. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  264. /**
  265. * Gets the next entry, starting from input one.
  266. * \param entry [in/out] On input, the entry to look for. On output, the next entry
  267. * \param find_mode [in] wrap/clamp
  268. * \return Self-Reference
  269. */
  270. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  271. Container& Container::FindNext(udword& entry, FindMode find_mode)
  272. {
  273. udword Location;
  274. if(Contains(entry, &Location))
  275. {
  276. Location++;
  277. if(Location==mCurNbEntries) Location = find_mode==FIND_WRAP ? 0 : mCurNbEntries-1;
  278. entry = mEntries[Location];
  279. }
  280. return *this;
  281. }
  282. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  283. /**
  284. * Gets the previous entry, starting from input one.
  285. * \param entry [in/out] On input, the entry to look for. On output, the previous entry
  286. * \param find_mode [in] wrap/clamp
  287. * \return Self-Reference
  288. */
  289. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  290. Container& Container::FindPrev(udword& entry, FindMode find_mode)
  291. {
  292. udword Location;
  293. if(Contains(entry, &Location))
  294. {
  295. Location--;
  296. if(Location==0xffffffff) Location = find_mode==FIND_WRAP ? mCurNbEntries-1 : 0;
  297. entry = mEntries[Location];
  298. }
  299. return *this;
  300. }
  301. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  302. /**
  303. * Gets the ram used by the container.
  304. * \return the ram used in bytes.
  305. */
  306. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  307. udword Container::GetUsedRam() const
  308. {
  309. return sizeof(Container) + mMaxNbEntries * sizeof(udword);
  310. }
  311. /*void Container::operator=(const Container& object)
  312. {
  313. SetSize(object.GetNbEntries());
  314. CopyMemory(mEntries, object.GetEntries(), mMaxNbEntries*sizeof(udword));
  315. mCurNbEntries = mMaxNbEntries;
  316. }*/