17 #ifndef _UTIL_POOL_ALLOCATOR_H_
18 #define _UTIL_POOL_ALLOCATOR_H_
24 #include <unordered_map>
33 #define NOEXCEPT _GLIBCXX_USE_NOEXCEPT
42 template <
size_t ELEM_SIZE,
unsigned CHUNK_SIZE = 4096>
class pool_allocator {
50 void* allocate(uint64_t
id = 0);
83 using chunk_type = uint8_t[ELEM_SIZE];
84 std::vector<std::array<chunk_type, CHUNK_SIZE>*> chunks{};
85 std::deque<void*> free_list{};
86 std::unordered_map<void*, uint64_t> used_blocks{};
88 const bool debug_memory{getenv(
"TLM_MM_CHECK") !=
nullptr};
90 const bool debug_memory{
false};
97 typedef value_type* pointer;
98 typedef const value_type* const_pointer;
99 typedef value_type& reference;
100 typedef const value_type& const_reference;
101 typedef std::size_t size_type;
102 typedef std::ptrdiff_t difference_type;
110 ~stl_pool_allocator() NOEXCEPT {}
113 pointer address(reference r) {
return std::addressof(r); }
114 const_pointer address(const_reference r) {
return std::addressof(r); }
116 pointer allocate(size_type n,
const void* = 0) {
117 size_type value = 16;
134 return static_cast<T*
>(::operator
new(n *
sizeof(T)));
138 void deallocate(T* p, size_type n) noexcept {
139 size_type value = 16;
162 ::operator
delete(p);
165 size_type max_size() const noexcept {
return std::numeric_limits<size_type>::max() /
sizeof(T); }
167 bool operator==(stl_pool_allocator
const&) {
return true; }
168 bool operator!=(stl_pool_allocator
const& oAllocator) {
return !operator==(oAllocator); }
179 auto* check = getenv(
"TLM_MM_CHECK");
180 auto diff = get_capacity() - get_free_entries_count();
182 std::cerr << __FUNCTION__ <<
": detected memory leak upon destruction, " << diff <<
" of " << get_capacity()
183 <<
" entries are not free'd" << std::endl;
185 if(check && _stricmp(check,
"DEBUG") == 0) {
187 if(check && strcasecmp(check,
"DEBUG") == 0) {
189 std::vector<std::pair<void*, uint64_t>> elems(used_blocks.begin(), used_blocks.end());
190 std::sort(elems.begin(), elems.end(), [](std::pair<void*, uint64_t>
const& a, std::pair<void*, uint64_t>
const& b) ->
bool {
191 return a.second == b.second ? a.first < b.first : a.second < b.second;
193 std::cerr <<
"The 10 blocks with smallest id are:\n";
194 for(
size_t i = 0; i < std::min<decltype(i)>(10UL, elems.size()); ++i) {
195 std::cerr <<
"\taddr=" << elems[i].first <<
", id=" << elems[i].second <<
"\n";
206 if(!free_list.size())
208 auto ret = free_list.back();
209 free_list.pop_back();
210 memset(ret, 0, ELEM_SIZE);
212 used_blocks.insert({ret,
id});
218 free_list.push_back(p);
220 used_blocks.erase(p);
225 auto* chunk =
new std::array<chunk_type, CHUNK_SIZE>();
226 chunks.push_back(chunk);
227 for(
auto& p : *chunk)
228 free_list.push_back(&p[0]);
232 return chunks.size() * CHUNK_SIZE;
236 return free_list.size();
a generic pool allocator singleton not being MT-safe
pool_allocator(const pool_allocator &)=delete
deleted constructor
void resize()
add CHUNK_SIZE elements to the pool
static pool_allocator & get()
pool allocator getter
pool_allocator(pool_allocator &&)=delete
deleted constructor
size_t get_capacity()
get the number of allocated bytes
void free(void *p)
pit the memory back into the pool
pool_allocator & operator=(pool_allocator &&)=delete
deleted assignment operator
size_t get_free_entries_count()
get the number of free elements
~pool_allocator()
deleted destructor
pool_allocator & operator=(const pool_allocator &)=delete
deleted assignment operator