// license:GPL-2.0+ // copyright-holders:Couriersud #ifndef PMEMPOOL_H_ #define PMEMPOOL_H_ /// /// \file pmempool.h /// #include "palloc.h" #include "pconfig.h" #include "pstream.h" // perrlogger //#include "pstring.h" #include "ptypes.h" //#include "putil.h" #include #include #include #include #include namespace plib { //============================================================ // Memory pool //============================================================ template class mempool_arena : public arena_base, false, false> { public: using size_type = typename BASEARENA::size_type; using base_type = arena_base, false, false>; template using base_allocator_type = typename BASEARENA::template allocator_type; mempool_arena(size_t min_align = MINALIGN, size_t min_alloc = (1<<21)) : m_min_alloc(min_alloc) , m_min_align(min_align) , m_block_align(1024) , m_blocks(base_allocator_type(m_arena)) { } PCOPYASSIGNMOVE(mempool_arena, delete) ~mempool_arena() { for (auto & b : m_blocks) { if (b->m_num_alloc != 0) { plib::perrlogger("Found {} info blocks\n", m_info.size()); plib::perrlogger("Found block with {} dangling allocations\n", b->m_num_alloc); } detail::free(m_arena, b); } if (!m_info.empty()) plib::perrlogger("Still found {} info blocks after mempool deleted\n", m_info.size()); } void *allocate(size_t align, size_t size) { block *b = nullptr; if (align < m_min_align) align = m_min_align; size_t rs = size + align; for (auto &bs : m_blocks) { if (bs->m_free > rs) { b = bs; break; } } if (b == nullptr) { b = new_block(rs); } b->m_free -= rs; b->m_num_alloc++; void *ret = reinterpret_cast(b->m_data + b->m_cur); // NOLINT(cppcoreguidelines-pro-type-reinterpret auto capacity(rs); ret = std::align(align, size, ret, capacity); m_info.insert({ ret, info(b, b->m_cur)}); rs -= (capacity - size); b->m_cur += rs; this->inc_alloc_stat(size); return ret; } void deallocate(void *ptr, size_t size) noexcept { auto it = m_info.find(ptr); if (it == m_info.end()) plib::terminate("mempool::free - pointer not found"); block *b = it->second.m_block; if (b->m_num_alloc == 0) plib::terminate("mempool::free - double free was called"); else { mempool_arena &mp = b->m_mempool; b->m_num_alloc--; mp.dec_alloc_stat(size); if (b->m_num_alloc == 0) { auto itb = std::find(mp.m_blocks.begin(), mp.m_blocks.end(), b); if (itb == mp.m_blocks.end()) plib::terminate("mempool::free - block not found"); mp.m_blocks.erase(itb); detail::free(mp.base_arena(), b); } m_info.erase(it); } } bool operator ==(const mempool_arena &rhs) const noexcept { return this == &rhs; } BASEARENA &base_arena() noexcept { return m_arena; } private: struct block { block(mempool_arena &mp, size_type min_bytes) : m_num_alloc(0) , m_cur(0) , m_data(nullptr) , m_mempool(mp) { min_bytes = std::max(mp.m_min_alloc, min_bytes); m_free = min_bytes; m_bytes_allocated = (min_bytes + mp.m_block_align); // - 1); // & ~(mp.m_min_align - 1); // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) //m_data_allocated = new std::uint8_t[alloc_bytes]; m_data_allocated = static_cast(mp.base_arena().allocate(mp.m_block_align, m_bytes_allocated)); void *r = m_data_allocated; std::align(mp.m_block_align, min_bytes, r, m_bytes_allocated); m_data = reinterpret_cast(r); // NOLINT(cppcoreguidelines-pro-type-reinterpret } ~block() { //::operator delete(m_data_allocated); //delete [] m_data_allocated; m_mempool.base_arena().deallocate(m_data_allocated, m_bytes_allocated); } block(const block &) = delete; block(block &&) = delete; block &operator =(const block &) = delete; block &operator =(block &&) = delete; size_type m_num_alloc; size_type m_free; size_type m_cur; size_type m_bytes_allocated; std::uint8_t *m_data; std::uint8_t *m_data_allocated; mempool_arena &m_mempool; }; struct info { info(block *b, size_type p) : m_block(b), m_pos(p) { } ~info() = default; PCOPYASSIGNMOVE(info, default) block * m_block; size_type m_pos; }; block * new_block(size_type min_bytes) { auto *b = detail::alloc(m_arena, *this, min_bytes); m_blocks.push_back(b); return b; } size_t m_min_alloc; size_t m_min_align; size_t m_block_align; BASEARENA m_arena; using base_allocator_typex = typename BASEARENA::template allocator_type>; std::unordered_map, std::equal_to, base_allocator_typex> m_info; // std::unordered_map m_info; std::vector> m_blocks; }; } // namespace plib #endif // PMEMPOOL_H_