riccaticpp
Loading...
Searching...
No Matches
memory.hpp
Go to the documentation of this file.
1#ifndef INCLUDE_RICCATI_MEMORY_ARENA_ALLOC_HPP
2#define INCLUDE_RICCATI_MEMORY_ARENA_ALLOC_HPP
3
4#include <riccati/macros.hpp>
5#include <riccati/utils.hpp>
6#include <Eigen/Dense>
7#include <stdint.h>
8#include <cstdlib>
9#include <cstddef>
10#include <sstream>
11#include <stdexcept>
12#include <vector>
13
14namespace riccati {
15
16namespace internal {
29template <unsigned int Alignment, typename T>
31 return (reinterpret_cast<uintptr_t>(ptr) % Alignment) == 0U;
32}
33
34constexpr size_t DEFAULT_INITIAL_NBYTES = 1 << 16; // 64KB
35
42 unsigned char* ptr = static_cast<unsigned char*>(malloc(size));
43 if (!ptr) {
44 return ptr; // malloc failed to alloc
45 }
46 if (!is_aligned<8U>(ptr)) {
47 [](auto* ptr) RICCATI_COLD_PATH {
48 std::stringstream s;
49 s << "invalid alignment to 8 bytes, ptr="
50 << reinterpret_cast<uintptr_t>(ptr) << std::endl;
51 throw std::runtime_error(s.str());
52 }(ptr);
53 }
54 return ptr;
55}
56
57} // namespace internal
58
79 public:
80 using byte_t = unsigned char;
81 std::vector<byte_t*> blocks_; // storage for blocks,
82 // may be bigger than cur_block_
83 std::vector<size_t> sizes_; // could store initial & shift for others
84 size_t cur_block_; // index into blocks_ for next alloc
85 byte_t* cur_block_end_; // ptr to cur_block_ptr_ + sizes_[cur_block_]
86 byte_t* next_loc_; // ptr to next available spot in cur
87 // block
88
98 byte_t* result;
99 ++cur_block_;
100 // Find the next block (if any) containing at least len bytes.
101 while ((cur_block_ < blocks_.size()) && (sizes_[cur_block_] < len)) {
102 ++cur_block_;
103 }
104 // Allocate a new block if necessary.
105 if (unlikely(cur_block_ >= blocks_.size())) {
106 // New block should be max(2*size of last block, len) bytes.
107 size_t newsize = sizes_.back() * 2;
108 if (newsize < len) {
109 newsize = len;
110 }
112 if (!blocks_.back()) {
113 throw std::bad_alloc();
114 }
115 sizes_.push_back(newsize);
116 }
117 result = blocks_[cur_block_];
118 // Get the object's state back in order.
119 next_loc_ = result + len;
120 cur_block_end_ = result + sizes_[cur_block_];
121 return result;
122 }
123
124 public:
134 RICCATI_NO_INLINE explicit arena_alloc(size_t initial_nbytes)
135 : blocks_(1, internal::eight_byte_aligned_malloc(initial_nbytes)),
136 sizes_(1, initial_nbytes),
137 cur_block_(0),
138 cur_block_end_(blocks_[0] + initial_nbytes),
139 next_loc_(blocks_[0]) {
140 if (unlikely(!blocks_[0])) {
141 throw std::bad_alloc(); // no msg allowed in bad_alloc ctor
142 }
143 }
145 : blocks_(1, internal::eight_byte_aligned_malloc(
146 internal::DEFAULT_INITIAL_NBYTES)),
147 sizes_(1, internal::DEFAULT_INITIAL_NBYTES),
148 cur_block_(0),
149 cur_block_end_(blocks_[0] + internal::DEFAULT_INITIAL_NBYTES),
150 next_loc_(blocks_[0]) {
151 if (unlikely(!blocks_[0])) {
152 throw std::bad_alloc(); // no msg allowed in bad_alloc ctor
153 }
154 }
155 arena_alloc(const arena_alloc&) = delete;
159
167 // free ALL blocks
168 for (auto& block : blocks_) {
169 if (block) {
170 free(block);
171 }
172 }
173 }
174
189 RICCATI_ALWAYS_INLINE void* alloc(size_t len) {
190 size_t pad = len % 8 == 0 ? 0 : 8 - len % 8;
191
192 // Typically, just return and increment the next location.
193 byte_t* result = next_loc_;
194 next_loc_ += len + pad;
195 // Occasionally, we have to switch blocks.
197 result = move_to_next_block(len);
198 }
199 return reinterpret_cast<void*>(result);
200 }
201
210 template <typename T>
212 return static_cast<T*>(alloc(n * sizeof(T)));
213 }
214
224 if (unlikely(blocks_.size() > 1)) {
225 std::size_t sum = 0;
226 for (size_t i = 1; i < blocks_.size(); ++i) {
227 sum += sizes_[i];
228 free(blocks_[i]);
229 }
230 blocks_.clear();
231 sizes_.clear();
233 sizes_.push_back(sum);
234 }
235 cur_block_ = 0;
236 next_loc_ = blocks_[0];
238 }
239
245 inline void free_all() {
246 // frees all BUT the first (index 0) block
247 for (size_t i = 1; i < blocks_.size(); ++i) {
248 if (blocks_[i]) {
249 free(blocks_[i]);
250 }
251 }
252 sizes_.resize(1);
253 blocks_.resize(1);
254 recover_all();
255 }
256
267 inline size_t bytes_allocated() const {
268 size_t sum = 0;
269 for (size_t i = 0; i <= cur_block_; ++i) {
270 sum += sizes_[i];
271 }
272 return sum;
273 }
274
283 inline bool in_stack(const void* ptr) const {
284 for (size_t i = 0; i < cur_block_; ++i) {
285 if (ptr >= blocks_[i] && ptr < blocks_[i] + sizes_[i]) {
286 return true;
287 }
288 }
289 if (ptr >= blocks_[cur_block_] && ptr < next_loc_) {
290 return true;
291 }
292 return false;
293 }
294};
295
309template <typename T, typename ArenaType>
311 ArenaType* alloc_;
312 bool owns_alloc_{false};
313 using value_type = T;
314 RICCATI_NO_INLINE explicit arena_allocator(ArenaType* alloc,
315 bool owns_alloc = false)
316 : alloc_(alloc), owns_alloc_(owns_alloc) {}
318 : alloc_(new ArenaType{}), owns_alloc_(true) {}
319
322 template <typename U, typename UArena>
325
327 if (owns_alloc_) {
328 delete alloc_;
329 }
330 }
331
338 template <typename T_ = T>
339 RICCATI_ALWAYS_INLINE T_* allocate(std::size_t n) {
340 return alloc_->template alloc_array<T_>(n);
341 }
342
347 alloc_->recover_all();
348 }
349
353 void deallocate(T* /*p*/, std::size_t /*n*/) noexcept {}
354
359 constexpr bool operator==(const arena_allocator&) const noexcept {
360 return true;
361 }
366 constexpr bool operator!=(const arena_allocator&) const noexcept {
367 return false;
368 }
369};
370
372 std::vector<void*> ptrs_;
373 template <typename T>
374 inline T* allocate(std::size_t n) {
375 void* ptr = std::malloc(n * sizeof(T));
376 ptrs_.push_back(ptr);
377 return reinterpret_cast<T*>(ptr);
378 }
379 constexpr inline void recover_memory() noexcept {}
380 template <typename T>
381 constexpr inline void deallocate(T* p, std::size_t n) noexcept {}
382 constexpr bool operator==(const dummy_allocator&) const noexcept {
383 return true;
384 }
385 constexpr bool operator!=(const dummy_allocator&) const noexcept {
386 return false;
387 }
389 for (auto ptr : ptrs_) {
390 std::free(ptr);
391 }
392 }
393};
394
395template <typename Expr>
396RICCATI_ALWAYS_INLINE auto eval(dummy_allocator& alloc, Expr&& expr) {
397 return eval(std::forward<Expr>(expr));
398}
399
400} // namespace riccati
401#endif
RICCATI_ALWAYS_INLINE void * alloc(size_t len)
Definition memory.hpp:189
byte_t * cur_block_end_
Definition memory.hpp:85
RICCATI_NO_INLINE arena_alloc(size_t initial_nbytes)
Definition memory.hpp:134
size_t bytes_allocated() const
Definition memory.hpp:267
arena_alloc & operator=(const arena_alloc &)=delete
RICCATI_NO_INLINE byte_t * move_to_next_block(size_t len)
Definition memory.hpp:97
std::vector< size_t > sizes_
Definition memory.hpp:83
unsigned char byte_t
Definition memory.hpp:80
RICCATI_NO_INLINE arena_alloc()
Definition memory.hpp:144
RICCATI_ALWAYS_INLINE T * alloc_array(size_t n)
Definition memory.hpp:211
RICCATI_ALWAYS_INLINE void recover_all()
Definition memory.hpp:223
arena_alloc(arena_alloc &&)=delete
arena_alloc(const arena_alloc &)=delete
bool in_stack(const void *ptr) const
Definition memory.hpp:283
RICCATI_NO_INLINE ~arena_alloc()
Definition memory.hpp:166
std::vector< byte_t * > blocks_
Definition memory.hpp:81
arena_alloc & operator=(arena_alloc &&)=delete
#define RICCATI_NO_INLINE
Definition macros.hpp:56
#define unlikely(x)
Definition macros.hpp:54
#define RICCATI_ALWAYS_INLINE
Definition macros.hpp:57
#define RICCATI_COLD_PATH
Definition macros.hpp:55
constexpr size_t DEFAULT_INITIAL_NBYTES
Definition memory.hpp:34
RICCATI_ALWAYS_INLINE bool is_aligned(T *ptr)
Definition memory.hpp:30
RICCATI_ALWAYS_INLINE unsigned char * eight_byte_aligned_malloc(size_t size)
Definition memory.hpp:41
auto eval(arena_allocator< T, arena_alloc > &arena, const Expr &expr) noexcept
RICCATI_NO_INLINE arena_allocator(const arena_allocator &rhs)
Definition memory.hpp:320
RICCATI_ALWAYS_INLINE void recover_memory() noexcept
Definition memory.hpp:346
RICCATI_NO_INLINE arena_allocator()
Definition memory.hpp:317
RICCATI_NO_INLINE arena_allocator(const arena_allocator< U, UArena > &rhs)
Definition memory.hpp:323
constexpr bool operator!=(const arena_allocator &) const noexcept
Definition memory.hpp:366
constexpr bool operator==(const arena_allocator &) const noexcept
Definition memory.hpp:359
void deallocate(T *, std::size_t) noexcept
Definition memory.hpp:353
RICCATI_ALWAYS_INLINE T_ * allocate(std::size_t n)
Definition memory.hpp:339
RICCATI_NO_INLINE arena_allocator(ArenaType *alloc, bool owns_alloc=false)
Definition memory.hpp:314
constexpr bool operator==(const dummy_allocator &) const noexcept
Definition memory.hpp:382
constexpr void deallocate(T *p, std::size_t n) noexcept
Definition memory.hpp:381
std::vector< void * > ptrs_
Definition memory.hpp:372
T * allocate(std::size_t n)
Definition memory.hpp:374
constexpr bool operator!=(const dummy_allocator &) const noexcept
Definition memory.hpp:385
constexpr void recover_memory() noexcept
Definition memory.hpp:379