![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 00002 00003 00004 00005 00006 00007 #ifndef __MEMORY_POOL_H 00008 #define __MEMORY_POOL_H 00009 00010 #ifndef __APPLE__ 00011 // Use stdlib and not malloc for compatibility 00012 #include <stdlib.h> 00013 #endif 00014 #include "RakAssert.h" 00015 #include "Export.h" 00016 00017 #include "RakMemoryOverride.h" 00018 00019 // DS_MEMORY_POOL_MAX_FREE_PAGES must be > 1 00020 #define DS_MEMORY_POOL_MAX_FREE_PAGES 4 00021 00022 //#define _DISABLE_MEMORY_POOL 00023 00024 namespace DataStructures 00025 { 00028 template <class MemoryBlockType> 00029 class RAK_DLL_EXPORT MemoryPool 00030 { 00031 public: 00032 struct Page; 00033 struct MemoryWithPage 00034 { 00035 MemoryBlockType userMemory; 00036 Page *parentPage; 00037 }; 00038 struct Page 00039 { 00040 MemoryWithPage** availableStack; 00041 int availableStackSize; 00042 MemoryWithPage* block; 00043 Page *next, *prev; 00044 }; 00045 00046 MemoryPool(); 00047 ~MemoryPool(); 00048 void SetPageSize(int size); // Defaults to 16384 bytes 00049 MemoryBlockType *Allocate(const char *file, unsigned int line); 00050 void Release(MemoryBlockType *m, const char *file, unsigned int line); 00051 void Clear(const char *file, unsigned int line); 00052 00053 int GetAvailablePagesSize(void) const {return availablePagesSize;} 00054 int GetUnavailablePagesSize(void) const {return unavailablePagesSize;} 00055 int GetMemoryPoolPageSize(void) const {return memoryPoolPageSize;} 00056 protected: 00057 int BlocksPerPage(void) const; 00058 void AllocateFirst(void); 00059 bool InitPage(Page *page, Page *prev, const char *file, unsigned int line); 00060 00061 // availablePages contains pages which have room to give the user new blocks. We return these blocks from the head of the list 00062 // unavailablePages are pages which are totally full, and from which we do not return new blocks. 00063 // Pages move from the head of unavailablePages to the tail of availablePages, and from the head of availablePages to the tail of unavailablePages 00064 Page *availablePages, *unavailablePages; 00065 int availablePagesSize, unavailablePagesSize; 00066 int memoryPoolPageSize; 00067 }; 00068 00069 template<class MemoryBlockType> 00070 MemoryPool<MemoryBlockType>::MemoryPool() 00071 { 00072 #ifndef _DISABLE_MEMORY_POOL 00073 //AllocateFirst(); 00074 availablePagesSize=0; 00075 unavailablePagesSize=0; 00076 memoryPoolPageSize=16384; 00077 #endif 00078 } 00079 template<class MemoryBlockType> 00080 MemoryPool<MemoryBlockType>::~MemoryPool() 00081 { 00082 #ifndef _DISABLE_MEMORY_POOL 00083 Clear(_FILE_AND_LINE_); 00084 #endif 00085 } 00086 00087 template<class MemoryBlockType> 00088 void MemoryPool<MemoryBlockType>::SetPageSize(int size) 00089 { 00090 memoryPoolPageSize=size; 00091 } 00092 00093 template<class MemoryBlockType> 00094 MemoryBlockType* MemoryPool<MemoryBlockType>::Allocate(const char *file, unsigned int line) 00095 { 00096 #ifdef _DISABLE_MEMORY_POOL 00097 return (MemoryBlockType*) rakMalloc_Ex(sizeof(MemoryBlockType), file, line); 00098 #else 00099 00100 if (availablePagesSize>0) 00101 { 00102 MemoryBlockType *retVal; 00103 Page *curPage; 00104 curPage=availablePages; 00105 retVal = (MemoryBlockType*) curPage->availableStack[--(curPage->availableStackSize)]; 00106 if (curPage->availableStackSize==0) 00107 { 00108 --availablePagesSize; 00109 availablePages=curPage->next; 00110 RakAssert(availablePagesSize==0 || availablePages->availableStackSize>0); 00111 curPage->next->prev=curPage->prev; 00112 curPage->prev->next=curPage->next; 00113 00114 if (unavailablePagesSize++==0) 00115 { 00116 unavailablePages=curPage; 00117 curPage->next=curPage; 00118 curPage->prev=curPage; 00119 } 00120 else 00121 { 00122 curPage->next=unavailablePages; 00123 curPage->prev=unavailablePages->prev; 00124 unavailablePages->prev->next=curPage; 00125 unavailablePages->prev=curPage; 00126 } 00127 } 00128 00129 RakAssert(availablePagesSize==0 || availablePages->availableStackSize>0); 00130 return retVal; 00131 } 00132 00133 availablePages = (Page *) rakMalloc_Ex(sizeof(Page), file, line); 00134 if (availablePages==0) 00135 return 0; 00136 availablePagesSize=1; 00137 if (InitPage(availablePages, availablePages, file, line)==false) 00138 return 0; 00139 // If this assert hits, we couldn't allocate even 1 block per page. Increase the page size 00140 RakAssert(availablePages->availableStackSize>1); 00141 00142 return (MemoryBlockType *) availablePages->availableStack[--availablePages->availableStackSize]; 00143 #endif 00144 } 00145 template<class MemoryBlockType> 00146 void MemoryPool<MemoryBlockType>::Release(MemoryBlockType *m, const char *file, unsigned int line) 00147 { 00148 #ifdef _DISABLE_MEMORY_POOL 00149 rakFree_Ex(m, file, line); 00150 return; 00151 #else 00152 // Find the page this block is in and return it. 00153 Page *curPage; 00154 MemoryWithPage *memoryWithPage = (MemoryWithPage*)m; 00155 curPage=memoryWithPage->parentPage; 00156 00157 if (curPage->availableStackSize==0) 00158 { 00159 // The page is in the unavailable list so move it to the available list 00160 curPage->availableStack[curPage->availableStackSize++]=memoryWithPage; 00161 unavailablePagesSize--; 00162 00163 // As this page is no longer totally empty, move it to the end of available pages 00164 curPage->next->prev=curPage->prev; 00165 curPage->prev->next=curPage->next; 00166 00167 if (unavailablePagesSize>0 && curPage==unavailablePages) 00168 unavailablePages=unavailablePages->next; 00169 00170 if (availablePagesSize++==0) 00171 { 00172 availablePages=curPage; 00173 curPage->next=curPage; 00174 curPage->prev=curPage; 00175 } 00176 else 00177 { 00178 curPage->next=availablePages; 00179 curPage->prev=availablePages->prev; 00180 availablePages->prev->next=curPage; 00181 availablePages->prev=curPage; 00182 } 00183 } 00184 else 00185 { 00186 curPage->availableStack[curPage->availableStackSize++]=memoryWithPage; 00187 00188 if (curPage->availableStackSize==BlocksPerPage() && 00189 availablePagesSize>=DS_MEMORY_POOL_MAX_FREE_PAGES) 00190 { 00191 // After a certain point, just deallocate empty pages rather than keep them around 00192 if (curPage==availablePages) 00193 { 00194 availablePages=curPage->next; 00195 RakAssert(availablePages->availableStackSize>0); 00196 } 00197 curPage->prev->next=curPage->next; 00198 curPage->next->prev=curPage->prev; 00199 availablePagesSize--; 00200 rakFree_Ex(curPage->availableStack, file, line ); 00201 rakFree_Ex(curPage->block, file, line ); 00202 rakFree_Ex(curPage, file, line ); 00203 } 00204 } 00205 #endif 00206 } 00207 template<class MemoryBlockType> 00208 void MemoryPool<MemoryBlockType>::Clear(const char *file, unsigned int line) 00209 { 00210 #ifdef _DISABLE_MEMORY_POOL 00211 return; 00212 #else 00213 Page *cur, *freed; 00214 00215 if (availablePagesSize>0) 00216 { 00217 cur = availablePages; 00218 #ifdef _MSC_VER 00219 #pragma warning(disable:4127) // conditional expression is constant 00220 #endif 00221 while (true) 00222 // do 00223 { 00224 rakFree_Ex(cur->availableStack, file, line ); 00225 rakFree_Ex(cur->block, file, line ); 00226 freed=cur; 00227 cur=cur->next; 00228 if (cur==availablePages) 00229 { 00230 rakFree_Ex(freed, file, line ); 00231 break; 00232 } 00233 rakFree_Ex(freed, file, line ); 00234 }// while(cur!=availablePages); 00235 } 00236 00237 if (unavailablePagesSize>0) 00238 { 00239 cur = unavailablePages; 00240 while (1) 00241 //do 00242 { 00243 rakFree_Ex(cur->availableStack, file, line ); 00244 rakFree_Ex(cur->block, file, line ); 00245 freed=cur; 00246 cur=cur->next; 00247 if (cur==unavailablePages) 00248 { 00249 rakFree_Ex(freed, file, line ); 00250 break; 00251 } 00252 rakFree_Ex(freed, file, line ); 00253 } // while(cur!=unavailablePages); 00254 } 00255 00256 availablePagesSize=0; 00257 unavailablePagesSize=0; 00258 #endif 00259 } 00260 template<class MemoryBlockType> 00261 int MemoryPool<MemoryBlockType>::BlocksPerPage(void) const 00262 { 00263 return memoryPoolPageSize / sizeof(MemoryWithPage); 00264 } 00265 template<class MemoryBlockType> 00266 bool MemoryPool<MemoryBlockType>::InitPage(Page *page, Page *prev, const char *file, unsigned int line) 00267 { 00268 int i=0; 00269 const int bpp = BlocksPerPage(); 00270 page->block=(MemoryWithPage*) rakMalloc_Ex(memoryPoolPageSize, file, line); 00271 if (page->block==0) 00272 return false; 00273 page->availableStack=(MemoryWithPage**)rakMalloc_Ex(sizeof(MemoryWithPage*)*bpp, file, line); 00274 if (page->availableStack==0) 00275 { 00276 rakFree_Ex(page->block, file, line ); 00277 return false; 00278 } 00279 MemoryWithPage *curBlock = page->block; 00280 MemoryWithPage **curStack = page->availableStack; 00281 while (i < bpp) 00282 { 00283 curBlock->parentPage=page; 00284 curStack[i]=curBlock++; 00285 i++; 00286 } 00287 page->availableStackSize=bpp; 00288 page->next=availablePages; 00289 page->prev=prev; 00290 return true; 00291 } 00292 } 00293 00294 #endif
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.