7 #include <aws/common/assert.h>
11 #include <type_traits>
18 namespace VariantDetail
20 template <
typename T> constexpr
const T &
ConstExprMax(
const T &a,
const T &b)
22 return (a < b) ? b : a;
25 namespace ParameterPackSize
28 template <
typename Last> constexpr std::size_t
GetMaxSizeOf(std::size_t curMax = 0)
33 template <
typename First,
typename Second,
typename... Rest>
40 template <
typename Last> constexpr std::size_t
AlignAsPack(std::size_t curMax = 0)
45 template <
typename First,
typename Second,
typename... Rest>
58 return std::is_same<T, Last>::value ? curIndex : -1;
61 template <
typename T,
typename First,
typename Second,
typename... Rest>
64 return std::is_same<T, First>::value ? curIndex :
GetIndexOf<T, Second, Rest...>(++curIndex);
74 return std::is_same<T, Last>::value;
77 template <
typename T,
typename First,
typename Second,
typename... Rest> constexpr
bool ContainsType()
79 return std::is_same<T, First>::value ||
ContainsType<T, Second, Rest...>();
88 template <
typename T,
typename... Ts>
struct HasType
93 #if defined(AWS_CRT_ENABLE_VARIANT_DEBUG)
94 namespace VariantDebug
96 template <
typename... Ts>
class VariantDebugBrowser
99 VariantDebugBrowser(
char *storage) { InitTuple<0, Ts...>(storage); }
100 std::tuple<typename std::add_pointer<Ts>::type...> as_tuple;
103 template <IndexT Index,
typename First,
typename Second,
typename... Rest>
104 void InitTuple(
char *storage)
106 First *value =
reinterpret_cast<First *
>(storage);
107 std::get<Index>(as_tuple) = value;
108 InitTuple<Index + 1, Second, Rest...>(storage);
111 template <IndexT Index,
typename Last>
void InitTuple(
char *storage)
113 Last *value =
reinterpret_cast<Last *
>(storage);
114 std::get<Index>(as_tuple) = value;
121 template <std::size_t Index,
typename... Ts>
class VariantAlternative;
132 template <
typename OtherT>
133 using EnableIfOtherIsThisVariantAlternative =
typename std::
134 enable_if<VariantDetail::Checker::HasType<typename std::decay<OtherT>::type, Ts...>::value,
int>::type;
143 new (m_storage) FirstAlternative();
149 AWS_FATAL_ASSERT(other.m_index != -1);
150 m_index = other.m_index;
151 VisitorUtil<0, Ts...>::VisitBinary(
this, other, CopyMoveConstructor());
156 AWS_FATAL_ASSERT(other.m_index != -1);
157 m_index = other.m_index;
158 VisitorUtil<0, Ts...>::VisitBinary(
this, std::move(other), CopyMoveConstructor());
161 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1>
Variant(
const T &val)
165 "This variant does not have such alternative T.");
167 sizeof(T) <= STORAGE_SIZE,
168 "Attempting to instantiate a Variant with a type bigger than all alternatives.");
170 using PlainT =
typename std::decay<T>::type;
171 new (m_storage) PlainT(val);
173 AWS_ASSERT(m_index != -1);
176 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1>
Variant(T &&val)
180 "This variant does not have such alternative T.");
182 sizeof(T) <= STORAGE_SIZE,
183 "Attempting to instantiate a Variant with a type bigger than all alternatives.");
185 using PlainT =
typename std::decay<T>::type;
186 new (m_storage) PlainT(std::forward<T>(val));
188 AWS_ASSERT(m_index != -1);
196 "This variant does not have such alternative T.");
198 sizeof(T) <= STORAGE_SIZE,
199 "Attempting to instantiate a Variant with a type bigger than all alternatives.");
201 using PlainT =
typename std::decay<T>::type;
202 new (m_storage) PlainT(std::forward<Args>(args)...);
204 AWS_ASSERT(m_index != -1);
211 AWS_FATAL_ASSERT(other.m_index != -1);
212 if (m_index != other.m_index)
215 m_index = other.m_index;
216 VisitorUtil<0, Ts...>::VisitBinary(
this, other, CopyMoveConstructor());
220 VisitorUtil<0, Ts...>::VisitBinary(
this, other, CopyMoveAssigner());
230 AWS_FATAL_ASSERT(other.m_index != -1);
231 if (m_index != other.m_index)
234 m_index = other.m_index;
235 VisitorUtil<0, Ts...>::VisitBinary(
this, std::move(other), CopyMoveConstructor());
239 VisitorUtil<0, Ts...>::VisitBinary(
this, std::move(other), CopyMoveAssigner());
246 template <
typename T,
typename... Args, EnableIfOtherIsThisVariantAlternative<T> = 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.");
258 using PlainT =
typename std::decay<T>::type;
259 new (m_storage) PlainT(std::forward<Args>(args)...);
261 AWS_ASSERT(m_index != -1);
263 T *value =
reinterpret_cast<T *
>(m_storage);
267 template <std::size_t Index,
typename... Args>
270 static_assert(Index <
AlternativeCount,
"Unknown alternative index to emplace");
273 return emplace<AlternativeT, Args...>(std::forward<Args>(args)...);
276 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1>
bool holds_alternative()
const
278 AWS_ASSERT(m_index != -1);
283 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1> T &
get()
285 AWS_FATAL_ASSERT(holds_alternative<T>());
286 T *value =
reinterpret_cast<T *
>(m_storage);
290 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1> T *
get_if()
292 if (holds_alternative<T>())
294 T *value =
reinterpret_cast<T *
>(m_storage);
305 static_assert(Index <
AlternativeCount,
"Unknown alternative index to get");
306 AWS_FATAL_ASSERT(holds_alternative<Index>());
308 AlternativeT *ret =
reinterpret_cast<AlternativeT *
>(m_storage);
313 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1>
const T &
get()
const
315 AWS_FATAL_ASSERT(holds_alternative<T>());
316 const T *value =
reinterpret_cast<const T *
>(m_storage);
320 template <
typename T, EnableIfOtherIsThisVariantAlternative<T> = 1>
const T *
get_if()
const
322 if (holds_alternative<T>())
324 T *value =
reinterpret_cast<T *
>(m_storage);
335 static_assert(Index <
AlternativeCount,
"Unknown alternative index to get");
336 AWS_ASSERT(Index == m_index);
338 const AlternativeT *ret =
reinterpret_cast<const AlternativeT *
>(m_storage);
345 template <std::
size_t Index>
347 typename std::add_pointer<typename ThisVariantAlternative<Index>::type>::type;
351 static_assert(Index <
AlternativeCount,
"Unknown alternative index to get");
352 if (holds_alternative<Index>())
355 AlternativePtrT value =
reinterpret_cast<AlternativePtrT
>(m_storage);
364 template <std::
size_t Index>
366 typename std::add_const<typename ThisVariantAlternative<Index>::type>::type>::type;
370 static_assert(Index <
AlternativeCount,
"Unknown alternative index to get");
371 if (holds_alternative<Index>())
374 AlternativePtrT value =
reinterpret_cast<AlternativePtrT
>(m_storage);
383 std::size_t
index()
const {
return m_index; }
387 template <
typename VisitorT>
void Visit(VisitorT &&visitor)
389 return VisitorUtil<0, Ts...>::Visit(
this, std::forward<VisitorT>(visitor));
397 #if defined(AWS_CRT_ENABLE_VARIANT_DEBUG)
398 VariantDetail::VariantDebug::VariantDebugBrowser<Ts...> browser = m_storage;
401 template <
size_t Index> constexpr
bool holds_alternative()
const {
return Index == m_index; }
405 template <
typename AlternativeT>
void operator()(AlternativeT &&value)
const
407 using PlaintT =
typename std::remove_reference<AlternativeT>::type;
414 AWS_FATAL_ASSERT(m_index != -1);
420 struct CopyMoveConstructor
422 template <
typename AlternativeT>
void operator()(AlternativeT &&value, AlternativeT &&other)
const
424 using PlaintT =
typename std::remove_reference<AlternativeT>::type;
425 new (&value) PlaintT(std::move<AlternativeT>(other));
428 template <
typename AlternativeT,
typename ConstAlternativeT>
429 void operator()(AlternativeT &&value, ConstAlternativeT &other)
const
431 using PlaintT =
typename std::remove_reference<AlternativeT>::type;
433 typename std::remove_const<typename std::remove_reference<AlternativeT>::type>::type;
434 static_assert(std::is_same<PlaintT, PlaintOtherT>::value,
"Incompatible types");
436 new (&value) PlaintT(other);
440 struct CopyMoveAssigner
442 template <
typename AlternativeT>
void operator()(AlternativeT &&value, AlternativeT &&other)
const
444 value = std::move(other);
447 template <
typename AlternativeT,
typename ConstAlternativeT>
448 void operator()(AlternativeT &&value, ConstAlternativeT &other)
const
450 using PlaintT =
typename std::remove_reference<AlternativeT>::type;
452 typename std::remove_const<typename std::remove_reference<AlternativeT>::type>::type;
453 static_assert(std::is_same<PlaintT, PlaintOtherT>::value,
"Incompatible types");
459 template <
IndexT Index,
typename... Args>
struct VisitorUtil;
461 template <
IndexT Index,
typename First,
typename Second,
typename... Rest>
462 struct VisitorUtil<Index, First, Second, Rest...>
464 template <
typename VisitorStruct>
static void Visit(
Variant *pThis, VisitorStruct &&visitor)
466 static_assert(Index <
AlternativeCount,
"Attempting to visit unknown Index Type");
468 if (Index == pThis->m_index)
471 AlternativeT *value =
reinterpret_cast<AlternativeT *
>(pThis->m_storage);
476 VisitorUtil<static_cast<IndexT>(Index + 1), Second, Rest...>
::Visit(
477 pThis, std::forward<VisitorStruct>(visitor));
481 template <
typename VisitorStruct>
482 static void VisitBinary(Variant<Ts...> *pThis, Variant<Ts...> &&other, VisitorStruct &&visitor)
484 static_assert(Index <
AlternativeCount,
"Attempting to visit unknown Index Type");
486 if (Index == pThis->m_index)
489 AlternativeT *value =
reinterpret_cast<AlternativeT *
>(pThis->m_storage);
490 visitor(*value, other.get<AlternativeT>());
494 VisitorUtil<static_cast<IndexT>(Index + 1), Second, Rest...>::VisitBinary(
495 pThis, std::forward<Variant<Ts...>>(other), std::forward<VisitorStruct>(visitor));
499 template <
typename VisitorStruct>
500 static void VisitBinary(Variant<Ts...> *pThis,
const Variant<Ts...> &other, VisitorStruct &&visitor)
502 static_assert(Index <
AlternativeCount,
"Attempting to visit unknown Index Type");
504 if (Index == pThis->m_index)
507 AlternativeT *value =
reinterpret_cast<AlternativeT *
>(pThis->m_storage);
508 const AlternativeT &otherValue = other.get<AlternativeT>();
509 visitor(*value, otherValue);
513 VisitorUtil<static_cast<IndexT>(Index + 1), Second, Rest...>::VisitBinary(
514 pThis, other, std::forward<VisitorStruct>(visitor));
519 template <IndexT Index,
typename Last>
struct VisitorUtil<Index, Last>
521 template <
typename VisitorStruct>
static void Visit(
Variant *pThis, VisitorStruct &&visitor)
523 static_assert(Index <
AlternativeCount,
"Attempting to visit unknown Index Type");
525 if (Index == pThis->m_index)
528 AlternativeT *value =
reinterpret_cast<AlternativeT *
>(pThis->m_storage);
533 AWS_FATAL_ASSERT(!
"Unknown variant alternative to visit!");
537 template <
typename VisitorStruct>
538 static void VisitBinary(Variant<Ts...> *pThis, Variant<Ts...> &&other, VisitorStruct &&visitor)
540 static_assert(Index <
AlternativeCount,
"Attempting to visit unknown Index Type");
542 if (Index == pThis->m_index)
545 AlternativeT *value =
reinterpret_cast<AlternativeT *
>(pThis->m_storage);
546 visitor(*value, other.get<AlternativeT>());
550 AWS_FATAL_ASSERT(!
"Unknown variant alternative to visit!");
554 template <
typename VisitorStruct>
555 static void VisitBinary(Variant<Ts...> *pThis,
const Variant<Ts...> &other, VisitorStruct &&visitor)
557 static_assert(Index <
AlternativeCount,
"Attempting to visit unknown Index Type");
559 if (Index == pThis->m_index)
562 AlternativeT *value =
reinterpret_cast<AlternativeT *
>(pThis->m_storage);
563 const AlternativeT &otherValue = other.get<AlternativeT>();
564 visitor(*value, otherValue);
568 AWS_FATAL_ASSERT(!
"Unknown variant alternative to visit!");
579 using type =
typename std::tuple_element<Index, std::tuple<Ts...>>
::type;
588 constexpr
static const std::size_t Value = T::AlternativeCount;