Banuba SDK
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 
9 namespace 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>
36  struct rebind
37  {
39  };
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>
67  class static_pool_allocator_fallback : public static_pool_allocator<T, MAX_ELEMENTS>
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
bnb::static_pool_allocator::rebind
Definition: static_pool_allocator.hpp:36
bnb::static_pool_allocator
Doesn't support N allocs (std::vector)
Definition: static_pool_allocator.hpp:23
bnb::static_pool_allocator_fallback
Definition: static_pool_allocator.hpp:67