Table of Contents

include/AK/Tools/Common/AkDynaBlkPool.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 _AKBLOCKPOOL_H
00029 #define _AKBLOCKPOOL_H
00030 
00031 #include <AK/Tools/Common/AkObject.h>
00032 #include <AK/Tools/Common/AkAssert.h>
00033 #include <AK/Tools/Common/AkListBareLight.h>
00034 
00035 //
00036 //  AkDynaBlkPool   - A dynamic block pool allocator which will grow (and shrink) in size in contiguous chunks of 'uPoolChunkSize' objects.
00037 //                  - Fragmentation in the pool will prevent it from shrinking, but in many use cases this is acceptable.
00038 //
00039 
00040 #ifdef _DEBUG
00041 //#define AK_DYNA_BLK_STATS
00042 #define AK_DYNA_BLK_SCRUB_MEM
00043 #endif
00044 
00045 #ifdef AK_DYNA_BLK_STATS
00046 #define STATS_ALLOC() Stats_Alloc()
00047 #define STATS_NEWCHUNK() Stats_NewChunk()
00048 #define STATS_FREE() Stats_Free()
00049 #define STATS_DELCHUNK() Stats_DelChunk()
00050 #else
00051 #define STATS_ALLOC()
00052 #define STATS_NEWCHUNK()
00053 #define STATS_FREE()
00054 #define STATS_DELCHUNK()
00055 #endif
00056 
00057 #ifdef AK_DYNA_BLK_SCRUB_MEM
00058 #define SCRUB_NEW_CHUNK() memset(&memory, 0xCC, sizeof(T)*uPoolChunkSize)
00059 #define SCRUB_NEW_ALLOC(pItem) memset(pItem, 0xAA, sizeof(T))
00060 #define SCRUB_FREE_BLOCK(pObj) memset(pObj, 0xDD, sizeof(T))
00061 #else
00062 #define SCRUB_NEW_CHUNK()
00063 #define SCRUB_NEW_ALLOC(pItem)
00064 #define SCRUB_FREE_BLOCK(pObj)
00065 #endif
00066 
00067 template  < typename T, AkUInt32 uPoolChunkSize, class TAlloc = ArrayPoolDefault>
00068 class AkDynaBlkPool: public TAlloc
00069 {
00070     enum { kChunkMemoryBytes = sizeof(T)*uPoolChunkSize };
00071 
00072     struct FreeBlock
00073     {
00074         FreeBlock* pNextItem;
00075         char padding[ sizeof(T) - sizeof(FreeBlock*) ];
00076     };
00077     typedef AkListBare< FreeBlock, AkListBareNextItem, AkCountPolicyWithCount, AkLastPolicyNoLast > tFreeList;
00078 
00079     struct PoolChunk
00080     {
00081         PoolChunk() : pNextLightItem(NULL)
00082         {
00083             SCRUB_NEW_CHUNK();
00084             for( AkUInt32 i=0; i<uPoolChunkSize; ++i )
00085             {
00086                 FreeBlock* pBlk = reinterpret_cast<FreeBlock*>( &memory ) + i;
00087                 freeList.AddFirst(pBlk);
00088             }
00089         }
00090 
00091         inline bool BelongsTo( FreeBlock* pMem ) const { return (AkUInt8*)pMem >= memory && (AkUInt8*)pMem < (memory+kChunkMemoryBytes); }
00092         inline bool AllFree() const { return freeList.Length() == uPoolChunkSize; }
00093         inline bool AllAllocd() const { return freeList.IsEmpty();  }
00094 
00095         AkUInt8 memory[ kChunkMemoryBytes ];
00096         PoolChunk* pNextLightItem;
00097         tFreeList freeList;
00098     };
00099     typedef AkListBareLight< PoolChunk > tChunkList;
00100 
00101 public:
00102 
00103     T* New()
00104     {
00105         T* ptr = Alloc();
00106         if (ptr) AkPlacementNew(ptr) T;
00107         return ptr;
00108     }
00109 
00110     template<typename A1>
00111     T* New(A1 a1)
00112     {
00113         T* ptr = Alloc();
00114         if (ptr) AkPlacementNew(ptr) T(a1);
00115         return ptr;
00116     }
00117 
00118     template<typename A1, typename A2>
00119     T* New(A1 a1, A2 a2)
00120     {
00121         T* ptr = Alloc();
00122         if (ptr) AkPlacementNew(ptr) T(a1, a2);
00123         return ptr;
00124     }
00125 
00126     template<typename A1, typename A2, typename A3>
00127     T* New(A1 a1, A2 a2, A3 a3)
00128     {
00129         T* ptr = Alloc();
00130         if (ptr) AkPlacementNew(ptr) T(a1, a2, a3);
00131         return ptr;
00132     }
00133 
00134     template<typename A1, typename A2, typename A3, typename A4>
00135     T* New(A1 a1, A2 a2, A3 a3, A4 a4)
00136     {
00137         T* ptr = Alloc();
00138         if (ptr) AkPlacementNew(ptr) T(a1,a2,a3,a4);
00139         return ptr;
00140     }
00141 
00142     void Delete(T* ptr)
00143     {
00144         ptr->~T();
00145         Free(ptr);
00146     }
00147 
00148 private:
00149     T* Alloc()
00150     {
00151         FreeBlock* pItem = NULL;
00152         PoolChunk* pChunk = NULL;
00153         
00154         pChunk = m_chunkList.First();
00155         while (pChunk != NULL && pChunk->AllAllocd())
00156             pChunk = pChunk->pNextLightItem;
00157 
00158         if (pChunk == NULL)
00159         {
00160             pChunk = (PoolChunk *) TAlloc::Alloc( sizeof( PoolChunk ) );
00161             AkPlacementNew(pChunk) PoolChunk();
00162             STATS_NEWCHUNK();
00163             if (pChunk != NULL)
00164                 m_chunkList.AddFirst(pChunk);
00165         }
00166 
00167         if (pChunk != NULL)
00168         {
00169             pItem = pChunk->freeList.First();
00170             AKASSERT(pItem != NULL);
00171             pChunk->freeList.RemoveFirst();
00172             SCRUB_NEW_ALLOC(pItem);
00173             STATS_ALLOC();
00174         }
00175 
00176         return reinterpret_cast<T*>(pItem);
00177     }
00178 
00179     void Free( T* pObj )
00180     {
00181         SCRUB_FREE_BLOCK((void*)pObj);
00182         
00183         FreeBlock* pItem = reinterpret_cast<FreeBlock*>(pObj);
00184 
00185         PoolChunk* pPrevChunk = NULL;
00186         PoolChunk* pChunk = m_chunkList.First();
00187         while (pChunk != NULL && !pChunk->BelongsTo(pItem))
00188         {
00189             pPrevChunk = pChunk;
00190             pChunk = pChunk->pNextLightItem;
00191         }
00192 
00193         AKASSERT(pChunk != NULL);
00194         pChunk->freeList.AddFirst(pItem);
00195         STATS_FREE();
00196 
00197         if (pChunk->AllFree())
00198         {
00199             m_chunkList.RemoveItem(pChunk, pPrevChunk);
00200             pChunk->~PoolChunk();
00201             TAlloc::Free( pChunk );
00202             STATS_DELCHUNK();
00203         }
00204     }
00205 
00206     tChunkList m_chunkList;
00207 
00208 #ifdef AK_DYNA_BLK_STATS
00209     void Stats_Alloc()
00210     {
00211         uCurrentUsedBytes += sizeof(T);
00212         uPeakUsedBytes = AkMax(uCurrentUsedBytes, uPeakUsedBytes);
00213     }
00214     void Stats_NewChunk()
00215     {
00216         uCurrentAllocdBytes += sizeof(PoolChunk);
00217         uPeakAllocdBytes = AkMax(uCurrentAllocdBytes, uPeakAllocdBytes);
00218     }
00219     void Stats_Free()
00220     {
00221         uCurrentUsedBytes -= sizeof(T);
00222     }
00223     void Stats_DelChunk()
00224     {
00225         uCurrentAllocdBytes -= sizeof(PoolChunk);
00226     }
00227 public:
00228     AkUInt32 uPeakUsedBytes;
00229     AkUInt32 uPeakAllocdBytes;
00230     AkUInt32 uCurrentAllocdBytes;
00231     AkUInt32 uCurrentUsedBytes;
00232 #endif
00233 };
00234 
00235 
00236 #endif