22#include "lib/stdcompat/type_traits.h"
23#include "pw_assert/assert.h"
24#include "pw_containers/bitset.h"
25#include "pw_polyfill/language_feature_macros.h"
29template <
typename... Types>
32namespace containers::internal {
54 template <
typename... Args>
55 constexpr Maybe(Args&&... args) : value(std::forward<Args>(args)...) {}
64template <
typename T,
typename First,
typename... Other>
65constexpr size_t FindFirstIndexOf() {
66 if constexpr (std::is_same_v<T, First>) {
68 }
else if constexpr (
sizeof...(Other) > 0u) {
69 return 1 + FindFirstIndexOf<T, Other...>();
71 static_assert(
sizeof...(Other) != 0u,
72 "The type is not present in the type parameter pack");
79template <
typename... Types>
96 containers::internal::OptionalTupleNullPlaceholder::InternalUseOnly();
111template <
typename... Types>
114 template <
typename T>
115 static constexpr size_t TypeToIndex();
117 template <
size_t kIndex>
118 using Element = std::tuple_element_t<kIndex, std::tuple<Types...>>;
120 template <
typename T>
121 using ElementByType = Element<TypeToIndex<T>()>;
132 typename = std::enable_if_t<
133 (std::is_constructible_v<containers::internal::Maybe<Types>, Args> &&
136 cpp20::remove_cvref_t<Args>>
::value &&
140 std::forward<Args>(args)...,
143 cpp20::remove_cvref_t<Args>,
148 : tuple_(kToTupleNull<Types>...,
Bits{}) {
149 UninitializedCopyFrom(other, kAllIdx);
155 UninitializedCopyFrom(std::move(other), kAllIdx);
161 : tuple_(kToTupleNull<Types>...,
Bits{}) {
162 UninitializedMoveFrom(other, kAllIdx);
168 UninitializedMoveFrom(other, kAllIdx);
180 constexpr bool empty()
const {
return active().none(); }
183 constexpr size_t count()
const {
return active().count(); }
187 constexpr size_t size()
const {
return sizeof...(Types); }
190 template <
size_t kIndex>
192 return active().template test<kIndex>();
196 template <
typename T>
198 return has_value<TypeToIndex<T>()>();
203 template <
size_t kIndex>
204 constexpr Element<kIndex>&
value() & {
205 PW_ASSERT(has_value<kIndex>());
206 return RawValue<kIndex>();
211 template <
size_t kIndex>
212 constexpr const Element<kIndex>&
value() const& {
213 PW_ASSERT(has_value<kIndex>());
214 return RawValue<kIndex>();
219 template <
size_t kIndex>
220 constexpr Element<kIndex>&&
value() && {
221 PW_ASSERT(has_value<kIndex>());
222 return std::move(RawValue<kIndex>());
227 template <
size_t kIndex>
228 constexpr const Element<kIndex>&&
value() const&& {
229 PW_ASSERT(has_value<kIndex>());
230 return std::move(RawValue<kIndex>());
235 template <
typename T>
236 constexpr ElementByType<T>&
value() & {
237 return value<TypeToIndex<T>()>();
242 template <
typename T>
243 constexpr const ElementByType<T>&
value() const& {
244 return value<TypeToIndex<T>()>();
249 template <
typename T>
250 constexpr ElementByType<T>&&
value() && {
251 return std::move(
value<TypeToIndex<T>()>());
256 template <
typename T>
257 constexpr const ElementByType<T>&&
value() const&& {
258 return std::move(
value<TypeToIndex<T>()>());
263 template <
size_t kIndex,
int... kExplicitGuard,
typename U>
264 constexpr Element<kIndex>
value_or(U&& default_value)
const& {
265 return has_value<kIndex>()
267 :
static_cast<Element<kIndex>
>(std::forward<U>(default_value));
272 template <
typename T,
int... kExplicitGuard,
typename U>
273 constexpr ElementByType<T>
value_or(U&& default_value)
const& {
274 return value_or<TypeToIndex<T>()>(std::forward<U>(default_value));
279 template <
size_t kIndex,
int... kExplicitGuard,
typename U>
280 constexpr Element<kIndex>
value_or(U&& default_value) && {
281 return has_value<kIndex>()
282 ? std::move(RawValue<kIndex>())
283 :
static_cast<Element<kIndex>
>(std::forward<U>(default_value));
288 template <
typename T,
int... kExplicitGuard,
typename U>
289 constexpr ElementByType<T>
value_or(U&& default_value) && {
290 return std::move(*this).template
value_or<TypeToIndex<T>()>(
291 std::forward<U>(default_value));
298 template <
size_t kIndex,
int... kExplicitGuard,
typename... Args>
299 constexpr Element<kIndex>&
emplace(Args&&... args) {
300 DestroyIfActive<kIndex>();
301 active().template set<kIndex>();
302 return *
new (&RawValue<kIndex>())
303 Element<kIndex>(std::forward<Args>(args)...);
310 template <
typename T,
int... kExplicitGuard,
typename... Args>
311 constexpr ElementByType<T>&
emplace(Args&&... args) {
312 return emplace<TypeToIndex<T>()>(std::forward<Args>(args)...);
316 template <
size_t kIndex>
318 DestroyIfActive<kIndex>();
319 active().template reset<kIndex>();
323 template <
typename T>
325 return reset<TypeToIndex<T>()>();
329 static constexpr auto kAllIdx = std::make_index_sequence<
sizeof...(Types)>{};
333 static constexpr auto kToTupleNull =
kTupleNull;
335 template <
size_t... kIndices>
336 constexpr void DestroyAll(std::index_sequence<kIndices...>) {
337 (DestroyIfActive<kIndices>(), ...);
340 template <
size_t kIndex>
341 constexpr void DestroyIfActive() {
342 if (has_value<kIndex>()) {
343 std::destroy_at(&RawValue<kIndex>());
347 template <
size_t... kIndices>
348 constexpr void UninitializedCopyFrom(
const OptionalTuple& other,
349 std::index_sequence<kIndices...>) {
350 (CopyElement<kIndices>(other), ...);
351 active() = other.active();
354 template <
size_t kIndex>
356 if (other.has_value<kIndex>()) {
357 new (&RawValue<kIndex>()) Element<kIndex>(other.RawValue<kIndex>());
361 template <
size_t... kIndices>
363 std::index_sequence<kIndices...>) {
364 (MoveElement<kIndices>(other), ...);
365 active() = other.active();
366 other.active().reset();
369 template <
size_t kIndex>
371 if (other.has_value<kIndex>()) {
372 new (&RawValue<kIndex>())
373 Element<kIndex>(std::move(other.RawValue<kIndex>()));
374 std::destroy_at(&other.RawValue<kIndex>());
378 template <
size_t kIndex>
379 constexpr Element<kIndex>& RawValue() {
380 static_assert(kIndex <
sizeof...(Types));
381 return std::get<kIndex>(tuple_).value;
384 template <
size_t kIndex>
385 constexpr const Element<kIndex>& RawValue()
const {
386 static_assert(kIndex <
sizeof...(Types));
387 return std::get<kIndex>(tuple_).value;
391 using Bits = BitSet<
sizeof...(Types)>;
393 constexpr Bits& active() {
return std::get<
sizeof...(Types)>(tuple_); }
394 constexpr const Bits& active()
const {
395 return std::get<
sizeof...(Types)>(tuple_);
399 std::tuple<containers::internal::Maybe<Types>..., Bits> tuple_;
404template <
typename... Types>
406constexpr size_t OptionalTuple<Types...>::TypeToIndex() {
407 if constexpr ((std::is_same_v<T, Types> + ...) == 1) {
408 return containers::internal::FindFirstIndexOf<T, Types...>();
411 (std::is_same_v<T, Types> + ...) == 1,
412 "To access an item by type, the type must appear exactly once in the "
413 "OptionalTuple. Specify the item's index instead.");
421template <
typename First,
typename... Other>
426template <std::size_t kIndex,
typename First,
typename... Other>
428 :
public std::tuple_element<kIndex - 1, ::pw::OptionalTuple<Other...>> {};
431template <
typename... Types>
433 : std::integral_constant<std::size_t, sizeof...(Types)> {};
static constexpr BitSet LittleEndian(Args... bits_least_to_most_significant)
Definition: bitset.h:58
Definition: optional_tuple.h:112
constexpr OptionalTuple & operator=(OptionalTuple &&other)
Move assigns this from another OptionalTuple.
Definition: optional_tuple.h:166
constexpr Element< kIndex > value_or(U &&default_value) &&
Definition: optional_tuple.h:280
constexpr const ElementByType< T > & value() const &
Definition: optional_tuple.h:243
constexpr ElementByType< T > value_or(U &&default_value) &&
Definition: optional_tuple.h:289
~OptionalTuple()
Destroys the OptionalTuple and all its active elements.
Definition: optional_tuple.h:175
constexpr const ElementByType< T > && value() const &&
Definition: optional_tuple.h:257
constexpr bool empty() const
Checks if the OptionalTuple contains no active elements.
Definition: optional_tuple.h:180
constexpr ElementByType< T > && value() &&
Definition: optional_tuple.h:250
constexpr ElementByType< T > & value() &
Definition: optional_tuple.h:236
constexpr Element< kIndex > value_or(U &&default_value) const &
Definition: optional_tuple.h:264
constexpr bool has_value() const
Checks if the element at kIndex has a value.
Definition: optional_tuple.h:191
constexpr Element< kIndex > && value() &&
Definition: optional_tuple.h:220
constexpr size_t size() const
Definition: optional_tuple.h:187
constexpr const Element< kIndex > && value() const &&
Definition: optional_tuple.h:228
constexpr OptionalTuple & operator=(const OptionalTuple &other)
Copy assigns this from another OptionalTuple.
Definition: optional_tuple.h:153
constexpr OptionalTuple(OptionalTuple &&other)
Move constructs from another OptionalTuple.
Definition: optional_tuple.h:160
constexpr void reset()
Resets (clears) the value at the specified index, if any.
Definition: optional_tuple.h:317
constexpr Element< kIndex > & value() &
Definition: optional_tuple.h:204
constexpr ElementByType< T > & emplace(Args &&... args)
Definition: optional_tuple.h:311
constexpr OptionalTuple(const OptionalTuple &other)
Copy constructs from another OptionalTuple.
Definition: optional_tuple.h:147
constexpr OptionalTuple(Args &&... args)
Definition: optional_tuple.h:138
constexpr OptionalTuple()
Default constructs an OptionalTuple with all elements unset.
Definition: optional_tuple.h:125
constexpr ElementByType< T > value_or(U &&default_value) const &
Definition: optional_tuple.h:273
constexpr Element< kIndex > & emplace(Args &&... args)
Definition: optional_tuple.h:299
constexpr const Element< kIndex > & value() const &
Definition: optional_tuple.h:212
constexpr size_t count() const
Returns the number of active elements in the OptionalTuple.
Definition: optional_tuple.h:183
Definition: optional_tuple.h:39
constexpr auto kTupleNull
Definition: optional_tuple.h:95
#define PW_CONSTEXPR_CPP20
Definition: language_feature_macros.h:27
The Pigweed namespace.
Definition: alignment.h:27
Definition: optional_tuple.h:47
Definition: optional_tuple.h:77
Definition: optional_tuple.h:51