AkKeyArray.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  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 _KEYARRAY_H_
  21. #define _KEYARRAY_H_
  22. #include <AK/Tools/Common/AkArray.h>
  23. #include <AK/Tools/Common/AkKeyDef.h>
  24. // The Key list is simply a list that may be referenced using a key
  25. // NOTE :
  26. template <class T_KEY, class T_ITEM, class U_POOL = ArrayPoolDefault, class TGrowBy = AkGrowByPolicy_DEFAULT, class TMovePolicy = AkAssignmentMovePolicy<MapStruct<T_KEY, T_ITEM> > >
  27. class CAkKeyArray : public AkArray< MapStruct<T_KEY, T_ITEM>, const MapStruct<T_KEY, T_ITEM>&, U_POOL, TGrowBy, TMovePolicy>
  28. {
  29. public:
  30. //====================================================================================================
  31. // Return NULL if the Key does not exisis
  32. // Return T_ITEM* otherwise
  33. //====================================================================================================
  34. T_ITEM* Exists(T_KEY in_Key) const
  35. {
  36. typename CAkKeyArray< T_KEY, T_ITEM, U_POOL, TGrowBy, TMovePolicy >::Iterator it = this->FindEx(in_Key);
  37. return (it != this->End()) ? &(it.pItem->item) : NULL;
  38. }
  39. public:
  40. //====================================================================================================
  41. // Sets the item referenced by the specified key and item
  42. // Return AK_Fail if the list max size was exceeded
  43. //====================================================================================================
  44. T_ITEM * Set(T_KEY in_Key, const T_ITEM & in_Item)
  45. {
  46. T_ITEM* pSearchedItem = Exists(in_Key);
  47. if (pSearchedItem)
  48. {
  49. *pSearchedItem = in_Item;
  50. }
  51. else
  52. {
  53. MapStruct<T_KEY, T_ITEM> * pStruct = this->AddLast();
  54. if (pStruct)
  55. {
  56. pStruct->key = in_Key;
  57. pStruct->item = in_Item;
  58. pSearchedItem = &(pStruct->item);
  59. }
  60. }
  61. return pSearchedItem;
  62. }
  63. T_ITEM * SetFirst(T_KEY in_Key, const T_ITEM & in_Item)
  64. {
  65. T_ITEM* pSearchedItem = Exists(in_Key);
  66. if (pSearchedItem)
  67. {
  68. *pSearchedItem = in_Item;
  69. }
  70. else
  71. {
  72. MapStruct<T_KEY, T_ITEM> * pStruct = this->Insert(0); //insert at index 0 is AddFirst.
  73. if (pStruct)
  74. {
  75. pStruct->key = in_Key;
  76. pStruct->item = in_Item;
  77. pSearchedItem = &(pStruct->item);
  78. }
  79. }
  80. return pSearchedItem;
  81. }
  82. T_ITEM * Set(T_KEY in_Key)
  83. {
  84. T_ITEM* pSearchedItem = Exists(in_Key);
  85. if (!pSearchedItem)
  86. {
  87. MapStruct<T_KEY, T_ITEM> * pStruct = this->AddLast();
  88. if (pStruct)
  89. {
  90. pStruct->key = in_Key;
  91. pSearchedItem = &(pStruct->item);
  92. }
  93. }
  94. return pSearchedItem;
  95. }
  96. // NOTE: The real definition should be
  97. // typename CAkKeyArray<T_KEY,T_ITEM,TGrowBy, TMovePolicy>::Iterator FindEx( T_KEY in_Item ) const
  98. // Typenaming the base class is a workaround for bug MTWX33123 in the new Freescale CodeWarrior.
  99. typename AkArray< MapStruct<T_KEY, T_ITEM>, const MapStruct<T_KEY, T_ITEM>&, U_POOL, TGrowBy, TMovePolicy>::Iterator FindEx(T_KEY in_Item) const
  100. {
  101. typename CAkKeyArray< T_KEY, T_ITEM, U_POOL, TGrowBy, TMovePolicy >::Iterator it = this->Begin();
  102. typename CAkKeyArray< T_KEY, T_ITEM, U_POOL, TGrowBy, TMovePolicy >::Iterator itEnd = this->End();
  103. for (; it != itEnd; ++it)
  104. {
  105. if ((*it).key == in_Item)
  106. break;
  107. }
  108. return it;
  109. }
  110. //====================================================================================================
  111. // Remove the item referenced by the specified key
  112. //====================================================================================================
  113. void Unset(T_KEY in_Key)
  114. {
  115. typename CAkKeyArray< T_KEY, T_ITEM, U_POOL, TGrowBy, TMovePolicy >::Iterator it = FindEx(in_Key);
  116. if (it != this->End())
  117. {
  118. this->Erase(it);
  119. }
  120. }
  121. //====================================================================================================
  122. // More efficient version of Unset when order is unimportant
  123. //====================================================================================================
  124. void UnsetSwap(T_KEY in_Key)
  125. {
  126. typename CAkKeyArray< T_KEY, T_ITEM, U_POOL, TGrowBy, TMovePolicy >::Iterator it = FindEx(in_Key);
  127. if (it != this->End())
  128. {
  129. this->EraseSwap(it);
  130. }
  131. }
  132. };
  133. /// Key policy for AkSortedKeyArray.
  134. template <class T_KEY, class T_ITEM> struct AkGetArrayKey
  135. {
  136. /// Default policy.
  137. static AkForceInline T_KEY & Get(T_ITEM & in_item)
  138. {
  139. return in_item.key;
  140. }
  141. };
  142. template <class T_KEY, class T_ITEM> struct AkGetArrayKeyFunc
  143. {
  144. /// Default policy.
  145. static AkForceInline T_KEY& Get(T_ITEM& in_item)
  146. {
  147. return in_item.Key();
  148. }
  149. };
  150. /// Trivial key policy for AkSortedKeyArray, when T_KEY is T_ITEM.
  151. struct AkGetArrayKeyTrivial
  152. {
  153. /// Default policy.
  154. template <class T_KEY>
  155. static AkForceInline T_KEY& Get(T_KEY& in_item)
  156. {
  157. return in_item;
  158. }
  159. };
  160. //Default comparison policy for AkSortedKeyArray.
  161. template <class T_KEY> struct AkDefaultSortedKeyCompare
  162. {
  163. public:
  164. template<class THIS_CLASS>
  165. static AkForceInline bool Lesser(THIS_CLASS*, T_KEY &a, T_KEY &b)
  166. {
  167. return a < b;
  168. }
  169. template<class THIS_CLASS>
  170. static AkForceInline bool Equal(THIS_CLASS*, T_KEY &a, T_KEY &b)
  171. {
  172. return a == b;
  173. }
  174. };
  175. /// Array of items, sorted by key. Uses binary search for lookups. BEWARE WHEN
  176. /// MODIFYING THE ARRAY USING BASE CLASS METHODS.
  177. template <class T_KEY, class T_ITEM, class U_POOL = ArrayPoolDefault, class U_KEY = AkGetArrayKey< T_KEY, T_ITEM >, class TGrowBy = AkGrowByPolicy_DEFAULT, class TMovePolicy = AkAssignmentMovePolicy<T_ITEM>, class TComparePolicy = AkDefaultSortedKeyCompare<T_KEY> >
  178. class AkSortedKeyArray : public AkArray< T_ITEM, const T_ITEM &, U_POOL, TGrowBy, TMovePolicy >
  179. {
  180. public:
  181. using base = AkArray<T_ITEM, const T_ITEM&, U_POOL, TGrowBy, TMovePolicy>;
  182. using Iterator = typename base::Iterator;
  183. AkForceInline bool Lesser(T_KEY &a, T_KEY &b) const
  184. {
  185. return TComparePolicy::Lesser((void*)this, a, b);
  186. }
  187. AkForceInline bool Equal(T_KEY &a, T_KEY &b) const
  188. {
  189. return TComparePolicy::Equal((void*)this, a, b);
  190. }
  191. T_ITEM* Exists(T_KEY in_key) const
  192. {
  193. bool bFound;
  194. T_ITEM* pItem = BinarySearch(in_key, bFound);
  195. return bFound ? pItem : NULL;
  196. }
  197. // Add an item to the list (allowing duplicate keys)
  198. T_ITEM * Add(T_KEY in_key)
  199. {
  200. T_ITEM * pItem = AddNoSetKey(in_key);
  201. // Then set the key
  202. if (pItem)
  203. U_KEY::Get(*pItem) = in_key;
  204. return pItem;
  205. }
  206. // Add an item to the list (allowing duplicate keys)
  207. T_ITEM * AddNoSetKey(T_KEY in_key)
  208. {
  209. bool bFound;
  210. return AddNoSetKey(in_key, bFound);
  211. }
  212. T_ITEM * AddNoSetKey(T_KEY in_key, bool& out_bFound)
  213. {
  214. T_ITEM * pItem = BinarySearch(in_key, out_bFound);
  215. if (pItem)
  216. {
  217. unsigned int uIdx = (unsigned int)(pItem - this->m_pItems);
  218. pItem = this->Insert(uIdx);
  219. }
  220. else
  221. {
  222. pItem = this->AddLast();
  223. }
  224. return pItem;
  225. }
  226. // Set an item in the list (returning existing item if present)
  227. T_ITEM * Set(T_KEY in_key)
  228. {
  229. bool bFound;
  230. return Set(in_key, bFound);
  231. }
  232. T_ITEM * Set(T_KEY in_key, bool & out_bExists)
  233. {
  234. T_ITEM * pItem = BinarySearch(in_key, out_bExists);
  235. if (!out_bExists)
  236. {
  237. if (pItem)
  238. {
  239. unsigned int uIdx = (unsigned int)(pItem - this->m_pItems);
  240. pItem = this->Insert(uIdx);
  241. }
  242. else
  243. {
  244. pItem = this->AddLast();
  245. }
  246. if (pItem)
  247. U_KEY::Get(*pItem) = in_key;
  248. }
  249. return pItem;
  250. }
  251. bool Unset(T_KEY in_key)
  252. {
  253. T_ITEM * pItem = Exists(in_key);
  254. if (pItem)
  255. {
  256. Iterator it;
  257. it.pItem = pItem;
  258. this->Erase(it);
  259. return true;
  260. }
  261. return false;
  262. }
  263. // WARNING: Do not use on types that need constructors or destructor called on Item objects at each creation.
  264. void Reorder(T_KEY in_OldKey, T_KEY in_NewKey, const T_ITEM & in_item)
  265. {
  266. bool bFound;
  267. T_ITEM * pItem = BinarySearch(in_OldKey, bFound);
  268. //AKASSERT( bFound );
  269. if (!bFound) return;// cannot be an assert for now.(WG-19496)
  270. unsigned int uIdx = (unsigned int)(pItem - this->m_pItems);
  271. unsigned int uLastIdx = this->Length() - 1;
  272. AKASSERT(*pItem == in_item);
  273. bool bNeedReordering = false;
  274. if (uIdx > 0) // if not first
  275. {
  276. T_ITEM * pPrevItem = this->m_pItems + (uIdx - 1);
  277. if (Lesser(in_NewKey, U_KEY::Get(*pPrevItem)))
  278. {
  279. // Check one step further
  280. if (uIdx > 1)
  281. {
  282. T_ITEM * pSecondPrevItem = this->m_pItems + (uIdx - 2);
  283. if (Lesser(U_KEY::Get(*pSecondPrevItem), in_NewKey))
  284. {
  285. return Swap(pPrevItem, pItem);
  286. }
  287. else
  288. {
  289. bNeedReordering = true;
  290. }
  291. }
  292. else
  293. {
  294. return Swap(pPrevItem, pItem);
  295. }
  296. }
  297. }
  298. if (!bNeedReordering && uIdx < uLastIdx)
  299. {
  300. T_ITEM * pNextItem = this->m_pItems + (uIdx + 1);
  301. if (Lesser(U_KEY::Get(*pNextItem), in_NewKey))
  302. {
  303. // Check one step further
  304. if (uIdx < (uLastIdx - 1))
  305. {
  306. T_ITEM * pSecondNextItem = this->m_pItems + (uIdx + 2);
  307. if (Lesser(in_NewKey, U_KEY::Get(*pSecondNextItem)))
  308. {
  309. return Swap(pNextItem, pItem);
  310. }
  311. else
  312. {
  313. bNeedReordering = true;
  314. }
  315. }
  316. else
  317. {
  318. return Swap(pNextItem, pItem);
  319. }
  320. }
  321. }
  322. if (bNeedReordering)
  323. {
  324. /////////////////////////////////////////////////////////
  325. // Faster implementation, moving only what is required.
  326. /////////////////////////////////////////////////////////
  327. unsigned int uIdxToInsert; // non initialized
  328. T_ITEM * pTargetItem = BinarySearch(in_NewKey, bFound);
  329. if (pTargetItem)
  330. {
  331. uIdxToInsert = (unsigned int)(pTargetItem - this->m_pItems);
  332. if (uIdxToInsert > uIdx)
  333. {
  334. --uIdxToInsert;// we are still in the list, don't count the item to be moved.
  335. }
  336. }
  337. else
  338. {
  339. uIdxToInsert = uLastIdx;
  340. }
  341. T_ITEM * pStartItem = this->m_pItems + uIdx;
  342. T_ITEM * pEndItem = this->m_pItems + uIdxToInsert;
  343. if (uIdxToInsert < uIdx)
  344. {
  345. // Slide backward.
  346. while (pStartItem != pEndItem)
  347. {
  348. --pStartItem;
  349. pStartItem[1] = pStartItem[0];
  350. }
  351. }
  352. else
  353. {
  354. // Slide forward.
  355. while (pStartItem != pEndItem)
  356. {
  357. pStartItem[0] = pStartItem[1];
  358. ++pStartItem;
  359. }
  360. }
  361. pEndItem[0] = in_item;
  362. ///////////////////////////////////////////////
  363. }
  364. }
  365. // WARNING: Do not use on types that need constructors or destructor called on Item objects at each creation.
  366. void ReSortArray() //To be used when the < > operator changed meaning.
  367. {
  368. AkInt32 NumItemsToReInsert = this->Length();
  369. if (NumItemsToReInsert != 0)
  370. {
  371. // Do a re-insertion sort.
  372. // Fool the table by faking it is empty, then re-insert one by one.
  373. T_ITEM * pReinsertionItem = this->m_pItems;
  374. this->m_uLength = 0; // Faking the Array Is Empty.
  375. for (AkInt32 idx = 0; idx < NumItemsToReInsert; ++idx)
  376. {
  377. T_ITEM ItemtoReinsert = pReinsertionItem[idx]; // make a copy as the source is about to be overriden.
  378. T_KEY keyToReinsert = U_KEY::Get(ItemtoReinsert);
  379. T_ITEM* pInsertionEmplacement = AddNoSetKey(keyToReinsert);
  380. AKASSERT(pInsertionEmplacement);
  381. *pInsertionEmplacement = ItemtoReinsert;
  382. }
  383. }
  384. }
  385. // If found, returns the first item it encounters, if not, returns the insertion point.
  386. T_ITEM * BinarySearch( T_KEY in_key, bool & out_bFound ) const
  387. {
  388. AkUInt32 uNumToSearch = this->Length();
  389. AkInt32 iBase = 0;
  390. AkInt32 iPivot = 0;
  391. while ( uNumToSearch > 0 )
  392. {
  393. iPivot = iBase + ( uNumToSearch >> 1 );
  394. T_KEY pivotKey = U_KEY::Get( this->m_pItems[ iPivot ] );
  395. if ( Equal( pivotKey, in_key ) )
  396. {
  397. out_bFound = true;
  398. return this->m_pItems + iPivot;
  399. }
  400. if ( Lesser( pivotKey, in_key ) )
  401. {
  402. iBase = iPivot + 1;
  403. uNumToSearch--;
  404. }
  405. uNumToSearch >>= 1;
  406. }
  407. out_bFound = false;
  408. return this->m_pItems + iBase;
  409. }
  410. T_ITEM* LowerBounds(T_KEY in_key) const
  411. {
  412. return LowerBounds(in_key, this->Begin(), this->End());
  413. }
  414. // Returns the first item in the array that is not less than the key,
  415. // or the insertion point, if no key is less then in_key.
  416. T_ITEM* LowerBounds(T_KEY in_key, Iterator in_from, Iterator in_to) const
  417. {
  418. AKASSERT(in_to.pItem >= in_from.pItem);
  419. AkUInt32 uBase = (AkUInt32)(in_from.pItem - this->m_pItems);
  420. AkInt64 uNumToSearch = (AkInt64)(in_to.pItem - in_from.pItem);
  421. AkUInt32 uPivot;
  422. while (uNumToSearch > 0)
  423. {
  424. uPivot = uBase + (AkUInt32)(uNumToSearch >> 1);
  425. T_KEY pivotKey = U_KEY::Get(this->m_pItems[uPivot]);
  426. if (Lesser(pivotKey, in_key))
  427. {
  428. uBase = uPivot + 1;
  429. uNumToSearch--;
  430. }
  431. uNumToSearch >>= 1;
  432. }
  433. return this->m_pItems + uBase;
  434. }
  435. AkForceInline void Swap(T_ITEM * in_ItemA, T_ITEM * in_ItemB)
  436. {
  437. T_ITEM ItemTemp = *in_ItemA;
  438. *in_ItemA = *in_ItemB;
  439. *in_ItemB = ItemTemp;
  440. }
  441. };
  442. #endif //_KEYARRAY_H_