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 
41 namespace Pt {
42 
69 class 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 
152  ~MemoryPool();
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 
245 class 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 
253  ~PoolAllocator();
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
void * allocate(std::size_t size)
Allocates size bytes of memory.
Definition: PoolAllocator.h:256
Protects derived classes from being copied.
Definition: NonCopyable.h:54
void * allocate()
Allocates memory.
Definition: PoolAllocator.h:155
void deallocate(void *ptr)
deallocates memory.
Definition: PoolAllocator.h:177
Pool based allocator.
Definition: PoolAllocator.h:245
Memory pool for objects of the same size.
Definition: PoolAllocator.h:69
Allocator interface.
Definition: Allocator.h:81
void deallocate(void *p, std::size_t size)
Deallocates memory of size bytes.
Definition: PoolAllocator.h:271