Banuba SDK
Loading...
Searching...
No Matches
static_pool_allocator.hpp
1#pragma once
2
3#include <bnb/utils/concurrency.hpp>
4
5#include <array>
6#include <algorithm>
7#include <new>
8
9namespace bnb
10{
11 /**
12 * @addtogroup Utils
13 * @{
14 */
15
16 template<typename T, size_t MAX_ELEMENTS>
17 alignas(T) inline static unsigned char static_pool[sizeof(T) * MAX_ELEMENTS];
18
19 /**
20 * Doesn't support N allocs (std::vector)
21 */
22 template<typename T, size_t MAX_ELEMENTS>
24 {
25 public:
26 using value_type = T;
27
28 static_pool_allocator() = default;
29
30 template<class U>
31 inline constexpr explicit static_pool_allocator(const static_pool_allocator<U, MAX_ELEMENTS>& u) noexcept
32 {
33 }
34
35 template<class U>
40
41 T* allocate(std::size_t n);
42 T* allocate(std::size_t n, const std::nothrow_t&) noexcept;
43
44 void deallocate(T* p, std::size_t n);
45
46 bool is_mine(T* p);
47
48 private:
49 T* _allocate() noexcept;
50 bool _have_free() noexcept;
51
52 using free_slots_t = std::array<size_t, MAX_ELEMENTS>;
53
54 inline static struct static_data_t
55 {
56 static_data_t();
57
58 free_slots_t free_slots;
59 typename free_slots_t::iterator free_slots_end;
60 std::atomic_flag pool_lock;
61 unsigned char (&pool)[sizeof(T) * MAX_ELEMENTS];
62 } static_data;
63 };
64
65
66 template<typename T, size_t MAX_ELEMENTS, template<typename> class Alloc_fallback = std::allocator>
68 {
69 Alloc_fallback<T> alloc;
70
71 public:
72 T* allocate(std::size_t n)
73 {
74 if (T* p = static_pool_allocator<T, MAX_ELEMENTS>::allocate(n, std::nothrow); p != nullptr) {
75 return p;
76 } else {
77 return alloc.allocate(n);
78 }
79 }
80 void deallocate(T* p, std::size_t n)
81 {
84 } else {
85 alloc.deallocate(p, n);
86 }
87 }
88 };
89
90
91 template<typename T, size_t MAX_ELEMENTS>
93 : pool(bnb::static_pool<T, MAX_ELEMENTS>)
94 {
95 int i = 0;
96 std::generate(free_slots.begin(), free_slots.end(), [i]() mutable { return i++; });
97 free_slots_end = free_slots.end();
98 pool_lock.clear();
99 }
100
101
102 template<typename T, size_t MAX_ELEMENTS>
103 inline T* static_pool_allocator<T, MAX_ELEMENTS>::allocate(std::size_t n)
104 {
105 spin_lock l(static_data.pool_lock);
106
107 if (!_have_free() || n > 1)
108 throw std::bad_alloc();
109
110 return _allocate();
111 }
112
113 template<typename T, size_t MAX_ELEMENTS>
114 inline T* static_pool_allocator<T, MAX_ELEMENTS>::allocate(std::size_t n, const std::nothrow_t&) noexcept
115 {
116 spin_lock l(static_data.pool_lock);
117
118 if (!_have_free() || n > 1)
119 return nullptr;
120
121 return _allocate();
122 }
123
124 template<typename T, size_t MAX_ELEMENTS>
125 inline T* static_pool_allocator<T, MAX_ELEMENTS>::_allocate() noexcept
126 {
127 --static_data.free_slots_end;
128 const size_t slot = *static_data.free_slots_end;
129
130 void* mem = &static_data.pool[slot * sizeof(T)];
131
132 return reinterpret_cast<T*>(mem);
133 }
134
135 template<typename T, size_t MAX_ELEMENTS>
136 inline void static_pool_allocator<T, MAX_ELEMENTS>::deallocate(T* p, std::size_t n)
137 {
138 (void) n;
139 spin_lock l(static_data.pool_lock);
140
141 const size_t slot = (reinterpret_cast<unsigned char*>(p) - reinterpret_cast<unsigned char*>(static_data.pool)) / sizeof(T);
142 *static_data.free_slots_end = slot;
143 ++static_data.free_slots_end;
144 }
145
146 template<typename T, size_t MAX_ELEMENTS>
147 inline bool static_pool_allocator<T, MAX_ELEMENTS>::_have_free() noexcept
148 {
149 if (static_data.free_slots_end == static_data.free_slots.begin())
150 return false;
151 return true;
152 }
153
154 template<typename T, size_t MAX_ELEMENTS>
155 inline bool static_pool_allocator<T, MAX_ELEMENTS>::is_mine(T* p)
156 {
157 if (reinterpret_cast<char*>(p) < reinterpret_cast<char*>(static_data.pool) || reinterpret_cast<char*>(p) > reinterpret_cast<char*>(static_data.pool) + sizeof(static_data.pool))
158 return false;
159 return true;
160 }
161
162 /** @} */ // endgroup utils
163
164} // namespace bnb
Doesn't support N allocs (std::vector)