5#include "tpde/util/AddressSanitizer.hpp"
6#include "tpde/util/SmallVector.hpp"
7#include "tpde/util/misc.hpp"
15template <
size_t SlabSize = 4096>
19 SmallVector<void *> slabs;
20 SmallVector<std::pair<void *, size_t>, 0> large_slabs;
22 static constexpr auto SLAB_ALIGNMENT =
23 std::align_val_t(
alignof(std::max_align_t));
26 BumpAllocator() =
default;
27 ~BumpAllocator() noexcept {
29 deallocate_large_slabs();
32 BumpAllocator(
const BumpAllocator &) =
delete;
34 BumpAllocator &operator=(
const BumpAllocator &) =
delete;
37 void reset() noexcept {
41 util::poison_memory_region(slabs[0], SlabSize);
42 cur =
reinterpret_cast<uintptr_t
>(slabs[0]);
45 deallocate_large_slabs();
48 void *allocate(
size_t size,
size_t align)
noexcept {
49 assert(size > 0 &&
"cannot perform zero-sized allocation");
50 uintptr_t aligned = align_up(cur, align);
51 uintptr_t alloc_end = aligned + size;
52 if (alloc_end <= end) [[likely]] {
54 util::unpoison_memory_region(
reinterpret_cast<void *
>(aligned), size);
55 return reinterpret_cast<void *
>(aligned);
57 return allocate_slab(size, align);
60 void *allocate_slab(
size_t size, [[maybe_unused]]
size_t align)
noexcept {
61 assert(align <=
alignof(std::max_align_t) &&
"alignment type unsupported");
62 if (size > SlabSize) [[unlikely]] {
63 void *slab = allocate_mem(size, SLAB_ALIGNMENT);
64 large_slabs.emplace_back(slab, size);
68 void *slab = allocate_mem(SlabSize, SLAB_ALIGNMENT);
69 util::poison_memory_region(slab, SlabSize);
70 slabs.push_back(slab);
71 cur =
reinterpret_cast<uintptr_t
>(slab) + size;
72 end =
reinterpret_cast<uintptr_t
>(slab) + SlabSize;
73 util::unpoison_memory_region(slab, size);
78 void *allocate_mem(
size_t size, std::align_val_t align)
noexcept {
79 return ::operator
new(size, align, std::nothrow);
82 void deallocate_mem(
void *ptr,
83 [[maybe_unused]]
size_t size,
84 std::align_val_t align)
noexcept {
85#ifdef __cpp_sized_deallocation
86 ::operator
delete(ptr, size, align);
88 ::operator
delete(ptr, align);
92 void deallocate_slabs(
size_t skip = 0) noexcept {
93 for (
size_t i = skip; i < slabs.size(); ++i) {
94 deallocate_mem(slabs[i], SlabSize, SLAB_ALIGNMENT);
98 void deallocate_large_slabs() noexcept {
99 for (
auto [slab, size] : large_slabs) {
100 deallocate_mem(slab, size, SLAB_ALIGNMENT);
106struct BumpAllocatorDeleter {
107 constexpr BumpAllocatorDeleter() noexcept = default;
108 void operator()(T *ptr)
const { std::destroy_at(ptr); }
112using BumpAllocUniquePtr = std::unique_ptr<T, BumpAllocatorDeleter<T>>;
116template <
size_t SlabSize>
117void *
operator new(
size_t s, tpde::util::BumpAllocator<SlabSize> &a)
noexcept {
118 return a.allocate(s, std::min(s,
alignof(std::max_align_t)));
121template <
size_t SlabSize>
122void *
operator new[](
size_t s,
123 tpde::util::BumpAllocator<SlabSize> &a)
noexcept {
124 return a.allocate(s, std::min(s,
alignof(std::max_align_t)));
127template <
size_t SlabSize>
128void operator delete(
void *, tpde::util::BumpAllocator<SlabSize> &)
noexcept {}
130template <
size_t SlabSize>
131void operator delete[](
void *, tpde::util::BumpAllocator<SlabSize> &)
noexcept {