aboutsummaryrefslogtreecommitdiffstats
path: root/common/almalloc.h
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2020-12-27 04:29:54 -0800
committerChris Robinson <[email protected]>2020-12-27 04:29:54 -0800
commit7833cfa8de1908710ac613ed4198f246ff0945db (patch)
tree18ddca7c9e55bbb42c9e7766f3d4488dda2bafb7 /common/almalloc.h
parentcf7f201c928625c841ca945300867cf3498feaeb (diff)
Make FlexArray trivially destructible when possible
Diffstat (limited to 'common/almalloc.h')
-rw-r--r--common/almalloc.h131
1 files changed, 89 insertions, 42 deletions
diff --git a/common/almalloc.h b/common/almalloc.h
index 0949efdc..75388d9d 100644
--- a/common/almalloc.h
+++ b/common/almalloc.h
@@ -66,8 +66,6 @@ enum FamCount : size_t { };
namespace al {
-#define REQUIRES(...) typename std::enable_if<(__VA_ARGS__),int>::type = 0
-
template<typename T, std::size_t alignment=alignof(T)>
struct allocator {
using value_type = T;
@@ -110,11 +108,20 @@ template<size_t alignment, typename T>
DIAGNOSTIC_PUSH
msc_pragma(warning(disable : 4100))
template<typename T>
-inline void destroy_at(T *ptr) { ptr->~T(); }
+constexpr std::enable_if_t<!std::is_array<T>::value>
+destroy_at(T *ptr) noexcept(std::is_nothrow_destructible<T>::value)
+{ ptr->~T(); }
DIAGNOSTIC_POP
+template<typename T>
+constexpr std::enable_if_t<std::is_array<T>::value>
+destroy_at(T *ptr) noexcept(std::is_nothrow_destructible<T>::value)
+{
+ for(auto &elem : *ptr)
+ al::destroy_at(std::addressof(elem));
+}
template<typename T>
-inline void destroy(T first, const T end)
+constexpr void destroy(T first, T end)
{
while(first != end)
{
@@ -123,8 +130,9 @@ inline void destroy(T first, const T end)
}
}
-template<typename T, typename N, REQUIRES(std::is_integral<N>::value)>
-inline T destroy_n(T first, N count)
+template<typename T, typename N>
+constexpr std::enable_if_t<std::is_integral<N>::value,T>
+destroy_n(T first, N count)
{
if(count != 0)
{
@@ -137,8 +145,9 @@ inline T destroy_n(T first, N count)
}
-template<typename T, typename N, REQUIRES(std::is_integral<N>::value)>
-inline T uninitialized_default_construct_n(T first, N count)
+template<typename T, typename N>
+inline std::enable_if_t<std::is_integral<N>::value,T>
+uninitialized_default_construct_n(T first, N count)
{
using ValueT = typename std::iterator_traits<T>::value_type;
T current{first};
@@ -159,6 +168,56 @@ inline T uninitialized_default_construct_n(T first, N count)
}
+/* Storage for flexible array data. This is trivially destructible if type T is
+ * trivially destructible.
+ */
+template<typename T, size_t alignment, bool = std::is_trivially_destructible<T>::value>
+struct FlexArrayStorage;
+
+template<typename T, size_t alignment>
+struct FlexArrayStorage<T,alignment,true> {
+ const size_t mSize;
+ union {
+ char mDummy;
+ alignas(alignment) T mArray[1];
+ };
+
+ static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept
+ {
+ return std::max<size_t>(offsetof(FlexArrayStorage, mArray) + sizeof(T)*count,
+ sizeof(FlexArrayStorage)) + base;
+ }
+
+ FlexArrayStorage(size_t size) : mSize{size}
+ { al::uninitialized_default_construct_n(mArray, mSize); }
+ ~FlexArrayStorage() = default;
+
+ FlexArrayStorage(const FlexArrayStorage&) = delete;
+ FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
+};
+
+template<typename T, size_t alignment>
+struct FlexArrayStorage<T,alignment,false> {
+ const size_t mSize;
+ union {
+ char mDummy;
+ alignas(alignment) T mArray[1];
+ };
+
+ static constexpr size_t Sizeof(size_t count, size_t base) noexcept
+ {
+ return std::max<size_t>(offsetof(FlexArrayStorage, mArray) + sizeof(T)*count,
+ sizeof(FlexArrayStorage)) + base;
+ }
+
+ FlexArrayStorage(size_t size) : mSize{size}
+ { al::uninitialized_default_construct_n(mArray, mSize); }
+ ~FlexArrayStorage() { al::destroy_n(mArray, mSize); }
+
+ FlexArrayStorage(const FlexArrayStorage&) = delete;
+ FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
+};
+
/* A flexible array type. Used either standalone or at the end of a parent
* struct, with placement new, to have a run-time-sized array that's embedded
* with its size.
@@ -180,52 +239,42 @@ struct FlexArray {
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ using Storage_t_ = FlexArrayStorage<element_type,alignment>;
- const index_type mSize;
- union {
- char mDummy;
- alignas(alignment) element_type mArray[1];
- };
+ Storage_t_ mStore;
+ static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept
+ { return Storage_t_::Sizeof(count, base); }
static std::unique_ptr<FlexArray> Create(index_type count)
{
void *ptr{al_calloc(alignof(FlexArray), Sizeof(count))};
return std::unique_ptr<FlexArray>{new(ptr) FlexArray{count}};
}
- static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept
- {
- return base +
- std::max<index_type>(offsetof(FlexArray, mArray) + sizeof(T)*count, sizeof(FlexArray));
- }
-
- FlexArray(index_type size) : mSize{size}
- { al::uninitialized_default_construct_n(mArray, mSize); }
- ~FlexArray() { al::destroy_n(mArray, mSize); }
- FlexArray(const FlexArray&) = delete;
- FlexArray& operator=(const FlexArray&) = delete;
+ FlexArray(index_type size) : mStore{size} { }
+ ~FlexArray() = default;
- index_type size() const noexcept { return mSize; }
- bool empty() const noexcept { return mSize == 0; }
+ index_type size() const noexcept { return mStore.mSize; }
+ bool empty() const noexcept { return mStore.mSize == 0; }
- pointer data() noexcept { return mArray; }
- const_pointer data() const noexcept { return mArray; }
+ pointer data() noexcept { return mStore.mArray; }
+ const_pointer data() const noexcept { return mStore.mArray; }
- reference operator[](index_type i) noexcept { return mArray[i]; }
- const_reference operator[](index_type i) const noexcept { return mArray[i]; }
+ reference operator[](index_type i) noexcept { return mStore.mArray[i]; }
+ const_reference operator[](index_type i) const noexcept { return mStore.mArray[i]; }
- reference front() noexcept { return mArray[0]; }
- const_reference front() const noexcept { return mArray[0]; }
+ reference front() noexcept { return mStore.mArray[0]; }
+ const_reference front() const noexcept { return mStore.mArray[0]; }
- reference back() noexcept { return mArray[mSize-1]; }
- const_reference back() const noexcept { return mArray[mSize-1]; }
+ reference back() noexcept { return mStore.mArray[mStore.mSize-1]; }
+ const_reference back() const noexcept { return mStore.mArray[mStore.mSize-1]; }
- iterator begin() noexcept { return mArray; }
- const_iterator begin() const noexcept { return mArray; }
- const_iterator cbegin() const noexcept { return mArray; }
- iterator end() noexcept { return mArray + mSize; }
- const_iterator end() const noexcept { return mArray + mSize; }
- const_iterator cend() const noexcept { return mArray + mSize; }
+ iterator begin() noexcept { return mStore.mArray; }
+ const_iterator begin() const noexcept { return mStore.mArray; }
+ const_iterator cbegin() const noexcept { return mStore.mArray; }
+ iterator end() noexcept { return mStore.mArray + mStore.mSize; }
+ const_iterator end() const noexcept { return mStore.mArray + mStore.mSize; }
+ const_iterator cend() const noexcept { return mStore.mArray + mStore.mSize; }
reverse_iterator rbegin() noexcept { return end(); }
const_reverse_iterator rbegin() const noexcept { return end(); }
@@ -237,8 +286,6 @@ struct FlexArray {
DEF_PLACE_NEWDEL()
};
-#undef REQUIRES
-
} // namespace al
#endif /* AL_MALLOC_H */