|
1 | 1 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
2 | 2 |
|
3 | 3 | #include <algorithm> |
| 4 | +#include <array> |
4 | 5 | #include <cassert> |
5 | 6 | #include <compare> |
6 | 7 | #include <concepts> |
@@ -42,13 +43,43 @@ using inplace_vector_internal_size_type = |
42 | 43 | If<Capacity <= std::numeric_limits<uint32_t>::max(), uint32_t, |
43 | 44 | uint64_t>>>; |
44 | 45 |
|
| 46 | +// array based storage is used so that we can satisfy constexpr requirement |
| 47 | +// |
| 48 | +// Selecting this storage type implies: std::is_trivial_v<T> |
| 49 | +template <typename T, std::size_t Capacity> |
| 50 | +struct inplace_vector_array_based_storage { |
| 51 | + std::array<T, Capacity> elems; |
| 52 | + |
| 53 | + constexpr T *begin() { return elems.data(); } |
| 54 | + constexpr const T *begin() const { return elems.data(); } |
| 55 | +}; |
| 56 | + |
| 57 | +// byte array based storage is used for non-constexpr environment, where default |
| 58 | +// initialization may not be available. |
| 59 | +// |
| 60 | +// Selecting this storage type implies: !std::is_trivial_v<T> |
| 61 | +template <typename T, std::size_t Capacity> |
| 62 | +struct inplace_vector_bytes_based_storage { |
| 63 | + alignas(T) unsigned char elems[Capacity * sizeof(T)]; |
| 64 | + |
| 65 | + T *begin() { return std::launder(reinterpret_cast<const T *>(elems)); } |
| 66 | + const T *begin() const { |
| 67 | + return std::launder(reinterpret_cast<const T *>(elems)); |
| 68 | + } |
| 69 | +}; |
| 70 | + |
45 | 71 | // Base class for inplace_vector |
46 | 72 | template <typename T, std::size_t Capacity> |
47 | 73 | struct inplace_vector_destruct_base { |
48 | 74 | using size_type = std::size_t; |
49 | 75 | using internal_size_type = inplace_vector_internal_size_type<Capacity>; |
50 | 76 |
|
51 | | - alignas(T) unsigned char elems[Capacity * sizeof(T)] = {}; |
| 77 | + using internal_storage_type = |
| 78 | + std::conditional_t<std::is_trivial_v<T>, |
| 79 | + inplace_vector_array_based_storage<T, Capacity>, |
| 80 | + inplace_vector_bytes_based_storage<T, Capacity>>; |
| 81 | + |
| 82 | + internal_storage_type elems; |
52 | 83 | internal_size_type size_{0}; |
53 | 84 |
|
54 | 85 | // [containers.sequences.inplace.vector.cons], construct/copy/destroy |
@@ -162,28 +193,27 @@ struct inplace_vector_base : public inplace_vector_destruct_base<T, Capacity> { |
162 | 193 | constexpr bool empty() const noexcept { return this->size_ == 0; } |
163 | 194 |
|
164 | 195 | // [containers.sequences.inplace.vector.data], data access |
165 | | - constexpr T *data() noexcept { |
166 | | - return std::launder(reinterpret_cast<T *>(this->elems)); |
167 | | - } |
168 | | - constexpr const T *data() const noexcept { |
169 | | - return std::launder(reinterpret_cast<const T *>(this->elems)); |
170 | | - } |
| 196 | + constexpr T *data() noexcept { return this->elems.begin(); } |
| 197 | + constexpr const T *data() const noexcept { return this->elems.begin(); } |
171 | 198 |
|
172 | 199 | // [containers.sequences.inplace.vector.iterators] iterators |
173 | | - iterator begin() noexcept { |
174 | | - return std::launder(reinterpret_cast<T *>(this->elems)); |
| 200 | + constexpr iterator begin() noexcept { |
| 201 | + if constexpr (Capacity == 0) |
| 202 | + return nullptr; |
| 203 | + else |
| 204 | + return this->elems.begin(); |
175 | 205 | } |
176 | | - const_iterator begin() const noexcept { |
177 | | - return std::launder(reinterpret_cast<const T *>(this->elems)); |
| 206 | + constexpr const_iterator begin() const noexcept { |
| 207 | + if constexpr (Capacity == 0) |
| 208 | + return nullptr; |
| 209 | + else |
| 210 | + return this->elems.begin(); |
178 | 211 | } |
179 | 212 |
|
180 | | - iterator end() noexcept { |
181 | | - return std::launder(reinterpret_cast<T *>(this->elems) + this->size()); |
182 | | - } |
| 213 | + constexpr iterator end() noexcept { return begin() + this->size(); } |
183 | 214 |
|
184 | | - const_iterator end() const noexcept { |
185 | | - return std::launder(reinterpret_cast<const T *>(this->elems) + |
186 | | - this->size()); |
| 215 | + constexpr const_iterator end() const noexcept { |
| 216 | + return begin() + this->size(); |
187 | 217 | } |
188 | 218 |
|
189 | 219 | // [containers.sequences.inplace.vector.modifiers], modifiers |
|
0 commit comments