バージョン
00001 /******************************************************************************* 00002 The content of this file includes portions of the AUDIOKINETIC Wwise Technology 00003 released in source code form as part of the SDK installer package. 00004 00005 Commercial License Usage 00006 00007 Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology 00008 may use this file in accordance with the end user license agreement provided 00009 with the software or, alternatively, in accordance with the terms contained in a 00010 written agreement between you and Audiokinetic Inc. 00011 00012 Apache License Usage 00013 00014 Alternatively, this file may be used under the Apache License, Version 2.0 (the 00015 "Apache License"); you may not use this file except in compliance with the 00016 Apache License. You may obtain a copy of the Apache License at 00017 http://www.apache.org/licenses/LICENSE-2.0. 00018 00019 Unless required by applicable law or agreed to in writing, software distributed 00020 under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES 00021 OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for 00022 the specific language governing permissions and limitations under the License. 00023 00024 Version: <VERSION> Build: <BUILDNUMBER> 00025 Copyright (c) <COPYRIGHTYEAR> Audiokinetic Inc. 00026 *******************************************************************************/ 00027 00028 #ifndef _AKARRAY_H 00029 #define _AKARRAY_H 00030 00031 #include <AK/Tools/Common/AkObject.h> 00032 #include <AK/Tools/Common/AkAssert.h> 00033 00034 #define AK_DEFINE_ARRAY_POOL( _name_, _poolID_ ) \ 00035 struct _name_ \ 00036 { \ 00037 static AkMemPoolId Get() \ 00038 { \ 00039 return _poolID_; \ 00040 } \ 00041 }; 00042 00043 AK_DEFINE_ARRAY_POOL( _ArrayPoolDefault, g_DefaultPoolId ) 00044 AK_DEFINE_ARRAY_POOL( _ArrayPoolLEngineDefault, g_LEngineDefaultPoolId ) 00045 00046 template <class U_POOL> 00047 struct AkArrayAllocatorNoAlign 00048 { 00049 static AkForceInline void * Alloc( size_t in_uSize ) 00050 { 00051 return AK::MemoryMgr::Malloc( U_POOL::Get(), in_uSize ); 00052 } 00053 00054 static AkForceInline void Free( void * in_pAddress ) 00055 { 00056 AK::MemoryMgr::Free( U_POOL::Get(), in_pAddress ); 00057 } 00058 }; 00059 00060 template <class U_POOL> 00061 struct AkArrayAllocatorAlignedSimd 00062 { 00063 static AkForceInline void * Alloc( size_t in_uSize ) 00064 { 00065 return AK::MemoryMgr::Malign( U_POOL::Get(), in_uSize, AK_SIMD_ALIGNMENT ); 00066 } 00067 00068 static AkForceInline void Free( void * in_pAddress ) 00069 { 00070 AK::MemoryMgr::Falign( U_POOL::Get(), in_pAddress ); 00071 } 00072 }; 00073 00074 00075 template <class T> 00076 struct AkAssignmentMovePolicy 00077 { 00078 // By default the assignment operator is invoked to move elements of an array from slot to slot. If desired, 00079 // a custom 'Move' operation can be passed into TMovePolicy to transfer ownership of resources from in_Src to in_Dest. 00080 static AkForceInline void Move( T& in_Dest, T& in_Src ) 00081 { 00082 in_Dest = in_Src; 00083 } 00084 }; 00085 00086 // Can be used as TMovePolicy to create arrays of arrays. 00087 template <class T> 00088 struct AkTransferMovePolicy 00089 { 00090 static AkForceInline void Move( T& in_Dest, T& in_Src ) 00091 { 00092 in_Dest.Transfer(in_Src); //transfer ownership of resources. 00093 } 00094 }; 00095 00096 // Common allocators: 00097 typedef AkArrayAllocatorNoAlign<_ArrayPoolDefault> ArrayPoolDefault; 00098 typedef AkArrayAllocatorNoAlign<_ArrayPoolLEngineDefault> ArrayPoolLEngineDefault; 00099 typedef AkArrayAllocatorAlignedSimd<_ArrayPoolLEngineDefault> ArrayPoolLEngineDefaultAlignedSimd; 00100 00102 template <class T, class ARG_T, class TAlloc = ArrayPoolDefault, unsigned long TGrowBy = 1, class TMovePolicy = AkAssignmentMovePolicy<T> > class AkArray : public TAlloc 00103 { 00104 public: 00106 AkArray() 00107 : m_pItems( 0 ) 00108 , m_uLength( 0 ) 00109 , m_ulReserved( 0 ) 00110 { 00111 } 00112 00114 ~AkArray() 00115 { 00116 AKASSERT( m_pItems == 0 ); 00117 AKASSERT( m_uLength == 0 ); 00118 AKASSERT( m_ulReserved == 0 ); 00119 } 00120 00121 // Workaround for SWIG to parse nested structure: 00122 // Bypass this inner struct and use a proxy in a separate header. 00123 #ifndef SWIG 00124 00125 struct Iterator 00126 { 00127 T* pItem; 00128 00130 Iterator& operator++() 00131 { 00132 AKASSERT( pItem ); 00133 ++pItem; 00134 return *this; 00135 } 00136 00138 Iterator& operator--() 00139 { 00140 AKASSERT( pItem ); 00141 --pItem; 00142 return *this; 00143 } 00144 00146 T& operator*() 00147 { 00148 AKASSERT( pItem ); 00149 return *pItem; 00150 } 00151 00153 bool operator ==( const Iterator& in_rOp ) const 00154 { 00155 return ( pItem == in_rOp.pItem ); 00156 } 00157 00159 bool operator !=( const Iterator& in_rOp ) const 00160 { 00161 return ( pItem != in_rOp.pItem ); 00162 } 00163 }; 00164 #endif // #ifndef SWIG 00165 00167 Iterator Begin() const 00168 { 00169 Iterator returnedIt; 00170 returnedIt.pItem = m_pItems; 00171 return returnedIt; 00172 } 00173 00175 Iterator End() const 00176 { 00177 Iterator returnedIt; 00178 returnedIt.pItem = m_pItems + m_uLength; 00179 return returnedIt; 00180 } 00181 00183 Iterator FindEx( ARG_T in_Item ) const 00184 { 00185 Iterator it = Begin(); 00186 00187 for ( Iterator itEnd = End(); it != itEnd; ++it ) 00188 { 00189 if ( *it == in_Item ) 00190 break; 00191 } 00192 00193 return it; 00194 } 00195 00198 Iterator BinarySearch( ARG_T in_Item ) const 00199 { 00200 Iterator itResult = End(); 00201 if (m_pItems) 00202 { 00203 T * pTop = m_pItems, * pBottom = m_pItems + m_uLength; 00204 00205 while ( pTop <= pBottom ) 00206 { 00207 T* pThis = ( pBottom - pTop ) / 2 + pTop; 00208 if( in_Item < *pThis ) 00209 pBottom = pThis - 1; 00210 else if ( in_Item > *pThis ) 00211 pTop = pThis + 1; 00212 else 00213 { 00214 itResult.pItem = pThis; 00215 break; 00216 } 00217 } 00218 } 00219 00220 return itResult; 00221 } 00222 00224 Iterator Erase( Iterator& in_rIter ) 00225 { 00226 AKASSERT( m_pItems != 0 ); 00227 00228 // Move items by 1 00229 00230 T * pItemLast = m_pItems + m_uLength - 1; 00231 00232 for ( T * pItem = in_rIter.pItem; pItem < pItemLast; pItem++ ) 00233 TMovePolicy::Move( pItem[ 0 ], pItem[ 1 ] ); 00234 00235 // Destroy the last item 00236 00237 pItemLast->~T(); 00238 00239 m_uLength--; 00240 00241 return in_rIter; 00242 } 00243 00245 void Erase( unsigned int in_uIndex ) 00246 { 00247 AKASSERT( m_pItems != 0 ); 00248 00249 // Move items by 1 00250 00251 T * pItemLast = m_pItems + m_uLength - 1; 00252 00253 for ( T * pItem = m_pItems+in_uIndex; pItem < pItemLast; pItem++ ) 00254 TMovePolicy::Move( pItem[ 0 ], pItem[ 1 ] ); 00255 00256 // Destroy the last item 00257 00258 pItemLast->~T(); 00259 00260 m_uLength--; 00261 } 00262 00265 Iterator EraseSwap( Iterator& in_rIter ) 00266 { 00267 AKASSERT( m_pItems != 0 ); 00268 00269 if ( Length( ) > 1 ) 00270 { 00271 // Swap last item with this one. 00272 TMovePolicy::Move( *in_rIter.pItem, Last( ) ); 00273 } 00274 00275 // Destroy. 00276 AKASSERT( Length( ) > 0 ); 00277 Last( ).~T(); 00278 00279 m_uLength--; 00280 00281 return in_rIter; 00282 } 00283 00285 AKRESULT Reserve( AkUInt32 in_ulReserve ) 00286 { 00287 AKASSERT( m_pItems == 0 && m_uLength == 0 ); 00288 AKASSERT( in_ulReserve || TGrowBy ); 00289 00290 if ( in_ulReserve ) 00291 { 00292 m_pItems = (T *) TAlloc::Alloc( sizeof( T ) * in_ulReserve ); 00293 if ( m_pItems == 0 ) 00294 return AK_InsufficientMemory; 00295 00296 m_ulReserved = in_ulReserve; 00297 } 00298 00299 return AK_Success; 00300 } 00301 00302 AkUInt32 Reserved() const { return m_ulReserved; } 00303 00305 void Term() 00306 { 00307 if ( m_pItems ) 00308 { 00309 RemoveAll(); 00310 TAlloc::Free( m_pItems ); 00311 m_pItems = 0; 00312 m_ulReserved = 0; 00313 } 00314 } 00315 00317 AkForceInline AkUInt32 Length() const 00318 { 00319 return m_uLength; 00320 } 00321 00323 AkForceInline bool IsEmpty() const 00324 { 00325 return m_uLength == 0; 00326 } 00327 00329 T* Exists(ARG_T in_Item) const 00330 { 00331 Iterator it = FindEx( in_Item ); 00332 return ( it != End() ) ? it.pItem : 0; 00333 } 00334 00337 T * AddLast() 00338 { 00339 size_t cItems = Length(); 00340 00341 #if defined(_MSC_VER) 00342 #pragma warning( push ) 00343 #pragma warning( disable : 4127 ) 00344 #endif 00345 if ( ( cItems >= m_ulReserved ) && TGrowBy > 0 ) 00346 { 00347 if ( !GrowArray() ) 00348 return 0; 00349 } 00350 #if defined(_MSC_VER) 00351 #pragma warning( pop ) 00352 #endif 00353 00354 // have we got space for a new one ? 00355 if( cItems < m_ulReserved ) 00356 { 00357 T * pEnd = m_pItems + m_uLength++; 00358 AkPlacementNew( pEnd ) T; 00359 return pEnd; 00360 } 00361 00362 return 0; 00363 } 00364 00366 T * AddLast(ARG_T in_rItem) 00367 { 00368 T * pItem = AddLast(); 00369 if ( pItem ) 00370 *pItem = in_rItem; 00371 return pItem; 00372 } 00373 00375 T& Last() 00376 { 00377 AKASSERT( m_uLength ); 00378 00379 return *( m_pItems + m_uLength - 1 ); 00380 } 00381 00383 void RemoveLast() 00384 { 00385 AKASSERT( m_uLength ); 00386 ( m_pItems + m_uLength - 1 )->~T(); 00387 m_uLength--; 00388 } 00389 00391 AKRESULT Remove(ARG_T in_rItem) 00392 { 00393 Iterator it = FindEx( in_rItem ); 00394 if ( it != End() ) 00395 { 00396 Erase( it ); 00397 return AK_Success; 00398 } 00399 00400 return AK_Fail; 00401 } 00402 00405 AKRESULT RemoveSwap(ARG_T in_rItem) 00406 { 00407 Iterator it = FindEx( in_rItem ); 00408 if ( it != End() ) 00409 { 00410 EraseSwap( it ); 00411 return AK_Success; 00412 } 00413 00414 return AK_Fail; 00415 } 00416 00418 void RemoveAll() 00419 { 00420 for ( Iterator it = Begin(), itEnd = End(); it != itEnd; ++it ) 00421 (*it).~T(); 00422 m_uLength = 0; 00423 } 00424 00426 T& operator[](unsigned int uiIndex) const 00427 { 00428 AKASSERT( m_pItems ); 00429 AKASSERT( uiIndex < Length() ); 00430 return m_pItems[uiIndex]; 00431 } 00432 00435 T * Insert(unsigned int in_uIndex) 00436 { 00437 AKASSERT( in_uIndex <= Length() ); 00438 00439 size_t cItems = Length(); 00440 00441 #if defined(_MSC_VER) 00442 #pragma warning( push ) 00443 #pragma warning( disable : 4127 ) 00444 #endif 00445 if ( ( cItems >= m_ulReserved ) && TGrowBy > 0 ) 00446 { 00447 if ( !GrowArray() ) 00448 return 0; 00449 } 00450 #if defined(_MSC_VER) 00451 #pragma warning( pop ) 00452 #endif 00453 00454 // have we got space for a new one ? 00455 if( cItems < m_ulReserved ) 00456 { 00457 T * pItemLast = m_pItems + m_uLength++; 00458 AkPlacementNew( pItemLast ) T; 00459 00460 // Move items by 1 00461 00462 for ( T * pItem = pItemLast; pItem > ( m_pItems + in_uIndex ); --pItem ) 00463 TMovePolicy::Move( pItem[ 0 ], pItem[ -1 ] ); 00464 00465 // Reinitialize item at index 00466 00467 ( m_pItems + in_uIndex )->~T(); 00468 AkPlacementNew( m_pItems + in_uIndex ) T; 00469 00470 return m_pItems + in_uIndex; 00471 } 00472 00473 return 0; 00474 } 00475 00477 bool GrowArray( AkUInt32 in_uGrowBy = TGrowBy ) 00478 { 00479 AKASSERT( in_uGrowBy ); 00480 00481 AkUInt32 ulNewReserve = m_ulReserved + in_uGrowBy; 00482 T * pNewItems = (T *) TAlloc::Alloc( sizeof( T ) * ulNewReserve ); 00483 if ( !pNewItems ) 00484 return false; 00485 00486 // Copy all elements in new array, destroy old ones 00487 00488 size_t cItems = Length(); 00489 00490 if ( m_pItems ) 00491 { 00492 for ( size_t i = 0; i < cItems; ++i ) 00493 { 00494 AkPlacementNew( pNewItems + i ) T; 00495 00496 TMovePolicy::Move( pNewItems[ i ], m_pItems[ i ] ); 00497 00498 m_pItems[ i ].~T(); 00499 } 00500 00501 TAlloc::Free( m_pItems ); 00502 } 00503 00504 m_pItems = pNewItems; 00505 m_ulReserved = ulNewReserve; 00506 00507 return true; 00508 } 00509 00511 bool Resize(AkUInt32 in_uiSize) 00512 { 00513 AkUInt32 cItems = Length(); 00514 if (in_uiSize < cItems) 00515 { 00516 //Destroy superfluous elements 00517 for(AkUInt32 i = in_uiSize - 1 ; i < cItems; i++) 00518 { 00519 m_pItems[ i ].~T(); 00520 } 00521 m_uLength = in_uiSize; 00522 return true; 00523 } 00524 00525 if ( in_uiSize > m_ulReserved ) 00526 { 00527 if ( !GrowArray(in_uiSize - cItems) ) 00528 return false; 00529 } 00530 00531 //Create the missing items. 00532 for(size_t i = cItems; i < in_uiSize; i++) 00533 { 00534 AkPlacementNew( m_pItems + i ) T; 00535 } 00536 00537 m_uLength = in_uiSize; 00538 return true; 00539 } 00540 00541 void Transfer(AkArray<T,ARG_T,TAlloc,TGrowBy,TMovePolicy>& in_rSource) 00542 { 00543 if (m_pItems) 00544 Term(); 00545 00546 m_pItems = in_rSource.m_pItems; 00547 m_uLength = in_rSource.m_uLength; 00548 m_ulReserved = in_rSource.m_ulReserved; 00549 00550 in_rSource.m_pItems = NULL; 00551 in_rSource.m_uLength = 0; 00552 in_rSource.m_ulReserved = 0; 00553 } 00554 00555 protected: 00556 00557 T * m_pItems; 00558 AkUInt32 m_uLength; 00559 AkUInt32 m_ulReserved; 00560 }; 00561 00562 #endif