PoolAllocator.h
1/*
2 * Copyright (C) 2009-2010 by Bendri Batti
3 * Copyright (C) 2009-2012 by Marc Boris Duerner
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * As a special exception, you may use this file as part of a free
11 * software library without restriction. Specifically, if other files
12 * instantiate templates or use macros or inline functions from this
13 * file, or you compile this file and link it with other files to
14 * produce an executable, this file does not by itself cause the
15 * resulting executable to be covered by the GNU General Public
16 * License. This exception does not however invalidate any other
17 * reasons why the executable file might be covered by the GNU Library
18 * General Public License.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#ifndef PT_POOLALLOCATOR_H
31#define PT_POOLALLOCATOR_H
32
33#include <Pt/Api.h>
34#include <Pt/Allocator.h>
35#include <Pt/Types.h>
36#include <Pt/NonCopyable.h>
37#include <vector>
38#include <cassert>
39#include <cstddef>
40
41namespace Pt {
42
69class PT_API MemoryPool : public NonCopyable
70{
71 typedef std::size_t Record;
72 static const Record RecordSize = sizeof(Record);
73 static const Record InvalidIndex = std::size_t(-1);
74
76 class Block
77 {
78 Record* block;
79 std::size_t firstFreeIndex;
80 std::size_t unitSize;
81 std::size_t availUnits;
82 std::size_t endIndex;
83 std::size_t maxUnits;
84
85 public:
86 Block(std::size_t unitSize_, std::size_t numUnits)
87 : block(0)
88 , firstFreeIndex(InvalidIndex)
89 , unitSize(unitSize_)
90 , availUnits(numUnits)
91 , endIndex(0)
92 , maxUnits(numUnits)
93 {}
94
95 bool isFull() const
96 { return availUnits == 0; }
97
98 bool isEmpty() const
99 { return availUnits == maxUnits; }
100
101 void clear()
102 {
103 delete[] block;
104 block = 0;
105 firstFreeIndex = InvalidIndex;
106 }
107
108 Record* allocate()
109 {
110 assert(availUnits > 0);
111
112 if( firstFreeIndex != InvalidIndex )
113 {
114 assert(firstFreeIndex < endIndex);
115 Record* retval = block + firstFreeIndex;
116 firstFreeIndex = *retval;
117 --availUnits;
118 return retval;
119 }
120
121 if( ! block )
122 {
123 block = new Record[maxUnits*unitSize];
124 endIndex = 0;
125 }
126
127 Record* retval = block + endIndex;
128 endIndex += unitSize;
129
130 assert(endIndex <= maxUnits*unitSize);
131 --availUnits;
132 return retval;
133 }
134
135 void deallocate(Record* ptr)
136 {
137 assert(availUnits <= maxUnits);
138
139 *ptr = firstFreeIndex;
140 firstFreeIndex = ptr - block;
141 assert( ptr >= block );
142 assert( ptr <= (block + endIndex) );
143 ++availUnits;
144 }
145 };
146
147 public:
149 MemoryPool(std::size_t elemSize, std::size_t maxPageSize = 8192);
150
153
155 void* allocate()
156 {
157 if( _freelist.empty() )
158 {
159 _freelist.push_back( _blocks.size() );
160 _blocks.push_back( Block(_recordsPerUnit, _maxUnits) );
161 }
162
163 const std::size_t index = _freelist.back();
164 Block& block = _blocks[index];
165
166 Record* retval = block.allocate();
167 *retval = index;
168 ++retval;
169
170 if(block.isFull())
171 _freelist.pop_back();
172
173 return retval;
174 }
175
177 void deallocate(void* ptr)
178 {
179 if( ! ptr )
180 return;
181
182 Record* unitPtr = reinterpret_cast<Record*>(ptr);
183 --unitPtr;
184
185 const std::size_t blockIndex = *unitPtr;
186 Block& block = _blocks[blockIndex];
187
188 if( block.isFull() )
189 _freelist.push_back(blockIndex);
190
191 block.deallocate(unitPtr);
192
193 // keep the first block
194 if( block.isEmpty() && blockIndex > 0 )
195 block.clear();
196 }
197
198 private:
199 std::vector<Block> _blocks;
200 std::vector<std::size_t> _freelist;
201
203 std::size_t _recordsPerUnit;
204 std::size_t _maxUnits;
205};
206
245class PT_API PoolAllocator : public Allocator
246 , protected NonCopyable
247{
248 public:
250 PoolAllocator(std::size_t maxSize, std::size_t align = 16, std::size_t maxBlock = 8192);
251
254
255 // inherit docs
256 void* allocate(std::size_t size)
257 {
258 if (size > _maxObjectSize || 0 == size)
259 {
260 return ::operator new( size );
261 }
262
263 const std::size_t index = (size-1) / _objectAlignSize;
264
265 assert (index < _pools.size() );
266 MemoryPool* pool = _pools[index];
267 return pool->allocate();
268 }
269
270 // inherit docs
271 void deallocate(void* p, std::size_t size)
272 {
273 if (size > _maxObjectSize || NULL == p)
274 {
275 ::operator delete(p);
276 return;
277 }
278
279 assert(size > 0);
280
281 const std::size_t index = (size-1) / _objectAlignSize;
282 assert (index < _pools.size() );
283 MemoryPool* pool = _pools[index];
284 pool->deallocate(p);
285 }
286
287 private:
288 // TODO: use vector<PoolStorage>
289 // struct PoolStorage
290 // {
291 // char buffer[sizeof(MemoryPool)];
292 // };
293 //
294 std::vector<MemoryPool*> _pools;
295
297 const std::size_t _maxObjectSize;
298
300 const std::size_t _objectAlignSize;
301};
302
303} // namespace Pt
304
305#endif
Allocator()
Default constructor.
Definition Allocator.h:86
Memory pool for objects of the same size.
Definition PoolAllocator.h:70
~MemoryPool()
Destructor.
void deallocate(void *ptr)
deallocates memory.
Definition PoolAllocator.h:177
void * allocate()
Allocates memory.
Definition PoolAllocator.h:155
MemoryPool(std::size_t elemSize, std::size_t maxPageSize=8192)
Construct with element size and maximum page size.
NonCopyable()
Default constructor.
Definition NonCopyable.h:63
~PoolAllocator()
Destructor.
void deallocate(void *p, std::size_t size)
Deallocates memory of size bytes.
Definition PoolAllocator.h:271
void * allocate(std::size_t size)
Allocates size bytes of memory.
Definition PoolAllocator.h:256
PoolAllocator(std::size_t maxSize, std::size_t align=16, std::size_t maxBlock=8192)
Contruct with maximum record size, alignment and block size.
Core module.
Definition Allocator.h:33