btGenericPoolAllocator.cpp

Go to the documentation of this file.
00001 
00006 /*
00007 Bullet Continuous Collision Detection and Physics Library
00008 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
00009 
00010 This software is provided 'as-is', without any express or implied warranty.
00011 In no event will the authors be held liable for any damages arising from the use of this software.
00012 Permission is granted to anyone to use this software for any purpose,
00013 including commercial applications, and to alter it and redistribute it freely,
00014 subject to the following restrictions:
00015 
00016 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
00017 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
00018 3. This notice may not be removed or altered from any source distribution.
00019 */
00020 
00021 #include "btGenericPoolAllocator.h"
00022 
00023 
00024 
00026 
00027 size_t btGenericMemoryPool::allocate_from_free_nodes(size_t num_elements)
00028 {
00029         size_t ptr = BT_UINT_MAX;
00030 
00031         if(m_free_nodes_count == 0) return BT_UINT_MAX;
00032         // find an avaliable free node with the correct size
00033         size_t revindex = m_free_nodes_count;
00034 
00035         while(revindex-- && ptr == BT_UINT_MAX)
00036         {
00037                 if(m_allocated_sizes[m_free_nodes[revindex]]>=num_elements)
00038                 {
00039                         ptr = revindex;
00040                 }
00041         }
00042         if(ptr == BT_UINT_MAX) return BT_UINT_MAX; // not found
00043 
00044 
00045         revindex = ptr;
00046         ptr = m_free_nodes[revindex];
00047         // post: ptr contains the node index, and revindex the index in m_free_nodes
00048 
00049         size_t  finalsize = m_allocated_sizes[ptr];
00050         finalsize -= num_elements;
00051 
00052         m_allocated_sizes[ptr] = num_elements;
00053 
00054         // post: finalsize>=0, m_allocated_sizes[ptr] has the requested size
00055 
00056         if(finalsize>0) // preserve free node, there are some free memory
00057         {
00058                 m_free_nodes[revindex] = ptr + num_elements;
00059                 m_allocated_sizes[ptr + num_elements] = finalsize;
00060         }
00061         else // delete free node
00062         {
00063                 // swap with end
00064                 m_free_nodes[revindex] = m_free_nodes[m_free_nodes_count-1];
00065                 m_free_nodes_count--;
00066         }
00067 
00068         return ptr;
00069 }
00070 
00071 size_t btGenericMemoryPool::allocate_from_pool(size_t num_elements)
00072 {
00073         if(m_allocated_count+num_elements>m_max_element_count) return BT_UINT_MAX;
00074 
00075         size_t ptr = m_allocated_count;
00076 
00077         m_allocated_sizes[m_allocated_count] = num_elements;
00078         m_allocated_count+=num_elements;
00079 
00080         return ptr;
00081 }
00082 
00083 
00084 void btGenericMemoryPool::init_pool(size_t element_size, size_t element_count)
00085 {
00086         m_allocated_count = 0;
00087         m_free_nodes_count = 0;
00088 
00089         m_element_size = element_size;
00090         m_max_element_count = element_count;
00091 
00092 
00093 
00094 
00095         m_pool = (unsigned char *) btAlignedAlloc(m_element_size*m_max_element_count,16);
00096         m_free_nodes = (size_t *) btAlignedAlloc(sizeof(size_t)*m_max_element_count,16);
00097         m_allocated_sizes = (size_t *) btAlignedAlloc(sizeof(size_t)*m_max_element_count,16);
00098 
00099         for (size_t i = 0;i< m_max_element_count;i++ )
00100         {
00101                 m_allocated_sizes[i] = 0;
00102         }
00103 }
00104 
00105 void btGenericMemoryPool::end_pool()
00106 {
00107         btAlignedFree(m_pool);
00108         btAlignedFree(m_free_nodes);
00109         btAlignedFree(m_allocated_sizes);
00110         m_allocated_count = 0;
00111         m_free_nodes_count = 0;
00112 }
00113 
00114 
00116 
00119 void * btGenericMemoryPool::allocate(size_t size_bytes)
00120 {
00121 
00122         size_t module = size_bytes%m_element_size;
00123         size_t element_count = size_bytes/m_element_size;
00124         if(module>0) element_count++;
00125 
00126         size_t alloc_pos = allocate_from_free_nodes(element_count);
00127         // a free node is found
00128         if(alloc_pos != BT_UINT_MAX)
00129         {
00130                 return get_element_data(alloc_pos);
00131         }
00132         // allocate directly on pool
00133         alloc_pos = allocate_from_pool(element_count);
00134 
00135         if(alloc_pos == BT_UINT_MAX) return NULL; // not space
00136         return get_element_data(alloc_pos);
00137 }
00138 
00139 bool btGenericMemoryPool::freeMemory(void * pointer)
00140 {
00141         unsigned char * pointer_pos = (unsigned char *)pointer;
00142         unsigned char * pool_pos = (unsigned char *)m_pool;
00143         // calc offset
00144         if(pointer_pos<pool_pos) return false;//other pool
00145         size_t offset = size_t(pointer_pos - pool_pos);
00146         if(offset>=get_pool_capacity()) return false;// far away
00147 
00148         // find free position
00149         m_free_nodes[m_free_nodes_count] = offset/m_element_size;
00150         m_free_nodes_count++;
00151         return true;
00152 }
00153 
00154 
00156 
00157 
00158 btGenericPoolAllocator::~btGenericPoolAllocator()
00159 {
00160         // destroy pools
00161         size_t i;
00162         for (i=0;i<m_pool_count;i++)
00163         {
00164                 m_pools[i]->end_pool();
00165                 btAlignedFree(m_pools[i]);
00166         }
00167 }
00168 
00169 
00170 // creates a pool
00171 btGenericMemoryPool * btGenericPoolAllocator::push_new_pool()
00172 {
00173         if(m_pool_count >= BT_DEFAULT_MAX_POOLS) return NULL;
00174 
00175         btGenericMemoryPool * newptr = (btGenericMemoryPool *)btAlignedAlloc(sizeof(btGenericMemoryPool),16);
00176 
00177         m_pools[m_pool_count] = newptr;
00178 
00179         m_pools[m_pool_count]->init_pool(m_pool_element_size,m_pool_element_count);
00180 
00181         m_pool_count++;
00182         return newptr;
00183 }
00184 
00185 void * btGenericPoolAllocator::failback_alloc(size_t size_bytes)
00186 {
00187 
00188         btGenericMemoryPool * pool = NULL;
00189 
00190 
00191         if(size_bytes<=get_pool_capacity())
00192         {
00193                 pool =  push_new_pool();
00194         }
00195 
00196         if(pool==NULL) // failback
00197         {
00198                 return btAlignedAlloc(size_bytes,16);
00199         }
00200 
00201         return pool->allocate(size_bytes);
00202 }
00203 
00204 bool btGenericPoolAllocator::failback_free(void * pointer)
00205 {
00206         btAlignedFree(pointer);
00207         return true;
00208 }
00209 
00210 
00212 
00215 void * btGenericPoolAllocator::allocate(size_t size_bytes)
00216 {
00217         void * ptr = NULL;
00218 
00219         size_t i = 0;
00220         while(i<m_pool_count && ptr == NULL)
00221         {
00222                 ptr = m_pools[i]->allocate(size_bytes);
00223                 ++i;
00224         }
00225 
00226         if(ptr) return ptr;
00227 
00228         return failback_alloc(size_bytes);
00229 }
00230 
00231 bool btGenericPoolAllocator::freeMemory(void * pointer)
00232 {
00233         bool result = false;
00234 
00235         size_t i = 0;
00236         while(i<m_pool_count && result == false)
00237         {
00238                 result = m_pools[i]->freeMemory(pointer);
00239                 ++i;
00240         }
00241 
00242         if(result) return true;
00243 
00244         return failback_free(pointer);
00245 }
00246 
00248 
00249 
00250 #define BT_DEFAULT_POOL_SIZE 32768
00251 #define BT_DEFAULT_POOL_ELEMENT_SIZE 8
00252 
00253 // main allocator
00254 class GIM_STANDARD_ALLOCATOR: public btGenericPoolAllocator
00255 {
00256 public:
00257         GIM_STANDARD_ALLOCATOR():btGenericPoolAllocator(BT_DEFAULT_POOL_ELEMENT_SIZE,BT_DEFAULT_POOL_SIZE)
00258         {
00259         }
00260 };
00261 
00262 // global allocator
00263 GIM_STANDARD_ALLOCATOR g_main_allocator;
00264 
00265 
00266 void * btPoolAlloc(size_t size)
00267 {
00268         return g_main_allocator.allocate(size);
00269 }
00270 
00271 void * btPoolRealloc(void *ptr, size_t oldsize, size_t newsize)
00272 {
00273         void * newptr = btPoolAlloc(newsize);
00274     size_t copysize = oldsize<newsize?oldsize:newsize;
00275     memcpy(newptr,ptr,copysize);
00276     btPoolFree(ptr);
00277     return newptr;
00278 }
00279 
00280 void btPoolFree(void *ptr)
00281 {
00282         g_main_allocator.freeMemory(ptr);
00283 }