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.h535
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));
+ }
};