Allocator Builder
Policy Based C++ Template Allocator Library
 All Classes Functions Variables Enumerations Enumerator Groups Pages
stack_allocator.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 
14 namespace alb {
15  inline namespace v_100 {
26  template <size_t MaxSize, size_t Alignment = 16>
27 
29  alignas(Alignment) char _data[MaxSize];
30 
31  char *_p;
32 
33  bool is_last_used_block(const block &b) const noexcept {
34  return (static_cast<char *>(b.ptr) + b.length == _p);
35  }
36 
37  public:
38  using allocator = stack_allocator;
39 
40  static const bool supports_truncated_deallocation = true;
41  static const size_t max_size = MaxSize;
42  static const size_t alignment = Alignment;
43 
44  stack_allocator() noexcept
45  : _p(_data)
46  {
47  }
48 
49  block allocate(size_t n) noexcept {
50  block result;
51 
52  if (n == 0) {
53  return result;
54  }
55 
56  const auto alignedLength = internal::round_to_alignment(Alignment, n);
57  if (alignedLength + _p > _data + MaxSize) { // not enough memory left
58  return result;
59  }
60 
61  result.ptr = _p;
62  result.length = alignedLength;
63 
64  _p += alignedLength;
65  return result;
66  }
67 
68  void deallocate(block &b) noexcept {
69  if (!b) {
70  return;
71  }
72  if (!owns(b)) {
73  assert(false);
74  return;
75  }
76 
77  // If it was the most recent allocated MemoryBlock, then we can re-use the
78  // memory. Otherwise this freed MemoryBlock is not available for further
79  // allocations. Since all happens on the stack this is not a leak!
80  if (is_last_used_block(b)) {
81  _p = static_cast<char *>(b.ptr);
82  }
83  b.reset();
84  }
85 
86  bool reallocate(block &b, size_t n) noexcept {
87  if (b.length == n) {
88  return true;
89  }
90 
91  if (n == 0) {
92  deallocate(b);
93  return true;
94  }
95 
96  if (!b) {
97  b = allocate(n);
98  return true;
99  }
100 
101  const auto alignedLength = internal::round_to_alignment(Alignment, n);
102 
103  if (is_last_used_block(b)) {
104  if (static_cast<char *>(b.ptr) + alignedLength <= _data + MaxSize) {
105  b.length = alignedLength;
106  _p = static_cast<char *>(b.ptr) + alignedLength;
107  return true;
108  }
109  // out of memory
110  return false;
111  }
112  if (b.length > n) {
113  b.length = internal::round_to_alignment(Alignment, n);
114  return true;
115  }
116 
117  auto newBlock = allocate(alignedLength);
118  // we cannot deallocate the old block, because it is in between used ones,
119  // so we have to "leak" here.
120  if (newBlock) {
121  internal::block_copy(b, newBlock);
122  b = newBlock;
123  return true;
124  }
125  return false;
126  }
127 
135  bool expand(block &b, size_t delta) noexcept {
136  if (delta == 0) {
137  return true;
138  }
139  if (!b) {
140  b = allocate(delta);
141  return b.length != 0;
142  }
143  if (!is_last_used_block(b)) {
144  return false;
145  }
146  auto alignedBytes = internal::round_to_alignment(Alignment, delta);
147  if (_p + alignedBytes > _data + MaxSize) {
148  return false;
149  }
150  _p += alignedBytes;
151  b.length += alignedBytes;
152  return true;
153  }
154 
160  bool owns(const block &b) const noexcept {
161  return b && (b.ptr >= _data && b.ptr < _data + MaxSize);
162  }
163 
169  void deallocate_all() noexcept {
170  _p = _data;
171  }
172 
173  private:
174  // disable move ctor and move assignment operators
175  stack_allocator(stack_allocator &&) = delete;
176  stack_allocator &operator=(stack_allocator &&) = delete;
177  stack_allocator(const stack_allocator &) = delete;
178  stack_allocator &operator=(const stack_allocator &) = delete;
179  // disable heap allocation
180  void *operator new(size_t) = delete;
181  void *operator new[](size_t) = delete;
182  void operator delete(void *) = delete;
183  void operator delete[](void *) = delete;
184  // disable address taking
185  stack_allocator *operator&() = delete;
186  };
187 
188  template <size_t MaxSize, size_t Alignment>
190  template <size_t MaxSize, size_t Alignment>
192  }
193  using namespace v_100;
194 }
bool expand(block &b, size_t delta) noexcept
void reset() noexcept
void block_copy(const block &source, block &destination) noexcept
size_t length
This describes the length of the reserved bytes.
constexpr size_t round_to_alignment(size_t basis, size_t n) noexcept
void * ptr
This points to the start address of the described memory block.
bool owns(const block &b) const noexcept