Allocator Builder
Policy Based C++ Template Allocator Library
 All Classes Functions Variables Enumerations Enumerator Groups Pages
freelist.hpp
1 //
3 // Copyright 2014 Felix Petriconi
4 //
5 // License: http://boost.org/LICENSE_1_0.txt, Boost License 1.0
6 //
7 // Authors: http://petriconi.net, Felix Petriconi
8 //
10 #pragma once
11 
12 #include "allocator_base.hpp"
13 #include "internal/dynastic.hpp"
14 #include "internal/stack.hpp"
15 #include "internal/reallocator.hpp"
16 
17 #ifdef _MSC_VER
18 #pragma warning(push)
19 #pragma warning(disable : 4189)
20 #endif
21 
22 #include <boost/lockfree/stack.hpp>
23 
24 namespace alb {
25  inline namespace v_100 {
45  template <bool Shared, class Allocator, size_t MinSize, size_t MaxSize, unsigned PoolSize,
46  unsigned NumberOfBatchAllocations>
47  class freelist_base {
49  boost::lockfree::capacity<PoolSize >> ,
50  internal::stack<void *, PoolSize>, Shared>::type root_;
51 
52  internal::dynastic<(MinSize == internal::DynasticDynamicSet ? internal::DynasticDynamicSet
53  : MinSize),
54  internal::DynasticDynamicSet> _lowerBound;
55  internal::dynastic<(MaxSize == internal::DynasticDynamicSet ? internal::DynasticDynamicSet
56  : MaxSize),
57  internal::DynasticDynamicSet> _upperBound;
58 
59 
60  Allocator allocator_;
61 
62  public:
63  using allocator = Allocator;
64  static constexpr unsigned pool_size = PoolSize;
65  static constexpr unsigned number_of_batch_allocations = NumberOfBatchAllocations;
66  static constexpr bool supports_truncated_deallocation = Allocator::supports_truncated_deallocation;
67  static constexpr unsigned alignment = Allocator::alignment;
68 
69  freelist_base() noexcept
70  {}
71 
80  freelist_base(size_t minSize, size_t maxSize) noexcept {
81  _lowerBound.value(minSize);
82  _upperBound.value(maxSize);
83  }
84 
90  void *curBlock = nullptr;
91  while (root_.pop(curBlock)) {
92  block oldBlock(curBlock, _upperBound.value());
93  allocator_.deallocate(oldBlock);
94  }
95  }
96 
97 
105  void set_min_max(size_t minSize, size_t maxSize) noexcept {
106  assert(_lowerBound.value() == internal::DynasticUndefined);
107  // "Changing the lower bound during after initialization is not wise!"
108 
109  assert(_upperBound.value() == internal::DynasticUndefined);
110  // "Changing the upper bound during after initialization is not wise!"
111 
112  _lowerBound.value(minSize);
113  _upperBound.value(maxSize);
114  }
115 
119  size_t min_size() const noexcept {
120  return _lowerBound.value();
121  }
122 
126  size_t max_size() const noexcept {
127  return _upperBound.value();
128  }
129 
141  block allocate(size_t n) noexcept {
142  block result;
143 
144  assert(_lowerBound.value() != ::std::numeric_limits<size_t>::max()); // "The lower bound was not initialized!");
145  assert(_upperBound.value() != ::std::numeric_limits<size_t>::max()); // "The upper bound was not initialized!");
146 
147  if (_lowerBound.value() <= n && n <= _upperBound.value()) {
148  void *freeBlock = nullptr;
149 
150  if (root_.pop(freeBlock)) {
151  result.ptr = freeBlock;
152  result.length = _upperBound.value();
153  return result;
154  }
155 
156  size_t blockSize = _upperBound.value();
157  if (supports_truncated_deallocation) {
158  // allocating in a bunch to gain of having the allocator code in the
159  // cache
160  auto batchAllocatedBlocks = allocator_.allocate(blockSize * NumberOfBatchAllocations);
161 
162  if (batchAllocatedBlocks) {
163  // we use the very first block directly so we start at 1
164  for (size_t i = 1; i < NumberOfBatchAllocations; i++) {
165  if (!root_.push(static_cast<char *>(batchAllocatedBlocks.ptr) + i * blockSize)) {
166  assert(false);
167  alb::block oldBlock(static_cast<char *>(batchAllocatedBlocks.ptr) + i * blockSize,
168  blockSize);
169  allocator_.deallocate(oldBlock);
170  }
171  }
172  // returning the first within block
173  result.ptr = batchAllocatedBlocks.ptr;
174  result.length = blockSize;
175  return result;
176  }
177  result = allocator_.allocate(blockSize);
178  return result;
179  }
180  for (size_t i = 0; i < NumberOfBatchAllocations - 1; i++) {
181  result = allocator_.allocate(blockSize);
182  if (!root_.push(result.ptr)) { // the list is full in the meantime, so we
183  // exit early
184  return result;
185  }
186  }
187  result = allocator_.allocate(blockSize);
188  }
189 
190  return result;
191  }
192 
201  bool reallocate(block &b, size_t n) noexcept {
202  if (internal::is_reallocation_handled_default(*this, b, n)) {
203  return true;
204  }
205  return false;
206  }
207 
213  bool owns(const block &b) const noexcept {
214  return b && _lowerBound.value() <= b.length && b.length <= _upperBound.value();
215  }
216 
222  void deallocate(block &b) noexcept {
223  if (b && owns(b)) {
224  if (root_.push(b.ptr)) {
225  b.reset();
226  return;
227  }
228  allocator_.deallocate(b);
229  }
230  }
231  };
232 
239  template <class Allocator, size_t MinSize, size_t MaxSize, size_t PoolSize = 1024,
240  size_t NumberOfBatchAllocations = 8>
241  class shared_freelist : public freelist_base<true, Allocator, MinSize, MaxSize, PoolSize,
242  NumberOfBatchAllocations>
243  {
244  public:
245  shared_freelist() noexcept
247  {}
248 
249  shared_freelist(size_t minSize, size_t maxSize) noexcept
251  minSize, maxSize)
252  {}
253  };
254 
261  template <class Allocator, size_t MinSize, size_t MaxSize, size_t PoolSize = 1024,
262  size_t NumberOfBatchAllocations = 8>
263  class freelist : public freelist_base<false, Allocator, MinSize, MaxSize, PoolSize,
264  NumberOfBatchAllocations>
265  {
266  public:
267  freelist() noexcept
269  {}
270 
271  freelist(size_t minSize, size_t maxSize) noexcept
273  minSize, maxSize)
274  {}
275  };
276  }
277 
278  using namespace v_100;
279 }
280 
281 #ifdef _MSC_VER
282 #pragma warning(pop)
283 #endif
void set_min_max(size_t minSize, size_t maxSize) noexcept
Definition: freelist.hpp:105
bool reallocate(block &b, size_t n) noexcept
Definition: freelist.hpp:201
size_t length
This describes the length of the reserved bytes.
block allocate(size_t n) noexcept
Definition: freelist.hpp:141
void * ptr
This points to the start address of the described memory block.
freelist_base(size_t minSize, size_t maxSize) noexcept
Definition: freelist.hpp:80
bool owns(const block &b) const noexcept
Definition: freelist.hpp:213
size_t min_size() const noexcept
Definition: freelist.hpp:119
size_t max_size() const noexcept
Definition: freelist.hpp:126
void deallocate(block &b) noexcept
Definition: freelist.hpp:222