00001
00002
00003
00004
00005
00006
00007 #ifndef __MEMORY_POOL_H
00008 #define __MEMORY_POOL_H
00009
00010 #ifndef __APPLE__
00011
00012 #include <stdlib.h>
00013 #endif
00014 #include "RakAssert.h"
00015 #include "Export.h"
00016
00017 #include "RakMemoryOverride.h"
00018
00019
00020 #define DS_MEMORY_POOL_MAX_FREE_PAGES 4
00021
00022
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
00039 struct Page
00040 {
00041 MemoryWithPage** availableStack;
00042 int availableStackSize;
00043 MemoryWithPage* block;
00044 Page *next, *prev;
00045 };
00046
00047 MemoryPool();
00048 ~MemoryPool();
00049 void SetPageSize(int size);
00050 MemoryBlockType *Allocate(const char *file, unsigned int line);
00051 void Release(MemoryBlockType *m, const char *file, unsigned int line);
00052 void Clear(const char *file, unsigned int line);
00053
00054 int GetAvailablePagesSize(void) const {return availablePagesSize;}
00055 int GetUnavailablePagesSize(void) const {return unavailablePagesSize;}
00056 int GetMemoryPoolPageSize(void) const {return memoryPoolPageSize;}
00057 protected:
00058 int BlocksPerPage(void) const;
00059 void AllocateFirst(void);
00060 bool InitPage(Page *page, Page *prev, const char *file, unsigned int line);
00061
00062
00063
00064
00065 Page *availablePages, *unavailablePages;
00066 int availablePagesSize, unavailablePagesSize;
00067 int memoryPoolPageSize;
00068 };
00069
00070 template<class MemoryBlockType>
00071 MemoryPool<MemoryBlockType>::MemoryPool()
00072 {
00073 #ifndef _DISABLE_MEMORY_POOL
00074
00075 availablePagesSize=0;
00076 unavailablePagesSize=0;
00077 memoryPoolPageSize=16384;
00078 #endif
00079 }
00080 template<class MemoryBlockType>
00081 MemoryPool<MemoryBlockType>::~MemoryPool()
00082 {
00083 #ifndef _DISABLE_MEMORY_POOL
00084 Clear(__FILE__, __LINE__);
00085 #endif
00086 }
00087
00088 template<class MemoryBlockType>
00089 void MemoryPool<MemoryBlockType>::SetPageSize(int size)
00090 {
00091 memoryPoolPageSize=size;
00092 }
00093
00094 template<class MemoryBlockType>
00095 MemoryBlockType* MemoryPool<MemoryBlockType>::Allocate(const char *file, unsigned int line)
00096 {
00097 #ifdef _DISABLE_MEMORY_POOL
00098 return (MemoryBlockType*) rakMalloc_Ex(sizeof(MemoryBlockType), file, line);
00099 #else
00100
00101 if (availablePagesSize>0)
00102 {
00103 MemoryBlockType *retVal;
00104 Page *curPage;
00105 curPage=availablePages;
00106 retVal = (MemoryBlockType*) curPage->availableStack[--(curPage->availableStackSize)];
00107 if (curPage->availableStackSize==0)
00108 {
00109 --availablePagesSize;
00110 availablePages=curPage->next;
00111 RakAssert(availablePagesSize==0 || availablePages->availableStackSize>0);
00112 curPage->next->prev=curPage->prev;
00113 curPage->prev->next=curPage->next;
00114
00115 if (unavailablePagesSize++==0)
00116 {
00117 unavailablePages=curPage;
00118 curPage->next=curPage;
00119 curPage->prev=curPage;
00120 }
00121 else
00122 {
00123 curPage->next=unavailablePages;
00124 curPage->prev=unavailablePages->prev;
00125 unavailablePages->prev->next=curPage;
00126 unavailablePages->prev=curPage;
00127 }
00128 }
00129
00130 RakAssert(availablePagesSize==0 || availablePages->availableStackSize>0);
00131 return retVal;
00132 }
00133
00134 availablePages = (Page *) rakMalloc_Ex(sizeof(Page), file, line);
00135 if (availablePages==0)
00136 return 0;
00137 availablePagesSize=1;
00138 if (InitPage(availablePages, availablePages, file, line)==false)
00139 return 0;
00140
00141 RakAssert(availablePages->availableStackSize>1);
00142
00143 return (MemoryBlockType *) availablePages->availableStack[--availablePages->availableStackSize];
00144 #endif
00145 }
00146 template<class MemoryBlockType>
00147 void MemoryPool<MemoryBlockType>::Release(MemoryBlockType *m, const char *file, unsigned int line)
00148 {
00149 #ifdef _DISABLE_MEMORY_POOL
00150 rakFree_Ex(m, file, line);
00151 return;
00152 #else
00153
00154 Page *curPage;
00155 MemoryWithPage *memoryWithPage = (MemoryWithPage*)m;
00156 curPage=memoryWithPage->parentPage;
00157
00158 if (curPage->availableStackSize==0)
00159 {
00160
00161 curPage->availableStack[curPage->availableStackSize++]=memoryWithPage;
00162 unavailablePagesSize--;
00163
00164
00165 curPage->next->prev=curPage->prev;
00166 curPage->prev->next=curPage->next;
00167
00168 if (unavailablePagesSize>0 && curPage==unavailablePages)
00169 unavailablePages=unavailablePages->next;
00170
00171 if (availablePagesSize++==0)
00172 {
00173 availablePages=curPage;
00174 curPage->next=curPage;
00175 curPage->prev=curPage;
00176 }
00177 else
00178 {
00179 curPage->next=availablePages;
00180 curPage->prev=availablePages->prev;
00181 availablePages->prev->next=curPage;
00182 availablePages->prev=curPage;
00183 }
00184 }
00185 else
00186 {
00187 curPage->availableStack[curPage->availableStackSize++]=memoryWithPage;
00188
00189 if (curPage->availableStackSize==BlocksPerPage() &&
00190 availablePagesSize>=DS_MEMORY_POOL_MAX_FREE_PAGES)
00191 {
00192
00193 if (curPage==availablePages)
00194 {
00195 availablePages=curPage->next;
00196 RakAssert(availablePages->availableStackSize>0);
00197 }
00198 curPage->prev->next=curPage->next;
00199 curPage->next->prev=curPage->prev;
00200 availablePagesSize--;
00201 rakFree_Ex(curPage->availableStack, file, line );
00202 rakFree_Ex(curPage->block, file, line );
00203 rakFree_Ex(curPage, file, line );
00204 }
00205 }
00206 #endif
00207 }
00208 template<class MemoryBlockType>
00209 void MemoryPool<MemoryBlockType>::Clear(const char *file, unsigned int line)
00210 {
00211 #ifdef _DISABLE_MEMORY_POOL
00212 return;
00213 #else
00214 Page *cur, *freed;
00215
00216 if (availablePagesSize>0)
00217 {
00218 cur = availablePages;
00219 #ifdef _MSC_VER
00220 #pragma warning(disable:4127) // conditional expression is constant
00221 #endif
00222 while (true)
00223
00224 {
00225 rakFree_Ex(cur->availableStack, file, line );
00226 rakFree_Ex(cur->block, file, line );
00227 freed=cur;
00228 cur=cur->next;
00229 if (cur==availablePages)
00230 {
00231 rakFree_Ex(freed, file, line );
00232 break;
00233 }
00234 rakFree_Ex(freed, file, line );
00235 }
00236 }
00237
00238 if (unavailablePagesSize>0)
00239 {
00240 cur = unavailablePages;
00241 while (1)
00242
00243 {
00244 rakFree_Ex(cur->availableStack, file, line );
00245 rakFree_Ex(cur->block, file, line );
00246 freed=cur;
00247 cur=cur->next;
00248 if (cur==unavailablePages)
00249 {
00250 rakFree_Ex(freed, file, line );
00251 break;
00252 }
00253 rakFree_Ex(freed, file, line );
00254 }
00255 }
00256
00257 availablePagesSize=0;
00258 unavailablePagesSize=0;
00259 #endif
00260 }
00261 template<class MemoryBlockType>
00262 int MemoryPool<MemoryBlockType>::BlocksPerPage(void) const
00263 {
00264 return memoryPoolPageSize / sizeof(MemoryWithPage);
00265 }
00266 template<class MemoryBlockType>
00267 bool MemoryPool<MemoryBlockType>::InitPage(Page *page, Page *prev, const char *file, unsigned int line)
00268 {
00269 int i=0;
00270 const int bpp = BlocksPerPage();
00271 page->block=(MemoryWithPage*) rakMalloc_Ex(memoryPoolPageSize, file, line);
00272 if (page->block==0)
00273 return false;
00274 page->availableStack=(MemoryWithPage**)rakMalloc_Ex(sizeof(MemoryWithPage*)*bpp, file, line);
00275 if (page->availableStack==0)
00276 {
00277 rakFree_Ex(page->block, file, line );
00278 return false;
00279 }
00280 MemoryWithPage *curBlock = page->block;
00281 MemoryWithPage **curStack = page->availableStack;
00282 while (i < bpp)
00283 {
00284 curBlock->parentPage=page;
00285 curStack[i]=curBlock++;
00286 i++;
00287 }
00288 page->availableStackSize=bpp;
00289 page->next=availablePages;
00290 page->prev=prev;
00291 return true;
00292 }
00293 }
00294
00295 #endif