diff options
Diffstat (limited to 'src/lib/netlist/plib/palloc.h')
-rw-r--r-- | src/lib/netlist/plib/palloc.h | 378 |
1 files changed, 211 insertions, 167 deletions
diff --git a/src/lib/netlist/plib/palloc.h b/src/lib/netlist/plib/palloc.h index d7b00262f7f..f10fd548817 100644 --- a/src/lib/netlist/plib/palloc.h +++ b/src/lib/netlist/plib/palloc.h @@ -17,6 +17,7 @@ #include <memory> #include <utility> #include <vector> +#include <type_traits> #if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER) #include <malloc.h> @@ -25,127 +26,65 @@ namespace plib { //============================================================ - // Memory allocation + // Standard arena_deleter //============================================================ -#if (USE_ALIGNED_ALLOCATION) - static inline void *paligned_alloc( size_t alignment, size_t size ) + template <typename P, typename T> + struct arena_deleter { -#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; + //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; } - return p; -#else - return aligned_alloc(alignment, size); -#endif - } - - static inline void pfree( void *ptr ) - { - // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) - free(ptr); - } - -#else - static inline void *paligned_alloc( size_t alignment, size_t size ) - { - unused_var(alignment); - return ::operator new(size); - } - - static inline void pfree( void *ptr ) - { - ::operator delete(ptr); - } -#endif - - 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 T, std::size_t ALIGN> - constexpr const T *assume_aligned_ptr(const 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"); -#if (USE_ALIGNED_HINTS) - return reinterpret_cast<const T *>(__builtin_assume_aligned(p, ALIGN)); -#else - return p; -#endif - } - - template<typename T, typename... Args> - inline T *pnew(Args&&... args) - { - auto *p = paligned_alloc(alignof(T), sizeof(T)); - return new(p) T(std::forward<Args>(args)...); - } - template<typename T> - inline void pdelete(T *ptr) - { - ptr->~T(); - pfree(ptr); - } + constexpr arena_deleter(arena_storage_type a = arena_storage_type()) noexcept + : m_a(a) { } - template<typename T> - inline T* pnew_array(const std::size_t num) - { - return new T[num](); - } - - template<typename T> - inline void pdelete_array(T *ptr) - { - delete [] ptr; - } - - template <typename T> - struct pdefault_deleter - { - constexpr pdefault_deleter() noexcept = default; - - template<typename U, typename = typename + template<typename PU, typename U, typename = typename std::enable_if<std::is_convertible< U*, T*>::value>::type> - pdefault_deleter(const pdefault_deleter<U>&) noexcept { } + arena_deleter(const arena_deleter<PU, U> &rhs) noexcept : m_a(rhs.m_a) { } - void operator()(T *p) const + void operator()(T *p) //const { - pdelete(p); + /* call destructor */ + p->~T(); + getref(m_a).deallocate(p); } + //private: + arena_storage_type m_a; }; - template <typename SC, typename D = pdefault_deleter<SC>> + //============================================================ + // 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_is_owned(true) { } + : m_ptr(nullptr), m_deleter(), m_is_owned(true) { } template <typename, typename> friend class owned_ptr; - owned_ptr(SC *p, bool owned) noexcept + owned_ptr(pointer p, bool owned) noexcept : m_ptr(p), m_deleter(), m_is_owned(owned) { } - owned_ptr(SC *p, bool owned, D deleter) noexcept + owned_ptr(pointer p, bool owned, D deleter) noexcept : m_ptr(p), m_deleter(deleter), m_is_owned(owned) { } @@ -168,10 +107,10 @@ namespace plib { } owned_ptr(owned_ptr &&r) noexcept + : m_ptr(r.m_ptr) + , m_deleter(r.m_deleter) + , m_is_owned(r.m_is_owned) { - 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; } @@ -183,7 +122,7 @@ namespace plib { m_deleter(m_ptr); m_is_owned = r.m_is_owned; m_ptr = r.m_ptr; - m_deleter = r.m_deleter; + m_deleter = std::move(r.m_deleter); r.m_is_owned = false; r.m_ptr = nullptr; return *this; @@ -191,10 +130,10 @@ namespace plib { 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()) { - m_ptr = static_cast<SC *>(r.get()); - m_is_owned = r.is_owned(); - m_deleter = r.m_deleter; r.release(); } @@ -208,9 +147,9 @@ namespace plib { m_is_owned = false; m_ptr = nullptr; } - SC * release() + pointer release() { - SC *tmp = m_ptr; + pointer tmp = m_ptr; m_is_owned = false; m_ptr = nullptr; return tmp; @@ -218,98 +157,217 @@ namespace plib { bool is_owned() const { return m_is_owned; } - SC * operator ->() const { return m_ptr; } - SC & operator *() const { return *m_ptr; } - SC * get() const { return m_ptr; } + 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: - SC *m_ptr; + pointer m_ptr; D m_deleter; bool m_is_owned; }; - template <typename T> - using unique_ptr = std::unique_ptr<T, pdefault_deleter<T>>; - - template<typename T, typename... Args> - plib::unique_ptr<T> make_unique(Args&&... args) - { - return plib::unique_ptr<T>(pnew<T>(std::forward<Args>(args)...)); - } - - template<typename T, typename... Args> - static owned_ptr<T> make_owned(Args&&... args) - { - owned_ptr<T> a(pnew<T>(std::forward<Args>(args)...), true); - return std::move(a); - } - //============================================================ - // Aligned allocator for use with containers + // Arena allocator for use with containers //============================================================ - template <class T, std::size_t ALIGN = alignof(T)> - class aligned_allocator + template <class ARENA, class T, std::size_t ALIGN = alignof(T)> + class arena_allocator { 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"); - aligned_allocator() noexcept = default; - ~aligned_allocator() noexcept = default; + arena_allocator() noexcept + : m_a(arena_type::instance()) + { } + + ~arena_allocator() noexcept = default; - aligned_allocator(const aligned_allocator&) noexcept = default; - aligned_allocator& operator=(const aligned_allocator&) noexcept = delete; + arena_allocator(const arena_allocator &rhs) noexcept : m_a(rhs.m_a) { printf("copy called\n"); }//= default; + arena_allocator& operator=(const arena_allocator&) noexcept = delete; - aligned_allocator(aligned_allocator&&) noexcept = default; - aligned_allocator& operator=(aligned_allocator&&) = 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> - aligned_allocator(const aligned_allocator<U, ALIGN>& rhs) noexcept + arena_allocator(const arena_allocator<ARENA, U, ALIGN>& rhs) noexcept + : m_a(rhs.m_a) { - unused_var(rhs); } template <class U> struct rebind { - using other = aligned_allocator<U, ALIGN>; + using other = arena_allocator<ARENA, U, ALIGN>; }; T* allocate(std::size_t n) { - return reinterpret_cast<T *>(paligned_alloc(ALIGN, sizeof(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); - pfree(p); + m_a.deallocate(p); } - template <class T1, std::size_t A1, class U, std::size_t A2> - friend bool operator==(const aligned_allocator<T1, A1>& lhs, - const aligned_allocator<U, A2>& rhs) noexcept; + 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 U, std::size_t A> friend class aligned_allocator; + template <class AU, class U, std::size_t A> friend class arena_allocator; + private: + arena_type &m_a; }; - template <class T1, std::size_t A1, class U, std::size_t A2> - /*friend*/ inline bool operator==(const aligned_allocator<T1, A1>& lhs, - const aligned_allocator<U, A2>& rhs) noexcept + 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 { - unused_var(lhs, rhs); - return A1 == A2; + return A1 == A2 && rhs.m_a == lhs.m_a; } - template <class T1, std::size_t A1, class U, std::size_t A2> - /*friend*/ inline bool operator!=(const aligned_allocator<T1, A1>& lhs, - const aligned_allocator<U, A2>& rhs) noexcept + 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); } //============================================================ + // Memory allocation + //============================================================ + + struct aligned_arena + { + 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 T, std::size_t ALIGN> + constexpr const T *assume_aligned_ptr(const 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"); +#if (USE_ALIGNED_HINTS) + return reinterpret_cast<const T *>(__builtin_assume_aligned(p, ALIGN)); +#else + return p; +#endif + } + + // FIXME: remove + template<typename T, typename... Args> + inline T *pnew(Args&&... args) + { + auto *p = aligned_arena::allocate(alignof(T), sizeof(T)); + return new(p) T(std::forward<Args>(args)...); + } + + template<typename T> + inline void pdelete(T *ptr) + { + ptr->~T(); + aligned_arena::deallocate(ptr); + } + + + 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) + { + return plib::unique_ptr<T>(pnew<T>(std::forward<Args>(args)...)); + } + +#if 0 + template<typename T, typename... Args> + static owned_ptr<T> make_owned(Args&&... args) + { + return owned_ptr<T>(pnew<T>(std::forward<Args>(args)...), true); + } +#endif + + + template <class T, std::size_t ALIGN = alignof(T)> + using aligned_allocator = aligned_arena::allocator_type<T, ALIGN>; + + //============================================================ // traits to determine alignment size and stride size // from types supporting alignment //============================================================ @@ -321,14 +379,7 @@ namespace plib { { 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); -#if 0 - static constexpr const std::size_t stride_size = - ((value_size % align_size) == 0 ? 1 //T is a multiple of align_size - : ((align_size % value_size) != 0 ? align_size // align_size is not a multiple of T - : align_size / value_size)); -#else static constexpr const std::size_t stride_size = lcm(align_size, value_size) / value_size; -#endif }; template <typename T> @@ -336,14 +387,7 @@ namespace plib { { static constexpr const std::size_t align_size = T::align_size; static constexpr const std::size_t value_size = sizeof(typename T::value_type); -#if 0 - static constexpr const std::size_t stride_size = - ((value_size % align_size) == 0 ? 1 //T is a multiple of align_size - : ((align_size % value_size) != 0 ? align_size // align_size is not a multiple of T - : align_size / value_size)); -#else static constexpr const std::size_t stride_size = lcm(align_size, value_size) / value_size; -#endif }; //============================================================ |