AkHashList.h 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231
  1. /*******************************************************************************
  2. The content of this file includes portions of the AUDIOKINETIC Wwise Technology
  3. released in source code form as part of the SDK installer package.
  4. Commercial License Usage
  5. Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology
  6. may use this file in accordance with the end user license agreement provided
  7. with the software or, alternatively, in accordance with the terms contained in a
  8. written agreement between you and Audiokinetic Inc.
  9. Apache License Usage
  10. Alternatively, this file may be used under the Apache License, Version 2.0 (the
  11. "Apache License"); you may not use this file except in compliance with the
  12. Apache License. You may obtain a copy of the Apache License at
  13. http://www.apache.org/licenses/LICENSE-2.0.
  14. Unless required by applicable law or agreed to in writing, software distributed
  15. under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
  16. OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
  17. the specific language governing permissions and limitations under the License.
  18. Copyright (c) 2023 Audiokinetic Inc.
  19. *******************************************************************************/
  20. #ifndef _AKHASHLIST_H
  21. #define _AKHASHLIST_H
  22. #include <AK/Tools/Common/AkKeyDef.h>// for MapStruct
  23. #include <AK/Tools/Common/AkObject.h>
  24. #include <AK/Tools/Common/AkArray.h>
  25. // NOTE: when using this template, a hashing function of the following form must be available:
  26. //
  27. // AkHashType AkHash( T_KEY );
  28. typedef AkUInt32 AkHashType;
  29. template < class T_KEY >
  30. AkForceInline AkHashType AkHash(T_KEY in_key) { return (AkHashType)in_key; }
  31. #define AK_HASH_SIZE_VERY_SMALL 11
  32. static const AkHashType kHashSizes[] = { 29, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 };
  33. static const size_t kNumHashSizes = sizeof(kHashSizes) / sizeof(kHashSizes[0]);
  34. static const AkReal32 kHashTableGrowthFactor = 0.9f;
  35. template < class T_KEY, class T_ITEM, typename T_ALLOC = ArrayPoolDefault >
  36. class AkHashList: public T_ALLOC
  37. {
  38. public:
  39. struct Item
  40. {
  41. Item * pNextItem; // our next one
  42. MapStruct<T_KEY, T_ITEM> Assoc; // key-item association
  43. };
  44. typedef AkArray<Item*, Item*, T_ALLOC, AkGrowByPolicy_NoGrow > HashTableArray;
  45. struct Iterator
  46. {
  47. typename AkHashList<T_KEY,T_ITEM,T_ALLOC>::HashTableArray* pTable;
  48. AkHashType uiTable;
  49. Item* pItem;
  50. inline Iterator& operator++()
  51. {
  52. AKASSERT( pItem );
  53. pItem = pItem->pNextItem;
  54. while ( ( pItem == NULL ) && ( ++uiTable < pTable->Length() ) )
  55. pItem = (*pTable)[ uiTable ];
  56. return *this;
  57. }
  58. inline MapStruct<T_KEY, T_ITEM>& operator*()
  59. {
  60. AKASSERT( pItem );
  61. return pItem->Assoc;
  62. }
  63. inline MapStruct<T_KEY, T_ITEM>* operator->()
  64. {
  65. AKASSERT(pItem);
  66. return &pItem->Assoc;
  67. }
  68. bool operator ==(const Iterator& in_rOp) const
  69. {
  70. return pItem == in_rOp.pItem;
  71. }
  72. bool operator !=( const Iterator& in_rOp ) const
  73. {
  74. return !operator==(in_rOp);
  75. }
  76. };
  77. struct ConstIterator
  78. {
  79. const typename AkHashList<T_KEY, T_ITEM, T_ALLOC>::HashTableArray* pTable;
  80. AkHashType uiTable;
  81. Item* pItem;
  82. inline ConstIterator& operator++()
  83. {
  84. AKASSERT(pItem);
  85. pItem = pItem->pNextItem;
  86. while ((pItem == NULL) && (++uiTable < pTable->Length()))
  87. pItem = (*pTable)[uiTable];
  88. return *this;
  89. }
  90. inline const MapStruct<T_KEY, T_ITEM>& operator*()
  91. {
  92. AKASSERT(pItem);
  93. return pItem->Assoc;
  94. }
  95. inline MapStruct<T_KEY, T_ITEM>* operator->() const
  96. {
  97. AKASSERT(pItem);
  98. return &pItem->Assoc;
  99. }
  100. bool operator ==(const ConstIterator& in_rOp) const
  101. {
  102. return pItem == in_rOp.pItem;
  103. }
  104. bool operator !=(const ConstIterator& in_rOp) const
  105. {
  106. return !operator==(in_rOp);
  107. }
  108. };
  109. // The IteratorEx iterator is intended for usage when a possible erase may occurs
  110. // when simply iterating trough a list, use the simple Iterator, it is faster and lighter.
  111. struct IteratorEx : public Iterator
  112. {
  113. Item* pPrevItem;
  114. IteratorEx& operator++()
  115. {
  116. AKASSERT( this->pItem );
  117. pPrevItem = this->pItem;
  118. this->pItem = this->pItem->pNextItem;
  119. while ((this->pItem == NULL) && (++this->uiTable < this->pTable->Length()))
  120. {
  121. pPrevItem = NULL;
  122. this->pItem = (*this->pTable)[ this->uiTable ];
  123. }
  124. return *this;
  125. }
  126. };
  127. struct ConstIteratorEx : public ConstIterator
  128. {
  129. Item* pPrevItem;
  130. ConstIteratorEx& operator++()
  131. {
  132. AKASSERT(this->pItem);
  133. pPrevItem = this->pItem;
  134. this->pItem = this->pItem->pNextItem;
  135. while ((this->pItem == NULL) && (++this->uiTable < this->pTable->Length()))
  136. {
  137. pPrevItem = NULL;
  138. this->pItem = (*this->pTable)[this->uiTable];
  139. }
  140. return *this;
  141. }
  142. };
  143. Iterator Begin()
  144. {
  145. Iterator returnedIt;
  146. if (HashSize() > 0)
  147. {
  148. returnedIt.pTable = &m_table;
  149. returnedIt.uiTable = 0;
  150. returnedIt.pItem = m_table[0];
  151. while ((returnedIt.pItem == NULL) && (++returnedIt.uiTable < HashSize()))
  152. returnedIt.pItem = m_table[returnedIt.uiTable];
  153. }
  154. else
  155. {
  156. returnedIt.pTable = NULL;
  157. returnedIt.uiTable = 0;
  158. returnedIt.pItem = NULL;
  159. }
  160. return returnedIt;
  161. }
  162. ConstIterator Begin() const
  163. {
  164. ConstIterator returnedIt;
  165. if (HashSize() > 0)
  166. {
  167. returnedIt.pTable = &m_table;
  168. returnedIt.uiTable = 0;
  169. returnedIt.pItem = m_table[0];
  170. while ((returnedIt.pItem == NULL) && (++returnedIt.uiTable < HashSize()))
  171. returnedIt.pItem = m_table[returnedIt.uiTable];
  172. }
  173. else
  174. {
  175. returnedIt.pTable = NULL;
  176. returnedIt.uiTable = 0;
  177. returnedIt.pItem = NULL;
  178. }
  179. return returnedIt;
  180. }
  181. IteratorEx BeginEx()
  182. {
  183. IteratorEx returnedIt;
  184. if (HashSize() > 0)
  185. {
  186. returnedIt.pTable = &m_table;
  187. returnedIt.uiTable = 0;
  188. returnedIt.pItem = *(m_table.Begin());
  189. returnedIt.pPrevItem = NULL;
  190. while ((returnedIt.pItem == NULL) && (++returnedIt.uiTable < HashSize()))
  191. returnedIt.pItem = m_table[returnedIt.uiTable];
  192. }
  193. else
  194. {
  195. returnedIt.pTable = NULL;
  196. returnedIt.uiTable = 0;
  197. returnedIt.pItem = NULL;
  198. }
  199. return returnedIt;
  200. }
  201. ConstIteratorEx BeginEx() const
  202. {
  203. ConstIteratorEx returnedIt;
  204. if (HashSize() > 0)
  205. {
  206. returnedIt.pTable = &m_table;
  207. returnedIt.uiTable = 0;
  208. returnedIt.pItem = *(m_table.Begin());
  209. returnedIt.pPrevItem = NULL;
  210. while ((returnedIt.pItem == NULL) && (++returnedIt.uiTable < HashSize()))
  211. returnedIt.pItem = m_table[returnedIt.uiTable];
  212. }
  213. else
  214. {
  215. returnedIt.pTable = NULL;
  216. returnedIt.uiTable = 0;
  217. returnedIt.pItem = NULL;
  218. }
  219. return returnedIt;
  220. }
  221. inline Iterator End()
  222. {
  223. Iterator returnedIt;
  224. returnedIt.pItem = NULL;
  225. return returnedIt;
  226. }
  227. inline ConstIterator End() const
  228. {
  229. ConstIterator returnedIt;
  230. returnedIt.pItem = NULL;
  231. return returnedIt;
  232. }
  233. inline IteratorEx EndEx()
  234. {
  235. IteratorEx returnedIt;
  236. returnedIt.pItem = NULL;
  237. return returnedIt;
  238. }
  239. inline ConstIterator EndEx() const
  240. {
  241. ConstIteratorEx returnedIt;
  242. returnedIt.pItem = NULL;
  243. return returnedIt;
  244. }
  245. IteratorEx FindEx( T_KEY in_Key )
  246. {
  247. IteratorEx returnedIt;
  248. if (HashSize() > 0)
  249. {
  250. returnedIt.pTable = &m_table;
  251. returnedIt.uiTable = AkHash(in_Key) % HashSize();
  252. returnedIt.pItem = m_table.Length() > 0 ? m_table[returnedIt.uiTable] : NULL;
  253. returnedIt.pPrevItem = NULL;
  254. while (returnedIt.pItem != NULL)
  255. {
  256. if (returnedIt.pItem->Assoc.key == in_Key)
  257. break;
  258. returnedIt.pPrevItem = returnedIt.pItem;
  259. returnedIt.pItem = returnedIt.pItem->pNextItem;
  260. }
  261. }
  262. else
  263. {
  264. returnedIt.pTable = NULL;
  265. returnedIt.uiTable = 0;
  266. returnedIt.pItem = NULL;
  267. returnedIt.pPrevItem = NULL;
  268. }
  269. return returnedIt;
  270. }
  271. ConstIteratorEx FindEx(T_KEY in_Key) const
  272. {
  273. ConstIteratorEx returnedIt;
  274. if (HashSize() > 0)
  275. {
  276. returnedIt.pTable = &m_table;
  277. returnedIt.uiTable = AkHash(in_Key) % HashSize();
  278. returnedIt.pItem = m_table.Length() > 0 ? m_table[returnedIt.uiTable] : NULL;
  279. returnedIt.pPrevItem = NULL;
  280. while (returnedIt.pItem != NULL)
  281. {
  282. if (returnedIt.pItem->Assoc.key == in_Key)
  283. break;
  284. returnedIt.pPrevItem = returnedIt.pItem;
  285. returnedIt.pItem = returnedIt.pItem->pNextItem;
  286. }
  287. }
  288. else
  289. {
  290. returnedIt.pTable = NULL;
  291. returnedIt.uiTable = 0;
  292. returnedIt.pItem = NULL;
  293. returnedIt.pPrevItem = NULL;
  294. }
  295. return returnedIt;
  296. }
  297. AkHashList(): m_uiSize( 0 )
  298. {
  299. }
  300. ~AkHashList()
  301. {
  302. AKASSERT(m_uiSize == 0);
  303. m_table.Term();
  304. }
  305. void Term()
  306. {
  307. RemoveAll();
  308. m_table.Term();
  309. }
  310. void RemoveAll()
  311. {
  312. for (AkHashType i = 0; i < HashSize(); ++i)
  313. {
  314. Item * pItem = m_table[ i ];
  315. while ( pItem != NULL )
  316. {
  317. Item * pNextItem = pItem->pNextItem;
  318. pItem->Assoc.item.~T_ITEM();
  319. T_ALLOC::Free( pItem );
  320. pItem = pNextItem;
  321. }
  322. m_table[ i ] = NULL;
  323. }
  324. m_uiSize = 0;
  325. }
  326. T_ITEM * Exists( T_KEY in_Key )
  327. {
  328. if (HashSize() > 0)
  329. {
  330. AkUIntPtr uiTable = AkHash(in_Key) % HashSize();
  331. return ExistsInList(in_Key, uiTable);
  332. }
  333. return NULL;
  334. }
  335. // Set using an externally preallocated Item -- Hash list takes ownership of the Item.
  336. T_ITEM * Set( Item * in_pItem )
  337. {
  338. if (CheckSize())
  339. {
  340. AkHashType uiTable = AkHash(in_pItem->Assoc.key) % HashSize();
  341. AKASSERT(!ExistsInList(in_pItem->Assoc.key, uiTable)); // Item must not exist in list !
  342. // Add new entry
  343. in_pItem->pNextItem = m_table[uiTable];
  344. m_table[uiTable] = in_pItem;
  345. ++m_uiSize;
  346. return &(in_pItem->Assoc.item);
  347. }
  348. return NULL;
  349. }
  350. T_ITEM * Set( T_KEY in_Key )
  351. {
  352. if ( CheckSize() )
  353. {
  354. AkUIntPtr uiTable = AkHash(in_Key) % HashSize();
  355. T_ITEM * pItem = ExistsInList(in_Key, uiTable);
  356. if (pItem)
  357. return pItem;
  358. return CreateEntry(in_Key, uiTable);
  359. }
  360. return NULL;
  361. }
  362. T_ITEM * Set( T_KEY in_Key, bool& out_bWasAlreadyThere )
  363. {
  364. if (CheckSize())
  365. {
  366. AkHashType uiTable = AkHash(in_Key) % HashSize();
  367. T_ITEM * pItem = ExistsInList(in_Key, uiTable);
  368. if (pItem)
  369. {
  370. out_bWasAlreadyThere = true;
  371. return pItem;
  372. }
  373. else
  374. {
  375. out_bWasAlreadyThere = false;
  376. }
  377. return CreateEntry(in_Key, uiTable);
  378. }
  379. return NULL;
  380. }
  381. void Unset( T_KEY in_Key )
  382. {
  383. if (HashSize() > 0)
  384. {
  385. AkHashType uiTable = AkHash(in_Key) % HashSize();
  386. Item * pItem = m_table[uiTable];
  387. Item * pPrevItem = NULL;
  388. while (pItem != NULL)
  389. {
  390. if (pItem->Assoc.key == in_Key)
  391. break;
  392. pPrevItem = pItem;
  393. pItem = pItem->pNextItem;
  394. }
  395. if (pItem)
  396. RemoveItem(uiTable, pItem, pPrevItem);
  397. }
  398. }
  399. IteratorEx Erase( const IteratorEx& in_rIter )
  400. {
  401. IteratorEx returnedIt;
  402. returnedIt.pTable = in_rIter.pTable;
  403. returnedIt.uiTable = in_rIter.uiTable;
  404. returnedIt.pItem = in_rIter.pItem->pNextItem;
  405. returnedIt.pPrevItem = in_rIter.pPrevItem;
  406. while ( ( returnedIt.pItem == NULL ) && ( ++returnedIt.uiTable < HashSize() ) )
  407. {
  408. returnedIt.pPrevItem = NULL;
  409. returnedIt.pItem = (*returnedIt.pTable)[returnedIt.uiTable];
  410. }
  411. RemoveItem( in_rIter.uiTable, in_rIter.pItem, in_rIter.pPrevItem );
  412. return returnedIt;
  413. }
  414. void RemoveItem( AkHashType in_uiTable, Item* in_pItem, Item* in_pPrevItem )
  415. {
  416. if( in_pPrevItem )
  417. in_pPrevItem->pNextItem = in_pItem->pNextItem;
  418. else
  419. m_table[ in_uiTable ] = in_pItem->pNextItem;
  420. in_pItem->Assoc.item.~T_ITEM();
  421. T_ALLOC::Free(in_pItem);
  422. --m_uiSize;
  423. }
  424. AkUInt32 Length() const
  425. {
  426. return m_uiSize;
  427. }
  428. AKRESULT Reserve(AkUInt32 in_uNumberOfEntires)
  429. {
  430. if ((HashSize() == 0) || (AkReal32)in_uNumberOfEntires / (AkReal32)HashSize() > kHashTableGrowthFactor)
  431. return Resize((AkUInt32)((AkReal32)in_uNumberOfEntires / kHashTableGrowthFactor));
  432. return AK_Success;
  433. }
  434. AKRESULT Resize(AkUInt32 in_uExpectedNumberOfEntires)
  435. {
  436. AKRESULT res = AK_Fail;
  437. AkUInt32 uNewSize = 0;
  438. for (AkUInt32 i = 0; i < kNumHashSizes; ++i)
  439. {
  440. if (kHashSizes[i] > in_uExpectedNumberOfEntires)
  441. {
  442. uNewSize = kHashSizes[i];
  443. break;
  444. }
  445. }
  446. if (uNewSize > 0)
  447. {
  448. HashTableArray oldArray;
  449. oldArray.Transfer(m_table);
  450. if ( m_table.GrowArray(uNewSize) )
  451. {
  452. for (AkUInt32 i = 0; i < uNewSize; i++)
  453. m_table.AddLast(NULL);
  454. for (AkUInt32 i = 0; i < oldArray.Length(); i++)
  455. {
  456. Item * pItem = oldArray[i];
  457. while (pItem != NULL)
  458. {
  459. Item * pNextItem = pItem->pNextItem;
  460. {
  461. AkHashType uiTable = AkHash(pItem->Assoc.key) % HashSize();
  462. pItem->pNextItem = m_table[uiTable];
  463. m_table[uiTable] = pItem;
  464. }
  465. pItem = pNextItem;
  466. }
  467. }
  468. oldArray.Term();
  469. res = AK_Success;
  470. }
  471. else
  472. {
  473. //Backpedal..
  474. m_table.Transfer(oldArray);
  475. }
  476. }
  477. return res;
  478. }
  479. inline AkUInt32 HashSize() const
  480. {
  481. return m_table.Length();
  482. }
  483. inline bool CheckSize()
  484. {
  485. if ( HashSize() == 0 || (AkReal32)m_uiSize / (AkReal32)HashSize() > kHashTableGrowthFactor )
  486. Resize(HashSize());
  487. return (HashSize() > 0);
  488. }
  489. void Transfer(AkHashList< T_KEY, T_ITEM, T_ALLOC >& in_source)
  490. {
  491. Term();
  492. m_table.Transfer(in_source.m_table);
  493. m_uiSize = in_source.m_uiSize;
  494. in_source.m_uiSize = 0;
  495. }
  496. protected:
  497. T_ITEM * ExistsInList( T_KEY in_Key, AkUIntPtr in_uiTable )
  498. {
  499. AKASSERT(HashSize() > 0);
  500. Item * pItem = m_table[(AkUInt32)in_uiTable];
  501. while (pItem != NULL)
  502. {
  503. if (pItem->Assoc.key == in_Key)
  504. return &(pItem->Assoc.item); // found
  505. pItem = pItem->pNextItem;
  506. }
  507. return NULL; // not found
  508. }
  509. T_ITEM * CreateEntry( T_KEY in_Key, AkUIntPtr in_uiTable )
  510. {
  511. Item * pNewItem = (Item *)T_ALLOC::Alloc(sizeof(Item));
  512. if ( pNewItem == NULL )
  513. return NULL;
  514. pNewItem->pNextItem = m_table[ (AkUInt32)in_uiTable ];
  515. pNewItem->Assoc.key = in_Key;
  516. AkPlacementNew( &(pNewItem->Assoc.item) ) T_ITEM;
  517. m_table[(AkUInt32)in_uiTable] = pNewItem;
  518. ++m_uiSize;
  519. return &(pNewItem->Assoc.item);
  520. }
  521. HashTableArray m_table;
  522. AkUInt32 m_uiSize;
  523. };
  524. // this one lets you define the structure
  525. // only requirement is that T_MAPSTRUCT must have members pNextItem and key.
  526. // client is responsible for allocation/deallocation of T_MAPSTRUCTS.
  527. template <class T_KEY, class T_MAPSTRUCT>
  528. struct AkHashListBareMemberPolicy
  529. {
  530. static const T_KEY& Key(const T_MAPSTRUCT* in_pItem) {return in_pItem->key;}
  531. static T_MAPSTRUCT*& Next(T_MAPSTRUCT* in_pItem) { return (*in_pItem).pNextItem; }
  532. };
  533. template <class T_KEY, class T_MAPSTRUCT>
  534. struct AkHashListBareFuncPolicy
  535. {
  536. static const T_KEY& Key(const T_MAPSTRUCT* in_pItem) { return in_pItem->Key(); }
  537. static T_MAPSTRUCT*& Next(T_MAPSTRUCT* in_pItem) { return (*in_pItem).pNextItem; }
  538. };
  539. template <class T_KEY, class T_MAPSTRUCT>
  540. using AkDefaultHashListBarePolicy = AkHashListBareMemberPolicy<T_KEY, T_MAPSTRUCT>;
  541. template <class T_KEY, class T_MAPSTRUCT, typename T_ALLOC = ArrayPoolDefault, class KEY_POLICY = AkDefaultHashListBarePolicy<T_KEY, T_MAPSTRUCT>, class LIST_POLICY = AkDefaultHashListBarePolicy<T_KEY, T_MAPSTRUCT>>
  542. class AkHashListBare
  543. {
  544. typedef AkArray<T_MAPSTRUCT*, T_MAPSTRUCT*, T_ALLOC, AkGrowByPolicy_NoGrow > HashTableArray;
  545. public:
  546. struct Iterator
  547. {
  548. typename AkHashListBare<T_KEY,T_MAPSTRUCT,T_ALLOC,KEY_POLICY,LIST_POLICY>::HashTableArray* pTable;
  549. AkHashType uiTable;
  550. T_MAPSTRUCT* pItem;
  551. inline Iterator& operator++()
  552. {
  553. AKASSERT( pItem );
  554. pItem = LIST_POLICY::Next(pItem);
  555. while ((pItem == NULL) && (++uiTable < pTable->Length()))
  556. pItem = (*pTable)[ uiTable ];
  557. return *this;
  558. }
  559. inline T_MAPSTRUCT * operator*()
  560. {
  561. AKASSERT( pItem );
  562. return pItem;
  563. }
  564. inline T_MAPSTRUCT* operator->()
  565. {
  566. AKASSERT(pItem);
  567. return pItem;
  568. }
  569. bool operator !=( const Iterator& in_rOp ) const
  570. {
  571. return ( pItem != in_rOp.pItem );
  572. }
  573. bool operator ==(const Iterator& in_rOp) const
  574. {
  575. return (pItem == in_rOp.pItem);
  576. }
  577. };
  578. struct ConstIterator
  579. {
  580. const typename AkHashListBare<T_KEY, T_MAPSTRUCT, T_ALLOC, KEY_POLICY>::HashTableArray* pTable;
  581. AkHashType uiTable;
  582. T_MAPSTRUCT* pItem;
  583. inline ConstIterator& operator++()
  584. {
  585. AKASSERT(pItem);
  586. pItem = pItem->pNextItem;
  587. while ((pItem == NULL) && (++uiTable < pTable->Length()))
  588. pItem = (*pTable)[uiTable];
  589. return *this;
  590. }
  591. inline const T_MAPSTRUCT* operator*()
  592. {
  593. AKASSERT(pItem);
  594. return pItem;
  595. }
  596. inline const T_MAPSTRUCT* operator->() const
  597. {
  598. AKASSERT(pItem);
  599. return pItem;
  600. }
  601. bool operator !=(const ConstIterator& in_rOp) const
  602. {
  603. return (pItem != in_rOp.pItem);
  604. }
  605. bool operator ==(const ConstIterator& in_rOp) const
  606. {
  607. return (pItem == in_rOp.pItem);
  608. }
  609. };
  610. // The IteratorEx iterator is intended for usage when a possible erase may occurs
  611. // when simply iterating trough a list, use the simple Iterator, it is faster and lighter.
  612. struct IteratorEx : public Iterator
  613. {
  614. T_MAPSTRUCT* pPrevItem;
  615. IteratorEx& operator++()
  616. {
  617. AKASSERT(this->pItem);
  618. pPrevItem = this->pItem;
  619. this->pItem = this->pItem->pNextItem;
  620. while ((this->pItem == NULL) && (++this->uiTable < this->pTable->Length()))
  621. {
  622. pPrevItem = NULL;
  623. this->pItem = (*this->pTable)[this->uiTable];
  624. }
  625. return *this;
  626. }
  627. };
  628. struct ConstIteratorEx : public ConstIterator
  629. {
  630. T_MAPSTRUCT* pPrevItem;
  631. ConstIteratorEx& operator++()
  632. {
  633. AKASSERT( this->pItem );
  634. pPrevItem = this->pItem;
  635. this->pItem = LIST_POLICY::Next(this->pItem);
  636. while ( ( this->pItem == NULL ) && ( ++this->uiTable < this->pTable->Length() ) )
  637. {
  638. pPrevItem = NULL;
  639. this->pItem = (*this->pTable)[ this->uiTable ];
  640. }
  641. return *this;
  642. }
  643. };
  644. Iterator Begin()
  645. {
  646. Iterator returnedIt;
  647. if (HashSize() > 0)
  648. {
  649. returnedIt.pTable = &m_table;
  650. returnedIt.uiTable = 0;
  651. returnedIt.pItem = m_table[0];
  652. while ((returnedIt.pItem == NULL) && (++returnedIt.uiTable < HashSize()))
  653. returnedIt.pItem = m_table[returnedIt.uiTable];
  654. }
  655. else
  656. {
  657. returnedIt.pTable = NULL;
  658. returnedIt.uiTable = 0;
  659. returnedIt.pItem = NULL;
  660. }
  661. return returnedIt;
  662. }
  663. ConstIterator Begin() const
  664. {
  665. ConstIterator returnedIt;
  666. if (HashSize() > 0)
  667. {
  668. returnedIt.pTable = &m_table;
  669. returnedIt.uiTable = 0;
  670. returnedIt.pItem = m_table[0];
  671. while ((returnedIt.pItem == NULL) && (++returnedIt.uiTable < HashSize()))
  672. returnedIt.pItem = m_table[returnedIt.uiTable];
  673. }
  674. else
  675. {
  676. returnedIt.pTable = NULL;
  677. returnedIt.uiTable = 0;
  678. returnedIt.pItem = NULL;
  679. }
  680. return returnedIt;
  681. }
  682. IteratorEx BeginEx()
  683. {
  684. IteratorEx returnedIt;
  685. if (HashSize() > 0)
  686. {
  687. returnedIt.pTable = &m_table;
  688. returnedIt.uiTable = 0;
  689. returnedIt.pItem = m_table[0];
  690. returnedIt.pPrevItem = NULL;
  691. while ( ( returnedIt.pItem == NULL ) && ( ++returnedIt.uiTable < HashSize() ) )
  692. returnedIt.pItem = m_table[ returnedIt.uiTable ];
  693. }
  694. else
  695. {
  696. returnedIt.pTable = NULL;
  697. returnedIt.uiTable = 0;
  698. returnedIt.pItem = NULL;
  699. returnedIt.pPrevItem = NULL;
  700. }
  701. return returnedIt;
  702. }
  703. ConstIteratorEx BeginEx() const
  704. {
  705. ConstIteratorEx returnedIt;
  706. if (HashSize() > 0)
  707. {
  708. returnedIt.pTable = &m_table;
  709. returnedIt.uiTable = 0;
  710. returnedIt.pItem = m_table[0];
  711. returnedIt.pPrevItem = NULL;
  712. while ((returnedIt.pItem == NULL) && (++returnedIt.uiTable < HashSize()))
  713. returnedIt.pItem = m_table[returnedIt.uiTable];
  714. }
  715. else
  716. {
  717. returnedIt.pTable = NULL;
  718. returnedIt.uiTable = 0;
  719. returnedIt.pItem = NULL;
  720. returnedIt.pPrevItem = NULL;
  721. }
  722. return returnedIt;
  723. }
  724. inline Iterator End()
  725. {
  726. Iterator returnedIt;
  727. returnedIt.pItem = NULL;
  728. return returnedIt;
  729. }
  730. inline ConstIterator End() const
  731. {
  732. ConstIterator returnedIt;
  733. returnedIt.pItem = NULL;
  734. return returnedIt;
  735. }
  736. IteratorEx FindEx( T_KEY in_Key )
  737. {
  738. IteratorEx returnedIt;
  739. if (HashSize() > 0)
  740. {
  741. returnedIt.pTable = &m_table;
  742. returnedIt.uiTable = AkHash(in_Key) % HashSize();
  743. returnedIt.pItem = m_table[returnedIt.uiTable];
  744. returnedIt.pPrevItem = NULL;
  745. while (returnedIt.pItem != NULL)
  746. {
  747. if (KEY_POLICY::Key(returnedIt.pItem) == in_Key)
  748. break;
  749. returnedIt.pPrevItem = returnedIt.pItem;
  750. returnedIt.pItem = LIST_POLICY::Next(returnedIt.pItem);
  751. }
  752. }
  753. else
  754. {
  755. returnedIt.pTable = NULL;
  756. returnedIt.uiTable = 0;
  757. returnedIt.pItem = NULL;
  758. returnedIt.pPrevItem = NULL;
  759. }
  760. return returnedIt;
  761. }
  762. ConstIteratorEx FindEx(T_KEY in_Key) const
  763. {
  764. ConstIteratorEx returnedIt;
  765. if (HashSize() > 0)
  766. {
  767. returnedIt.pTable = &m_table;
  768. returnedIt.uiTable = AkHash(in_Key) % HashSize();
  769. returnedIt.pItem = m_table[returnedIt.uiTable];
  770. returnedIt.pPrevItem = NULL;
  771. while (returnedIt.pItem != NULL)
  772. {
  773. if (KEY_POLICY::Key(returnedIt.pItem) == in_Key)
  774. break;
  775. returnedIt.pPrevItem = returnedIt.pItem;
  776. returnedIt.pItem = returnedIt.pItem->pNextItem;
  777. }
  778. }
  779. else
  780. {
  781. returnedIt.pTable = NULL;
  782. returnedIt.uiTable = 0;
  783. returnedIt.pItem = NULL;
  784. returnedIt.pPrevItem = NULL;
  785. }
  786. return returnedIt;
  787. }
  788. AkHashListBare()
  789. : m_uiSize( 0 )
  790. {
  791. }
  792. ~AkHashListBare()
  793. {
  794. }
  795. //If you set 0 as the starting size, you *must* check all returns of Set() calls.
  796. //If you initialize with anything else, you can ignore return codes of Set(), they will always succeed.
  797. bool Init(AkUInt32 in_iStartingSize)
  798. {
  799. m_uiSize = 0;
  800. if(!m_table.Resize(in_iStartingSize))
  801. return false;
  802. for ( AkHashType i = 0; i < HashSize(); ++i )
  803. m_table[ i ] = NULL;
  804. return true;
  805. }
  806. void Term()
  807. {
  808. AKASSERT( m_uiSize == 0 );
  809. m_table.Term();
  810. }
  811. /*
  812. void RemoveAll()
  813. {
  814. for ( AkHashType i = 0; i < HashSize(); ++i )
  815. {
  816. T_MAPSTRUCT * pItem = m_table[ i ];
  817. while ( pItem != NULL )
  818. {
  819. T_MAPSTRUCT * pNextItem = LIST_POLICY::Next(pItem);
  820. pItem->~T_MAPSTRUCT();
  821. T_ALLOD::Free( pItem );
  822. pItem = pNextItem;
  823. }
  824. m_table[ i ] = NULL;
  825. }
  826. m_uiSize = 0;
  827. }
  828. */
  829. T_MAPSTRUCT * Exists( T_KEY in_Key ) const
  830. {
  831. if (HashSize() > 0)
  832. {
  833. AkHashType uiTable = AkHash(in_Key) % HashSize();
  834. return ExistsInList(in_Key, uiTable);
  835. }
  836. return NULL;
  837. }
  838. // Set using an externally preallocated T_MAPSTRUCT -- Hash list takes ownership of the T_MAPSTRUCT.
  839. bool Set( T_MAPSTRUCT * in_pItem, bool& out_exists )
  840. {
  841. out_exists = false;
  842. if (CheckSize())
  843. {
  844. AkHashType uiTable = AkHash(KEY_POLICY::Key(in_pItem)) % HashSize();
  845. if (ExistsInList(KEY_POLICY::Key(in_pItem), uiTable))
  846. {
  847. out_exists = true;
  848. return false;
  849. }
  850. _Set(in_pItem, uiTable);
  851. return true;
  852. }
  853. //This can only happen if the initial size of the map was 0.
  854. return false;
  855. }
  856. bool Set( T_MAPSTRUCT * in_pItem )
  857. {
  858. if (CheckSize())
  859. {
  860. AkHashType uiTable = AkHash(KEY_POLICY::Key(in_pItem)) % HashSize();
  861. AKASSERT(!ExistsInList(KEY_POLICY::Key(in_pItem), uiTable)); // T_MAPSTRUCT must not exist in list !
  862. _Set(in_pItem, uiTable);
  863. return true;
  864. }
  865. //This can only happen if the initial size of the map was 0.
  866. return false;
  867. }
  868. private:
  869. void _Set( T_MAPSTRUCT * in_pItem, AkHashType in_uiTable )
  870. {
  871. LIST_POLICY::Next(in_pItem) = m_table[in_uiTable];
  872. m_table[in_uiTable] = in_pItem;
  873. ++m_uiSize;
  874. }
  875. public:
  876. T_MAPSTRUCT * Unset( const T_KEY &in_Key )
  877. {
  878. T_MAPSTRUCT * pItem = NULL;
  879. if (HashSize() > 0)
  880. {
  881. AkHashType uiTable = AkHash(in_Key) % HashSize();
  882. pItem = m_table[uiTable];
  883. T_MAPSTRUCT * pPrevItem = NULL;
  884. while (pItem != NULL)
  885. {
  886. if (KEY_POLICY::Key(pItem) == in_Key)
  887. break;
  888. pPrevItem = pItem;
  889. pItem = LIST_POLICY::Next(pItem);
  890. }
  891. if (pItem)
  892. RemoveItem(uiTable, pItem, pPrevItem);
  893. }
  894. return pItem;
  895. }
  896. IteratorEx Erase( const IteratorEx& in_rIter )
  897. {
  898. IteratorEx returnedIt;
  899. returnedIt.pTable = in_rIter.pTable;
  900. returnedIt.uiTable = in_rIter.uiTable;
  901. returnedIt.pItem = LIST_POLICY::Next(in_rIter.pItem);
  902. returnedIt.pPrevItem = in_rIter.pPrevItem;
  903. while ((returnedIt.pItem == NULL) && (++returnedIt.uiTable < returnedIt.pTable->Length()))
  904. {
  905. returnedIt.pPrevItem = NULL;
  906. returnedIt.pItem = (*returnedIt.pTable)[ returnedIt.uiTable ];
  907. }
  908. RemoveItem( in_rIter.uiTable, in_rIter.pItem, in_rIter.pPrevItem );
  909. return returnedIt;
  910. }
  911. AkUInt32 Length() const
  912. {
  913. return m_uiSize;
  914. }
  915. AKRESULT Reserve(AkUInt32 in_uNumberOfEntires)
  916. {
  917. if ((HashSize() == 0) || (AkReal32)in_uNumberOfEntires / (AkReal32)HashSize() > kHashTableGrowthFactor)
  918. return Resize((AkUInt32)((AkReal32)in_uNumberOfEntires / kHashTableGrowthFactor));
  919. return AK_Success;
  920. }
  921. AKRESULT Resize(AkUInt32 in_uExpectedNumberOfEntires)
  922. {
  923. AKRESULT res = AK_Fail;
  924. AkHashType uNewSize = 0;
  925. for (AkUInt32 i = 0; i < kNumHashSizes; ++i)
  926. {
  927. if (kHashSizes[i] > in_uExpectedNumberOfEntires)
  928. {
  929. uNewSize = kHashSizes[i];
  930. break;
  931. }
  932. }
  933. if (uNewSize > 0)
  934. {
  935. HashTableArray oldArray;
  936. oldArray.Transfer(m_table);
  937. if (m_table.GrowArray(uNewSize))
  938. {
  939. for (AkUInt32 i = 0; i < uNewSize; i++)
  940. m_table.AddLast(NULL);
  941. for (AkUInt32 i = 0; i < oldArray.Length(); i++)
  942. {
  943. T_MAPSTRUCT* pItem = oldArray[i];
  944. while (pItem != NULL)
  945. {
  946. T_MAPSTRUCT* pNextItem = LIST_POLICY::Next(pItem);
  947. {
  948. AkHashType uiTable = AkHash(KEY_POLICY::Key(pItem)) % uNewSize;
  949. LIST_POLICY::Next(pItem) = m_table[uiTable];
  950. m_table[uiTable] = pItem;
  951. }
  952. pItem = pNextItem;
  953. }
  954. }
  955. oldArray.Term();
  956. res = AK_Success;
  957. }
  958. else
  959. {
  960. //Backpedal..
  961. m_table.Transfer(oldArray);
  962. }
  963. }
  964. return res;
  965. }
  966. inline AkHashType HashSize() const
  967. {
  968. return m_table.Length();
  969. }
  970. inline bool CheckSize()
  971. {
  972. if ( (HashSize() == 0) || (AkReal32)m_uiSize / (AkReal32)HashSize() > kHashTableGrowthFactor )
  973. Resize(HashSize());
  974. return (HashSize() > 0);
  975. }
  976. protected:
  977. void RemoveItem( AkHashType in_uiTable, T_MAPSTRUCT* in_pItem, T_MAPSTRUCT* in_pPrevItem )
  978. {
  979. if( in_pPrevItem )
  980. LIST_POLICY::Next(in_pPrevItem) = LIST_POLICY::Next(in_pItem);
  981. else
  982. m_table[ in_uiTable ] = LIST_POLICY::Next(in_pItem);
  983. --m_uiSize;
  984. }
  985. T_MAPSTRUCT * ExistsInList( T_KEY in_Key, AkHashType in_uiTable ) const
  986. {
  987. T_MAPSTRUCT * pItem = m_table[in_uiTable];
  988. while (pItem != NULL)
  989. {
  990. if (KEY_POLICY::Key(pItem) == in_Key)
  991. return pItem; // found
  992. pItem = LIST_POLICY::Next(pItem);
  993. }
  994. return NULL; // not found
  995. }
  996. HashTableArray m_table;
  997. AkUInt32 m_uiSize;
  998. };
  999. #endif // _AKHASHLIST_H