25#ifndef JOIN_CORE_BUMP_ALLOCATOR_HPP
26#define JOIN_CORE_BUMP_ALLOCATOR_HPP
48 template <
typename Backend,
size_t Capacity,
typename SyncPolicy>
49 class BasicBumpAllocator
51 static_assert (Capacity > 0,
"capacity must be at least 1");
59 template <
typename... Args>
61 : _backend (Capacity,
std::forward<Args> (args)...)
62 , _base (static_cast<char*> (_backend.get ()))
83 : _backend (std::move (other._backend))
84 , _previous (other._previous)
86 , _capacity (other._capacity)
87 , _cursor (std::move (other._cursor))
89 other._previous =
nullptr;
90 other._base =
nullptr;
91 other._capacity = Capacity;
92 other._cursor.store (0);
106 _backend = std::move (other._backend);
107 _previous = other._previous;
109 _capacity = other._capacity;
110 _cursor = std::move (other._cursor);
112 other._previous =
nullptr;
113 other._base =
nullptr;
114 other._capacity = Capacity;
115 other._cursor.store (0);
136 const size_t bits = size |
alignof (std::max_align_t);
137 return allocate (size, bits & (~bits + 1));
146 void*
allocate (
size_t size,
size_t alignment)
noexcept
153 const uintptr_t
base =
reinterpret_cast<uintptr_t
> (_base);
154 uint64_t current = _cursor.load ();
159 offset = ((
base + current + alignment - 1) & ~(alignment - 1)) -
base;
161 if (
JOIN_UNLIKELY ((offset > _capacity) || (size > _capacity - offset)))
163 if constexpr (std::is_same_v<SyncPolicy, BumpPlain>)
165 return grow (size, alignment);
170 while (!_cursor.advance (current, offset + size));
172 return _base + offset;
180 void deallocate ([[maybe_unused]]
void* p, [[maybe_unused]]
size_t size)
noexcept
208 return _cursor.load ();
217 return _backend.mapped ();
226 int mbind (
int numa)
const noexcept
228 return _backend.mbind (numa);
238 return _backend.mlock ();
248 void* grow (
size_t size,
size_t alignment)
noexcept
258 (std::max<uint64_t> (_capacity * 2, size + alignment) +
alignof (
BasicBumpAllocator) - 1) &
263 _backend = std::move (backend);
264 _base =
static_cast<char*
> (_backend.get ());
278 void release () noexcept
280 if (_previous !=
nullptr)
294 char* _base =
nullptr;
297 uint64_t _capacity = Capacity;
319 : _value (other._value.
load (
std::memory_order_relaxed))
330 _value.store (other._value.load (std::memory_order_relaxed), std::memory_order_relaxed);
338 uint64_t
load () const noexcept
340 return _value.load (std::memory_order_relaxed);
347 void store (uint64_t value)
noexcept
349 _value.store (value, std::memory_order_relaxed);
358 bool advance (uint64_t& expected, uint64_t desired)
noexcept
360 return _value.compare_exchange_weak (expected, desired, std::memory_order_relaxed);
365 alignas (64) std::atomic_uint64_t _value{0};
378 uint64_t
load () const noexcept
387 void store (uint64_t value)
noexcept
398 bool advance ([[maybe_unused]] uint64_t& expected, uint64_t desired)
noexcept
bump allocator owning its backends.
Definition memory.hpp:60
BasicBumpAllocator(BasicBumpAllocator &&other) noexcept
move constructor.
Definition bump_allocator.hpp:82
void * allocate(size_t size) noexcept
allocate memory at the cursor, aligned on the largest power of 2 dividing size, up to max_align_t.
Definition bump_allocator.hpp:134
static constexpr size_t capacity() noexcept
get the initial capacity.
Definition bump_allocator.hpp:197
void reset() noexcept
release all allocations at once.
Definition bump_allocator.hpp:187
void deallocate(void *p, size_t size) noexcept
release memory (no-op).
Definition bump_allocator.hpp:180
BasicBumpAllocator & operator=(const BasicBumpAllocator &other)=delete
copy assignment operator.
BasicBumpAllocator(const BasicBumpAllocator &other)=delete
copy constructor.
~BasicBumpAllocator()
destroy instance.
Definition bump_allocator.hpp:124
void * allocate(size_t size, size_t alignment) noexcept
allocate memory at the cursor with an explicit alignment.
Definition bump_allocator.hpp:146
size_t used() const noexcept
get the number of bytes consumed in the current block, alignment padding included.
Definition bump_allocator.hpp:206
BasicBumpAllocator(Args &&... args)
create instance.
Definition bump_allocator.hpp:60
bool hasBackend() const noexcept
check if the bump allocator still owns a memory region.
Definition bump_allocator.hpp:215
int mlock() const noexcept
lock the current block in RAM.
Definition bump_allocator.hpp:236
bump sync policy using a lock-free cursor.
Definition bump_allocator.hpp:307
BumpAtomic() noexcept=default
default constructor.
void store(uint64_t value) noexcept
store the cursor.
Definition bump_allocator.hpp:347
uint64_t load() const noexcept
load the cursor.
Definition bump_allocator.hpp:338
bool advance(uint64_t &expected, uint64_t desired) noexcept
advance the cursor.
Definition bump_allocator.hpp:358
BumpAtomic & operator=(BumpAtomic &&other) noexcept
move assignment operator.
Definition bump_allocator.hpp:328
bump sync policy using a plain cursor, single thread only.
Definition bump_allocator.hpp:372
uint64_t load() const noexcept
load the cursor.
Definition bump_allocator.hpp:378
bool advance(uint64_t &expected, uint64_t desired) noexcept
advance the cursor.
Definition bump_allocator.hpp:398
void store(uint64_t value) noexcept
store the cursor.
Definition bump_allocator.hpp:387
Definition acceptor.hpp:32
constexpr bool isPow2(uint64_t value) noexcept
check if a value is a power of two.
Definition utils.hpp:465
std::string base(const std::string &filepath)
get base path of the specified file.
Definition filesystem.hpp:41
#define JOIN_UNLIKELY(x)
Definition utils.hpp:51