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 static constexpr size_t slab_size(
size_t i) {
28 return SlabSize << (i / 8);
32 BumpAllocator() =
default;
33 ~BumpAllocator() noexcept {
35 deallocate_large_slabs();
38 BumpAllocator(
const BumpAllocator &) =
delete;
40 BumpAllocator &operator=(
const BumpAllocator &) =
delete;
43 void reset() noexcept {
47 util::poison_memory_region(slabs[0], slab_size(0));
48 cur =
reinterpret_cast<uintptr_t
>(slabs[0]);
49 end = cur + slab_size(0);
51 deallocate_large_slabs();
54 void *allocate(
size_t size,
size_t align)
noexcept {
55 assert(size > 0 &&
"cannot perform zero-sized allocation");
56 uintptr_t aligned = align_up(cur, align);
57 uintptr_t alloc_end = aligned + size;
58 if (alloc_end <= end) [[likely]] {
60 util::unpoison_memory_region(
reinterpret_cast<void *
>(aligned), size);
61 return reinterpret_cast<void *
>(aligned);
63 return allocate_slab(size, align);
66 void *allocate_slab(
size_t size, [[maybe_unused]]
size_t align)
noexcept {
67 assert(align <=
alignof(std::max_align_t) &&
"alignment type unsupported");
68 size_t slab_sz = slab_size(slabs.size());
69 if (size > slab_sz) [[unlikely]] {
70 void *slab = allocate_mem(size, SLAB_ALIGNMENT);
71 large_slabs.emplace_back(slab, size);
75 void *slab = allocate_mem(slab_sz, SLAB_ALIGNMENT);
76 util::poison_memory_region(slab, slab_sz);
77 slabs.push_back(slab);
78 cur =
reinterpret_cast<uintptr_t
>(slab) + size;
79 end =
reinterpret_cast<uintptr_t
>(slab) + slab_sz;
80 util::unpoison_memory_region(slab, size);
85 void *allocate_mem(
size_t size, std::align_val_t align)
noexcept {
86 return ::operator
new(size, align, std::nothrow);
89 void deallocate_mem(
void *ptr,
90 [[maybe_unused]]
size_t size,
91 std::align_val_t align)
noexcept {
92#ifdef __cpp_sized_deallocation
93 ::operator
delete(ptr, size, align);
95 ::operator
delete(ptr, align);
99 void deallocate_slabs(
size_t skip = 0) noexcept {
100 for (
size_t i = skip; i < slabs.size(); ++i) {
101 deallocate_mem(slabs[i], slab_size(i), SLAB_ALIGNMENT);
105 void deallocate_large_slabs() noexcept {
106 for (
auto [slab, size] : large_slabs) {
107 deallocate_mem(slab, size, SLAB_ALIGNMENT);
113struct BumpAllocatorDeleter {
114 constexpr BumpAllocatorDeleter() noexcept = default;
115 void operator()(T *ptr)
const { std::destroy_at(ptr); }
119using BumpAllocUniquePtr = std::unique_ptr<T, BumpAllocatorDeleter<T>>;
123template <
size_t SlabSize>
124void *
operator new(
size_t s, tpde::util::BumpAllocator<SlabSize> &a)
noexcept {
125 return a.allocate(s, std::min(s,
alignof(std::max_align_t)));
128template <
size_t SlabSize>
129void *
operator new[](
size_t s,
130 tpde::util::BumpAllocator<SlabSize> &a)
noexcept {
131 return a.allocate(s, std::min(s,
alignof(std::max_align_t)));
134template <
size_t SlabSize>
135void operator delete(
void *, tpde::util::BumpAllocator<SlabSize> &)
noexcept {}
137template <
size_t SlabSize>
138void operator delete[](
void *, tpde::util::BumpAllocator<SlabSize> &)
noexcept {