iffl  1.3.4
Implements Intrusive Flat Forward List container
iffl_allocator.h
Go to the documentation of this file.
1 #pragma once
2 
13 
14 #include <iffl_config.h>
15 #include <iffl_common.h>
16 
21 namespace iffl {
22 
60  : public FFL_PMR::memory_resource {
61 
62 public:
63 
64  debug_memory_resource() = default;
65 
71  }
72 
77  size_t get_busy_blocks_count() const noexcept {
78  return busy_blocks_count_.load(std::memory_order_relaxed);
79  }
80 
84  void validate_no_busy_blocks() const noexcept {
86  }
87 
88 private:
89 
90  using pattern_type = size_t;
94  struct prefix_t {
95  size_t size;
96  size_t alignment;
97  debug_memory_resource *memory_resource;
98  pattern_type pattern;
99  };
103  struct suffix_t {
104  pattern_type pattern;
105  };
109  constexpr static size_t min_allocation_size{ sizeof(prefix_t) + sizeof(suffix_t) };
110 
111  constexpr static pattern_type busy_block_prefix_pattern{ 0xBEEFABCD };
112  constexpr static pattern_type free_block_prefix_pattern{ 0xBEEFABCE };
113  constexpr static pattern_type busy_block_suffix_pattern{ 0xDEADABCD };
114  constexpr static pattern_type free_block_suffix_pattern{ 0xDEADABCE };
115 
116  constexpr static int fill_pattern{ 0xFE };
125  void* do_allocate(size_t bytes, [[maybe_unused]] size_t alignment) override {
126 
127  size_t bytes_with_debug_info = bytes + min_allocation_size;
128  void *ptr = FFL_ALLIGNED_ALLOC(bytes_with_debug_info, alignment);
129  if (nullptr == ptr) {
130  throw std::bad_alloc{};
131  }
132 
133  prefix_t *prefix{ static_cast<prefix_t *>(ptr) };
134  suffix_t *suffix{ reinterpret_cast<suffix_t *>( static_cast<char *>(ptr) + bytes_with_debug_info) - 1 };
135 
136  prefix->size = bytes_with_debug_info;
137  prefix->alignment = alignment;
138  prefix->memory_resource = this;
139  prefix->pattern = busy_block_prefix_pattern;
140  suffix->pattern = busy_block_suffix_pattern;
141 
142  increment_busy_block_count();
143 
144  char *user_buffer = reinterpret_cast<char *>(prefix + 1);
145  fill_buffer(user_buffer, fill_pattern, bytes);
146 
147  return user_buffer;
148  }
156  void do_deallocate(void* p, size_t bytes, [[maybe_unused]] size_t alignment) noexcept override {
157 
158  decrement_busy_block_count();
159 
160  prefix_t *prefix{ static_cast<prefix_t *>(p) - 1 };
161  FFL_CODDING_ERROR_IF_NOT(prefix->pattern == busy_block_prefix_pattern);
162  FFL_CODDING_ERROR_IF_NOT(prefix->memory_resource == this);
163  FFL_CODDING_ERROR_IF_NOT(prefix->size > min_allocation_size);
164  size_t const user_allocation_size = prefix->size - min_allocation_size;
165  FFL_CODDING_ERROR_IF_NOT(user_allocation_size == bytes);
166  FFL_CODDING_ERROR_IF_NOT(prefix->alignment == alignment);
167  suffix_t *suffix{ reinterpret_cast<suffix_t *>(reinterpret_cast<char *>(prefix) + prefix->size) - 1 };
168  FFL_CODDING_ERROR_IF_NOT(suffix->pattern == busy_block_suffix_pattern);
169 
170  prefix->memory_resource = nullptr;
171  prefix->pattern = free_block_prefix_pattern;
172  suffix->pattern = free_block_suffix_pattern;
173 
174  FFL_ALLIGNED_FREE(prefix);
175  }
183  bool do_is_equal(memory_resource const & other) const noexcept override {
184  return (&other == this);
185  }
189  void increment_busy_block_count() noexcept {
190  size_t const prev_busy_blocks_count = busy_blocks_count_.fetch_add(1, std::memory_order_relaxed);
191  FFL_CODDING_ERROR_IF_NOT(prev_busy_blocks_count >= 0);
192  }
196  void decrement_busy_block_count() noexcept {
197  size_t const prev_busy_blocks_count = busy_blocks_count_.fetch_sub(1, std::memory_order_relaxed);
198  FFL_CODDING_ERROR_IF_NOT(prev_busy_blocks_count > 0);
199  }
203  std::atomic<size_t> busy_blocks_count_{ 0 };
204 };
205 
206 
265  : public FFL_PMR::memory_resource {
266 
267 public:
274  explicit input_buffer_memory_resource(void *buffer,
275  size_t buffer_size) noexcept
276  : used_(buffer ? false : true)
277  , buffer_{buffer}
278  , buffer_size_{ buffer_size } {
279  }
280 
286  }
287 
292  size_t get_busy_blocks_count() const noexcept {
293  return (used_ ? 1 : 0);
294  }
295 
299  void validate_no_busy_blocks() const noexcept {
301  }
302 
303 protected:
304 
313  void* do_allocate(size_t bytes, [[maybe_unused]] size_t alignment) override {
314  if (!used_ && buffer_ && bytes <= buffer_size_) {
315  used_ = true;
316  return buffer_;
317  } else {
318  throw std::bad_alloc{};
319  }
320  }
329  void do_deallocate(void* p, size_t bytes, [[maybe_unused]] size_t alignment) noexcept override {
330  FFL_CODDING_ERROR_IF_NOT(p == buffer_ && bytes <= buffer_size_);
331  used_ = false;
332  }
333 
341  bool do_is_equal(memory_resource const & other) const noexcept override {
342  return (&other == this);
343  }
344 
345 private:
346  bool used_{ false };
347  void *buffer_{ nullptr };
348  size_t buffer_size_{ 0 };
349 };
350 
351 } // namespace iffl
#define FFL_ALLIGNED_FREE(PTR)
In MSVC define to function matching to _aligned_malloc.
Definition: iffl_common.h:92
This file is supposed to be generated by cmake. Cmake pushes output to the folder where it generates ...
void * do_allocate(size_t bytes, [[maybe_unused]] size_t alignment) override
Overrides memory resource virtual method that performs allocation.
Definition: iffl_allocator.h:313
implements std::pmr::memory_resource interface.
Definition: iffl_allocator.h:59
size_t get_busy_blocks_count() const noexcept
Can be used to query number of outstanding allocations.
Definition: iffl_allocator.h:292
void fill_buffer(char *buffer, int value, size_t length) noexcept
sets "length" consecutive bytes of "to_buffer" to "value".
Definition: iffl_common.h:336
void validate_no_busy_blocks() const noexcept
Triggers fail fast if there are outstanding allocations.
Definition: iffl_allocator.h:299
implements std::pmr::memory_resource interface.
Definition: iffl_allocator.h:264
#define FFL_CODDING_ERROR_IF(C)
If expression is true then fail fast with error ENOTRECOVERABLE(127 or 0x7f)
Definition: iffl_common.h:113
intrusive flat forward list
void validate_no_busy_blocks() const noexcept
Triggers fail fast if there are outstanding allocations.
Definition: iffl_allocator.h:84
Common definitions, utility functions and vocabulary types.
bool do_is_equal(memory_resource const &other) const noexcept override
Validates that two memory resources are equivalent. For this class they must be equal.
Definition: iffl_allocator.h:341
void do_deallocate(void *p, size_t bytes, [[maybe_unused]] size_t alignment) noexcept override
Overrides memory resource virtual method that performs deallocation.
Definition: iffl_allocator.h:329
~input_buffer_memory_resource() noexcept
Destructor verifies that there are no outstanding allocations.
Definition: iffl_allocator.h:284
size_t get_busy_blocks_count() const noexcept
Can be used to query number of outstanding allocations.
Definition: iffl_allocator.h:77
#define FFL_ALLIGNED_ALLOC(BYTES, ALIGNMENT)
In MSVC define to function that allocates aligned buffer.
Definition: iffl_common.h:88
input_buffer_memory_resource(void *buffer, size_t buffer_size) noexcept
Constructs memory resource with information about buffer that should be used for allocation.
Definition: iffl_allocator.h:274
~debug_memory_resource() noexcept
Destructor triggers fail fast if there are outstanding allocations.
Definition: iffl_allocator.h:69
#define FFL_CODDING_ERROR_IF_NOT(C)
If expression is false then fail fast with error ENOTRECOVERABLE(127 or 0x7f)
Definition: iffl_common.h:120