42#include <boost/pool/pool_alloc.hpp>
43#include <boost/pool/singleton_pool.hpp>
49 template <
typename T, std::
size_t ChunkSize = 4096,
bool Omega = false, std::
size_t Instance = 0>
61 typedef std::allocator<T> backup_allocator_t;
65 struct link { link* iNext; };
67 static constexpr std::size_t chunk_size()
69 if constexpr (ChunkSize >
sizeof(T))
75 static constexpr std::size_t element_size()
82 alignas(T)
char iMem[chunk_size()];
88 pool() : iChunks(nullptr), iHead(nullptr)
104 if (iHead ==
nullptr)
107 if constexpr (!Omega)
109 else if (
reinterpret_cast<intptr_t
>(iHead->iNext) == intptr_t{ -1 })
110 iHead =
reinterpret_cast<link*
>(
reinterpret_cast<char*
>(p) + element_size());
115 void deallocate(
void* aObject)
117 if constexpr (!Omega)
119 link* p =
reinterpret_cast<link*
>(aObject);
129 for (chunk* n = iChunks; n !=
nullptr; n = n->iNext)
131 constexpr std::size_t nelem = chunk_size() / element_size();
132 char* start = n->iMem;
133 char* last = start + nelem * element_size();
134 std::memset(start, 0xFF, last - start);
135 reinterpret_cast<link*
>(last - element_size())->iNext = (n->iNext !=
nullptr ?
reinterpret_cast<link*
>(n->iNext->iMem) :
nullptr);
137 iHead =
reinterpret_cast<link*
>(iChunks->iMem);
140 template <
typename CharT,
typename Traits>
141 void info(std::basic_ostream<CharT, Traits>& aOutput)
145 for (chunk* n = iChunks; n !=
nullptr; n = n->iNext)
148 char* start = n->iMem;
149 char* last = start + chunk_size();
150 if (
reinterpret_cast<char*
>(iHead) >= start &&
reinterpret_cast<char*
>(iHead) < last)
151 pct =
static_cast<uint32_t
>((
reinterpret_cast<char*
>(iHead) - start) * 100 / (last - start));
153 aOutput <<
"Number of chunks: " << total << std::endl;
155 aOutput <<
"% utilization of last used chunk: " << pct <<
"%" << std::endl;
160 chunk* n =
new chunk;
164 constexpr std::size_t nelem = chunk_size() / element_size();
165 char* start = n->iMem;
166 char* last = start + nelem * element_size();
167 if constexpr (!Omega)
168 for (
char* p = start; p < last; p += element_size())
169 reinterpret_cast<link*
>(p)->iNext =
reinterpret_cast<link*
>(p + element_size());
171 std::memset(start, 0xFF, last - start);
173 reinterpret_cast<link*
>(last - element_size())->iNext =
nullptr;
174 iHead =
reinterpret_cast<link*
>(start);
191 template <
typename U>
205 return reinterpret_cast<pointer>(get_pool().allocate());
207 return backup_allocator().allocate(aCount);
212 if constexpr (!Omega)
215 get_pool().deallocate(aObject);
217 backup_allocator().deallocate(aObject, aCount);
223 new (aObject) T(val);
226 template <
typename... Args>
229 new (aObject) T(std::forward<Args>(aArguments)...);
234 if constexpr (!Omega)
240 get_pool().omega_recycle();
243 template <
typename CharT,
typename Traits>
244 static void info(std::basic_ostream<CharT, Traits>& aOutput)
246 get_pool().info(aOutput);
249 template <
typename U>
262 static backup_allocator_t& backup_allocator()
264 static backup_allocator_t sBackupAllocator;
265 return sBackupAllocator;
267 static pool& get_pool()
274 template <
typename T, std::
size_t N, std::
size_t Instance = 0>
288 struct link { link* iNext; };
296 alignas(T)
char a[
sizeof(T)];
297 alignas(link)
char b[
sizeof(link)];
302 block() : iElementSize(sizeof(T) < sizeof(link) ? sizeof(link) : sizeof(T)), iMem(reinterpret_cast<char*>(iBuffer.iBuffer)), iHead(reinterpret_cast<link*>(iMem)) { init(); }
306 char* last = &start[(N - 1) * iElementSize];
307 for (
char* p = start; p < last; p += iElementSize)
308 reinterpret_cast<link*
>(p)->iNext =
reinterpret_cast<link*
>(p + iElementSize);
309 reinterpret_cast<link*
>(last)->iNext =
nullptr;
313 if (iHead ==
nullptr)
314 throw std::bad_alloc();
319 void deallocate(
void* aObject)
321 link* p =
reinterpret_cast<link*
>(aObject);
331 template <
typename U>
340 throw std::bad_alloc();
341 return reinterpret_cast<T*
>(get_block().allocate());
347 throw std::logic_error(
"neolib::reserve_allocator::deallocate");
348 get_block().deallocate(aObject);
353 new (aObject) T(val);
361 template <
typename U>
374 static block& get_block()
381 template <
typename T, std::
size_t SmallBufferSize = 8u>
384 template <
typename T,
typename R>
391 template <
typename T, std::
size_t SmallBufferSize>
403 template <
typename T,
typename R, std::
size_t SmallBufferSize>
407 template <
typename, std::
size_t>
410 struct no_small_buffer : std::logic_error {
no_small_buffer() : std::logic_error(
"neolib::basic_small_buffer_allocator::no_small_buffer") {} };
420 typedef typename std::allocator_traits<default_allocator_type>::pointer
pointer;
435 iBuffer{ aOther.iBuffer }
443 template <
typename U>
449 template <
typename U>
458 iBuffer = aOther.iBuffer;
466 template <
typename U>
472 template <
typename U>
490 return allocate(n,
nullptr);
494 if constexpr (std::is_same_v<value_type, controlled_value_type>)
496 if (n <= SmallBufferSize && is_buffer_available())
498 buffer().allocated =
true;
499 return reinterpret_cast<pointer>(&buffer().storage);
502 return default_allocator_type::allocate(n);
505 return default_allocator_type::allocate(n);
509 if constexpr (std::is_same_v<value_type, controlled_value_type>)
511 if (is_buffer_used() && p ==
reinterpret_cast<pointer>(&buffer().storage))
512 buffer().allocated =
false;
514 default_allocator_type::deallocate(p, n);
517 default_allocator_type::deallocate(p, n);
522 return iBuffer !=
nullptr;
526 return has_buffer() && !buffer().allocated;
530 return has_buffer() && buffer().allocated;
536 throw no_small_buffer();
543 small_buffer_type* iBuffer;
546 template <
typename T,
typename U, std::
size_t SmallBufferSize>
552 template <
typename T,
typename U, std::
size_t SmallBufferSize>
558 template <
typename T, std::
size_t SmallBufferSize = 8u>
562 template <
typename T, std::
size_t ChunkSize = 1 * 1024 * 1024>
565 template <
typename T,
unsigned NextSize = 32>
566 using thread_safe_pool_allocator = boost::pool_allocator<T, boost::default_user_allocator_new_delete, boost::details::pool::default_mutex, NextSize>;
567 template <
typename T,
unsigned NextSize = 32>
568 using pool_allocator = boost::pool_allocator<T, boost::default_user_allocator_new_delete, boost::details::pool::null_mutex, NextSize>;
570 template <
typename T,
unsigned NextSize = 32>
572 template <
typename T,
unsigned NextSize = 32>
573 using fast_pool_allocator = boost::fast_pool_allocator<T, boost::default_user_allocator_new_delete, boost::details::pool::null_mutex, NextSize>;
basic_small_buffer_allocator & operator=(const basic_small_buffer_allocator &aOther)
small_buffer_type & buffer()
bool is_buffer_used() const
bool is_buffer_available() const
bool operator!=(const basic_small_buffer_allocator &aOther) const
const small_buffer_type & buffer() const
basic_small_buffer_allocator(basic_small_buffer_allocator &&aOther)
basic_small_buffer_allocator()
std::allocator_traits< default_allocator_type >::pointer pointer
basic_small_buffer_allocator(small_buffer_type &aBuffer)
pointer allocate(std::size_t n, const void *)
basic_small_buffer_allocator(const basic_small_buffer_allocator &aOther)
pointer allocate(std::size_t n)
basic_small_buffer_allocator(const basic_small_buffer_allocator< U, SmallBufferSize > &aOther)
small_buffer_allocator_types< T, R > types
std::allocator< value_type > default_allocator_type
basic_small_buffer_allocator & operator=(basic_small_buffer_allocator &&aOther)
basic_small_buffer_allocator(const basic_small_buffer_allocator< U, SmallBufferSize > &&aOther)
bool operator==(const basic_small_buffer_allocator &aOther) const
std::false_type is_always_equal
basic_small_buffer_allocator & operator=(basic_small_buffer_allocator< U, SmallBufferSize > &&aOther)
small_buffer< controlled_value_type, SmallBufferSize > small_buffer_type
basic_small_buffer_allocator & operator=(const basic_small_buffer_allocator< U, SmallBufferSize > &aOther)
void deallocate(pointer p, std::size_t n)
std::false_type propagate_on_container_move_assignment
neo_pool_allocator(const neo_pool_allocator< U, ChunkSize, Omega, Instance > &)
static void construct(pointer aObject, const_reference val)
const T & const_reference
neo_pool_allocator(const neo_pool_allocator &)
bool operator==(const neo_pool_allocator &) const
static void deallocate(pointer aObject, size_type aCount=1)
ptrdiff_t difference_type
static void destroy(pointer aObject)
static void construct(pointer aObject, Args &&... aArguments)
size_type max_size() const
static void info(std::basic_ostream< CharT, Traits > &aOutput)
static pointer allocate(size_type aCount=1)
bool operator!=(const neo_pool_allocator &) const
static void omega_recycle()
void deallocate(T *aObject, size_type aCount=1)
const T & const_reference
reserve_allocator(const reserve_allocator &rhs)
bool operator!=(const reserve_allocator &) const
ptrdiff_t difference_type
T * allocate(size_type aCount=1)
bool operator==(const reserve_allocator &) const
reserve_allocator(const reserve_allocator< U, N, Instance > &rhs)
size_type max_size() const
void construct(pointer aObject, const_reference val)
void destroy(pointer aObject)
basic_length< T > pct(T aValue)
boost::pool_allocator< T, boost::default_user_allocator_new_delete, boost::details::pool::default_mutex, NextSize > thread_safe_pool_allocator
boost::fast_pool_allocator< T, boost::default_user_allocator_new_delete, boost::details::pool::default_mutex, NextSize > thread_safe_fast_pool_allocator
to_const_reference_t< T > to_const(T &&object)
boost::fast_pool_allocator< T, boost::default_user_allocator_new_delete, boost::details::pool::null_mutex, NextSize > fast_pool_allocator
neo_pool_allocator< T, ChunkSize, true > omega_pool_allocator
boost::pool_allocator< T, boost::default_user_allocator_new_delete, boost::details::pool::null_mutex, NextSize > pool_allocator
basic_small_buffer_allocator< small_buffer_allocator_types< T, U >, SmallBufferSize > other
neo_pool_allocator< U, ChunkSize, Omega, Instance > other
reserve_allocator< U, N, Instance > other
std::aligned_storage_t< sizeof(value_type) *SmallBufferSize > buffer_storage_t
small_buffer & operator=(const small_buffer &)
small_buffer(const small_buffer &)