1 /*! \file btGenericPoolAllocator.cpp
2 \author Francisco Leon Najera. email projectileman@yahoo.com
3 
4 General purpose allocator class
5 */
6 /*
7 Bullet Continuous Collision Detection and Physics Library
8 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
9 
10 This software is provided 'as-is', without any express or implied warranty.
11 In no event will the authors be held liable for any damages arising from the use of this software.
12 Permission is granted to anyone to use this software for any purpose,
13 including commercial applications, and to alter it and redistribute it freely,
14 subject to the following restrictions:
15 
16 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.
17 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
19 */
20 
21 #include "btGenericPoolAllocator.h"
22 
23 
24 
25 /// *************** btGenericMemoryPool ******************///////////
26 
allocate_from_free_nodes(size_t num_elements)27 size_t btGenericMemoryPool::allocate_from_free_nodes(size_t num_elements)
28 {
29 	size_t ptr = BT_UINT_MAX;
30 
31 	if(m_free_nodes_count == 0) return BT_UINT_MAX;
32 	// find an avaliable free node with the correct size
33 	size_t revindex = m_free_nodes_count;
34 
35 	while(revindex-- && ptr == BT_UINT_MAX)
36 	{
37 		if(m_allocated_sizes[m_free_nodes[revindex]]>=num_elements)
38 		{
39 			ptr = revindex;
40 		}
41 	}
42 	if(ptr == BT_UINT_MAX) return BT_UINT_MAX; // not found
43 
44 
45 	revindex = ptr;
46 	ptr = m_free_nodes[revindex];
47 	// post: ptr contains the node index, and revindex the index in m_free_nodes
48 
49 	size_t  finalsize = m_allocated_sizes[ptr];
50 	finalsize -= num_elements;
51 
52 	m_allocated_sizes[ptr] = num_elements;
53 
54 	// post: finalsize>=0, m_allocated_sizes[ptr] has the requested size
55 
56 	if(finalsize>0) // preserve free node, there are some free memory
57 	{
58 		m_free_nodes[revindex] = ptr + num_elements;
59 		m_allocated_sizes[ptr + num_elements] = finalsize;
60 	}
61 	else // delete free node
62 	{
63 		// swap with end
64 		m_free_nodes[revindex] = m_free_nodes[m_free_nodes_count-1];
65 		m_free_nodes_count--;
66 	}
67 
68 	return ptr;
69 }
70 
allocate_from_pool(size_t num_elements)71 size_t btGenericMemoryPool::allocate_from_pool(size_t num_elements)
72 {
73 	if(m_allocated_count+num_elements>m_max_element_count) return BT_UINT_MAX;
74 
75 	size_t ptr = m_allocated_count;
76 
77 	m_allocated_sizes[m_allocated_count] = num_elements;
78 	m_allocated_count+=num_elements;
79 
80 	return ptr;
81 }
82 
83 
init_pool(size_t element_size,size_t element_count)84 void btGenericMemoryPool::init_pool(size_t element_size, size_t element_count)
85 {
86 	m_allocated_count = 0;
87 	m_free_nodes_count = 0;
88 
89 	m_element_size = element_size;
90 	m_max_element_count = element_count;
91 
92 
93 
94 
95 	m_pool = (unsigned char *) btAlignedAlloc(m_element_size*m_max_element_count,16);
96 	m_free_nodes = (size_t *) btAlignedAlloc(sizeof(size_t)*m_max_element_count,16);
97 	m_allocated_sizes = (size_t *) btAlignedAlloc(sizeof(size_t)*m_max_element_count,16);
98 
99 	for (size_t i = 0;i< m_max_element_count;i++ )
100 	{
101 		m_allocated_sizes[i] = 0;
102 	}
103 }
104 
end_pool()105 void btGenericMemoryPool::end_pool()
106 {
107 	btAlignedFree(m_pool);
108 	btAlignedFree(m_free_nodes);
109 	btAlignedFree(m_allocated_sizes);
110 	m_allocated_count = 0;
111 	m_free_nodes_count = 0;
112 }
113 
114 
115 //! Allocates memory in pool
116 /*!
117 \param size_bytes size in bytes of the buffer
118 */
allocate(size_t size_bytes)119 void * btGenericMemoryPool::allocate(size_t size_bytes)
120 {
121 
122 	size_t module = size_bytes%m_element_size;
123 	size_t element_count = size_bytes/m_element_size;
124 	if(module>0) element_count++;
125 
126 	size_t alloc_pos = allocate_from_free_nodes(element_count);
127 	// a free node is found
128 	if(alloc_pos != BT_UINT_MAX)
129 	{
130 		return get_element_data(alloc_pos);
131 	}
132 	// allocate directly on pool
133 	alloc_pos = allocate_from_pool(element_count);
134 
135 	if(alloc_pos == BT_UINT_MAX) return NULL; // not space
136 	return get_element_data(alloc_pos);
137 }
138 
freeMemory(void * pointer)139 bool btGenericMemoryPool::freeMemory(void * pointer)
140 {
141 	unsigned char * pointer_pos = (unsigned char *)pointer;
142 	unsigned char * pool_pos = (unsigned char *)m_pool;
143 	// calc offset
144 	if(pointer_pos<pool_pos) return false;//other pool
145 	size_t offset = size_t(pointer_pos - pool_pos);
146 	if(offset>=get_pool_capacity()) return false;// far away
147 
148 	// find free position
149 	m_free_nodes[m_free_nodes_count] = offset/m_element_size;
150 	m_free_nodes_count++;
151 	return true;
152 }
153 
154 
155 /// *******************! btGenericPoolAllocator *******************!///
156 
157 
~btGenericPoolAllocator()158 btGenericPoolAllocator::~btGenericPoolAllocator()
159 {
160 	// destroy pools
161 	size_t i;
162 	for (i=0;i<m_pool_count;i++)
163 	{
164 		m_pools[i]->end_pool();
165 		btAlignedFree(m_pools[i]);
166 	}
167 }
168 
169 
170 // creates a pool
push_new_pool()171 btGenericMemoryPool * btGenericPoolAllocator::push_new_pool()
172 {
173 	if(m_pool_count >= BT_DEFAULT_MAX_POOLS) return NULL;
174 
175 	btGenericMemoryPool * newptr = (btGenericMemoryPool *)btAlignedAlloc(sizeof(btGenericMemoryPool),16);
176 
177 	m_pools[m_pool_count] = newptr;
178 
179 	m_pools[m_pool_count]->init_pool(m_pool_element_size,m_pool_element_count);
180 
181 	m_pool_count++;
182 	return newptr;
183 }
184 
failback_alloc(size_t size_bytes)185 void * btGenericPoolAllocator::failback_alloc(size_t size_bytes)
186 {
187 
188 	btGenericMemoryPool * pool = NULL;
189 
190 
191 	if(size_bytes<=get_pool_capacity())
192 	{
193 		pool = 	push_new_pool();
194 	}
195 
196 	if(pool==NULL) // failback
197 	{
198 		return btAlignedAlloc(size_bytes,16);
199 	}
200 
201 	return pool->allocate(size_bytes);
202 }
203 
failback_free(void * pointer)204 bool btGenericPoolAllocator::failback_free(void * pointer)
205 {
206 	btAlignedFree(pointer);
207 	return true;
208 }
209 
210 
211 //! Allocates memory in pool
212 /*!
213 \param size_bytes size in bytes of the buffer
214 */
allocate(size_t size_bytes)215 void * btGenericPoolAllocator::allocate(size_t size_bytes)
216 {
217 	void * ptr = NULL;
218 
219 	size_t i = 0;
220 	while(i<m_pool_count && ptr == NULL)
221 	{
222 		ptr = m_pools[i]->allocate(size_bytes);
223 		++i;
224 	}
225 
226 	if(ptr) return ptr;
227 
228 	return failback_alloc(size_bytes);
229 }
230 
freeMemory(void * pointer)231 bool btGenericPoolAllocator::freeMemory(void * pointer)
232 {
233 	bool result = false;
234 
235 	size_t i = 0;
236 	while(i<m_pool_count && result == false)
237 	{
238 		result = m_pools[i]->freeMemory(pointer);
239 		++i;
240 	}
241 
242 	if(result) return true;
243 
244 	return failback_free(pointer);
245 }
246 
247 /// ************** STANDARD ALLOCATOR ***************************///
248 
249 
250 #define BT_DEFAULT_POOL_SIZE 32768
251 #define BT_DEFAULT_POOL_ELEMENT_SIZE 8
252 
253 // main allocator
254 class GIM_STANDARD_ALLOCATOR: public btGenericPoolAllocator
255 {
256 public:
GIM_STANDARD_ALLOCATOR()257 	GIM_STANDARD_ALLOCATOR():btGenericPoolAllocator(BT_DEFAULT_POOL_ELEMENT_SIZE,BT_DEFAULT_POOL_SIZE)
258 	{
259 	}
260 };
261 
262 // global allocator
263 GIM_STANDARD_ALLOCATOR g_main_allocator;
264 
265 
btPoolAlloc(size_t size)266 void * btPoolAlloc(size_t size)
267 {
268 	return g_main_allocator.allocate(size);
269 }
270 
btPoolRealloc(void * ptr,size_t oldsize,size_t newsize)271 void * btPoolRealloc(void *ptr, size_t oldsize, size_t newsize)
272 {
273 	void * newptr = btPoolAlloc(newsize);
274     size_t copysize = oldsize<newsize?oldsize:newsize;
275     memcpy(newptr,ptr,copysize);
276     btPoolFree(ptr);
277     return newptr;
278 }
279 
btPoolFree(void * ptr)280 void btPoolFree(void *ptr)
281 {
282 	g_main_allocator.freeMemory(ptr);
283 }
284