AkArray.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  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. struct AkGrowByPolicy_Proportional
  187. {
  188. static AkUInt32 GrowBy( AkUInt32 in_CurrentArraySize )
  189. {
  190. if ( in_CurrentArraySize == 0 )
  191. return 1;
  192. else
  193. return in_CurrentArraySize + ( in_CurrentArraySize >> 1 );
  194. }
  195. };
  196. //#define AkGrowByPolicy_DEFAULT AkGrowByPolicy_Legacy
  197. #define AkGrowByPolicy_DEFAULT AkGrowByPolicy_Proportional
  198. /// Specific implementation of array
  199. template <class T, class ARG_T, class TAlloc = ArrayPoolDefault, class TGrowBy = AkGrowByPolicy_DEFAULT, class TMovePolicy = AkAssignmentMovePolicy<T> > class AkArray : public TAlloc
  200. {
  201. public:
  202. /// Constructor
  203. AkArray()
  204. : m_pItems( 0 )
  205. , m_uLength( 0 )
  206. , m_ulReserved( 0 )
  207. {
  208. }
  209. /// Destructor
  210. ~AkArray()
  211. {
  212. AKASSERT( m_pItems == 0 );
  213. AKASSERT( m_uLength == 0 );
  214. AKASSERT( m_ulReserved == 0 );
  215. }
  216. // Workaround for SWIG to parse nested structure:
  217. // Bypass this inner struct and use a proxy in a separate header.
  218. #ifndef SWIG
  219. /// Iterator
  220. struct Iterator
  221. {
  222. T* pItem; ///< Pointer to the item in the array.
  223. /// + operator
  224. Iterator operator+(AkUInt32 inc) const
  225. {
  226. AKASSERT( pItem );
  227. Iterator returnedIt;
  228. returnedIt.pItem = pItem + inc;
  229. return returnedIt;
  230. }
  231. /// - operator
  232. AkUInt32 operator-(Iterator const& rhs) const
  233. {
  234. AKASSERT((pItem && rhs.pItem)||(!pItem && !rhs.pItem));
  235. return (AkUInt32)(pItem - rhs.pItem);
  236. }
  237. /// ++ operator
  238. Iterator& operator++()
  239. {
  240. AKASSERT( pItem );
  241. ++pItem;
  242. return *this;
  243. }
  244. /// -- operator
  245. Iterator& operator--()
  246. {
  247. AKASSERT( pItem );
  248. --pItem;
  249. return *this;
  250. }
  251. /// * operator
  252. T& operator*()
  253. {
  254. AKASSERT( pItem );
  255. return *pItem;
  256. }
  257. T* operator->() const
  258. {
  259. AKASSERT( pItem );
  260. return pItem;
  261. }
  262. /// == operator
  263. bool operator ==( const Iterator& in_rOp ) const
  264. {
  265. return ( pItem == in_rOp.pItem );
  266. }
  267. /// != operator
  268. bool operator !=( const Iterator& in_rOp ) const
  269. {
  270. return ( pItem != in_rOp.pItem );
  271. }
  272. };
  273. #endif // #ifndef SWIG
  274. /// Returns the iterator to the first item of the array, will be End() if the array is empty.
  275. Iterator Begin() const
  276. {
  277. Iterator returnedIt;
  278. returnedIt.pItem = m_pItems;
  279. return returnedIt;
  280. }
  281. /// Returns the iterator to the end of the array
  282. Iterator End() const
  283. {
  284. Iterator returnedIt;
  285. returnedIt.pItem = m_pItems + m_uLength;
  286. return returnedIt;
  287. }
  288. /// Returns the iterator th the specified item, will be End() if the item is not found
  289. Iterator FindEx( ARG_T in_Item ) const
  290. {
  291. Iterator it = Begin();
  292. for ( Iterator itEnd = End(); it != itEnd; ++it )
  293. {
  294. if ( *it == in_Item )
  295. break;
  296. }
  297. return it;
  298. }
  299. /// Returns the iterator of the specified item, will be End() if the item is not found
  300. /// The array must be in ascending sorted order.
  301. Iterator BinarySearch( ARG_T in_Item ) const
  302. {
  303. AkUInt32 uNumToSearch = Length();
  304. T* pBase = m_pItems;
  305. T* pPivot;
  306. while ( uNumToSearch > 0 )
  307. {
  308. pPivot = pBase + ( uNumToSearch >> 1 );
  309. if ( in_Item == *pPivot )
  310. {
  311. Iterator result;
  312. result.pItem = pPivot;
  313. return result;
  314. }
  315. if ( in_Item > *pPivot )
  316. {
  317. pBase = pPivot + 1;
  318. uNumToSearch--;
  319. }
  320. uNumToSearch >>= 1;
  321. }
  322. return End();
  323. }
  324. /// Erase the specified iterator from the array
  325. Iterator Erase( Iterator& in_rIter )
  326. {
  327. AKASSERT( m_pItems != 0 );
  328. if (TMovePolicy::IsTrivial())
  329. {
  330. T* pItem = in_rIter.pItem;
  331. T* pLastItem = m_pItems + (m_uLength - 1);
  332. // Destroy item
  333. pItem->~T();
  334. // Move all others by one <-
  335. if (pItem < pLastItem)
  336. {
  337. AKPLATFORM::AkMemMove(
  338. pItem,
  339. pItem + 1,
  340. (AkUInt32)(pLastItem - pItem) * sizeof(T)
  341. );
  342. }
  343. }
  344. else
  345. {
  346. // Move items by 1 <-
  347. T* pItemLast = m_pItems + m_uLength - 1;
  348. for (T* pItem = in_rIter.pItem; pItem < pItemLast; pItem++)
  349. TMovePolicy::Move(pItem[0], pItem[1]);
  350. // Destroy the last item
  351. pItemLast->~T();
  352. }
  353. m_uLength--;
  354. return in_rIter;
  355. }
  356. /// Erase the item at the specified index
  357. void Erase( unsigned int in_uIndex )
  358. {
  359. AKASSERT( m_pItems != 0 );
  360. if (TMovePolicy::IsTrivial())
  361. {
  362. T* pItem = m_pItems + in_uIndex;
  363. // Destroy item
  364. pItem->~T();
  365. // Move all others by one <-
  366. if (in_uIndex + 1 < m_uLength)
  367. {
  368. AKPLATFORM::AkMemMove(
  369. pItem,
  370. pItem + 1,
  371. (m_uLength - in_uIndex - 1) * sizeof(T)
  372. );
  373. }
  374. }
  375. else
  376. {
  377. // Move items by 1 <-
  378. T* pItemLast = m_pItems + m_uLength - 1;
  379. for (T* pItem = m_pItems + in_uIndex; pItem < pItemLast; pItem++)
  380. TMovePolicy::Move(pItem[0], pItem[1]);
  381. // Destroy the last item
  382. pItemLast->~T();
  383. }
  384. m_uLength--;
  385. }
  386. /// Erase the specified iterator in the array. but it does not guarantee the ordering in the array.
  387. /// This version should be used only when the order in the array is not an issue.
  388. Iterator EraseSwap( Iterator& in_rIter )
  389. {
  390. AKASSERT( m_pItems != 0 && Length() > 0 );
  391. if (in_rIter.pItem < (m_pItems + m_uLength - 1))
  392. {
  393. // Swap last item with this one.
  394. TMovePolicy::Move( *in_rIter.pItem, Last( ) );
  395. }
  396. // Destroy.
  397. AKASSERT( Length( ) > 0 );
  398. Last( ).~T();
  399. m_uLength--;
  400. return in_rIter;
  401. }
  402. /// Erase the item at the specified index, 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. void EraseSwap(unsigned int in_uIndex)
  405. {
  406. Iterator Iterator;
  407. Iterator.pItem = m_pItems + in_uIndex;
  408. EraseSwap(Iterator);
  409. }
  410. bool IsGrowingAllowed() const
  411. {
  412. return TGrowBy::GrowBy( 1 ) != 0;
  413. }
  414. /// Ensure preallocation of a number of items.
  415. ///
  416. /// Reserve() won't change the Length() of the array and does nothing if
  417. /// in_ulReserve is smaller or equal to current Reserved() size.
  418. ///
  419. /// If an allocation occurs, i.e. `in_ulReserve > Reserved()`, all iterators and
  420. /// all references to the array elements are invalidated.
  421. ///
  422. /// \note When template parameter `TGrowBy = AkGrowByPolicy_NoGrow`, Reserve() shall
  423. /// only be called if the current reserved size is zero.
  424. /// It should normally only be called once on init.
  425. ///
  426. /// \note When template parameter `TGrowBy = AkGrowByPolicy_Proportional`, inappropriate
  427. /// calls to Reserve(), e.g. calling it before every AddLast(), may increase the
  428. /// number of reallocations and result in decreased performance.
  429. inline AKRESULT Reserve(AkUInt32 in_ulReserve)
  430. {
  431. if (in_ulReserve <= m_ulReserved)
  432. return AK_Success;
  433. if (m_ulReserved && !IsGrowingAllowed())
  434. {
  435. AKASSERT(!"AkArray calling Reserve() with AkGrowByPolicy_NoGrow is only allowed when reserved size is zero");
  436. return AK_InvalidParameter;
  437. }
  438. return GrowArray(in_ulReserve - m_ulReserved) ? AK_Success : AK_InsufficientMemory;
  439. }
  440. /// Ensure preallocation of a number of extra items on top of current array size.
  441. /// Same as calling `myArray.Reserve(myArray.Length() + extraItemCount)`.
  442. /// \see Reserve()
  443. inline AKRESULT ReserveExtra(AkUInt32 in_ulReserve)
  444. {
  445. return Reserve(Length() + in_ulReserve);
  446. }
  447. AkUInt32 Reserved() const { return m_ulReserved; }
  448. /// Term the array. Must be called before destroying the object.
  449. void Term()
  450. {
  451. if ( m_pItems )
  452. {
  453. RemoveAll();
  454. TAlloc::Free( m_pItems );
  455. m_pItems = 0;
  456. m_ulReserved = 0;
  457. }
  458. }
  459. /// Returns the numbers of items in the array.
  460. AkForceInline AkUInt32 Length() const
  461. {
  462. return m_uLength;
  463. }
  464. /// Returns a pointer to the first item in the array.
  465. AkForceInline T * Data() const
  466. {
  467. return m_pItems;
  468. }
  469. /// Returns true if the number items in the array is 0, false otherwise.
  470. AkForceInline bool IsEmpty() const
  471. {
  472. return m_uLength == 0;
  473. }
  474. /// Returns a pointer to the specified item in the list if it exists, 0 if not found.
  475. AkForceInline T* Exists(ARG_T in_Item) const
  476. {
  477. Iterator it = FindEx( in_Item );
  478. return ( it != End() ) ? it.pItem : 0;
  479. }
  480. /// Add an item in the array, without filling it.
  481. /// Returns a pointer to the location to be filled.
  482. AkForceInline T * AddLast()
  483. {
  484. size_t cItems = Length();
  485. #if defined(_MSC_VER)
  486. #pragma warning( push )
  487. #pragma warning( disable : 4127 )
  488. #endif
  489. if ( ( cItems >= m_ulReserved ) && IsGrowingAllowed() )
  490. {
  491. if ( !GrowArray() )
  492. return 0;
  493. }
  494. #if defined(_MSC_VER)
  495. #pragma warning( pop )
  496. #endif
  497. // have we got space for a new one ?
  498. if( cItems < m_ulReserved )
  499. {
  500. T * pEnd = m_pItems + m_uLength++;
  501. AkPlacementNew( pEnd ) T;
  502. return pEnd;
  503. }
  504. return 0;
  505. }
  506. /// Add an item in the array, and fills it with the provided item.
  507. AkForceInline T * AddLast(ARG_T in_rItem)
  508. {
  509. T * pItem = AddLast();
  510. if ( pItem )
  511. *pItem = in_rItem;
  512. return pItem;
  513. }
  514. /// Returns a reference to the last item in the array.
  515. T& Last()
  516. {
  517. AKASSERT( m_uLength );
  518. return *( m_pItems + m_uLength - 1 );
  519. }
  520. /// Removes the last item from the array.
  521. void RemoveLast()
  522. {
  523. AKASSERT( m_uLength );
  524. ( m_pItems + m_uLength - 1 )->~T();
  525. m_uLength--;
  526. }
  527. /// Removes the specified item if found in the array.
  528. AKRESULT Remove(ARG_T in_rItem)
  529. {
  530. Iterator it = FindEx( in_rItem );
  531. if ( it != End() )
  532. {
  533. Erase( it );
  534. return AK_Success;
  535. }
  536. return AK_Fail;
  537. }
  538. /// Fast remove of the specified item in the array.
  539. /// This method do not guarantee keeping ordering of the array.
  540. AKRESULT RemoveSwap(ARG_T in_rItem)
  541. {
  542. Iterator it = FindEx( in_rItem );
  543. if ( it != End() )
  544. {
  545. EraseSwap( it );
  546. return AK_Success;
  547. }
  548. return AK_Fail;
  549. }
  550. /// Removes all items in the array
  551. void RemoveAll()
  552. {
  553. for ( Iterator it = Begin(), itEnd = End(); it != itEnd; ++it )
  554. (*it).~T();
  555. m_uLength = 0;
  556. }
  557. /// Operator [], return a reference to the specified index.
  558. AkForceInline T& operator[](unsigned int uiIndex) const
  559. {
  560. AKASSERT( m_pItems );
  561. AKASSERT( uiIndex < Length() );
  562. return m_pItems[uiIndex];
  563. }
  564. /// Insert an item at the specified position without filling it.
  565. /// Returns the pointer to the item to be filled.
  566. T * Insert(unsigned int in_uIndex)
  567. {
  568. AKASSERT( in_uIndex <= Length() );
  569. size_t cItems = Length();
  570. #if defined(_MSC_VER)
  571. #pragma warning( push )
  572. #pragma warning( disable : 4127 )
  573. #endif
  574. if ( ( cItems >= m_ulReserved ) && IsGrowingAllowed() )
  575. {
  576. if ( !GrowArray() )
  577. return 0;
  578. }
  579. #if defined(_MSC_VER)
  580. #pragma warning( pop )
  581. #endif
  582. // have we got space for a new one ?
  583. if (cItems < m_ulReserved)
  584. {
  585. if (TMovePolicy::IsTrivial())
  586. {
  587. T* pItem = m_pItems + in_uIndex;
  588. // Move items by one ->
  589. if (in_uIndex < m_uLength)
  590. {
  591. AKPLATFORM::AkMemMove(
  592. pItem + 1,
  593. pItem,
  594. (m_uLength - in_uIndex) * sizeof(T)
  595. );
  596. }
  597. // Initialize the new item
  598. AkPlacementNew(pItem) T;
  599. m_uLength++;
  600. }
  601. else
  602. {
  603. T* pItemLast = m_pItems + m_uLength++;
  604. AkPlacementNew(pItemLast) T;
  605. // Move items by 1 ->
  606. for (T* pItem = pItemLast; pItem > (m_pItems + in_uIndex); --pItem)
  607. TMovePolicy::Move(pItem[0], pItem[-1]);
  608. // Reinitialize item at index
  609. (m_pItems + in_uIndex)->~T();
  610. AkPlacementNew(m_pItems + in_uIndex) T;
  611. }
  612. return m_pItems + in_uIndex;
  613. }
  614. return 0;
  615. }
  616. bool GrowArray()
  617. {
  618. // If no size specified, growing by the declared growth policy of the array.
  619. return GrowArray( TGrowBy::GrowBy( m_ulReserved ) );
  620. }
  621. /// Resize the array.
  622. bool GrowArray( AkUInt32 in_uGrowBy )
  623. {
  624. AKASSERT( in_uGrowBy );
  625. AkUInt32 ulNewReserve = m_ulReserved + in_uGrowBy;
  626. T * pNewItems = NULL;
  627. size_t cItems = Length();
  628. // Reallocate only if IsTrivial() and m_pItems is already allocated.
  629. if (m_pItems && TMovePolicy::IsTrivial())
  630. {
  631. pNewItems = (T *)TAlloc::ReAlloc(m_pItems, sizeof(T) * cItems, sizeof(T) * ulNewReserve);
  632. if (!pNewItems)
  633. return false;
  634. }
  635. else
  636. {
  637. pNewItems = (T *)TAlloc::Alloc(sizeof(T) * ulNewReserve);
  638. if (!pNewItems)
  639. return false;
  640. // Copy all elements in new array, destroy old ones
  641. if (m_pItems && m_pItems != pNewItems /*AkHybridAllocator may serve up same memory*/)
  642. {
  643. for (size_t i = 0; i < cItems; ++i)
  644. {
  645. AkPlacementNew(pNewItems + i) T;
  646. TMovePolicy::Move(pNewItems[i], m_pItems[i]);
  647. m_pItems[i].~T();
  648. }
  649. TAlloc::Free(m_pItems);
  650. }
  651. }
  652. m_pItems = pNewItems;
  653. m_ulReserved = ulNewReserve;
  654. return true;
  655. }
  656. /// Resize the array to the specified size.
  657. bool Resize(AkUInt32 in_uiSize)
  658. {
  659. AkUInt32 cItems = Length();
  660. if (in_uiSize < cItems)
  661. {
  662. for (AkUInt32 i = in_uiSize; i < cItems; i++)
  663. {
  664. m_pItems[i].~T();
  665. }
  666. m_uLength = in_uiSize;
  667. return true;
  668. }
  669. if ( in_uiSize > m_ulReserved )
  670. {
  671. if ( !GrowArray(in_uiSize - m_ulReserved) )
  672. return false;
  673. }
  674. //Create the missing items.
  675. for(size_t i = cItems; i < in_uiSize; i++)
  676. {
  677. AkPlacementNew( m_pItems + i ) T;
  678. }
  679. m_uLength = in_uiSize;
  680. return true;
  681. }
  682. void Transfer(AkArray<T,ARG_T,TAlloc,TGrowBy,TMovePolicy>& in_rSource)
  683. {
  684. Term();
  685. TAlloc::TransferMem( (void*&)m_pItems, in_rSource, (void*)in_rSource.m_pItems );
  686. m_uLength = in_rSource.m_uLength;
  687. m_ulReserved = in_rSource.m_ulReserved;
  688. in_rSource.m_pItems = NULL;
  689. in_rSource.m_uLength = 0;
  690. in_rSource.m_ulReserved = 0;
  691. }
  692. AKRESULT Copy(const AkArray<T, ARG_T, TAlloc, TGrowBy, TMovePolicy>& in_rSource)
  693. {
  694. RemoveAll();
  695. if (Resize(in_rSource.Length()))
  696. {
  697. for (AkUInt32 i = 0; i < in_rSource.Length(); ++i)
  698. m_pItems[i] = in_rSource.m_pItems[i];
  699. return AK_Success;
  700. }
  701. return AK_Fail;
  702. }
  703. protected:
  704. T * m_pItems; ///< pointer to the beginning of the array.
  705. AkUInt32 m_uLength; ///< number of items in the array.
  706. AkUInt32 m_ulReserved; ///< how many we can have at most (currently allocated).
  707. };
  708. #endif