summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/plib/pmempool.h
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2019-03-26 11:13:37 +1100
committer Vas Crabb <vas@vastheman.com>2019-03-26 11:13:37 +1100
commit97b67170277437131adf6ed4d60139c172529e4f (patch)
tree7a5cbf608f191075f1612b1af15832c206a3fe2d /src/lib/netlist/plib/pmempool.h
parentb380514764cf857469bae61c11143a19f79a74c5 (diff)
(nw) Clean up the mess on master
This effectively reverts b380514764cf857469bae61c11143a19f79a74c5 and c24473ddff715ecec2e258a6eb38960cf8c8e98e, restoring the state at 598cd5227223c3b04ca31f0dbc1981256d9ea3ff. Before pushing, please check that what you're about to push is sane. Check your local commit log and ensure there isn't anything out-of-place before pushing to mainline. When things like this happen, it wastes everyone's time. I really don't need this in a week when real work™ is busting my balls and I'm behind where I want to be with preparing for MAME release.
Diffstat (limited to 'src/lib/netlist/plib/pmempool.h')
-rw-r--r--src/lib/netlist/plib/pmempool.h187
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_ */