Make FlexArray trivially destructible when possible
This commit is contained in:
+89
-42
@@ -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(index_type size) : mStore{size} { }
|
||||
~FlexArray() = default;
|
||||
|
||||
FlexArray(const FlexArray&) = delete;
|
||||
FlexArray& operator=(const FlexArray&) = delete;
|
||||
index_type size() const noexcept { return mStore.mSize; }
|
||||
bool empty() const noexcept { return mStore.mSize == 0; }
|
||||
|
||||
index_type size() const noexcept { return mSize; }
|
||||
bool empty() const noexcept { return mSize == 0; }
|
||||
pointer data() noexcept { return mStore.mArray; }
|
||||
const_pointer data() const noexcept { return mStore.mArray; }
|
||||
|
||||
pointer data() noexcept { return mArray; }
|
||||
const_pointer data() const noexcept { return mArray; }
|
||||
reference operator[](index_type i) noexcept { return mStore.mArray[i]; }
|
||||
const_reference operator[](index_type i) const noexcept { return mStore.mArray[i]; }
|
||||
|
||||
reference operator[](index_type i) noexcept { return mArray[i]; }
|
||||
const_reference operator[](index_type i) const noexcept { return mArray[i]; }
|
||||
reference front() noexcept { return mStore.mArray[0]; }
|
||||
const_reference front() const noexcept { return mStore.mArray[0]; }
|
||||
|
||||
reference front() noexcept { return mArray[0]; }
|
||||
const_reference front() const noexcept { return mArray[0]; }
|
||||
reference back() noexcept { return mStore.mArray[mStore.mSize-1]; }
|
||||
const_reference back() const noexcept { return mStore.mArray[mStore.mSize-1]; }
|
||||
|
||||
reference back() noexcept { return mArray[mSize-1]; }
|
||||
const_reference back() const noexcept { return mArray[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 */
|
||||
|
||||
Reference in New Issue
Block a user