16 /* Storage for flexible array data. This is trivially destructible if type T is
17 * trivially destructible.
19 template<typename T
, size_t alignment
, bool = std::is_trivially_destructible
<T
>::value
>
20 struct alignas(alignment
) FlexArrayStorage
: al::span
<T
> {
21 /* NOLINTBEGIN(bugprone-sizeof-expression) clang-tidy warns about the
22 * sizeof(T) being suspicious when T is a pointer type, which it will be
23 * for flexible arrays of pointers.
25 static constexpr size_t Sizeof(size_t count
, size_t base
=0u) noexcept
26 { return sizeof(FlexArrayStorage
) + sizeof(T
)*count
+ base
; }
27 /* NOLINTEND(bugprone-sizeof-expression) */
29 /* NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) Flexible
30 * arrays store their payloads after the end of the object, which must be
31 * the last in the whole parent chain.
33 FlexArrayStorage(size_t size
) noexcept(std::is_nothrow_constructible_v
<T
>)
34 : al::span
<T
>{::new(static_cast<void*>(this+1)) T
[size
], size
}
36 /* NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) */
37 ~FlexArrayStorage() = default;
39 FlexArrayStorage(const FlexArrayStorage
&) = delete;
40 FlexArrayStorage
& operator=(const FlexArrayStorage
&) = delete;
43 template<typename T
, size_t alignment
>
44 struct alignas(alignment
) FlexArrayStorage
<T
,alignment
,false> : al::span
<T
> {
45 static constexpr size_t Sizeof(size_t count
, size_t base
=0u) noexcept
46 { return sizeof(FlexArrayStorage
) + sizeof(T
)*count
+ base
; }
48 /* NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) */
49 FlexArrayStorage(size_t size
) noexcept(std::is_nothrow_constructible_v
<T
>)
50 : al::span
<T
>{::new(static_cast<void*>(this+1)) T
[size
], size
}
52 /* NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) */
53 ~FlexArrayStorage() { std::destroy(this->begin(), this->end()); }
55 FlexArrayStorage(const FlexArrayStorage
&) = delete;
56 FlexArrayStorage
& operator=(const FlexArrayStorage
&) = delete;
59 /* A flexible array type. Used either standalone or at the end of a parent
60 * struct, to have a run-time-sized array that's embedded with its size. Should
61 * be used delicately, ensuring there's no additional data after the FlexArray
64 template<typename T
, size_t Align
=alignof(T
)>
66 using element_type
= T
;
67 using value_type
= std::remove_cv_t
<T
>;
68 using index_type
= size_t;
69 using difference_type
= ptrdiff_t;
72 using const_pointer
= const T
*;
74 using const_reference
= const T
&;
76 static constexpr std::size_t StorageAlign
{std::max(alignof(T
), Align
)};
77 using Storage_t_
= FlexArrayStorage
<element_type
,std::max(alignof(al::span
<T
>), StorageAlign
)>;
79 using iterator
= typename
Storage_t_::iterator
;
80 using const_iterator
= typename
Storage_t_::const_iterator
;
81 using reverse_iterator
= typename
Storage_t_::reverse_iterator
;
82 using const_reverse_iterator
= typename
Storage_t_::const_reverse_iterator
;
84 const Storage_t_ mStore
;
86 static constexpr index_type
Sizeof(index_type count
, index_type base
=0u) noexcept
87 { return Storage_t_::Sizeof(count
, base
); }
88 static std::unique_ptr
<FlexArray
> Create(index_type count
)
89 { return std::unique_ptr
<FlexArray
>{new(FamCount
{count
}) FlexArray
{count
}}; }
91 FlexArray(index_type size
) noexcept(std::is_nothrow_constructible_v
<Storage_t_
,index_type
>)
94 ~FlexArray() = default;
96 [[nodiscard
]] auto size() const noexcept
-> index_type
{ return mStore
.size(); }
97 [[nodiscard
]] auto empty() const noexcept
-> bool { return mStore
.empty(); }
99 [[nodiscard
]] auto data() noexcept
-> pointer
{ return mStore
.data(); }
100 [[nodiscard
]] auto data() const noexcept
-> const_pointer
{ return mStore
.data(); }
102 [[nodiscard
]] auto operator[](index_type i
) noexcept
-> reference
{ return mStore
[i
]; }
103 [[nodiscard
]] auto operator[](index_type i
) const noexcept
-> const_reference
{ return mStore
[i
]; }
105 [[nodiscard
]] auto front() noexcept
-> reference
{ return mStore
.front(); }
106 [[nodiscard
]] auto front() const noexcept
-> const_reference
{ return mStore
.front(); }
108 [[nodiscard
]] auto back() noexcept
-> reference
{ return mStore
.back(); }
109 [[nodiscard
]] auto back() const noexcept
-> const_reference
{ return mStore
.back(); }
111 [[nodiscard
]] auto begin() noexcept
-> iterator
{ return mStore
.begin(); }
112 [[nodiscard
]] auto begin() const noexcept
-> const_iterator
{ return mStore
.cbegin(); }
113 [[nodiscard
]] auto cbegin() const noexcept
-> const_iterator
{ return mStore
.cbegin(); }
114 [[nodiscard
]] auto end() noexcept
-> iterator
{ return mStore
.end(); }
115 [[nodiscard
]] auto end() const noexcept
-> const_iterator
{ return mStore
.cend(); }
116 [[nodiscard
]] auto cend() const noexcept
-> const_iterator
{ return mStore
.cend(); }
118 [[nodiscard
]] auto rbegin() noexcept
-> reverse_iterator
{ return mStore
.rbegin(); }
119 [[nodiscard
]] auto rbegin() const noexcept
-> const_reverse_iterator
{ return mStore
.crbegin(); }
120 [[nodiscard
]] auto crbegin() const noexcept
-> const_reverse_iterator
{ return mStore
.crbegin(); }
121 [[nodiscard
]] auto rend() noexcept
-> reverse_iterator
{ return mStore
.rend(); }
122 [[nodiscard
]] auto rend() const noexcept
-> const_reverse_iterator
{ return mStore
.crend(); }
123 [[nodiscard
]] auto crend() const noexcept
-> const_reverse_iterator
{ return mStore
.crend(); }
125 gsl::owner
<void*> operator new(size_t, FamCount count
)
126 { return ::operator new[](Sizeof(count
), std::align_val_t
{alignof(FlexArray
)}); }
127 void operator delete(gsl::owner
<void*> block
, FamCount
) noexcept
128 { ::operator delete[](block
, std::align_val_t
{alignof(FlexArray
)}); }
129 void operator delete(gsl::owner
<void*> block
) noexcept
130 { ::operator delete[](block
, std::align_val_t
{alignof(FlexArray
)}); }
132 void *operator new(size_t size
) = delete;
133 void *operator new[](size_t size
) = delete;
134 void operator delete[](void *block
) = delete;
139 #endif /* AL_FLEXARRAY_H */