Container System 0.1.0
High-performance C++20 type-safe container framework with SIMD-accelerated serialization
Loading...
Searching...
No Matches
pool_allocator.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
5#pragma once
6
20#include "memory_pool.h"
21
22#include <cstddef>
23#include <atomic>
24#include <new>
25#include <type_traits>
26#include <utility>
27
29
34 static constexpr std::size_t small_threshold = 64; // <= 64 bytes
35 static constexpr std::size_t medium_threshold = 256; // <= 256 bytes
36 static constexpr std::size_t blocks_per_chunk = 1024;
37};
38
43 std::size_t pool_hits{0}; // Allocations satisfied from pool
44 std::size_t pool_misses{0}; // Allocations that went to heap
45 std::size_t small_pool_allocs{0}; // Small pool allocations
46 std::size_t medium_pool_allocs{0}; // Medium pool allocations
47 std::size_t deallocations{0}; // Total deallocations
48
49 double hit_rate() const noexcept {
50 auto total = pool_hits + pool_misses;
51 return total > 0 ? static_cast<double>(pool_hits) / total : 0.0;
52 }
53};
54
62public:
67 static pool_allocator& instance() noexcept {
68 thread_local pool_allocator allocator;
69 return allocator;
70 }
71
77 void* allocate(std::size_t size) noexcept {
78 if (size == 0) {
79 return nullptr;
80 }
81
82#if CONTAINER_USE_MEMORY_POOL
83 try {
85 void* ptr = small_pool_.allocate();
88 return ptr;
89 } else if (size <= pool_size_class::medium_threshold) {
90 void* ptr = medium_pool_.allocate();
93 return ptr;
94 }
95 } catch (...) {
96 // Pool allocation failed, fall through to heap
97 }
98#endif
99 // Large allocation or pool disabled: use heap
101 return ::operator new(size, std::nothrow);
102 }
103
109 void deallocate(void* ptr, std::size_t size) noexcept {
110 if (!ptr) {
111 return;
112 }
113
115
116#if CONTAINER_USE_MEMORY_POOL
119 return;
120 } else if (size <= pool_size_class::medium_threshold) {
122 return;
123 }
124#endif
125 // Large allocation: use heap
126 ::operator delete(ptr);
127 }
128
134 return stats_;
135 }
136
144
152
156 void reset_stats() noexcept {
158 }
159
160private:
162 : small_pool_(pool_size_class::small_threshold, pool_size_class::blocks_per_chunk)
163 , medium_pool_(pool_size_class::medium_threshold, pool_size_class::blocks_per_chunk)
164 {}
165
166 // Non-copyable, non-movable
171
175};
176
184template<typename T, typename... Args>
185T* pool_allocate(Args&&... args) noexcept {
186 static_assert(std::is_nothrow_destructible_v<T>,
187 "pool_allocate requires nothrow destructible types");
188
189 void* ptr = pool_allocator::instance().allocate(sizeof(T));
190 if (!ptr) {
191 return nullptr;
192 }
193
194 try {
195 return new (ptr) T(std::forward<Args>(args)...);
196 } catch (...) {
197 pool_allocator::instance().deallocate(ptr, sizeof(T));
198 return nullptr;
199 }
200}
201
207template<typename T>
208void pool_deallocate(T* ptr) noexcept {
209 if (!ptr) {
210 return;
211 }
212
213 ptr->~T();
214 pool_allocator::instance().deallocate(ptr, sizeof(T));
215}
216
222template<typename T>
223constexpr bool is_pool_allocatable() noexcept {
224 return sizeof(T) <= pool_size_class::medium_threshold;
225}
226
232inline constexpr int get_size_class(std::size_t size) noexcept {
234 return 0;
235 } else if (size <= pool_size_class::medium_threshold) {
236 return 1;
237 }
238 return 2;
239}
240
241} // namespace kcenon::container::internal
statistics get_statistics() const
Get current pool statistics.
Thread-local pool manager for value_container allocations.
static pool_allocator & instance() noexcept
Get the singleton instance.
pool_allocator_stats get_stats() const noexcept
Get allocation statistics.
fixed_block_pool::statistics get_medium_pool_stats() const
Get statistics from the medium pool.
void reset_stats() noexcept
Reset statistics (for benchmarking)
pool_allocator & operator=(const pool_allocator &)=delete
pool_allocator(const pool_allocator &)=delete
void deallocate(void *ptr, std::size_t size) noexcept
Deallocate memory to the appropriate pool.
pool_allocator(pool_allocator &&)=delete
pool_allocator & operator=(pool_allocator &&)=delete
fixed_block_pool::statistics get_small_pool_stats() const
Get statistics from the small pool.
void * allocate(std::size_t size) noexcept
Allocate memory from the appropriate pool.
constexpr bool is_pool_allocatable() noexcept
Check if a type is suitable for pool allocation.
void pool_deallocate(T *ptr) noexcept
Destroy and deallocate an object allocated with pool_allocate.
constexpr int get_size_class(std::size_t size) noexcept
Get the size class for a given size.
T * pool_allocate(Args &&... args) noexcept
Allocate and construct an object using pool allocation.
Statistics for monitoring memory pool usage.
Definition memory_pool.h:81
Extended pool statistics with hit/miss tracking.
Size class thresholds for pool allocation.
static constexpr std::size_t medium_threshold
static constexpr std::size_t blocks_per_chunk
static constexpr std::size_t small_threshold