summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/plib/palloc.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/netlist/plib/palloc.h')
-rw-r--r--src/lib/netlist/plib/palloc.h513
1 files changed, 384 insertions, 129 deletions
diff --git a/src/lib/netlist/plib/palloc.h b/src/lib/netlist/plib/palloc.h
index a35bc50ff17..15fede3a99b 100644
--- a/src/lib/netlist/plib/palloc.h
+++ b/src/lib/netlist/plib/palloc.h
@@ -8,172 +8,427 @@
#ifndef PALLOC_H_
#define PALLOC_H_
+#include "pconfig.h"
#include "pstring.h"
+#include "ptypes.h"
-#include <vector>
+#include <cstddef>
+#include <cstdlib>
#include <memory>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER)
+#include <malloc.h>
+#endif
namespace plib {
-//============================================================
-// Memory allocation
-//============================================================
-
-template<typename T, typename... Args>
-T *palloc(Args&&... args)
-{
- return new T(std::forward<Args>(args)...);
-}
-
-template<typename T>
-void pfree(T *ptr)
-{
- delete ptr;
-}
-
-template<typename T>
-T* palloc_array(const std::size_t num)
-{
- return new T[num]();
-}
-
-template<typename T>
-void pfree_array(T *ptr)
-{
- delete [] ptr;
-}
-
-template<typename T, typename... Args>
-std::unique_ptr<T> make_unique(Args&&... args)
-{
- return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
-}
-
-template<typename BC, typename DC, typename... Args>
-static std::unique_ptr<BC> make_unique_base(Args&&... args)
-{
- std::unique_ptr<BC> ret(new DC(std::forward<Args>(args)...));
- return ret;
-}
-
-template <typename SC>
-class owned_ptr
-{
-private:
- owned_ptr()
- : m_ptr(nullptr), m_is_owned(true) { }
-public:
- owned_ptr(SC *p, bool owned) noexcept
- : m_ptr(p), m_is_owned(owned)
- { }
-
- owned_ptr(const owned_ptr &r) = delete;
- owned_ptr & operator =(owned_ptr &r) = delete;
-
- template<typename DC>
- owned_ptr & operator =(owned_ptr<DC> &&r)
+ //============================================================
+ // Standard arena_deleter
+ //============================================================
+
+ template <typename P, typename T>
+ struct arena_deleter
+ {
+ //using arena_storage_type = P *;
+ using arena_storage_type = typename std::conditional<P::is_stateless, P, P *>::type;
+ template <typename X, typename Y = void>
+ typename std::enable_if<!X::is_stateless, X&>::type getref(X *x) { return *x;}
+ template <typename X, typename Y = void *>
+ typename std::enable_if<std::remove_pointer<X>::type::is_stateless, X&>::type
+ getref(X &x, Y y = nullptr)
+ {
+ unused_var(y);
+ return x;
+ }
+
+ constexpr arena_deleter(arena_storage_type a = arena_storage_type()) noexcept
+ : m_a(a) { }
+
+ template<typename PU, typename U, typename = typename
+ std::enable_if<std::is_convertible< U*, T*>::value>::type>
+ arena_deleter(const arena_deleter<PU, U> &rhs) noexcept : m_a(rhs.m_a) { }
+
+ void operator()(T *p) //const
+ {
+ /* call destructor */
+ p->~T();
+ getref(m_a).deallocate(p);
+ }
+ //private:
+ arena_storage_type m_a;
+ };
+
+ //============================================================
+ // owned_ptr: smart pointer with ownership information
+ //============================================================
+
+ template <typename SC, typename D>
+ class owned_ptr
+ {
+ public:
+
+ using pointer = SC *;
+ using element_type = SC;
+ using deleter_type = D;
+
+ owned_ptr()
+ : m_ptr(nullptr), m_deleter(), m_is_owned(true) { }
+
+ template <typename, typename>
+ friend class owned_ptr;
+
+ owned_ptr(pointer p, bool owned) noexcept
+ : m_ptr(p), m_deleter(), m_is_owned(owned)
+ { }
+
+ owned_ptr(pointer p, bool owned, D deleter) noexcept
+ : m_ptr(p), m_deleter(deleter), m_is_owned(owned)
+ { }
+
+
+ owned_ptr(const owned_ptr &r) = delete;
+ owned_ptr & operator =(owned_ptr &r) = delete;
+
+ template<typename DC, typename DC_D>
+ owned_ptr & operator =(owned_ptr<DC, DC_D> &&r)
+ {
+ if (m_is_owned && (m_ptr != nullptr))
+ //delete m_ptr;
+ m_deleter(m_ptr);
+ m_is_owned = r.m_is_owned;
+ m_ptr = r.m_ptr;
+ m_deleter = r.m_deleter;
+ r.m_is_owned = false;
+ r.m_ptr = nullptr;
+ return *this;
+ }
+
+ owned_ptr(owned_ptr &&r) noexcept
+ : m_ptr(r.m_ptr)
+ , m_deleter(r.m_deleter)
+ , m_is_owned(r.m_is_owned)
+ {
+ r.m_is_owned = false;
+ r.m_ptr = nullptr;
+ }
+
+ owned_ptr &operator=(owned_ptr &&r) noexcept
+ {
+ if (m_is_owned && (m_ptr != nullptr))
+ //delete m_ptr;
+ m_deleter(m_ptr);
+ m_is_owned = r.m_is_owned;
+ m_ptr = r.m_ptr;
+ m_deleter = std::move(r.m_deleter);
+ r.m_is_owned = false;
+ r.m_ptr = nullptr;
+ return *this;
+ }
+
+ template<typename DC, typename DC_D>
+ owned_ptr(owned_ptr<DC, DC_D> &&r) noexcept
+ : m_ptr(static_cast<pointer >(r.get()))
+ , m_deleter(r.m_deleter)
+ , m_is_owned(r.is_owned())
+ {
+ r.release();
+ }
+
+ ~owned_ptr() noexcept
+ {
+ if (m_is_owned && (m_ptr != nullptr))
+ {
+ //delete m_ptr;
+ m_deleter(m_ptr);
+ }
+ m_is_owned = false;
+ m_ptr = nullptr;
+ }
+
+ /**
+ * \brief Return @c true if the stored pointer is not null.
+ */
+ explicit operator bool() const noexcept { return m_ptr != nullptr; }
+
+ pointer release()
+ {
+ pointer tmp = m_ptr;
+ m_is_owned = false;
+ m_ptr = nullptr;
+ return tmp;
+ }
+
+ bool is_owned() const { return m_is_owned; }
+
+ pointer operator ->() const noexcept { return m_ptr; }
+ typename std::add_lvalue_reference<element_type>::type operator *() const noexcept { return *m_ptr; }
+ pointer get() const noexcept { return m_ptr; }
+
+ deleter_type& get_deleter() noexcept { return m_deleter; }
+ const deleter_type& get_deleter() const noexcept { return m_deleter; }
+
+ private:
+ pointer m_ptr;
+ D m_deleter;
+ bool m_is_owned;
+ };
+
+ //============================================================
+ // Arena allocator for use with containers
+ //============================================================
+
+ template <class ARENA, class T, std::size_t ALIGN = alignof(T)>
+ class arena_allocator
{
- if (m_is_owned && (m_ptr != nullptr))
- delete m_ptr;
- m_is_owned = r.m_is_owned;
- m_ptr = r.m_ptr;
- r.m_is_owned = false;
- r.m_ptr = nullptr;
- return *this;
+ public:
+ using value_type = T;
+ static constexpr const std::size_t align_size = ALIGN;
+ using arena_type = ARENA;
+
+ static_assert(align_size >= alignof(T) && (align_size % alignof(T)) == 0,
+ "ALIGN must be greater than alignof(T) and a multiple");
+
+ arena_allocator() noexcept
+ : m_a(arena_type::instance())
+ { }
+
+ ~arena_allocator() noexcept = default;
+
+ arena_allocator(const arena_allocator &rhs) noexcept = default;
+ arena_allocator& operator=(const arena_allocator&) noexcept = delete;
+
+ arena_allocator(arena_allocator&&) noexcept = default;
+ arena_allocator& operator=(arena_allocator&&) = delete;
+
+ arena_allocator(arena_type & a) noexcept : m_a(a)
+ {
+ }
+
+ template <class U>
+ arena_allocator(const arena_allocator<ARENA, U, ALIGN>& rhs) noexcept
+ : m_a(rhs.m_a)
+ {
+ }
+
+ template <class U> struct rebind
+ {
+ using other = arena_allocator<ARENA, U, ALIGN>;
+ };
+
+ T* allocate(std::size_t n)
+ {
+ return reinterpret_cast<T *>(m_a.allocate(ALIGN, sizeof(T) * n));
+ }
+
+ void deallocate(T* p, std::size_t n) noexcept
+ {
+ unused_var(n);
+ m_a.deallocate(p);
+ }
+
+ template <class AR1, class T1, std::size_t A1, class AR2, class T2, std::size_t A2>
+ friend bool operator==(const arena_allocator<AR1, T1, A1>& lhs,
+ const arena_allocator<AR2, T2, A2>& rhs) noexcept;
+
+ template <class AU, class U, std::size_t A> friend class arena_allocator;
+ private:
+ arena_type &m_a;
+ };
+
+ template <class AR1, class T1, std::size_t A1, class AR2, class T2, std::size_t A2>
+ inline bool operator==(const arena_allocator<AR1, T1, A1>& lhs,
+ const arena_allocator<AR2, T2, A2>& rhs) noexcept
+ {
+ return A1 == A2 && rhs.m_a == lhs.m_a;
+ }
+ template <class AR1, class T1, std::size_t A1, class AR2, class T2, std::size_t A2>
+ inline bool operator!=(const arena_allocator<AR1, T1, A1>& lhs,
+ const arena_allocator<AR2, T2, A2>& rhs) noexcept
+ {
+ return !(lhs == rhs);
}
- owned_ptr(owned_ptr &&r) noexcept
+ //============================================================
+ // Memory allocation
+ //============================================================
+
+ struct aligned_arena
{
- m_is_owned = r.m_is_owned;
- m_ptr = r.m_ptr;
- r.m_is_owned = false;
- r.m_ptr = nullptr;
+ static constexpr const bool is_stateless = true;
+ template <class T, std::size_t ALIGN = alignof(T)>
+ using allocator_type = arena_allocator<aligned_arena, T, ALIGN>;
+
+ template <typename T>
+ using owned_pool_ptr = plib::owned_ptr<T, arena_deleter<aligned_arena, T>>;
+
+ static inline aligned_arena &instance()
+ {
+ static aligned_arena s_arena;
+ return s_arena;
+ }
+
+ static inline void *allocate( size_t alignment, size_t size )
+ {
+ #if (USE_ALIGNED_ALLOCATION)
+ #if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER)
+ return _aligned_malloc(size, alignment);
+ #elif defined(__APPLE__)
+ void* p;
+ if (::posix_memalign(&p, alignment, size) != 0) {
+ p = nullptr;
+ }
+ return p;
+ #else
+ return aligned_alloc(alignment, size);
+ #endif
+ #else
+ unused_var(alignment);
+ return ::operator new(size);
+ #endif
+ }
+
+ static inline void deallocate( void *ptr )
+ {
+ #if (USE_ALIGNED_ALLOCATION)
+ // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
+ free(ptr);
+ #else
+ ::operator delete(ptr);
+ #endif
+ }
+
+ template<typename T, typename... Args>
+ owned_pool_ptr<T> make_poolptr(Args&&... args)
+ {
+ auto *mem = allocate(alignof(T), sizeof(T));
+ return owned_pool_ptr<T>(new (mem) T(std::forward<Args>(args)...), true, arena_deleter<aligned_arena, T>(*this));
+ }
+
+ };
+
+ template <typename T, std::size_t ALIGN>
+ /*inline */ C14CONSTEXPR T *assume_aligned_ptr(T *p) noexcept
+ {
+ static_assert(ALIGN >= alignof(T), "Alignment must be greater or equal to alignof(T)");
+ static_assert(is_pow2(ALIGN), "Alignment must be a power of 2");
+ //auto t = reinterpret_cast<std::uintptr_t>(p);
+ //if (t & (ALIGN-1))
+ // printf("alignment error!");
+#if (USE_ALIGNED_HINTS)
+ return reinterpret_cast<T *>(__builtin_assume_aligned(p, ALIGN));
+#else
+ return p;
+#endif
}
- template<typename DC>
- owned_ptr(owned_ptr<DC> &&r) noexcept
+ template <typename T, std::size_t ALIGN>
+ constexpr const T *assume_aligned_ptr(const T *p) noexcept
{
- m_ptr = static_cast<SC *>(r.get());
- m_is_owned = r.is_owned();
- r.release();
+ static_assert(ALIGN >= alignof(T), "Alignment must be greater or equal to alignof(T)");
+ static_assert(is_pow2(ALIGN), "Alignment must be a power of 2");
+#if (USE_ALIGNED_HINTS)
+ return reinterpret_cast<const T *>(__builtin_assume_aligned(p, ALIGN));
+#else
+ return p;
+#endif
}
- ~owned_ptr()
+ // FIXME: remove
+ template<typename T, typename... Args>
+ inline T *pnew(Args&&... args)
{
- if (m_is_owned && (m_ptr != nullptr))
- delete m_ptr;
- m_is_owned = false;
- m_ptr = nullptr;
+ auto *p = aligned_arena::allocate(alignof(T), sizeof(T));
+ return new(p) T(std::forward<Args>(args)...);
}
- template<typename DC, typename... Args>
- static owned_ptr Create(Args&&... args)
+
+ template<typename T>
+ inline void pdelete(T *ptr)
{
- owned_ptr a;
- DC *x = new DC(std::forward<Args>(args)...);
- a.m_ptr = static_cast<SC *>(x);
- return std::move(a);
+ ptr->~T();
+ aligned_arena::deallocate(ptr);
}
- template<typename... Args>
- static owned_ptr Create(Args&&... args)
+
+ template <typename T>
+ using unique_ptr = std::unique_ptr<T, arena_deleter<aligned_arena, T>>;
+
+ template<typename T, typename... Args>
+ plib::unique_ptr<T> make_unique(Args&&... args)
{
- owned_ptr a;
- a.m_ptr = new SC(std::forward<Args>(args)...);
- return std::move(a);
+ return plib::unique_ptr<T>(pnew<T>(std::forward<Args>(args)...));
}
- SC * release()
+
+#if 0
+ template<typename T, typename... Args>
+ static owned_ptr<T> make_owned(Args&&... args)
{
- SC *tmp = m_ptr;
- m_is_owned = false;
- m_ptr = nullptr;
- return tmp;
+ return owned_ptr<T>(pnew<T>(std::forward<Args>(args)...), true);
}
+#endif
+
- bool is_owned() const { return m_is_owned; }
+ template <class T, std::size_t ALIGN = alignof(T)>
+ using aligned_allocator = aligned_arena::allocator_type<T, ALIGN>;
- SC * operator ->() const { return m_ptr; }
- SC & operator *() const { return *m_ptr; }
- SC * get() const { return m_ptr; }
-private:
- SC *m_ptr;
- bool m_is_owned;
-};
+ //============================================================
+ // traits to determine alignment size and stride size
+ // from types supporting alignment
+ //============================================================
-class mempool
-{
-private:
- struct block
+ PDEFINE_HAS_MEMBER(has_align, align_size);
+
+ template <typename T, typename X = void>
+ struct align_traits
{
- block() : m_num_alloc(0), m_free(0), cur_ptr(nullptr), data(nullptr) { }
- std::size_t m_num_alloc;
- std::size_t m_free;
- char *cur_ptr;
- char *data;
+ static constexpr const std::size_t align_size = alignof(std::max_align_t);
+ static constexpr const std::size_t value_size = sizeof(typename T::value_type);
+ static constexpr const std::size_t stride_size = lcm(align_size, value_size) / value_size;
};
- size_t new_block();
- size_t mininfosize();
-
- struct info
+ template <typename T>
+ struct align_traits<T, typename std::enable_if<has_align<T>::value, void>::type>
{
- info() : m_block(0) { }
- size_t m_block;
+ static constexpr const std::size_t align_size = T::align_size;
+ static constexpr const std::size_t value_size = sizeof(typename T::value_type);
+ static constexpr const std::size_t stride_size = lcm(align_size, value_size) / value_size;
};
- size_t m_min_alloc;
- size_t m_min_align;
+ //============================================================
+ // Aligned vector
+ //============================================================
- std::vector<block> m_blocks;
+ // FIXME: needs a separate file
+ template <class T, std::size_t ALIGN = alignof(T)>
+ class aligned_vector : public std::vector<T, aligned_allocator<T, ALIGN>>
+ {
+ public:
+ using base = std::vector<T, aligned_allocator<T, ALIGN>>;
+
+ using reference = typename base::reference;
+ using const_reference = typename base::const_reference;
+ using pointer = typename base::pointer;
+ using const_pointer = typename base::const_pointer;
+ using size_type = typename base::size_type;
-public:
- mempool(size_t min_alloc, size_t min_align);
- ~mempool();
+ using base::base;
- void *alloc(size_t size);
- void free(void *ptr);
+ C14CONSTEXPR reference operator[](size_type i) noexcept
+ {
+ return assume_aligned_ptr<T, ALIGN>(&(base::operator[](0)))[i];
+ }
+ constexpr const_reference operator[](size_type i) const noexcept
+ {
+ return assume_aligned_ptr<T, ALIGN>(&(base::operator[](0)))[i];
+ }
-};
+ pointer data() noexcept { return assume_aligned_ptr<T, ALIGN>(base::data()); }
+ const_pointer data() const noexcept { return assume_aligned_ptr<T, ALIGN>(base::data()); }
+
+ };
-}
+} // namespace plib
#endif /* PALLOC_H_ */