Version

menu_open

include/AK/Tools/Common/AkArray.h

Go to the documentation of this file.
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

Was this page helpful?

Need Support?

Questions? Problems? Need more info? Contact us, and we can help!

Visit our Support page

Tell us about your project. We're here to help.

Register your project and we'll help you get started with no strings attached!

Get started with Wwise