Shadowrun: Awakened 29 September 2011 - Build 871
DS_MemoryPool.h
Go to the documentation of this file.
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.

GNU Lesser General Public License 3 Sourceforge.net