2
0

IceContainer.cpp 14 KB

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