diff options
author | Chris Robinson <[email protected]> | 2020-12-27 04:29:54 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2020-12-27 04:29:54 -0800 |
commit | 7833cfa8de1908710ac613ed4198f246ff0945db (patch) | |
tree | 18ddca7c9e55bbb42c9e7766f3d4488dda2bafb7 /common/almalloc.h | |
parent | cf7f201c928625c841ca945300867cf3498feaeb (diff) |
Make FlexArray trivially destructible when possible
Diffstat (limited to 'common/almalloc.h')
-rw-r--r-- | common/almalloc.h | 131 |
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 */ |