diff options
Diffstat (limited to 'src/lib/netlist/plib/pmempool.h')
-rw-r--r-- | src/lib/netlist/plib/pmempool.h | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/src/lib/netlist/plib/pmempool.h b/src/lib/netlist/plib/pmempool.h new file mode 100644 index 00000000000..f55807c86dc --- /dev/null +++ b/src/lib/netlist/plib/pmempool.h @@ -0,0 +1,187 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * pmempool.h + * + */ + +#ifndef PMEMPOOL_H_ +#define PMEMPOOL_H_ + +#include "palloc.h" +#include "pstream.h" +#include "pstring.h" +#include "ptypes.h" +#include "putil.h" + +#include <algorithm> +#include <cstddef> +#include <memory> +#include <unordered_map> +#include <utility> +#include <vector> + +namespace plib { + + //============================================================ + // Memory pool + //============================================================ + + class mempool + { + private: + struct block + { + block(mempool *mp, std::size_t 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; + std::size_t alloc_bytes = (min_bytes + mp->m_min_align - 1) & ~(mp->m_min_align - 1); + m_data_allocated = static_cast<char *>(::operator new(alloc_bytes)); + void *r = m_data_allocated; + std::align(mp->m_min_align, min_bytes, r, alloc_bytes); + m_data = reinterpret_cast<char *>(r); + } + std::size_t m_num_alloc; + std::size_t m_free; + std::size_t m_cur; + char *m_data; + char *m_data_allocated; + mempool *m_mempool; + }; + + struct info + { + info(block *b, std::size_t p) : m_block(b), m_pos(p) { } + ~info() = default; + COPYASSIGNMOVE(info, default) + + block * m_block; + std::size_t m_pos; + }; + + + block * new_block(std::size_t min_bytes) + { + auto *b = plib::pnew<block>(this, min_bytes); + m_blocks.push_back(b); + return b; + } + + + static std::unordered_map<void *, info> &sinfo() + { + static std::unordered_map<void *, info> spinfo; + return spinfo; + } + + size_t m_min_alloc; + size_t m_min_align; + + std::vector<block *> m_blocks; + + public: + static constexpr const bool is_stateless = false; + template <class T, std::size_t ALIGN = alignof(T)> + using allocator_type = arena_allocator<mempool, T, ALIGN>; + + mempool(size_t min_alloc = (1<<21), size_t min_align = 16) + : m_min_alloc(min_alloc), m_min_align(min_align) + { + } + + COPYASSIGNMOVE(mempool, delete) + + ~mempool() + { + + for (auto & b : m_blocks) + { + if (b->m_num_alloc != 0) + { + plib::perrlogger("Found {} info blocks\n", sinfo().size()); + plib::perrlogger("Found block with {} dangling allocations\n", b->m_num_alloc); + } + ::operator delete(b->m_data); + } + } + + void *allocate(size_t align, size_t size) + { + if (align < m_min_align) + align = m_min_align; + + size_t rs = size + align; + for (auto &b : m_blocks) + { + if (b->m_free > rs) + { + b->m_free -= rs; + b->m_num_alloc++; + auto *ret = reinterpret_cast<void *>(b->m_data + b->m_cur); + auto capacity(rs); + ret = std::align(align, size, ret, capacity); + // FIXME: if (ret == nullptr) + // printf("Oh no\n"); + sinfo().insert({ ret, info(b, b->m_cur)}); + rs -= (capacity - size); + b->m_cur += rs; + + return ret; + } + } + { + block *b = new_block(rs); + b->m_num_alloc = 1; + b->m_free = m_min_alloc - rs; + auto *ret = reinterpret_cast<void *>(b->m_data + b->m_cur); + auto capacity(rs); + ret = std::align(align, size, ret, capacity); + // FIXME: if (ret == nullptr) + // printf("Oh no\n"); + sinfo().insert({ ret, info(b, b->m_cur)}); + rs -= (capacity - size); + b->m_cur += rs; + return ret; + } + } + + static void deallocate(void *ptr) + { + + auto it = sinfo().find(ptr); + if (it == sinfo().end()) + plib::terminate("mempool::free - pointer not found\n"); + info i = it->second; + block *b = i.m_block; + if (b->m_num_alloc == 0) + plib::terminate("mempool::free - double free was called\n"); + else + { + //b->m_free = m_min_alloc; + //b->cur_ptr = b->data; + } + b->m_num_alloc--; + //printf("Freeing in block %p %lu\n", b, b->m_num_alloc); + sinfo().erase(it); + } + + template <typename T> + using owned_pool_ptr = plib::owned_ptr<T, arena_deleter<mempool, T>>; + + template<typename T, typename... Args> + owned_pool_ptr<T> make_poolptr(Args&&... args) + { + auto *mem = this->allocate(alignof(T), sizeof(T)); + return owned_pool_ptr<T>(new (mem) T(std::forward<Args>(args)...), true, arena_deleter<mempool, T>(this)); + } + + }; + +} // namespace plib + +#endif /* PMEMPOOL_H_ */ |