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