7 #include <aws/common/assert.h>
12 #include <type_traits>
19 namespace VariantDetail
21 template <
typename T> constexpr
const T &
ConstExprMax(
const T &a,
const T &b)
23 return (a < b) ? b : a;
26 namespace ParameterPackSize
29 template <
typename Last> constexpr std::size_t
GetMaxSizeOf(std::size_t curMax = 0)
34 template <
typename First,
typename Second,
typename... Rest>
41 template <
typename Last> constexpr std::size_t
AlignAsPack(std::size_t curMax = 0)
46 template <
typename First,
typename Second,
typename... Rest>
59 return std::is_same<T, Last>::value ? curIndex : -1;
62 template <
typename T,
typename First,
typename Second,
typename... Rest>
65 return std::is_same<T, First>::value ? curIndex :
GetIndexOf<T, Second, Rest...>(++curIndex);
75 return std::is_same<T, Last>::value;
78 template <
typename T,
typename First,
typename Second,
typename... Rest> constexpr
bool ContainsType()
80 return std::is_same<T, First>::value ||
ContainsType<T, Second, Rest...>();
89 template <
typename T,
typename... Ts>
struct HasType
94 #if defined(AWS_CRT_ENABLE_VARIANT_DEBUG)
95 namespace VariantDebug
97 template <
typename... Ts>
class VariantDebugBrowser
100 VariantDebugBrowser(
char *storage) { InitTuple<0, Ts...>(storage); }
101 std::tuple<typename std::add_pointer<Ts>::type...> as_tuple;
104 template <IndexT Index,
typename First,
typename Second,
typename... Rest>
105 void InitTuple(
char *storage)
107 First *value =
reinterpret_cast<First *
>(storage);
108 std::get<Index>(as_tuple) = value;
109 InitTuple<Index + 1, Second, Rest...>(storage);
112 template <IndexT Index,
typename Last>
void InitTuple(
char *storage)
114 Last *value =
reinterpret_cast<Last *
>(storage);
115 std::get<Index>(as_tuple) = value;
175 template <
typename OtherT>
176 using EnableIfOtherIsThisVariantAlternative =
typename std::enable_if<
184 std::is_nothrow_default_constructible<FirstAlternative>::value;
187 std::is_nothrow_constructible<FirstAlternative>::value;
200 AWS_FATAL_ASSERT(other.m_index != -1);
201 m_index = other.m_index;
202 VisitorUtil<0, Ts...>::VisitBinary(
this, other, CopyMoveConstructor());
207 AWS_FATAL_ASSERT(other.m_index != -1);
208 m_index = other.m_index;
209 VisitorUtil<0, Ts...>::VisitBinary(
this, std::move(other), CopyMoveConstructor());
212 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1>
214 std::is_nothrow_constructible<
typename std::decay<T>::type, decltype(val)>::value)
218 "This variant does not have such alternative T.");
220 sizeof(T) <= STORAGE_SIZE,
221 "Attempting to instantiate a Variant with a type bigger than all alternatives.");
223 using PlainT =
typename std::decay<T>::type;
224 new (m_storage) PlainT(val);
226 AWS_ASSERT(m_index != -1);
229 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1>
231 std::is_nothrow_constructible<
typename std::decay<T>::type, decltype(val)>::value)
235 "This variant does not have such alternative T.");
237 sizeof(T) <= STORAGE_SIZE,
238 "Attempting to instantiate a Variant with a type bigger than all alternatives.");
240 using PlainT =
typename std::decay<T>::type;
241 new (m_storage) PlainT(std::forward<T>(val));
243 AWS_ASSERT(m_index != -1);
251 "This variant does not have such alternative T.");
253 sizeof(T) <= STORAGE_SIZE,
254 "Attempting to instantiate a Variant with a type bigger than all alternatives.");
256 using PlainT =
typename std::decay<T>::type;
257 new (m_storage) PlainT(std::forward<Args>(args)...);
259 AWS_ASSERT(m_index != -1);
266 AWS_FATAL_ASSERT(other.m_index != -1);
267 if (m_index != other.m_index)
270 m_index = other.m_index;
271 VisitorUtil<0, Ts...>::VisitBinary(
this, other, CopyMoveConstructor());
275 VisitorUtil<0, Ts...>::VisitBinary(
this, other, CopyMoveAssigner());
285 AWS_FATAL_ASSERT(other.m_index != -1);
286 if (m_index != other.m_index)
289 m_index = other.m_index;
290 VisitorUtil<0, Ts...>::VisitBinary(
this, std::move(other), CopyMoveConstructor());
294 VisitorUtil<0, Ts...>::VisitBinary(
this, std::move(other), CopyMoveAssigner());
301 template <
typename T,
typename... Args, EnableIfOtherIsThisVariantAlternative<T> = 1>
306 "This variant does not have such alternative T.");
308 sizeof(T) <= STORAGE_SIZE,
309 "Attempting to instantiate a Variant with a type bigger than all alternatives.");
313 using PlainT =
typename std::decay<T>::type;
314 new (m_storage) PlainT(std::forward<Args>(args)...);
316 AWS_ASSERT(m_index != -1);
318 T *value =
reinterpret_cast<T *
>(m_storage);
322 template <std::size_t Index,
typename... Args>
325 static_assert(Index <
AlternativeCount,
"Unknown alternative index to emplace");
328 return emplace<AlternativeT, Args...>(std::forward<Args>(args)...);
331 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1>
bool holds_alternative()
const
333 AWS_ASSERT(m_index != -1);
338 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1> T &
get()
340 AWS_FATAL_ASSERT(holds_alternative<T>());
341 T *value =
reinterpret_cast<T *
>(m_storage);
345 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1> T *
get_if()
347 if (holds_alternative<T>())
349 T *value =
reinterpret_cast<T *
>(m_storage);
360 static_assert(Index <
AlternativeCount,
"Unknown alternative index to get");
361 AWS_FATAL_ASSERT(holds_alternative<Index>());
363 AlternativeT *ret =
reinterpret_cast<AlternativeT *
>(m_storage);
368 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1>
const T &
get()
const
370 AWS_FATAL_ASSERT(holds_alternative<T>());
371 const T *value =
reinterpret_cast<const T *
>(m_storage);
375 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1>
const T *
get_if()
const
377 if (holds_alternative<T>())
379 T *value =
reinterpret_cast<T *
>(m_storage);
390 static_assert(Index <
AlternativeCount,
"Unknown alternative index to get");
391 AWS_ASSERT(Index == m_index);
393 const AlternativeT *ret =
reinterpret_cast<const AlternativeT *
>(m_storage);
400 template <std::
size_t Index>
402 typename std::add_pointer<typename ThisVariantAlternative<Index>::type>::type;
406 static_assert(Index <
AlternativeCount,
"Unknown alternative index to get");
407 if (holds_alternative<Index>())
410 AlternativePtrT value =
reinterpret_cast<AlternativePtrT
>(m_storage);
419 template <std::
size_t Index>
421 typename std::add_const<typename ThisVariantAlternative<Index>::type>::type>::type;
425 static_assert(Index <
AlternativeCount,
"Unknown alternative index to get");
426 if (holds_alternative<Index>())
429 AlternativePtrT value =
reinterpret_cast<AlternativePtrT
>(m_storage);
438 std::size_t
index()
const {
return m_index; }
442 template <
typename VisitorT>
void Visit(VisitorT &&visitor)
444 return VisitorUtil<0, Ts...>::Visit(
this, std::forward<VisitorT>(visitor));
452 #if defined(AWS_CRT_ENABLE_VARIANT_DEBUG)
453 VariantDetail::VariantDebug::VariantDebugBrowser<Ts...> browser = m_storage;
456 template <
size_t Index> constexpr
bool holds_alternative()
const {
return Index == m_index; }
460 template <
typename AlternativeT>
void operator()(AlternativeT &&value)
const
463 using PlaintT =
typename std::remove_reference<AlternativeT>::type;
470 AWS_FATAL_ASSERT(m_index != -1);
476 struct CopyMoveConstructor
478 template <
typename AlternativeT>
void operator()(AlternativeT &&value, AlternativeT &&other)
const
480 using PlaintT =
typename std::remove_reference<AlternativeT>::type;
481 new (&value) PlaintT(std::move<AlternativeT>(other));
484 template <
typename AlternativeT,
typename ConstAlternativeT>
485 void operator()(AlternativeT &&value, ConstAlternativeT &other)
const
487 using PlaintT =
typename std::remove_reference<AlternativeT>::type;
489 typename std::remove_const<typename std::remove_reference<AlternativeT>::type>::type;
490 static_assert(std::is_same<PlaintT, PlaintOtherT>::value,
"Incompatible types");
492 new (&value) PlaintT(other);
496 struct CopyMoveAssigner
498 template <
typename AlternativeT>
void operator()(AlternativeT &&value, AlternativeT &&other)
const
500 value = std::move(other);
503 template <
typename AlternativeT,
typename ConstAlternativeT>
504 void operator()(AlternativeT &&value, ConstAlternativeT &other)
const
506 using PlaintT =
typename std::remove_reference<AlternativeT>::type;
508 typename std::remove_const<typename std::remove_reference<AlternativeT>::type>::type;
509 static_assert(std::is_same<PlaintT, PlaintOtherT>::value,
"Incompatible types");
515 template <
IndexT Index,
typename... Args>
struct VisitorUtil;
517 template <
IndexT Index,
typename First,
typename Second,
typename... Rest>
518 struct VisitorUtil<Index, First, Second, Rest...>
520 template <
typename VisitorStruct>
static void Visit(
VariantImpl *pThis, VisitorStruct &&visitor)
522 static_assert(Index <
AlternativeCount,
"Attempting to visit unknown Index Type");
524 if (Index == pThis->m_index)
527 AlternativeT *value =
reinterpret_cast<AlternativeT *
>(pThis->m_storage);
532 VisitorUtil<static_cast<IndexT>(Index + 1), Second, Rest...>
::Visit(
533 pThis, std::forward<VisitorStruct>(visitor));
537 template <
typename VisitorStruct>
538 static void VisitBinary(
539 VariantImpl<Ts...> *pThis,
540 VariantImpl<Ts...> &&other,
541 VisitorStruct &&visitor)
543 static_assert(Index <
AlternativeCount,
"Attempting to visit unknown Index Type");
545 if (Index == pThis->m_index)
548 AlternativeT *value =
reinterpret_cast<AlternativeT *
>(pThis->m_storage);
549 visitor(*value, other.get<AlternativeT>());
553 VisitorUtil<static_cast<IndexT>(Index + 1), Second, Rest...>::VisitBinary(
554 pThis, std::forward<VariantImpl<Ts...>>(other), std::forward<VisitorStruct>(visitor));
558 template <
typename VisitorStruct>
559 static void VisitBinary(
560 VariantImpl<Ts...> *pThis,
561 const VariantImpl<Ts...> &other,
562 VisitorStruct &&visitor)
564 static_assert(Index <
AlternativeCount,
"Attempting to visit unknown Index Type");
566 if (Index == pThis->m_index)
569 AlternativeT *value =
reinterpret_cast<AlternativeT *
>(pThis->m_storage);
570 const AlternativeT &otherValue = other.get<AlternativeT>();
571 visitor(*value, otherValue);
575 VisitorUtil<static_cast<IndexT>(Index + 1), Second, Rest...>::VisitBinary(
576 pThis, other, std::forward<VisitorStruct>(visitor));
581 template <IndexT Index,
typename Last>
struct VisitorUtil<Index, Last>
583 template <
typename VisitorStruct>
static void Visit(
VariantImpl *pThis, VisitorStruct &&visitor)
585 static_assert(Index <
AlternativeCount,
"Attempting to visit unknown Index Type");
587 if (Index == pThis->m_index)
590 AlternativeT *value =
reinterpret_cast<AlternativeT *
>(pThis->m_storage);
595 AWS_FATAL_ASSERT(!
"Unknown variant alternative to visit!");
599 template <
typename VisitorStruct>
600 static void VisitBinary(
601 VariantImpl<Ts...> *pThis,
602 VariantImpl<Ts...> &&other,
603 VisitorStruct &&visitor)
605 static_assert(Index <
AlternativeCount,
"Attempting to visit unknown Index Type");
607 if (Index == pThis->m_index)
610 AlternativeT *value =
reinterpret_cast<AlternativeT *
>(pThis->m_storage);
611 visitor(*value, other.get<AlternativeT>());
615 AWS_FATAL_ASSERT(!
"Unknown variant alternative to visit!");
619 template <
typename VisitorStruct>
620 static void VisitBinary(
621 VariantImpl<Ts...> *pThis,
622 const VariantImpl<Ts...> &other,
623 VisitorStruct &&visitor)
625 static_assert(Index <
AlternativeCount,
"Attempting to visit unknown Index Type");
627 if (Index == pThis->m_index)
630 AlternativeT *value =
reinterpret_cast<AlternativeT *
>(pThis->m_storage);
631 const AlternativeT &otherValue = other.get<AlternativeT>();
632 visitor(*value, otherValue);
636 AWS_FATAL_ASSERT(!
"Unknown variant alternative to visit!");
647 using type =
typename std::tuple_element<Index, std::tuple<Ts...>>
::type;
656 constexpr
static const std::size_t Value = T::AlternativeCount;
665 template <
typename... Ts>
678 template <
typename OtherT>
679 using EnableIfOtherIsThisVariantAlternative =
typename std::
680 enable_if<VariantDetail::Checker::HasType<typename std::decay<OtherT>::type, Ts...>::value,
int>::type;
682 static constexpr
bool isFirstAlternativeNothrowDefaultConstructible =
691 typename std::enable_if<std::is_default_constructible<T>::value,
bool>::type =
true>
692 Variant() noexcept(isFirstAlternativeNothrowDefaultConstructible)
698 typename std::enable_if<!std::is_default_constructible<T>::value,
bool>::type =
true>
701 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1>
703 std::is_nothrow_constructible<
typename std::decay<T>::type, decltype(val)>::value)
708 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1>
709 Variant(T &&val) noexcept(std::is_nothrow_constructible<
typename std::decay<T>::type, decltype(val)>::value)
710 : m_variant(
std::forward<T>(val))
714 template <
typename T,
typename... Args>
716 : m_variant(ipt,
std::forward<Args>(args)...)
720 template <
typename T,
typename... Args, EnableIfOtherIsThisVariantAlternative<T> = 1>
723 return m_variant.template emplace<T>(std::forward<Args>(args)...);
726 template <std::size_t Index,
typename... Args>
729 return m_variant.template emplace<Index>(std::forward<Args>(args)...);
732 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1>
bool holds_alternative()
const
734 return m_variant.template holds_alternative<T>();
737 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1> T &
get()
739 return m_variant.template get<T>();
742 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1> T *
get_if()
744 return m_variant.template get_if<T>();
749 return m_variant.template get<Index>();
752 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1>
const T &
get()
const
754 return m_variant.template get<T>();
757 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1>
const T *
get_if()
const
759 return m_variant.template get_if<T>();
764 return m_variant.template get<Index>();
767 template <std::
size_t Index>
769 typename std::add_pointer<typename ThisVariantAlternative<Index>::type>::type;
773 return m_variant.template get_if<Index>();
776 template <std::
size_t Index>
778 typename std::add_const<typename ThisVariantAlternative<Index>::type>::type>::type;
782 return m_variant.template get_if<Index>();
787 template <
typename VisitorT>
void Visit(VisitorT &&visitor)
789 m_variant.
Visit(std::forward<VisitorT>(visitor));