AkArray.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886
  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 _AKARRAY_H
  21. #define _AKARRAY_H
  22. #include <AK/Tools/Common/AkObject.h>
  23. #include <AK/Tools/Common/AkAssert.h>
  24. #include <AK/Tools/Common/AkPlatformFuncs.h>
  25. #include <utility>
  26. template <AkMemID T_MEMID>
  27. struct AkArrayAllocatorNoAlign
  28. {
  29. static AkForceInline void * Alloc( size_t in_uSize )
  30. {
  31. return AkAlloc(T_MEMID, in_uSize);
  32. }
  33. static AkForceInline void * ReAlloc( void * in_pCurrent, size_t in_uOldSize, size_t in_uNewSize )
  34. {
  35. return AkRealloc(T_MEMID, in_pCurrent, in_uNewSize);
  36. }
  37. static AkForceInline void Free( void * in_pAddress )
  38. {
  39. AkFree(T_MEMID, in_pAddress);
  40. }
  41. static AkForceInline void TransferMem(void *& io_pDest, AkArrayAllocatorNoAlign<T_MEMID> in_srcAlloc, void * in_pSrc )
  42. {
  43. io_pDest = in_pSrc;
  44. }
  45. };
  46. template <AkMemID T_MEMID>
  47. struct AkArrayAllocatorAlignedSimd
  48. {
  49. AkForceInline void * Alloc( size_t in_uSize )
  50. {
  51. return AkMalign(T_MEMID, in_uSize, AK_SIMD_ALIGNMENT);
  52. }
  53. AkForceInline void * ReAlloc(void * in_pCurrent, size_t in_uOldSize, size_t in_uNewSize)
  54. {
  55. return AkReallocAligned(T_MEMID, in_pCurrent, in_uNewSize, AK_SIMD_ALIGNMENT);
  56. }
  57. AkForceInline void Free( void * in_pAddress )
  58. {
  59. AkFree(T_MEMID, in_pAddress);
  60. }
  61. AkForceInline void TransferMem(void *& io_pDest, AkArrayAllocatorAlignedSimd<T_MEMID> in_srcAlloc, void * in_pSrc )
  62. {
  63. io_pDest = in_pSrc;
  64. }
  65. };
  66. // AkHybridAllocator
  67. // Attempts to allocate from a small buffer of size uBufferSizeBytes, which is contained within the array type. Useful if the array is expected to contain a small number of elements.
  68. // If the array grows to a larger size than uBufferSizeBytes, the the memory is allocated with the specified AkMemID.
  69. // NOTE: The use of this allocator is not allowed when AkArray::TMovePolicy::IsTrivial() == false,
  70. // since TMovePolicy::Move will not be invoked in TransferMem.
  71. template< AkUInt32 uBufferSizeBytes, AkUInt8 uAlignmentSize = 1, AkMemID T_MEMID = AkMemID_Object>
  72. struct AkHybridAllocator
  73. {
  74. static const AkUInt32 _uBufferSizeBytes = uBufferSizeBytes;
  75. AkForceInline void * Alloc(size_t in_uSize)
  76. {
  77. if (in_uSize <= uBufferSizeBytes)
  78. return (void *)&m_buffer;
  79. return AkMalign(T_MEMID, in_uSize, uAlignmentSize);
  80. }
  81. AkForceInline void * ReAlloc(void * in_pCurrent, size_t in_uOldSize, size_t in_uNewSize)
  82. {
  83. if (in_uNewSize <= uBufferSizeBytes)
  84. return (void *)&m_buffer;
  85. if (&m_buffer != in_pCurrent)
  86. return AkReallocAligned(T_MEMID, in_pCurrent, in_uNewSize, uAlignmentSize);
  87. void* pAddress = AkMalign(T_MEMID, in_uNewSize, uAlignmentSize);
  88. if (!pAddress)
  89. return NULL;
  90. AKPLATFORM::AkMemCpy(pAddress, m_buffer, (AkUInt32)in_uOldSize);
  91. return pAddress;
  92. }
  93. AkForceInline void Free(void * in_pAddress)
  94. {
  95. if (&m_buffer != in_pAddress)
  96. AkFree(T_MEMID, in_pAddress);
  97. }
  98. AkForceInline void TransferMem(void *& io_pDest, AkHybridAllocator<uBufferSizeBytes, uAlignmentSize, T_MEMID>& in_srcAlloc, void * in_pSrc)
  99. {
  100. if (&in_srcAlloc.m_buffer == in_pSrc)
  101. {
  102. AKPLATFORM::AkMemCpy(m_buffer, in_srcAlloc.m_buffer, uBufferSizeBytes);
  103. io_pDest = m_buffer;
  104. }
  105. else
  106. {
  107. io_pDest = in_pSrc;
  108. }
  109. }
  110. AK_ALIGN(char m_buffer[uBufferSizeBytes], uAlignmentSize);
  111. };
  112. // Helper for AkHybridAllocator for uCount items of type T.
  113. // NOTE: The use of this allocator is not allowed when AkArray::TMovePolicy::IsTrivial() == false,
  114. // since TMovePolicy::Move will not be invoked in TransferMem.
  115. template <class T, AkUInt32 uCount = 1, AkMemID MemID = AkMemID_Object>
  116. using AkSmallArrayAllocator = AkHybridAllocator<sizeof(T)* uCount, alignof(T), MemID>;
  117. template <class T>
  118. struct AkAssignmentMovePolicy
  119. {
  120. // By default the assignment operator is invoked to move elements of an array from slot to slot. If desired,
  121. // a custom 'Move' operation can be passed into TMovePolicy to transfer ownership of resources from in_Src to in_Dest.
  122. static AkForceInline void Move( T& in_Dest, T& in_Src )
  123. {
  124. in_Dest = in_Src;
  125. }
  126. // todo: use std::is_trivially_copyable<T>::value everywhere instead
  127. // To do so, we must revise usage of the different policies first.
  128. // Until then, it is not recommended to use this policy if T is not trivially copyable.
  129. static AkForceInline bool IsTrivial()
  130. {
  131. return true;
  132. }
  133. };
  134. // AkStdMovePolicy, for non-trivially copyable types.
  135. struct AkStdMovePolicy
  136. {
  137. template <class T>
  138. static AkForceInline void Move(T&& io_Dest, T&& io_Src)
  139. {
  140. io_Dest = std::move(io_Src);
  141. }
  142. static AkForceInline bool IsTrivial()
  143. {
  144. return false;
  145. }
  146. };
  147. // AkStdMovePolicy, for trivially copyable types.
  148. struct AkTrivialStdMovePolicy
  149. {
  150. template <class T>
  151. static AkForceInline void Move(T&& io_Dest, T&& io_Src)
  152. {
  153. io_Dest = std::move(io_Src);
  154. }
  155. static AkForceInline bool IsTrivial()
  156. {
  157. return true;
  158. }
  159. };
  160. // Can be used as TMovePolicy to create arrays of arrays.
  161. template <class T>
  162. struct AkTransferMovePolicy
  163. {
  164. static AkForceInline void Move( T& in_Dest, T& in_Src )
  165. {
  166. in_Dest.Transfer(in_Src); //transfer ownership of resources.
  167. }
  168. static AkForceInline bool IsTrivial()
  169. {
  170. return false;
  171. }
  172. };
  173. // Common allocators:
  174. typedef AkArrayAllocatorNoAlign<AkMemID_Object> ArrayPoolDefault;
  175. typedef AkArrayAllocatorNoAlign<AkMemID_Processing> ArrayPoolLEngineDefault;
  176. typedef AkArrayAllocatorNoAlign<AkMemID_Profiler> ArrayPoolProfiler;
  177. typedef AkArrayAllocatorAlignedSimd<AkMemID_Processing> ArrayPoolLEngineDefaultAlignedSimd;
  178. struct AkGrowByPolicy_Legacy
  179. {
  180. static AkUInt32 GrowBy( AkUInt32 /*in_CurrentArraySize*/ ) { return 1; }
  181. };
  182. struct AkGrowByPolicy_NoGrow
  183. {
  184. static AkUInt32 GrowBy( AkUInt32 /*in_CurrentArraySize*/ ) { return 0; }
  185. };
  186. // The hybrid GrowBy policy will try to grow to exactly uCount before growing farther to prevent unneccesary allocations.
  187. // The goal is to avoid expanding past uBufferSizeBytes until you have to, then behave like AkGrowByPolicy_Proportional
  188. // uCount should be uBufferSizeBytes / sizeof(T)
  189. template <AkUInt32 uCount>
  190. struct AkGrowByPolicy_Hybrid
  191. {
  192. static AkUInt32 GrowBy(AkUInt32 in_CurrentArraySize)
  193. {
  194. if (in_CurrentArraySize < uCount)
  195. return uCount - in_CurrentArraySize;
  196. else
  197. {
  198. return in_CurrentArraySize + (in_CurrentArraySize >> 1);
  199. }
  200. }
  201. };
  202. struct AkGrowByPolicy_Proportional
  203. {
  204. static AkUInt32 GrowBy( AkUInt32 in_CurrentArraySize )
  205. {
  206. if ( in_CurrentArraySize == 0 )
  207. return 1;
  208. else
  209. return in_CurrentArraySize + ( in_CurrentArraySize >> 1 );
  210. }
  211. };
  212. //#define AkGrowByPolicy_DEFAULT AkGrowByPolicy_Legacy
  213. #define AkGrowByPolicy_DEFAULT AkGrowByPolicy_Proportional
  214. /// Specific implementation of array
  215. template <class T, class ARG_T, class TAlloc = ArrayPoolDefault, class TGrowBy = AkGrowByPolicy_DEFAULT, class TMovePolicy = AkAssignmentMovePolicy<T> > class AkArray : public TAlloc
  216. {
  217. public:
  218. /// Constructor
  219. AkArray()
  220. : m_pItems( 0 )
  221. , m_uLength( 0 )
  222. , m_ulReserved( 0 )
  223. {
  224. }
  225. /// Destructor
  226. ~AkArray()
  227. {
  228. AKASSERT( m_pItems == 0 );
  229. AKASSERT( m_uLength == 0 );
  230. AKASSERT( m_ulReserved == 0 );
  231. }
  232. // Workaround for SWIG to parse nested structure:
  233. // Bypass this inner struct and use a proxy in a separate header.
  234. #ifndef SWIG
  235. /// Iterator
  236. struct Iterator
  237. {
  238. T* pItem; ///< Pointer to the item in the array.
  239. /// + operator
  240. Iterator operator+(AkUInt32 inc) const
  241. {
  242. AKASSERT( pItem );
  243. Iterator returnedIt;
  244. returnedIt.pItem = pItem + inc;
  245. return returnedIt;
  246. }
  247. /// - operator
  248. AkUInt32 operator-(Iterator const& rhs) const
  249. {
  250. AKASSERT((pItem && rhs.pItem)||(!pItem && !rhs.pItem));
  251. return (AkUInt32)(pItem - rhs.pItem);
  252. }
  253. /// ++ operator
  254. Iterator& operator++()
  255. {
  256. AKASSERT( pItem );
  257. ++pItem;
  258. return *this;
  259. }
  260. /// -- operator
  261. Iterator& operator--()
  262. {
  263. AKASSERT( pItem );
  264. --pItem;
  265. return *this;
  266. }
  267. /// * operator
  268. T& operator*()
  269. {
  270. AKASSERT( pItem );
  271. return *pItem;
  272. }
  273. T* operator->() const
  274. {
  275. AKASSERT( pItem );
  276. return pItem;
  277. }
  278. /// == operator
  279. bool operator ==( const Iterator& in_rOp ) const
  280. {
  281. return ( pItem == in_rOp.pItem );
  282. }
  283. /// != operator
  284. bool operator !=( const Iterator& in_rOp ) const
  285. {
  286. return ( pItem != in_rOp.pItem );
  287. }
  288. };
  289. #endif // #ifndef SWIG
  290. /// Returns the iterator to the first item of the array, will be End() if the array is empty.
  291. Iterator Begin() const
  292. {
  293. Iterator returnedIt;
  294. returnedIt.pItem = m_pItems;
  295. return returnedIt;
  296. }
  297. /// Returns the iterator to the end of the array
  298. Iterator End() const
  299. {
  300. Iterator returnedIt;
  301. returnedIt.pItem = m_pItems + m_uLength;
  302. return returnedIt;
  303. }
  304. /// Returns the iterator th the specified item, will be End() if the item is not found
  305. Iterator FindEx( ARG_T in_Item ) const
  306. {
  307. Iterator it = Begin();
  308. for ( Iterator itEnd = End(); it != itEnd; ++it )
  309. {
  310. if ( *it == in_Item )
  311. break;
  312. }
  313. return it;
  314. }
  315. /// Returns the iterator of the specified item, will be End() if the item is not found
  316. /// The array must be in ascending sorted order.
  317. Iterator BinarySearch( ARG_T in_Item ) const
  318. {
  319. AkUInt32 uNumToSearch = Length();
  320. T* pBase = m_pItems;
  321. T* pPivot;
  322. while ( uNumToSearch > 0 )
  323. {
  324. pPivot = pBase + ( uNumToSearch >> 1 );
  325. if ( in_Item == *pPivot )
  326. {
  327. Iterator result;
  328. result.pItem = pPivot;
  329. return result;
  330. }
  331. if ( in_Item > *pPivot )
  332. {
  333. pBase = pPivot + 1;
  334. uNumToSearch--;
  335. }
  336. uNumToSearch >>= 1;
  337. }
  338. return End();
  339. }
  340. /// Erase the specified iterator from the array
  341. Iterator Erase( Iterator& in_rIter )
  342. {
  343. AKASSERT( m_pItems != 0 );
  344. if (TMovePolicy::IsTrivial())
  345. {
  346. T* pItem = in_rIter.pItem;
  347. T* pLastItem = m_pItems + (m_uLength - 1);
  348. // Destroy item
  349. pItem->~T();
  350. // Move all others by one <-
  351. if (pItem < pLastItem)
  352. {
  353. AKPLATFORM::AkMemMove(
  354. pItem,
  355. pItem + 1,
  356. (AkUInt32)(pLastItem - pItem) * sizeof(T)
  357. );
  358. }
  359. }
  360. else
  361. {
  362. // Move items by 1 <-
  363. T* pItemLast = m_pItems + m_uLength - 1;
  364. for (T* pItem = in_rIter.pItem; pItem < pItemLast; pItem++)
  365. TMovePolicy::Move(pItem[0], pItem[1]);
  366. // Destroy the last item
  367. pItemLast->~T();
  368. }
  369. m_uLength--;
  370. return in_rIter;
  371. }
  372. /// Erase the item at the specified index
  373. void Erase( unsigned int in_uIndex )
  374. {
  375. AKASSERT( m_pItems != 0 );
  376. if (TMovePolicy::IsTrivial())
  377. {
  378. T* pItem = m_pItems + in_uIndex;
  379. // Destroy item
  380. pItem->~T();
  381. // Move all others by one <-
  382. if (in_uIndex + 1 < m_uLength)
  383. {
  384. AKPLATFORM::AkMemMove(
  385. pItem,
  386. pItem + 1,
  387. (m_uLength - in_uIndex - 1) * sizeof(T)
  388. );
  389. }
  390. }
  391. else
  392. {
  393. // Move items by 1 <-
  394. T* pItemLast = m_pItems + m_uLength - 1;
  395. for (T* pItem = m_pItems + in_uIndex; pItem < pItemLast; pItem++)
  396. TMovePolicy::Move(pItem[0], pItem[1]);
  397. // Destroy the last item
  398. pItemLast->~T();
  399. }
  400. m_uLength--;
  401. }
  402. /// Erase the specified iterator in the array. but it does not guarantee the ordering in the array.
  403. /// This version should be used only when the order in the array is not an issue.
  404. Iterator EraseSwap( Iterator& in_rIter )
  405. {
  406. AKASSERT( m_pItems != 0 && Length() > 0 );
  407. if (in_rIter.pItem < (m_pItems + m_uLength - 1))
  408. {
  409. // Swap last item with this one.
  410. TMovePolicy::Move( *in_rIter.pItem, Last( ) );
  411. }
  412. // Destroy.
  413. AKASSERT( Length( ) > 0 );
  414. Last( ).~T();
  415. m_uLength--;
  416. return in_rIter;
  417. }
  418. /// Erase the item at the specified index, but it does not guarantee the ordering in the array.
  419. /// This version should be used only when the order in the array is not an issue.
  420. void EraseSwap(unsigned int in_uIndex)
  421. {
  422. Iterator Iterator;
  423. Iterator.pItem = m_pItems + in_uIndex;
  424. EraseSwap(Iterator);
  425. }
  426. bool IsGrowingAllowed() const
  427. {
  428. return TGrowBy::GrowBy( 1 ) != 0;
  429. }
  430. /// Ensure preallocation of a number of items.
  431. ///
  432. /// Reserve() won't change the Length() of the array and does nothing if
  433. /// in_ulReserve is smaller or equal to current Reserved() size.
  434. ///
  435. /// If an allocation occurs, i.e. `in_ulReserve > Reserved()`, all iterators and
  436. /// all references to the array elements are invalidated.
  437. ///
  438. /// \note When template parameter `TGrowBy = AkGrowByPolicy_NoGrow`, Reserve() shall
  439. /// only be called if the current reserved size is zero.
  440. /// It should normally only be called once on init.
  441. ///
  442. /// \note When template parameter `TGrowBy = AkGrowByPolicy_Proportional`, inappropriate
  443. /// calls to Reserve(), e.g. calling it before every AddLast(), may increase the
  444. /// number of reallocations and result in decreased performance.
  445. inline AKRESULT Reserve(AkUInt32 in_ulReserve)
  446. {
  447. if (in_ulReserve <= m_ulReserved)
  448. return AK_Success;
  449. if (m_ulReserved && !IsGrowingAllowed())
  450. {
  451. AKASSERT(!"AkArray calling Reserve() with AkGrowByPolicy_NoGrow is only allowed when reserved size is zero");
  452. return AK_InvalidParameter;
  453. }
  454. return GrowArray(in_ulReserve - m_ulReserved) ? AK_Success : AK_InsufficientMemory;
  455. }
  456. /// Ensure preallocation of a number of extra items on top of current array size.
  457. /// Same as calling `myArray.Reserve(myArray.Length() + extraItemCount)`.
  458. /// \see Reserve()
  459. inline AKRESULT ReserveExtra(AkUInt32 in_ulReserve)
  460. {
  461. return Reserve(Length() + in_ulReserve);
  462. }
  463. AkUInt32 Reserved() const { return m_ulReserved; }
  464. /// Term the array. Must be called before destroying the object.
  465. void Term()
  466. {
  467. if ( m_pItems )
  468. {
  469. RemoveAll();
  470. TAlloc::Free( m_pItems );
  471. m_pItems = 0;
  472. m_ulReserved = 0;
  473. }
  474. }
  475. /// Returns the numbers of items in the array.
  476. AkForceInline AkUInt32 Length() const
  477. {
  478. return m_uLength;
  479. }
  480. /// Returns a pointer to the first item in the array.
  481. AkForceInline T * Data() const
  482. {
  483. return m_pItems;
  484. }
  485. /// Returns true if the number items in the array is 0, false otherwise.
  486. AkForceInline bool IsEmpty() const
  487. {
  488. return m_uLength == 0;
  489. }
  490. /// Returns a pointer to the specified item in the list if it exists, 0 if not found.
  491. AkForceInline T* Exists(ARG_T in_Item) const
  492. {
  493. Iterator it = FindEx( in_Item );
  494. return ( it != End() ) ? it.pItem : 0;
  495. }
  496. /// Add an item in the array, without filling it.
  497. /// Returns a pointer to the location to be filled.
  498. AkForceInline T * AddLast()
  499. {
  500. size_t cItems = Length();
  501. #if defined(_MSC_VER)
  502. #pragma warning( push )
  503. #pragma warning( disable : 4127 )
  504. #endif
  505. if ( ( cItems >= m_ulReserved ) && IsGrowingAllowed() )
  506. {
  507. if ( !GrowArray() )
  508. return 0;
  509. }
  510. #if defined(_MSC_VER)
  511. #pragma warning( pop )
  512. #endif
  513. // have we got space for a new one ?
  514. if( cItems < m_ulReserved )
  515. {
  516. T * pEnd = m_pItems + m_uLength++;
  517. AkPlacementNew( pEnd ) T;
  518. return pEnd;
  519. }
  520. return 0;
  521. }
  522. /// Add an item in the array, and fills it with the provided item.
  523. AkForceInline T * AddLast(ARG_T in_rItem)
  524. {
  525. T * pItem = AddLast();
  526. if ( pItem )
  527. *pItem = in_rItem;
  528. return pItem;
  529. }
  530. /// Returns a reference to the last item in the array.
  531. T& Last()
  532. {
  533. AKASSERT( m_uLength );
  534. return *( m_pItems + m_uLength - 1 );
  535. }
  536. /// Removes the last item from the array.
  537. void RemoveLast()
  538. {
  539. AKASSERT( m_uLength );
  540. ( m_pItems + m_uLength - 1 )->~T();
  541. m_uLength--;
  542. }
  543. /// Removes the specified item if found in the array.
  544. AKRESULT Remove(ARG_T in_rItem)
  545. {
  546. Iterator it = FindEx( in_rItem );
  547. if ( it != End() )
  548. {
  549. Erase( it );
  550. return AK_Success;
  551. }
  552. return AK_Fail;
  553. }
  554. /// Fast remove of the specified item in the array.
  555. /// This method do not guarantee keeping ordering of the array.
  556. AKRESULT RemoveSwap(ARG_T in_rItem)
  557. {
  558. Iterator it = FindEx( in_rItem );
  559. if ( it != End() )
  560. {
  561. EraseSwap( it );
  562. return AK_Success;
  563. }
  564. return AK_Fail;
  565. }
  566. /// Removes all items in the array
  567. void RemoveAll()
  568. {
  569. for ( Iterator it = Begin(), itEnd = End(); it != itEnd; ++it )
  570. (*it).~T();
  571. m_uLength = 0;
  572. }
  573. /// Operator [], return a reference to the specified index.
  574. AkForceInline T& operator[](unsigned int uiIndex) const
  575. {
  576. AKASSERT( m_pItems );
  577. AKASSERT( uiIndex < Length() );
  578. return m_pItems[uiIndex];
  579. }
  580. /// Insert an item at the specified position without filling it.
  581. /// Success: returns an iterator pointing to the new item.
  582. /// Failure: returns end iterator.
  583. Iterator Insert(Iterator& in_rIter)
  584. {
  585. AKASSERT(!in_rIter.pItem || m_pItems);
  586. AkUInt32 index = (in_rIter.pItem && m_pItems) ? (AkUInt32)(in_rIter.pItem - m_pItems) : 0;
  587. if (index <= Length())
  588. {
  589. if (T* ptr = Insert(index))
  590. {
  591. Iterator it;
  592. it.pItem = ptr;
  593. return it;
  594. }
  595. }
  596. return End();
  597. }
  598. /// Insert an item at the specified position without filling it.
  599. /// Returns the pointer to the item to be filled.
  600. T * Insert(unsigned int in_uIndex)
  601. {
  602. AKASSERT( in_uIndex <= Length() );
  603. size_t cItems = Length();
  604. #if defined(_MSC_VER)
  605. #pragma warning( push )
  606. #pragma warning( disable : 4127 )
  607. #endif
  608. if ( ( cItems >= m_ulReserved ) && IsGrowingAllowed() )
  609. {
  610. if ( !GrowArray() )
  611. return 0;
  612. }
  613. #if defined(_MSC_VER)
  614. #pragma warning( pop )
  615. #endif
  616. // have we got space for a new one ?
  617. if (cItems < m_ulReserved)
  618. {
  619. if (TMovePolicy::IsTrivial())
  620. {
  621. T* pItem = m_pItems + in_uIndex;
  622. // Move items by one ->
  623. if (in_uIndex < m_uLength)
  624. {
  625. AKPLATFORM::AkMemMove(
  626. pItem + 1,
  627. pItem,
  628. (m_uLength - in_uIndex) * sizeof(T)
  629. );
  630. }
  631. // Initialize the new item
  632. AkPlacementNew(pItem) T;
  633. m_uLength++;
  634. }
  635. else
  636. {
  637. T* pItemLast = m_pItems + m_uLength++;
  638. AkPlacementNew(pItemLast) T;
  639. // Move items by 1 ->
  640. for (T* pItem = pItemLast; pItem > (m_pItems + in_uIndex); --pItem)
  641. TMovePolicy::Move(pItem[0], pItem[-1]);
  642. // Reinitialize item at index
  643. (m_pItems + in_uIndex)->~T();
  644. AkPlacementNew(m_pItems + in_uIndex) T;
  645. }
  646. return m_pItems + in_uIndex;
  647. }
  648. return 0;
  649. }
  650. bool GrowArray()
  651. {
  652. // If no size specified, growing by the declared growth policy of the array.
  653. return GrowArray( TGrowBy::GrowBy( m_ulReserved ) );
  654. }
  655. /// Resize the array.
  656. bool GrowArray( AkUInt32 in_uGrowBy )
  657. {
  658. AKASSERT( in_uGrowBy );
  659. AkUInt32 ulNewReserve = m_ulReserved + in_uGrowBy;
  660. T * pNewItems = NULL;
  661. size_t cItems = Length();
  662. // Reallocate only if IsTrivial() and m_pItems is already allocated.
  663. if (m_pItems && TMovePolicy::IsTrivial())
  664. {
  665. pNewItems = (T *)TAlloc::ReAlloc(m_pItems, sizeof(T) * cItems, sizeof(T) * ulNewReserve);
  666. if (!pNewItems)
  667. return false;
  668. }
  669. else
  670. {
  671. pNewItems = (T *)TAlloc::Alloc(sizeof(T) * ulNewReserve);
  672. if (!pNewItems)
  673. return false;
  674. // Copy all elements in new array, destroy old ones
  675. if (m_pItems && m_pItems != pNewItems /*AkHybridAllocator may serve up same memory*/)
  676. {
  677. for (size_t i = 0; i < cItems; ++i)
  678. {
  679. AkPlacementNew(pNewItems + i) T;
  680. TMovePolicy::Move(pNewItems[i], m_pItems[i]);
  681. m_pItems[i].~T();
  682. }
  683. TAlloc::Free(m_pItems);
  684. }
  685. }
  686. m_pItems = pNewItems;
  687. m_ulReserved = ulNewReserve;
  688. return true;
  689. }
  690. /// Resize the array to the specified size.
  691. bool Resize(AkUInt32 in_uiSize)
  692. {
  693. AkUInt32 cItems = Length();
  694. if (in_uiSize < cItems)
  695. {
  696. for (AkUInt32 i = in_uiSize; i < cItems; i++)
  697. {
  698. m_pItems[i].~T();
  699. }
  700. m_uLength = in_uiSize;
  701. return true;
  702. }
  703. if ( in_uiSize > m_ulReserved )
  704. {
  705. if ( !GrowArray(in_uiSize - m_ulReserved) )
  706. return false;
  707. }
  708. //Create the missing items.
  709. for(size_t i = cItems; i < in_uiSize; i++)
  710. {
  711. AkPlacementNew( m_pItems + i ) T;
  712. }
  713. m_uLength = in_uiSize;
  714. return true;
  715. }
  716. void Transfer(AkArray<T,ARG_T,TAlloc,TGrowBy,TMovePolicy>& in_rSource)
  717. {
  718. Term();
  719. TAlloc::TransferMem( (void*&)m_pItems, in_rSource, (void*)in_rSource.m_pItems );
  720. m_uLength = in_rSource.m_uLength;
  721. m_ulReserved = in_rSource.m_ulReserved;
  722. in_rSource.m_pItems = NULL;
  723. in_rSource.m_uLength = 0;
  724. in_rSource.m_ulReserved = 0;
  725. }
  726. AKRESULT Copy(const AkArray<T, ARG_T, TAlloc, TGrowBy, TMovePolicy>& in_rSource)
  727. {
  728. RemoveAll();
  729. if (Resize(in_rSource.Length()))
  730. {
  731. for (AkUInt32 i = 0; i < in_rSource.Length(); ++i)
  732. m_pItems[i] = in_rSource.m_pItems[i];
  733. return AK_Success;
  734. }
  735. return AK_Fail;
  736. }
  737. protected:
  738. T * m_pItems; ///< pointer to the beginning of the array.
  739. AkUInt32 m_uLength; ///< number of items in the array.
  740. AkUInt32 m_ulReserved; ///< how many we can have at most (currently allocated).
  741. };
  742. #endif