diff options
Diffstat (limited to 'src/lib/netlist/plib/palloc.h')
-rw-r--r-- | src/lib/netlist/plib/palloc.h | 535 |
1 files changed, 334 insertions, 201 deletions
diff --git a/src/lib/netlist/plib/palloc.h b/src/lib/netlist/plib/palloc.h index eff105e224f..01bc131f926 100644 --- a/src/lib/netlist/plib/palloc.h +++ b/src/lib/netlist/plib/palloc.h @@ -28,94 +28,84 @@ namespace plib { //============================================================ - // aligned types - //============================================================ - -#if 0 -#if (PUSE_ALIGNED_HINTS) - template <typename T, std::size_t A> - using aligned_type __attribute__((aligned(A))) = T; -#else - template <typename T, std::size_t A> - using aligned_type = T; -#endif - - template <typename T, std::size_t A> - using aligned_pointer = aligned_type<T, A> *; - - template <typename T, std::size_t A> - using const_aligned_pointer = const aligned_type<T, A> *; - - template <typename T, std::size_t A> - using aligned_reference = aligned_type<T, A> &; - - template <typename T, std::size_t A> - using const_aligned_reference = const aligned_type<T, A> &; -#endif - //============================================================ // Standard arena_deleter //============================================================ - template <typename P, typename T, bool X> + template <typename P, typename T, std::size_t ALIGN, bool X> struct arena_deleter_base { }; - - template <typename P, typename T> - struct arena_deleter_base<P, T, false> + struct deleter_info_t { - using arena_storage_type = P; + std::size_t alignment; + std::size_t size; + }; - constexpr arena_deleter_base(arena_storage_type *a = nullptr) noexcept - : m_a(a) { } + template <typename P, typename T, std::size_t ALIGN> + struct arena_deleter_base<P, T, ALIGN, false> + { + constexpr arena_deleter_base(P *a = nullptr) noexcept + : m_arena(a), m_info({ALIGN ? ALIGN : alignof(T), sizeof(T)} ) { } template<typename U, typename = - std::enable_if_t<std::is_convertible< U*, T*>::value>> - arena_deleter_base(const arena_deleter_base<P, U, false> &rhs) noexcept - : m_a(rhs.m_a) { } + std::enable_if_t<std::is_convertible_v< U*, T*>>> + constexpr arena_deleter_base(const arena_deleter_base<P, U, ALIGN, false> &rhs) noexcept + : m_arena(rhs.m_arena), m_info(rhs.m_info) { } void operator()(T *p) noexcept { // call destructor p->~T(); - m_a->deallocate(p, sizeof(T)); + m_arena->deallocate(p, m_info.alignment, m_info.size); } - //private: - arena_storage_type *m_a; + + P *m_arena; + deleter_info_t m_info; }; - template <typename P, typename T> - struct arena_deleter_base<P, T, true> + template <typename P, typename T, std::size_t ALIGN> + struct arena_deleter_base<P, T, ALIGN, true> { - using arena_storage_type = P; - - constexpr arena_deleter_base( /*[[maybe_unused]]*/ arena_storage_type *a = nullptr) noexcept + constexpr arena_deleter_base(/*[[maybe_unused]]*/ P *a = nullptr) noexcept + : m_info({ALIGN ? ALIGN : alignof(T), sizeof(T)}) { - // gcc 7.2 (mingw) and 7.5 (ubuntu) don't accept maybe_unused here - plib::unused_var(a); + plib::unused_var(a); // GCC 7.x does not like the maybe_unused } - template<typename U, typename = typename - std::enable_if<std::is_convertible< U*, T*>::value>::type> - arena_deleter_base( /*[[maybe_unused]]*/ const arena_deleter_base<P, U, true> &rhs) noexcept + template<typename U, typename = + std::enable_if_t<std::is_convertible_v< U*, T*>>> + constexpr arena_deleter_base(const arena_deleter_base<P, U, ALIGN, true> &rhs) noexcept + : m_info(rhs.m_info) { - // gcc 7.2 (mingw) and 7.5 (ubuntu) don't accept maybe_unused here - plib::unused_var(rhs); } void operator()(T *p) noexcept { // call destructor p->~T(); - P::deallocate(p, sizeof(T)); + P::deallocate(p, m_info.alignment, m_info.size); } + + deleter_info_t m_info; }; - template <typename P, typename T> - struct arena_deleter : public arena_deleter_base<P, T, P::has_static_deallocator> + + /// + /// \brief alignment aware deleter class + /// + /// The deleter class expects the object to have been allocated with + /// `alignof(T)` alignment if the ALIGN parameter is omitted. If ALIGN is + /// given, this is used. + /// + /// \tparam A Arena type + /// \tparam T Object type + /// \tparam ALIGN alignment + /// + template <typename A, typename T, std::size_t ALIGN = 0> + struct arena_deleter : public arena_deleter_base<A, T, ALIGN, A::has_static_deallocator> { - using base_type = arena_deleter_base<P, T, P::has_static_deallocator>; + using base_type = arena_deleter_base<A, T, ALIGN, A::has_static_deallocator>; using base_type::base_type; }; @@ -143,22 +133,21 @@ namespace plib { { } owned_ptr(pointer p, bool owned, D deleter) - : m_ptr(p), m_deleter(deleter), m_is_owned(owned) + : m_ptr(p), m_deleter(std::move(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> + template <typename DC, typename DC_D> owned_ptr & operator =(owned_ptr<DC, DC_D> &&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 = r.m_deleter; + m_deleter = std::move(r.m_deleter); r.m_is_owned = false; r.m_ptr = nullptr; return *this; @@ -166,7 +155,7 @@ namespace plib { owned_ptr(owned_ptr &&r) noexcept : m_ptr(r.m_ptr) - , m_deleter(r.m_deleter) + , m_deleter(std::move(r.m_deleter)) , m_is_owned(r.m_is_owned) { r.m_is_owned = false; @@ -176,11 +165,10 @@ namespace plib { 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 = r.m_deleter; + m_deleter = std::move(r.m_deleter); r.m_is_owned = false; r.m_ptr = nullptr; return *this; @@ -189,7 +177,7 @@ 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_deleter(std::move(r.m_deleter)) , m_is_owned(r.is_owned()) { r.release(); @@ -238,20 +226,20 @@ namespace plib { // Arena allocator for use with containers //============================================================ - template <class ARENA, class T, std::size_t ALIGN = alignof(T)> + template <class ARENA, class T, std::size_t ALIGN, bool HSA> class arena_allocator { public: using value_type = T; using pointer = T *; - static /*constexpr*/ const std::size_t align_size = ALIGN; + static constexpr const std::size_t align_size = ALIGN ? ALIGN : alignof(T); using arena_type = ARENA; - static_assert(align_size >= alignof(T), - "ALIGN must be greater than alignof(T) and a multiple"); static_assert((align_size % alignof(T)) == 0, "ALIGN must be greater than alignof(T) and a multiple"); + template <typename U = int, typename = std::enable_if_t<HSA && sizeof(U)>> + //[[deprecated]] arena_allocator() noexcept : m_a(arena_type::instance()) { } @@ -263,12 +251,22 @@ namespace plib { arena_allocator(arena_allocator &&) noexcept = default; arena_allocator &operator=(arena_allocator &&) noexcept = default; - explicit arena_allocator(arena_type & a) noexcept : m_a(a) + template <typename U = int> + arena_allocator(/*[[maybe_unused]]*/ std::enable_if_t<HSA && sizeof(U), arena_type> & a) noexcept + : m_a(arena_type::instance()) { + plib::unused_var(a); // GCC 7.x does not like the maybe_unused } - template <class U> - arena_allocator(const arena_allocator<ARENA, U, ALIGN>& rhs) noexcept + template <typename U = int> + arena_allocator(/*[[maybe_unused]]*/ std::enable_if_t<!HSA && sizeof(U), arena_type> & a) noexcept + : m_a(a) + { + plib::unused_var(a); // GCC 7.x does not like the maybe_unused + } + + template <class U, typename = std::enable_if_t<!std::is_same<T, U>::value>> + arena_allocator(const arena_allocator<ARENA, U, ALIGN, HSA>& rhs) noexcept : m_a(rhs.m_a) { } @@ -276,17 +274,17 @@ namespace plib { template <class U> struct rebind { - using other = arena_allocator<ARENA, U, ALIGN>; + using other = arena_allocator<ARENA, U, ALIGN, HSA>; }; pointer allocate(std::size_t n) { - return reinterpret_cast<T *>(m_a.allocate(ALIGN, sizeof(T) * n)); //NOLINT + return reinterpret_cast<T *>(m_a.allocate(align_size, sizeof(T) * n)); //NOLINT } void deallocate(pointer p, std::size_t n) noexcept { - m_a.deallocate(p, sizeof(T) * n); + m_a.deallocate(p, align_size, sizeof(T) * n); } template<typename U, typename... Args> @@ -302,26 +300,26 @@ namespace plib { p->~U(); } - 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, // NOLINT - const arena_allocator<AR2, T2, A2>& rhs) noexcept; + template <class AR1, class T1, std::size_t A1, bool HSA1, class AR2, class T2, std::size_t A2, bool HSA2> + friend bool operator==(const arena_allocator<AR1, T1, A1, HSA1>& lhs, // NOLINT + const arena_allocator<AR2, T2, A2, HSA2>& rhs) noexcept; - template <class AU, class U, std::size_t A> + template <class AU1, class U1, std::size_t A1, bool HSA1> 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 + template <class AR1, class T1, std::size_t A1, bool HSA1, class AR2, class T2, std::size_t A2, bool HSA2> + inline bool operator==(const arena_allocator<AR1, T1, A1, HSA1>& lhs, + const arena_allocator<AR2, T2, A2, HSA2>& 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 + template <class AR1, class T1, std::size_t A1, bool HSA1,class AR2, class T2, std::size_t A2, bool HSA2> + inline bool operator!=(const arena_allocator<AR1, T1, A1, HSA1>& lhs, + const arena_allocator<AR2, T2, A2, HSA2>& rhs) noexcept { return !(lhs == rhs); } @@ -330,55 +328,61 @@ namespace plib { // Memory allocation //============================================================ - // MSVC has an issue with SFINAE and overloading resolution. - // A discussion can be found here: - // - // https://stackoverflow.com/questions/31062892/overloading-on-static-in-conjunction-with-sfinae - // - // The previous code compiled with gcc and clang on all platforms and - // compilers apart from MSVC. - - template <typename P, bool HSD, bool HSA> - struct arena_base; + //template <typename P, std::size_t MINALIGN, bool HSD, bool HSA> + //struct arena_base; - template <typename P, bool HSD, bool HSA> + template <typename P, std::size_t MINALIGN, bool HSD, bool HSA> struct arena_core { static constexpr const bool has_static_deallocator = HSD; static constexpr const bool has_static_allocator = HSA; + static constexpr const std::size_t min_align = MINALIGN; using size_type = std::size_t; - template <class T, size_type ALIGN = alignof(T)> - using allocator_type = arena_allocator<P, T, ALIGN>; + template <class T, size_type ALIGN = 0> + using allocator_type = arena_allocator<P, T, (ALIGN < MINALIGN) ? MINALIGN : ALIGN, HSA>; + + template <class T, size_type ALIGN = 0> + using deleter_type = arena_deleter<P, T, (ALIGN < MINALIGN) ? MINALIGN : ALIGN>; - template <class T> - using deleter_type = arena_deleter<P, T>; + template <typename T, size_type ALIGN = 0> + using unique_ptr = std::unique_ptr<T, deleter_type<T, (ALIGN < MINALIGN) ? MINALIGN : ALIGN>>; - template <typename T> - using unique_ptr = std::unique_ptr<T, deleter_type<T>>; + template <typename T, size_type ALIGN = 0> + using owned_ptr = plib::owned_ptr<T, deleter_type<T, (ALIGN < MINALIGN) ? MINALIGN : ALIGN>>; - template <typename T> - using owned_ptr = plib::owned_ptr<T, deleter_type<T>>; + static P &instance() noexcept; - static inline P &instance() noexcept + template <class T, size_type ALIGN = 0> + allocator_type<T, ALIGN> get_allocator() { - static P s_arena; - return s_arena; + return *static_cast<P *>(this); } - friend struct arena_base<P, HSD, HSA>; - private: + protected: size_t m_stat_cur_alloc = 0; size_t m_stat_max_alloc = 0; }; - template <typename P, bool HSD, bool HSA> - struct arena_base : public arena_core<P, HSD, HSA> + template <typename P, std::size_t MINALIGN, bool HSD, bool HSA> + inline P & arena_core<P, MINALIGN, HSD, HSA>::instance() noexcept { - using base_type = arena_core<P, HSD, HSA>; + static P s_arena; + return s_arena; + } + + template <typename P, std::size_t MINALIGN, bool HSD, bool HSA> + struct arena_base : public arena_core<P, MINALIGN, HSD, HSA> + { + using base_type = arena_core<P, MINALIGN, HSD, HSA>; using size_type = typename base_type::size_type; + ~arena_base() + { + //printf("%s %lu %lu %lu\n", typeid(*this).name(), MINALIGN, cur_alloc(), max_alloc()); + } + static size_type cur_alloc() noexcept { return base_type::instance().m_stat_cur_alloc; } static size_type max_alloc() noexcept { return base_type::instance().m_stat_max_alloc; } @@ -395,10 +399,15 @@ namespace plib { } }; - template <typename P> - struct arena_base<P, false, false> : public arena_core<P, false, false> + template <typename P, std::size_t MINALIGN> + struct arena_base<P, MINALIGN, false, false> : public arena_core<P, MINALIGN, false, false> { - using size_type = typename arena_core<P, false, false>::size_type; + using size_type = typename arena_core<P, MINALIGN, false, false>::size_type; + + ~arena_base() + { + //printf("%s %lu %lu %lu\n", typeid(*this).name(), MINALIGN, cur_alloc(), max_alloc()); + } size_type cur_alloc() const noexcept { return this->m_stat_cur_alloc; } size_type max_alloc() const noexcept { return this->m_stat_max_alloc; } @@ -415,12 +424,15 @@ namespace plib { } }; - struct aligned_arena : public arena_base<aligned_arena, true, true> + template <std::size_t MINALIGN> + struct aligned_arena : public arena_base<aligned_arena<MINALIGN>, MINALIGN, true, true> { + using base_type = arena_base<aligned_arena<MINALIGN>, MINALIGN, true, true>; + static inline gsl::owner<void *> allocate( size_t alignment, size_t size ) { - inc_alloc_stat(size); - + base_type::inc_alloc_stat(size); +#if 0 #if (PUSE_ALIGNED_ALLOCATION) #if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER) return _aligned_malloc(size, alignment); @@ -439,12 +451,16 @@ namespace plib { unused_var(alignment); return ::operator new(size); #endif +#else + return ::operator new(size, std::align_val_t(alignment)); +#endif } - static inline void deallocate(gsl::owner<void *> ptr, size_t size ) noexcept + static inline void deallocate(gsl::owner<void *> ptr, [[maybe_unused]] size_t alignment, size_t size ) noexcept { //unused_var(size); - dec_alloc_stat(size); + base_type::dec_alloc_stat(size); +#if 0 #if (PUSE_ALIGNED_ALLOCATION) #if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER) // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) @@ -456,6 +472,9 @@ namespace plib { #else ::operator delete(ptr); #endif +#else + ::operator delete(ptr, std::align_val_t(alignment)); +#endif } bool operator ==([[maybe_unused]] const aligned_arena &rhs) const noexcept @@ -465,21 +484,21 @@ namespace plib { }; - struct std_arena : public arena_base<std_arena, true, true> + struct std_arena : public arena_base<std_arena, 0, true, true> { - static inline void *allocate([[maybe_unused]] size_t alignment, size_t size ) + static inline void *allocate(size_t alignment, size_t size ) { inc_alloc_stat(size); - return ::operator new(size); + return ::operator new(size, static_cast<std::align_val_t>(alignment)); } - static inline void deallocate( void *ptr, size_t size ) noexcept + static inline void deallocate( void *ptr, size_t alignment, size_t size ) noexcept { dec_alloc_stat(size); - ::operator delete(ptr); + ::operator delete(ptr, static_cast<std::align_val_t>(alignment)); } - bool operator ==([[maybe_unused]] const aligned_arena &rhs) const noexcept + bool operator ==([[maybe_unused]] const std_arena &rhs) const noexcept { return true; } @@ -487,10 +506,25 @@ namespace plib { namespace detail { - template<typename T, typename ARENA, typename... Args> + /// + /// \brief Create new object T with an aligned memory + /// + /// The create object can be deallocate using \ref free or + /// using the arena_deleter type. This is the specialization for arenas + /// which have no state. + /// + /// \tparam T Object type + /// \tparam ALIGN Alignment of object to be created. If ALIGN equals 0, alignof(T) is used. + /// \tparam ARENA Arena type + /// \tparam Args Argument types + /// + /// \param args Arguments to be passed to constructor + /// + template<typename T, std::size_t ALIGN, typename ARENA, typename... Args> static inline T * alloc(Args&&... args) { - auto *mem = ARENA::allocate(alignof(T), sizeof(T)); + //using alloc_type = typename ARENA :: template allocator_type<T, alignof(T)>; + auto *mem = ARENA::allocate(ALIGN ? ALIGN : alignof(T), sizeof(T)); try { // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) @@ -498,22 +532,37 @@ namespace plib { } catch (...) { - ARENA::deallocate(mem, sizeof(T)); + ARENA::deallocate(mem, ALIGN ? ALIGN : alignof(T), sizeof(T)); throw; } } - template<typename ARENA, typename T> + template<std::size_t ALIGN, typename ARENA, typename T> static inline void free(T *ptr) noexcept { ptr->~T(); - ARENA::deallocate(ptr, sizeof(T)); + ARENA::deallocate(ptr, ALIGN ? ALIGN : alignof(T), sizeof(T)); } - template<typename T, typename ARENA, typename... Args> + /// + /// \brief Create new object T with an aligned memory + /// + /// The create object can be deallocate using \ref free or + /// using the arena_deleter type. This is the specialization for arenas + /// which do have state. + /// + /// \tparam T Object type + /// \tparam ALIGN Alignment of object to be created. If ALIGN equals 0, alignof(T) is used. + /// \tparam ARENA Arena type + /// \tparam Args Argument types + /// + /// \param arena Arena to provide memory + /// \param args Arguments to be passed to constructor + /// + template<typename T, std::size_t ALIGN, typename ARENA, typename... Args> static inline T * alloc(ARENA &arena, Args&&... args) { - auto *mem = arena.allocate(alignof(T), sizeof(T)); + auto *mem = arena.allocate(ALIGN ? ALIGN : alignof(T), sizeof(T)); try { // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) @@ -521,83 +570,135 @@ namespace plib { } catch (...) { - arena.deallocate(mem, sizeof(T)); + arena.deallocate(mem, ALIGN ? ALIGN : alignof(T), sizeof(T)); throw; } } - template<typename ARENA, typename T> + template<std::size_t ALIGN, typename ARENA, typename T> static inline void free(ARENA &arena, T *ptr) noexcept { ptr->~T(); - arena.deallocate(ptr, sizeof(T)); + arena.deallocate(ptr, ALIGN ? ALIGN : alignof(T), sizeof(T)); } } // namespace detail - - template<typename T, typename ARENA, typename... Args> - static inline - std::enable_if_t<ARENA::has_static_allocator, typename ARENA::template unique_ptr<T>> + /// + /// \brief Create new alignment and size aware std::unique_ptr + /// + /// `make_unique` creates a new shared pointer to the object it creates. + /// These version ensure that on deallocation the correct alignment and + /// size is used. Should the unique_ptr be down casted the deleter objects + /// used here track the size and alignment of the object created. + /// + /// std::standard_delete will use size and alignment of the base class. + /// + /// This function is deprecated since it hides the use of arenas. + /// + /// \tparam T Object type + /// \tparam ARENA Arena type + /// \tparam ALIGN Alignment of object to be created. If ALIGN equals 0, alignof(T) is used. + /// \tparam Args Argument types + /// + /// \param args Arguments to be passed to constructor + /// + template<typename T, typename ARENA, std::size_t ALIGN = 0, typename... Args> + //[[deprecated]] + std::enable_if_t<ARENA::has_static_allocator, typename ARENA::template unique_ptr<T, ALIGN>> make_unique(Args&&... args) { - using up_type = typename ARENA::template unique_ptr<T>; - using deleter_type = typename ARENA::template deleter_type<T>; - auto *mem = detail::alloc<T, ARENA>(std::forward<Args>(args)...); + using up_type = typename ARENA::template unique_ptr<T, ALIGN>; + using deleter_type = typename ARENA::template deleter_type<T, ALIGN>; + auto *mem = detail::alloc<T, ALIGN, ARENA>(std::forward<Args>(args)...); return up_type(mem, deleter_type()); } - template<typename T, typename ARENA, typename... Args> - static inline - std::enable_if_t<!ARENA::has_static_allocator, typename ARENA::template unique_ptr<T>> - make_unique(Args&&... args) - { - return make_unique<T>(ARENA::instance(), std::forward<Args>(args)...); - } - - template<typename T, typename ARENA, typename... Args> - static inline - typename ARENA::template unique_ptr<T> + /// + /// \brief Create new alignment and size aware std::unique_ptr + /// + /// `make_unique` creates a new shared pointer to the object it creates. + /// These version ensure that on deallocation the correct alignment and + /// size is used. Should the unique_ptr be down casted the deleter objects + /// used here track the size and alignment of the object created. + /// + /// std::standard_delete will use size and alignment of the base class. + /// + /// \tparam T Object type + /// \tparam ARENA Arena type + /// \tparam ALIGN Alignment of object to be created. If ALIGN equals 0, alignof(T) is used. + /// \tparam Args Argument types + /// + /// \param arena Arena to provide memory + /// \param args Arguments to be passed to constructor + /// + template<typename T, typename ARENA, std::size_t ALIGN = 0, typename... Args> + typename ARENA::template unique_ptr<T, ALIGN> make_unique(ARENA &arena, Args&&... args) { - using up_type = typename ARENA::template unique_ptr<T>; - using deleter_type = typename ARENA::template deleter_type<T>; - auto *mem = detail::alloc<T>(arena, std::forward<Args>(args)...); + using up_type = typename ARENA::template unique_ptr<T, ALIGN>; + using deleter_type = typename ARENA::template deleter_type<T, ALIGN>; + auto *mem = detail::alloc<T, ALIGN>(arena, std::forward<Args>(args)...); return up_type(mem, deleter_type(&arena)); } - template<typename T, typename ARENA, typename... Args> - static inline - std::enable_if_t<ARENA::has_static_allocator, typename ARENA::template owned_ptr<T>> + /// + /// \brief Create new alignment and size aware plib::owned_ptr + /// + /// `make_unique` creates a new shared pointer to the object it creates. + /// These version ensure that on deallocation the correct alignment and + /// size is used. Should the unique_ptr be down casted the deleter objects + /// used here track the size and alignment of the object created. + /// + /// std::standard_delete will use size and alignment of the base class. + /// + /// This function is deprecated since it hides the use of arenas. + /// + /// \tparam T Object type + /// \tparam ARENA Arena type + /// \tparam ALIGN Alignment of object to be created. If ALIGN equals 0, alignof(T) is used. + /// \tparam Args Argument types + /// + /// \param args Arguments to be passed to constructor + /// + template<typename T, typename ARENA, std::size_t ALIGN = 0, typename... Args> + //[[deprecated]] + std::enable_if_t<ARENA::has_static_allocator, typename ARENA::template owned_ptr<T, ALIGN>> make_owned(Args&&... args) { - using op_type = typename ARENA::template owned_ptr<T>; - using deleter_type = typename ARENA::template deleter_type<T>; - auto *mem = detail::alloc<T, ARENA>(std::forward<Args>(args)...); + using op_type = typename ARENA::template owned_ptr<T, ALIGN>; + using deleter_type = typename ARENA::template deleter_type<T, ALIGN>; + auto *mem = detail::alloc<T, ALIGN, ARENA>(std::forward<Args>(args)...); return op_type(mem, true, deleter_type()); } - template<typename T, typename ARENA, typename... Args> - static inline - std::enable_if_t<!ARENA::has_static_allocator, typename ARENA::template owned_ptr<T>> - make_owned(Args&&... args) - { - return make_owned<T>(ARENA::instance(), std::forward<Args>(args)...); - } - - template<typename T, typename ARENA, typename... Args> - static inline typename ARENA::template owned_ptr<T> make_owned(ARENA &arena, Args&&... args) + /// + /// \brief Create new alignment and size aware plib::owned_ptr + /// + /// `make_unique` creates a new shared pointer to the object it creates. + /// These version ensure that on deallocation the correct alignment and + /// size is used. Should the unique_ptr be down casted the deleter objects + /// used here track the size and alignment of the object created. + /// + /// std::standard_delete will use size and alignment of the base class. + /// + /// \tparam T Object type + /// \tparam ARENA Arena type + /// \tparam ALIGN Alignment of object to be created. If ALIGN equals 0, alignof(T) is used. + /// \tparam Args Argument types + /// + /// \param arena Arena to provide memory + /// \param args Arguments to be passed to constructor + /// + template<typename T, typename ARENA, std::size_t ALIGN = 0, typename... Args> + typename ARENA::template owned_ptr<T> make_owned(ARENA &arena, Args&&... args) { - using op_type = typename ARENA::template owned_ptr<T>; - using deleter_type = typename ARENA::template deleter_type<T>; - auto *mem = detail::alloc<T>(arena, std::forward<Args>(args)...); + using op_type = typename ARENA::template owned_ptr<T, ALIGN>; + using deleter_type = typename ARENA::template deleter_type<T, ALIGN>; + auto *mem = detail::alloc<T, ALIGN>(arena, std::forward<Args>(args)...); return op_type(mem, true, deleter_type(&arena)); } - - 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 @@ -627,46 +728,78 @@ namespace plib { struct align_traits : public align_traits_base<T, has_align<T>::value> {}; - template <typename BASEARENA = aligned_arena, std::size_t PG_SIZE = 1024> - class paged_arena : public arena_base<paged_arena<BASEARENA, PG_SIZE>, true, true> + /// + /// \brief Force BASEARENA to align memory allocations on page boundaries + /// + /// \tparam BASEARENA The base arena to use (optional, defaults to aligned_arena) + /// \tparam PG_SIZE The page size to use (optional, defaults to 1024) + /// + template <template<std::size_t> class BASEARENA = aligned_arena, std::size_t PG_SIZE = 1024> + using paged_arena = BASEARENA<PG_SIZE>; + + /// + /// \brief Helper class to create arena versions of standard library sequences + /// + /// \ref arena_vector on how to use this class + /// + /// \tparam A Arena typeThe base arena to use (optional, defaults to aligned_arena) + /// \tparam T Object type of objects in sequence + /// \tparam S Sequence, e.g. std::vector, std::list + /// \tparam ALIGN Alignment to use + /// + template <typename A, typename T, template <typename, typename> class S, std::size_t ALIGN = PALIGN_VECTOROPT> + class arena_sequence : public S<T, typename A::template allocator_type<T, ALIGN>> { public: - paged_arena() = default; + using arena_allocator_type = typename A::template allocator_type<T, ALIGN>; + using arena_sequence_base = S<T, arena_allocator_type>; + using arena_sequence_base::arena_sequence_base; - PCOPYASSIGNMOVE(paged_arena, delete) + using size_type = typename arena_sequence_base::size_type; - ~paged_arena() = default; - - static void *allocate([[maybe_unused]] size_t align, size_t size) + arena_sequence(A &arena) + : arena_sequence_base(seq_alloc(arena)) { - //size = ((size + PG_SIZE - 1) / PG_SIZE) * PG_SIZE; - return arena().allocate(PG_SIZE, size); } - static void deallocate(void *ptr, size_t size) noexcept + arena_sequence(A &arena, size_type n) + : arena_sequence_base(n, seq_alloc(arena)) { - //size = ((size + PG_SIZE - 1) / PG_SIZE) * PG_SIZE; - arena().deallocate(ptr, size); } - bool operator ==(const paged_arena &rhs) const noexcept { return this == &rhs; } - - static BASEARENA &arena() noexcept { static BASEARENA m_arena; return m_arena; } private: + arena_allocator_type seq_alloc(A &arena) const { return arena.template get_allocator<T, ALIGN>(); } }; - //============================================================ - // Aligned vector - //============================================================ - - // FIXME: needs a separate file - template <typename T, std::size_t ALIGN = PALIGN_VECTOROPT, typename A = paged_arena<>>//aligned_arena> - class aligned_vector : public std::vector<T, typename A::template allocator_type<T, ALIGN>> + /// + /// \brief Vector with arena allocations + /// + /// The Vector allocation will use the arena of type A of which an instance + /// has to be passed to the constructor. Should the minimum alignment exceed + /// the object size, min_align / sizeof(T) elements are reserved. + /// + /// \tparam A Arena type + /// \tparam T Object type of objects in sequence + /// \tparam ALIGN Alignment to use + /// + template <typename A, typename T, std::size_t ALIGN = PALIGN_VECTOROPT> + class arena_vector : public arena_sequence<A, T, std::vector, ALIGN> { public: - using base = std::vector<T, typename A::template allocator_type<T, ALIGN>>; + using arena_vector_base = arena_sequence<A, T, std::vector, ALIGN>; + using arena_vector_base::arena_vector_base; - using base::base; + /// + /// \brief Constructor + /// + /// \param arena Arena instance to use + /// + arena_vector(A &arena) + : arena_vector_base(arena) + { + if (A::min_align / sizeof(T) > 0) + this->reserve(A::min_align / sizeof(T)); + } }; |