1e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#ifndef ANDROID_PDX_RPC_VARIANT_H_ 2e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#define ANDROID_PDX_RPC_VARIANT_H_ 3e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 4e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <cstdint> 5e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <tuple> 6e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <type_traits> 7e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 8e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace android { 9e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace pdx { 10e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace rpc { 11e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 12e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Type tag denoting an empty variant. 13e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostruct EmptyVariant {}; 14e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 15e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace detail { 16e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 17e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Type for matching tagged overloads. 18e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename T> 19e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostruct TypeTag {}; 20e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 21e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Determines the type of the I-th element of Types.... 22e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <std::size_t I, typename... Types> 23e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkousing TypeForIndex = std::tuple_element_t<I, std::tuple<Types...>>; 24e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 25e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Determines the type tag for the I-th element of Types.... 26e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <std::size_t I, typename... Types> 27e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkousing TypeTagForIndex = TypeTag<TypeForIndex<I, Types...>>; 28e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 297190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka// Similar to std::is_constructible except that it evaluates to false for bool 307190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka// construction from pointer types: this helps prevent subtle to bugs caused by 317190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka// assigning values that decay to pointers to Variants with bool elements. 327190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka// 337190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka// Here is an example of the problematic situation this trait avoids: 347190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka// 357190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka// Variant<int, bool> v; 367190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka// const int array[3] = {1, 2, 3}; 377190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka// v = array; // This is allowed by regular std::is_constructible. 387190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka// 397190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabakatemplate <typename...> 407190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabakastruct IsConstructible; 417190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabakatemplate <typename T, typename U> 427190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabakastruct IsConstructible<T, U> 437190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka : std::integral_constant<bool, 447190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka std::is_constructible<T, U>::value && 457190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka !(std::is_same<std::decay_t<T>, bool>::value && 467190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka std::is_pointer<std::decay_t<U>>::value)> {}; 477190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabakatemplate <typename T, typename... Args> 487190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabakastruct IsConstructible<T, Args...> : std::is_constructible<T, Args...> {}; 497190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka 50e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Enable if T(Args...) is well formed. 51e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename R, typename T, typename... Args> 52e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkousing EnableIfConstructible = 537190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka typename std::enable_if<IsConstructible<T, Args...>::value, R>::type; 54e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Enable if T(Args...) is not well formed. 55e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename R, typename T, typename... Args> 56e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkousing EnableIfNotConstructible = 577190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka typename std::enable_if<!IsConstructible<T, Args...>::value, R>::type; 58e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 59e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Determines whether T is an element of Types...; 60e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename... Types> 61e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostruct HasType : std::false_type {}; 62e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename T, typename U> 63a44b9f94aa53e69ccbfb86a35b13872b6faf8e52Corey Tabakastruct HasType<T, U> : std::is_same<std::decay_t<T>, std::decay_t<U>> {}; 64e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename T, typename First, typename... Rest> 65e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostruct HasType<T, First, Rest...> 66a44b9f94aa53e69ccbfb86a35b13872b6faf8e52Corey Tabaka : std::integral_constant<bool, HasType<T, First>::value || 67a44b9f94aa53e69ccbfb86a35b13872b6faf8e52Corey Tabaka HasType<T, Rest...>::value> {}; 68e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 69e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Defines set operations on a set of Types... 70e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename... Types> 71e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostruct Set { 72e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Default specialization catches the empty set, which is always a subset. 73e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename...> 74e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko struct IsSubset : std::true_type {}; 75e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 76e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko struct IsSubset<T> : HasType<T, Types...> {}; 77e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename First, typename... Rest> 78e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko struct IsSubset<First, Rest...> 79a44b9f94aa53e69ccbfb86a35b13872b6faf8e52Corey Tabaka : std::integral_constant<bool, IsSubset<First>::value && 80a44b9f94aa53e69ccbfb86a35b13872b6faf8e52Corey Tabaka IsSubset<Rest...>::value> {}; 81e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}; 82e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 83e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Determines the number of elements of Types... that are constructible from 84e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// From. 85e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename... Types> 86e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostruct ConstructibleCount; 87e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename From, typename To> 88e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostruct ConstructibleCount<From, To> 897190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka : std::integral_constant<std::size_t, IsConstructible<To, From>::value> {}; 90e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename From, typename First, typename... Rest> 91e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostruct ConstructibleCount<From, First, Rest...> 92e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko : std::integral_constant<std::size_t, 937190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka IsConstructible<First, From>::value + 94e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ConstructibleCount<From, Rest...>::value> {}; 95e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 96e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Enable if T is an element of Types... 97e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename R, typename T, typename... Types> 98e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkousing EnableIfElement = 99a44b9f94aa53e69ccbfb86a35b13872b6faf8e52Corey Tabaka typename std::enable_if<HasType<T, Types...>::value, R>::type; 100e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Enable if T is not an element of Types... 101e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename R, typename T, typename... Types> 102e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkousing EnableIfNotElement = 103a44b9f94aa53e69ccbfb86a35b13872b6faf8e52Corey Tabaka typename std::enable_if<!HasType<T, Types...>::value, R>::type; 104e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 105e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Enable if T is convertible to an element of Types... T is considered 106e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// convertible IIF a single element of Types... is assignable from T and T is 107e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// not a direct element of Types... 108e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename R, typename T, typename... Types> 109e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkousing EnableIfConvertible = 110a44b9f94aa53e69ccbfb86a35b13872b6faf8e52Corey Tabaka typename std::enable_if<!HasType<T, Types...>::value && 111e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ConstructibleCount<T, Types...>::value == 1, 112e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko R>::type; 113e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 114e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Enable if T is assignable to an element of Types... T is considered 115e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// assignable IFF a single element of Types... is constructible from T or T is a 116e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// direct element of Types.... Note that T is REQUIRED to be an element of 117e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Types... when multiple elements are constructible from T to prevent ambiguity 118e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// in conversion. 119e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename R, typename T, typename... Types> 120e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkousing EnableIfAssignable = 121a44b9f94aa53e69ccbfb86a35b13872b6faf8e52Corey Tabaka typename std::enable_if<HasType<T, Types...>::value || 122e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ConstructibleCount<T, Types...>::value == 1, 123e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko R>::type; 124e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 125e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Selects a type for SFINAE constructor selection. 126e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <bool CondA, typename SelectA, typename SelectB> 127e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkousing Select = std::conditional_t<CondA, SelectA, SelectB>; 128e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 129e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Recursive union type. 130e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename... Types> 131e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkounion Union; 132e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 133e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Specialization handling a singular type, terminating template recursion. 134e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename Type> 135e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkounion Union<Type> { 136e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Union() {} 137e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ~Union() {} 138e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 139e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 140e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Union(std::int32_t index, std::int32_t* index_out, TypeTag<Type>, T&& value) 141e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko : first_(std::forward<T>(value)) { 142e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko *index_out = index; 143e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 144e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T, typename = EnableIfAssignable<void, T, Type>> 145e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Union(std::int32_t index, std::int32_t* index_out, T&& value) 146e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko : first_(std::forward<T>(value)) { 147e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko *index_out = index; 148e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 1497190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka Union(const Union& other, std::int32_t index) { 1507190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka if (index == 0) 1517190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka new (&first_) Type(other.first_); 1527190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka } 1537190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka Union(Union&& other, std::int32_t index) { 1547190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka if (index == 0) 1557190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka new (&first_) Type(std::move(other.first_)); 1567190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka } 1577190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka Union(const Union&) = delete; 1587190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka Union(Union&&) = delete; 1597190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka void operator=(const Union&) = delete; 1607190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka void operator=(Union&&) = delete; 161e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 162e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Type& get(TypeTag<Type>) { return first_; } 163e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko const Type& get(TypeTag<Type>) const { return first_; } 164e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko EmptyVariant get(TypeTag<EmptyVariant>) const { return {}; } 165e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko constexpr std::int32_t index(TypeTag<Type>) const { return 0; } 166e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 167e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename... Args> 168e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko std::int32_t Construct(TypeTag<Type>, Args&&... args) { 169e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko new (&first_) Type(std::forward<Args>(args)...); 170e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return 0; 171e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 172e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename... Args> 173e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko EnableIfConstructible<std::int32_t, Type, Args...> Construct(Args&&... args) { 174e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko new (&first_) Type(std::forward<Args>(args)...); 175e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return 0; 176e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 177e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 178e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko void Destruct(std::int32_t target_index) { 179e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (target_index == index(TypeTag<Type>{})) { 180e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko (&get(TypeTag<Type>{}))->~Type(); 181e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 182e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 183e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 184e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 185e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko bool Assign(TypeTag<Type>, std::int32_t target_index, T&& value) { 186e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (target_index == 0) { 187e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko first_ = std::forward<T>(value); 188e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return true; 189e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } else { 190e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return false; 191e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 192e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 193e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 194e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko EnableIfConstructible<bool, Type, T> Assign(std::int32_t target_index, 195e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko T&& value) { 196e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (target_index == 0) { 197e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko first_ = std::forward<T>(value); 198e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return true; 199e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } else { 200e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return false; 201e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 202e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 203e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 204e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko EnableIfNotConstructible<bool, Type, T> Assign(std::int32_t /*target_index*/, 205e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko T&& /*value*/) { 206e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return false; 207e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 208e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 209e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename Op> 210e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko decltype(auto) Visit(std::int32_t target_index, Op&& op) { 211e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (target_index == index(TypeTag<Type>{})) 212e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return std::forward<Op>(op)(get(TypeTag<Type>{})); 213e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko else 214e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return std::forward<Op>(op)(get(TypeTag<EmptyVariant>{})); 215e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 216e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename Op> 217e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko decltype(auto) Visit(std::int32_t target_index, Op&& op) const { 218e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (target_index == index(TypeTag<Type>{})) 219e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return std::forward<Op>(op)(get(TypeTag<Type>{})); 220e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko else 221e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return std::forward<Op>(op)(get(TypeTag<EmptyVariant>{})); 222e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 223e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 224e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename... Args> 225e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko bool Become(std::int32_t target_index, Args&&... args) { 226e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (target_index == index(TypeTag<Type>{})) { 227e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Construct(TypeTag<Type>{}, std::forward<Args>(args)...); 228e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return true; 229e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } else { 230e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return false; 231e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 232e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 233e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 234e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko private: 235e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Type first_; 236e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}; 237e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 238e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Specialization that recursively unions types from the paramater pack. 239e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename First, typename... Rest> 240e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkounion Union<First, Rest...> { 241e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Union() {} 242e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ~Union() {} 243e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 244e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 245e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Union(std::int32_t index, std::int32_t* index_out, TypeTag<First>, T&& value) 246e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko : first_(std::forward<T>(value)) { 247e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko *index_out = index; 248e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 249e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T, typename U> 250e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Union(std::int32_t index, std::int32_t* index_out, TypeTag<T>, U&& value) 251e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko : rest_(index + 1, index_out, TypeTag<T>{}, std::forward<U>(value)) {} 2527190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka Union(const Union& other, std::int32_t index) { 2537190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka if (index == 0) 2547190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka new (&first_) First(other.first_); 2557190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka else 2567190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka new (&rest_) Union<Rest...>(other.rest_, index - 1); 2577190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka } 2587190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka Union(Union&& other, std::int32_t index) { 2597190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka if (index == 0) 2607190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka new (&first_) First(std::move(other.first_)); 2617190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka else 2627190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka new (&rest_) Union<Rest...>(std::move(other.rest_), index - 1); 2637190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka } 2647190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka Union(const Union&) = delete; 2657190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka Union(Union&&) = delete; 2667190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka void operator=(const Union&) = delete; 2677190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka void operator=(Union&&) = delete; 268e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 269e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko struct FirstType {}; 270e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko struct RestType {}; 271e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 272e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko using SelectConstructor = 273e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Select<ConstructibleCount<T, First>::value == 1, FirstType, RestType>; 274e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 275e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 276e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Union(std::int32_t index, std::int32_t* index_out, T&& value) 277e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko : Union(index, index_out, std::forward<T>(value), 278e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko SelectConstructor<T>{}) {} 279e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 280e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 281e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Union(std::int32_t index, std::int32_t* index_out, T&& value, FirstType) 282e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko : first_(std::forward<T>(value)) { 283e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko *index_out = index; 284e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 285e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 286e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Union(std::int32_t index, std::int32_t* index_out, T&& value, RestType) 287e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko : rest_(index + 1, index_out, std::forward<T>(value)) {} 288e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 289e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko First& get(TypeTag<First>) { return first_; } 290e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko const First& get(TypeTag<First>) const { return first_; } 291e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko constexpr std::int32_t index(TypeTag<First>) const { return 0; } 292e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 293e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 294e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko T& get(TypeTag<T>) { 295e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return rest_.template get(TypeTag<T>{}); 296e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 297e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 298e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko const T& get(TypeTag<T>) const { 299e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return rest_.template get(TypeTag<T>{}); 300e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 301e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 302e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko constexpr std::int32_t index(TypeTag<T>) const { 303e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return 1 + rest_.template index(TypeTag<T>{}); 304e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 305e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 306e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename... Args> 307e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko std::int32_t Construct(TypeTag<First>, Args&&... args) { 308e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko new (&first_) First(std::forward<Args>(args)...); 309e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return 0; 310e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 311e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T, typename... Args> 312e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko std::int32_t Construct(TypeTag<T>, Args&&... args) { 313e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return 1 + 314e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko rest_.template Construct(TypeTag<T>{}, std::forward<Args>(args)...); 315e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 316e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 317e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename... Args> 318e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko EnableIfConstructible<std::int32_t, First, Args...> Construct( 319e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Args&&... args) { 320e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko new (&first_) First(std::forward<Args>(args)...); 321e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return 0; 322e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 323e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename... Args> 324e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko EnableIfNotConstructible<std::int32_t, First, Args...> Construct( 325e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Args&&... args) { 326e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return 1 + rest_.template Construct(std::forward<Args>(args)...); 327e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 328e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 329e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko void Destruct(std::int32_t target_index) { 330e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (target_index == index(TypeTag<First>{})) { 331e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko (get(TypeTag<First>{})).~First(); 332e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } else { 333e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko rest_.Destruct(target_index - 1); 334e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 335e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 336e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 337e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 338e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko bool Assign(TypeTag<First>, std::int32_t target_index, T&& value) { 339e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (target_index == 0) { 340e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko first_ = std::forward<T>(value); 341e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return true; 342e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } else { 343e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return false; 344e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 345e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 346e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T, typename U> 347e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko bool Assign(TypeTag<T>, std::int32_t target_index, U&& value) { 348e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return rest_.Assign(TypeTag<T>{}, target_index - 1, std::forward<U>(value)); 349e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 350e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 351e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko EnableIfConstructible<bool, First, T> Assign(std::int32_t target_index, 352e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko T&& value) { 353e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (target_index == 0) { 354e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko first_ = std::forward<T>(value); 355e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return true; 356e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } else { 357e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return rest_.Assign(target_index - 1, std::forward<T>(value)); 358e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 359e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 360e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 361e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko EnableIfNotConstructible<bool, First, T> Assign(std::int32_t target_index, 362e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko T&& value) { 363e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return rest_.Assign(target_index - 1, std::forward<T>(value)); 364e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 365e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 366e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Recursively traverses the union and calls Op on the active value when the 367e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // active type is found. If the union is empty Op is called on EmptyVariant. 368e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // TODO(eieio): This could be refactored into an array or jump table. It's 369e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // unclear whether this would be more efficient for practical variant arity. 370e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename Op> 371e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko decltype(auto) Visit(std::int32_t target_index, Op&& op) { 372e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (target_index == index(TypeTag<First>{})) 373e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return std::forward<Op>(op)(get(TypeTag<First>{})); 374e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko else 375e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return rest_.Visit(target_index - 1, std::forward<Op>(op)); 376e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 377e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename Op> 378e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko decltype(auto) Visit(std::int32_t target_index, Op&& op) const { 379e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (target_index == index(TypeTag<First>{})) 380e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return std::forward<Op>(op)(get(TypeTag<First>{})); 381e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko else 382e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return rest_.Visit(target_index - 1, std::forward<Op>(op)); 383e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 384e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 385e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename... Args> 386e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko bool Become(std::int32_t target_index, Args&&... args) { 387e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (target_index == index(TypeTag<First>{})) { 388e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Construct(TypeTag<First>{}, std::forward<Args>(args)...); 389e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return true; 390e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } else { 391e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return rest_.Become(target_index - 1, std::forward<Args>(args)...); 392e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 393e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 394e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 395e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko private: 396e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko First first_; 397e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Union<Rest...> rest_; 398e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}; 399e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 400e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} // namespace detail 401e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 4027190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka// Variant is a type safe union that can store values of any of its element 4037190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka// types. A Variant is different than std::tuple in that it only stores one type 4047190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka// at a time or a special empty type. Variants are always default constructible 4057190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka// to empty, even when none of the element types are default constructible. 406e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename... Types> 407e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkoclass Variant { 408e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko private: 409e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Convenience types. 410e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 411e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko using TypeTag = detail::TypeTag<T>; 412e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 413a44b9f94aa53e69ccbfb86a35b13872b6faf8e52Corey Tabaka using DecayedTypeTag = TypeTag<std::decay_t<T>>; 414e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <std::size_t I> 415e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko using TypeForIndex = detail::TypeForIndex<I, Types...>; 416e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <std::size_t I> 417e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko using TypeTagForIndex = detail::TypeTagForIndex<I, Types...>; 418e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 419e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko using HasType = detail::HasType<T, Types...>; 420e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename R, typename T> 421e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko using EnableIfElement = detail::EnableIfElement<R, T, Types...>; 422e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename R, typename T> 423e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko using EnableIfConvertible = detail::EnableIfConvertible<R, T, Types...>; 424e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename R, typename T> 425e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko using EnableIfAssignable = detail::EnableIfAssignable<R, T, Types...>; 426e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 427e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko struct Direct {}; 428e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko struct Convert {}; 429e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 430a44b9f94aa53e69ccbfb86a35b13872b6faf8e52Corey Tabaka using SelectConstructor = detail::Select<HasType<T>::value, Direct, Convert>; 431e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 432e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Constructs by type tag when T is an direct element of Types... 433e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 434e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko explicit Variant(T&& value, Direct) 435a44b9f94aa53e69ccbfb86a35b13872b6faf8e52Corey Tabaka : value_(0, &index_, DecayedTypeTag<T>{}, std::forward<T>(value)) {} 436e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Conversion constructor when T is not a direct element of Types... 437e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 438e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko explicit Variant(T&& value, Convert) 439e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko : value_(0, &index_, std::forward<T>(value)) {} 440e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 441e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko public: 442e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Variants are default construcible, regardless of whether the elements are 443e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // default constructible. Default consruction yields an empty Variant. 444e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Variant() {} 445e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko explicit Variant(EmptyVariant) {} 446e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ~Variant() { Destruct(); } 447e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 4487190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka Variant(const Variant& other) 4497190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka : index_{other.index_}, value_{other.value_, other.index_} {} 4507190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka Variant(Variant&& other) 4517190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka : index_{other.index_}, value_{std::move(other.value_), other.index_} {} 4527190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka 45396f471e0224e6e19dc05af18d178f1eb0fc858aeYi Kong// Recent Clang versions has a regression that produces bogus 45496f471e0224e6e19dc05af18d178f1eb0fc858aeYi Kong// unused-lambda-capture warning. Suppress the warning as a temporary 45596f471e0224e6e19dc05af18d178f1eb0fc858aeYi Kong// workaround. http://b/71356631 45696f471e0224e6e19dc05af18d178f1eb0fc858aeYi Kong#pragma clang diagnostic push 45796f471e0224e6e19dc05af18d178f1eb0fc858aeYi Kong#pragma clang diagnostic ignored "-Wunused-lambda-capture" 458e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Copy and move construction from Variant types. Each element of OtherTypes 459e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // must be convertible to an element of Types. 460e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename... OtherTypes> 461e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko explicit Variant(const Variant<OtherTypes...>& other) { 462e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko other.Visit([this](const auto& value) { Construct(value); }); 463e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 46496f471e0224e6e19dc05af18d178f1eb0fc858aeYi Kong#pragma clang diagnostic pop 46596f471e0224e6e19dc05af18d178f1eb0fc858aeYi Kong 466e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename... OtherTypes> 467e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko explicit Variant(Variant<OtherTypes...>&& other) { 468e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko other.Visit([this](auto&& value) { Construct(std::move(value)); }); 469e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 470e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 4717190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka Variant& operator=(const Variant& other) { 4727190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka other.Visit([this](const auto& value) { *this = value; }); 4737190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka return *this; 4747190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka } 4757190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka Variant& operator=(Variant&& other) { 4767190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka other.Visit([this](auto&& value) { *this = std::move(value); }); 4777190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka return *this; 4787190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka } 4797190e8af99a51fe2250e5ea988c962448e5b09f1Corey Tabaka 480e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Construction from non-Variant types. 481e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T, typename = EnableIfAssignable<void, T>> 482e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko explicit Variant(T&& value) 483e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko : Variant(std::forward<T>(value), SelectConstructor<T>{}) {} 484e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 485e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Performs assignment from type T belonging to Types. This overload takes 486e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // priority to prevent implicit conversion in cases where T is implicitly 487e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // convertible to multiple elements of Types. 488e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 489e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko EnableIfElement<Variant&, T> operator=(T&& value) { 490a44b9f94aa53e69ccbfb86a35b13872b6faf8e52Corey Tabaka Assign(DecayedTypeTag<T>{}, std::forward<T>(value)); 491e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return *this; 492e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 493e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 494e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Performs assignment from type T not belonging to Types. This overload 495e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // matches in cases where conversion is the only viable option. 496e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 497e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko EnableIfConvertible<Variant&, T> operator=(T&& value) { 498e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Assign(std::forward<T>(value)); 499e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return *this; 500e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 501e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 502e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Handles assignment from the empty type. This overload supports assignment 503e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // in visitors using generic lambdas. 504e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Variant& operator=(EmptyVariant) { 505dfee6a7b9491fd9b5e4d570d9dbc0336fa2e9acbCorey Tabaka Destruct(); 506e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return *this; 507e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 508e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 509e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Assignment from Variant types. Each element of OtherTypes must be 510e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // convertible to an element of Types. Forwards through non-Variant assignment 511e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // operators to apply conversion checks. 512e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename... OtherTypes> 513e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Variant& operator=(const Variant<OtherTypes...>& other) { 514e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko other.Visit([this](const auto& value) { *this = value; }); 515e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return *this; 516e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 517e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename... OtherTypes> 518e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Variant& operator=(Variant<OtherTypes...>&& other) { 519e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko other.Visit([this](auto&& value) { *this = std::move(value); }); 520e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return *this; 521e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 522e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 523e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Becomes the target type, constructing a new element from the given 524e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // arguments if necessary. No action is taken if the active element is already 525e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // the target type. Otherwise the active element is destroyed and replaced by 526e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // constructing an element of the new type using |Args|. An invalid target 527e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // type index results in an empty Variant. 528e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename... Args> 529e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko void Become(std::int32_t target_index, Args&&... args) { 530e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (target_index != index()) { 531e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Destruct(); 532e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko index_ = value_.Become(target_index, std::forward<Args>(args)...) 533e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ? target_index 534e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko : kEmptyIndex; 535e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 536e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 537e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 538e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Invokes |Op| on the active element. If the Variant is empty |Op| is invoked 539e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // on EmptyVariant. 540e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename Op> 541e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko decltype(auto) Visit(Op&& op) { 542e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return value_.Visit(index_, std::forward<Op>(op)); 543e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 544e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename Op> 545e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko decltype(auto) Visit(Op&& op) const { 546e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return value_.Visit(index_, std::forward<Op>(op)); 547e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 548e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 549e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Index returned when the Variant is empty. 550e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko enum : std::int32_t { kEmptyIndex = -1 }; 551e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 552e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Returns the index of the given type. 553e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 554e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko constexpr std::int32_t index_of() const { 555e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko static_assert(HasType<T>::value, "T is not an element type of Variant."); 556a44b9f94aa53e69ccbfb86a35b13872b6faf8e52Corey Tabaka return value_.template index(DecayedTypeTag<T>{}); 557e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 558e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 559e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Returns the index of the active type. If the Variant is empty -1 is 560e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // returned. 561e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko std::int32_t index() const { return index_; } 562e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 563e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Returns true if the given type is active, false otherwise. 564e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 565e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko bool is() const { 566e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko static_assert(HasType<T>::value, "T is not an element type of Variant."); 567e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return index() == index_of<T>(); 568e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 569e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 570e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Returns true if the Variant is empty, false otherwise. 571e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko bool empty() const { return index() == kEmptyIndex; } 572e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 573e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Element accessors. Returns a pointer to the active value if the given 574e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // type/index is active, otherwise nullptr is returned. 575e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 576e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko T* get() { 577e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (is<T>()) 578a44b9f94aa53e69ccbfb86a35b13872b6faf8e52Corey Tabaka return &value_.template get(DecayedTypeTag<T>{}); 579e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko else 580e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return nullptr; 581e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 582e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 583e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko const T* get() const { 584e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (is<T>()) 585a44b9f94aa53e69ccbfb86a35b13872b6faf8e52Corey Tabaka return &value_.template get(DecayedTypeTag<T>{}); 586e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko else 587e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return nullptr; 588e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 589e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <std::size_t I> 590e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko TypeForIndex<I>* get() { 591e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (is<TypeForIndex<I>>()) 592e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return &value_.template get(TypeTagForIndex<I>{}); 593e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko else 594e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return nullptr; 595e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 596e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <std::size_t I> 597e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko const TypeForIndex<I>* get() const { 598e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (is<TypeForIndex<I>>()) 599e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return &value_.template get(TypeTagForIndex<I>{}); 600e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko else 601e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return nullptr; 602e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 603e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 604e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko private: 605e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko std::int32_t index_ = kEmptyIndex; 606a44b9f94aa53e69ccbfb86a35b13872b6faf8e52Corey Tabaka detail::Union<std::decay_t<Types>...> value_; 607e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 608e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Constructs an element from the given arguments and sets the Variant to the 609e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // resulting type. 610e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename... Args> 611e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko void Construct(Args&&... args) { 612e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko index_ = value_.template Construct(std::forward<Args>(args)...); 613e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 614e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko void Construct(EmptyVariant) {} 615e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 616e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Destroys the active element of the Variant. 617dfee6a7b9491fd9b5e4d570d9dbc0336fa2e9acbCorey Tabaka void Destruct() { 618dfee6a7b9491fd9b5e4d570d9dbc0336fa2e9acbCorey Tabaka value_.Destruct(index_); 619dfee6a7b9491fd9b5e4d570d9dbc0336fa2e9acbCorey Tabaka index_ = kEmptyIndex; 620dfee6a7b9491fd9b5e4d570d9dbc0336fa2e9acbCorey Tabaka } 621e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 622e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Assigns the Variant when non-empty and the current type matches the target 623e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // type, otherwise destroys the current value and constructs a element of the 624e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // new type. Tagged assignment is used when T is an element of the Variant to 625e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // prevent implicit conversion in cases where T is implicitly convertible to 626e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // multiple element types. 627e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T, typename U> 628e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko void Assign(TypeTag<T>, U&& value) { 629e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (!value_.template Assign(TypeTag<T>{}, index_, std::forward<U>(value))) { 630e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Destruct(); 631e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Construct(TypeTag<T>{}, std::forward<U>(value)); 632e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 633e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 634e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T> 635e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko void Assign(T&& value) { 636e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (!value_.template Assign(index_, std::forward<T>(value))) { 637e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Destruct(); 638e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Construct(std::forward<T>(value)); 639e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 640e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 641e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}; 642e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 643e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Utility type to extract/convert values from a variant. This class simplifies 644e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// conditional logic to get/move/swap/action values from a variant when one or 645e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// more elements are compatible with the destination type. 646e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// 647e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Example: 648e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Variant<int, bool, std::string> v(10); 649e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// bool bool_value; 650e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// if (IfAnyOf<int, bool>::Get(v, &bool_value)) { 651e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// DoSomething(bool_value); 652e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// } else { 653e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// HandleInvalidType(); 654e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// } 655e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// IfAnyOf<int>::Call(v, [](const auto& value) { DoSomething(value); }); 656e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// 657e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename... ValidTypes> 658e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkostruct IfAnyOf { 659e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Calls Op on the underlying value of the variant and returns true when the 660e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // variant is a valid type, otherwise does nothing and returns false. 661e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename Op, typename... Types> 662e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko static bool Call(Variant<Types...>* variant, Op&& op) { 663e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko static_assert( 664e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko detail::Set<Types...>::template IsSubset<ValidTypes...>::value, 665e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko "ValidTypes may only contain element types from the Variant."); 666e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return variant->Visit(CallOp<Op>{std::forward<Op>(op)}); 667e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 668e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename Op, typename... Types> 669e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko static bool Call(const Variant<Types...>* variant, Op&& op) { 670e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko static_assert( 671e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko detail::Set<Types...>::template IsSubset<ValidTypes...>::value, 672e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko "ValidTypes may only contain element types from the Variant."); 673e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return variant->Visit(CallOp<Op>{std::forward<Op>(op)}); 674e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 675e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 676e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Gets/converts the underlying value of the variant to type T and returns 677e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // true when the variant is a valid type, otherwise does nothing and returns 678e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // false. 679e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T, typename... Types> 680e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko static bool Get(const Variant<Types...>* variant, T* value_out) { 681e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return Call(variant, 682e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko [value_out](const auto& value) { *value_out = value; }); 683e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 684e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 685e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Moves the underlying value of the variant and returns true when the variant 686e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // is a valid type, otherwise does nothing and returns false. 687e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T, typename... Types> 688e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko static bool Take(Variant<Types...>* variant, T* value_out) { 689e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return Call(variant, 690e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko [value_out](auto&& value) { *value_out = std::move(value); }); 691e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 692e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 693e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Swaps the underlying value of the variant with |*value_out| and returns 694e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // true when the variant is a valid type, otherwise does nothing and returns 695e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // false. 696e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename T, typename... Types> 697e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko static bool Swap(Variant<Types...>* variant, T* value_out) { 698e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return Call(variant, 699e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko [value_out](auto&& value) { std::swap(*value_out, value); }); 700e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 701e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 702e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko private: 703e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename Op> 704e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko struct CallOp { 705e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Op&& op; 706e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename U> 707e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko detail::EnableIfNotElement<bool, U, ValidTypes...> operator()(U&&) { 708e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return false; 709e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 710e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename U> 711e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko detail::EnableIfElement<bool, U, ValidTypes...> operator()(const U& value) { 712e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko std::forward<Op>(op)(value); 713e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return true; 714e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 715e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko template <typename U> 716e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko detail::EnableIfElement<bool, U, ValidTypes...> operator()(U&& value) { 717e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko std::forward<Op>(op)(std::forward<U>(value)); 718e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return true; 719e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 720e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko }; 721e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko}; 722e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 723e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} // namespace rpc 724e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} // namespace pdx 725e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} // namespace android 726e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 727e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko// Overloads of std::get<T> and std::get<I> for android::pdx::rpc::Variant. 728e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace std { 729e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 730e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename T, typename... Types> 731e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkoinline T& get(::android::pdx::rpc::Variant<Types...>& v) { 732e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return *v.template get<T>(); 733e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 734e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename T, typename... Types> 735e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkoinline T&& get(::android::pdx::rpc::Variant<Types...>&& v) { 736e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return std::move(*v.template get<T>()); 737e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 738e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <typename T, typename... Types> 739e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkoinline const T& get(const ::android::pdx::rpc::Variant<Types...>& v) { 740e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return *v.template get<T>(); 741e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 742e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <std::size_t I, typename... Types> 743e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkoinline ::android::pdx::rpc::detail::TypeForIndex<I, Types...>& get( 744e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ::android::pdx::rpc::Variant<Types...>& v) { 745e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return *v.template get<I>(); 746e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 747e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <std::size_t I, typename... Types> 748e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkoinline ::android::pdx::rpc::detail::TypeForIndex<I, Types...>&& get( 749e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ::android::pdx::rpc::Variant<Types...>&& v) { 750e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return std::move(*v.template get<I>()); 751e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 752e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkotemplate <std::size_t I, typename... Types> 753e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkoinline const ::android::pdx::rpc::detail::TypeForIndex<I, Types...>& get( 754e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko const ::android::pdx::rpc::Variant<Types...>& v) { 755e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko return *v.template get<I>(); 756e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 757e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 758e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} // namespace std 759e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 760e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#endif // ANDROID_PDX_RPC_VARIANT_H_ 761