xref: /aosp_15_r20/external/armnn/third-party/mapbox/variant.hpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1 //
2 // Copyright (c) MapBox All rights reserved.
3 // SPDX-License-Identifier: BSD-3-Clause
4 //
5 
6 #ifndef MAPBOX_UTIL_VARIANT_HPP
7 #define MAPBOX_UTIL_VARIANT_HPP
8 
9 #include <cassert>
10 #include <cstddef>   // size_t
11 #include <new>       // operator new
12 #include <stdexcept> // runtime_error
13 #include <string>
14 #include <tuple>
15 #include <type_traits>
16 #include <typeinfo>
17 #include <utility>
18 #include <functional>
19 #include <limits>
20 
21 #include <mapbox/recursive_wrapper.hpp>
22 #include <mapbox/variant_visitor.hpp>
23 
24 // clang-format off
25 // [[deprecated]] is only available in C++14, use this for the time being
26 #if __cplusplus <= 201103L
27 # ifdef __GNUC__
28 #  define MAPBOX_VARIANT_DEPRECATED __attribute__((deprecated))
29 # elif defined(_MSC_VER)
30 #  define MAPBOX_VARIANT_DEPRECATED __declspec(deprecated)
31 # else
32 #  define MAPBOX_VARIANT_DEPRECATED
33 # endif
34 #else
35 #  define MAPBOX_VARIANT_DEPRECATED [[deprecated]]
36 #endif
37 
38 
39 #ifdef _MSC_VER
40 // https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx
41 # ifdef NDEBUG
42 #  define VARIANT_INLINE __forceinline
43 # else
44 #  define VARIANT_INLINE //__declspec(noinline)
45 # endif
46 #else
47 # ifdef NDEBUG
48 #  define VARIANT_INLINE //inline __attribute__((always_inline))
49 # else
50 #  define VARIANT_INLINE __attribute__((noinline))
51 # endif
52 #endif
53 // clang-format on
54 
55 // Exceptions
56 #if defined( __EXCEPTIONS) || defined( _MSC_VER)
57 #define HAS_EXCEPTIONS
58 #endif
59 
60 #define VARIANT_MAJOR_VERSION 1
61 #define VARIANT_MINOR_VERSION 1
62 #define VARIANT_PATCH_VERSION 0
63 
64 #define VARIANT_VERSION (VARIANT_MAJOR_VERSION * 100000) + (VARIANT_MINOR_VERSION * 100) + (VARIANT_PATCH_VERSION)
65 
66 namespace mapbox {
67 namespace util {
68 
69 // XXX This should derive from std::logic_error instead of std::runtime_error.
70 //     See https://github.com/mapbox/variant/issues/48 for details.
71 class bad_variant_access : public std::runtime_error
72 {
73 
74 public:
bad_variant_access(const std::string & what_arg)75     explicit bad_variant_access(const std::string& what_arg)
76         : runtime_error(what_arg) {}
77 
bad_variant_access(const char * what_arg)78     explicit bad_variant_access(const char* what_arg)
79         : runtime_error(what_arg) {}
80 
81 }; // class bad_variant_access
82 
83 #if !defined(MAPBOX_VARIANT_MINIMIZE_SIZE)
84 using type_index_t = unsigned int;
85 #else
86 #if defined(MAPBOX_VARIANT_OPTIMIZE_FOR_SPEED)
87 using type_index_t = std::uint_fast8_t;
88 #else
89 using type_index_t = std::uint_least8_t;
90 #endif
91 #endif
92 
93 namespace detail {
94 
95 static constexpr type_index_t invalid_value = type_index_t(-1);
96 
97 template <typename T, typename... Types>
98 struct direct_type;
99 
100 template <typename T, typename First, typename... Types>
101 struct direct_type<T, First, Types...>
102 {
103     static constexpr type_index_t index = std::is_same<T, First>::value
104         ? sizeof...(Types)
105         : direct_type<T, Types...>::index;
106 };
107 
108 template <typename T>
109 struct direct_type<T>
110 {
111     static constexpr type_index_t index = invalid_value;
112 };
113 
114 #if __cpp_lib_logical_traits >= 201510L
115 
116 using std::conjunction;
117 using std::disjunction;
118 
119 #else
120 
121 template <typename...>
122 struct conjunction : std::true_type {};
123 
124 template <typename B1>
125 struct conjunction<B1> : B1 {};
126 
127 template <typename B1, typename B2>
128 struct conjunction<B1, B2> : std::conditional<B1::value, B2, B1>::type {};
129 
130 template <typename B1, typename... Bs>
131 struct conjunction<B1, Bs...> : std::conditional<B1::value, conjunction<Bs...>, B1>::type {};
132 
133 template <typename...>
134 struct disjunction : std::false_type {};
135 
136 template <typename B1>
137 struct disjunction<B1> : B1 {};
138 
139 template <typename B1, typename B2>
140 struct disjunction<B1, B2> : std::conditional<B1::value, B1, B2>::type {};
141 
142 template <typename B1, typename... Bs>
143 struct disjunction<B1, Bs...> : std::conditional<B1::value, B1, disjunction<Bs...>>::type {};
144 
145 #endif
146 
147 template <typename T, typename... Types>
148 struct convertible_type;
149 
150 template <typename T, typename First, typename... Types>
151 struct convertible_type<T, First, Types...>
152 {
153     static constexpr type_index_t index = std::is_convertible<T, First>::value
154         ? disjunction<std::is_convertible<T, Types>...>::value ? invalid_value : sizeof...(Types)
155         : convertible_type<T, Types...>::index;
156 };
157 
158 template <typename T>
159 struct convertible_type<T>
160 {
161     static constexpr type_index_t index = invalid_value;
162 };
163 
164 template <typename T, typename... Types>
165 struct value_traits
166 {
167     using value_type = typename std::remove_const<typename std::remove_reference<T>::type>::type;
168     using value_type_wrapper = recursive_wrapper<value_type>;
169     static constexpr type_index_t direct_index = direct_type<value_type, Types...>::index;
170     static constexpr bool is_direct = direct_index != invalid_value;
171     static constexpr type_index_t index_direct_or_wrapper = is_direct ? direct_index : direct_type<value_type_wrapper, Types...>::index;
172     static constexpr bool is_direct_or_wrapper = index_direct_or_wrapper != invalid_value;
173     static constexpr type_index_t index = is_direct_or_wrapper ? index_direct_or_wrapper : convertible_type<value_type, Types...>::index;
174     static constexpr bool is_valid = index != invalid_value;
175     static constexpr type_index_t tindex = is_valid ? sizeof...(Types)-index : 0;
176     using target_type = typename std::tuple_element<tindex, std::tuple<void, Types...>>::type;
177 };
178 
179 template <typename Src, typename Dest>
180 struct copy_cvref
181 {
182     using type = Dest;
183 };
184 
185 template <typename Src, typename Dest>
186 struct copy_cvref<Src const&, Dest>
187 {
188     using type = Dest const&;
189 };
190 
191 template <typename Src, typename Dest>
192 struct copy_cvref<Src&, Dest>
193 {
194     using type = Dest&;
195 };
196 
197 template <typename Src, typename Dest>
198 struct copy_cvref<Src&&, Dest>
199 {
200     using type = Dest&&;
201 };
202 
203 template <typename F, typename = void>
204 struct deduced_result_type
205 {};
206 
207 template <typename F, typename... Args>
208 struct deduced_result_type<F(Args...), decltype((void)std::declval<F>()(std::declval<Args>()...))>
209 {
210     using type = decltype(std::declval<F>()(std::declval<Args>()...));
211 };
212 
213 template <typename F, typename = void>
214 struct visitor_result_type : deduced_result_type<F>
215 {};
216 
217 // specialization for explicit result_type member in visitor class
218 template <typename F, typename... Args>
219 struct visitor_result_type<F(Args...), decltype((void)std::declval<typename std::decay<F>::type::result_type>())>
220 {
221     using type = typename std::decay<F>::type::result_type;
222 };
223 
224 template <typename F, typename T>
225 using result_of_unary_visit = typename visitor_result_type<F&&(T&&)>::type;
226 
227 template <typename F, typename T>
228 using result_of_binary_visit = typename visitor_result_type<F&&(T&&, T&&)>::type;
229 
230 template <type_index_t arg1, type_index_t... others>
231 struct static_max;
232 
233 template <type_index_t arg>
234 struct static_max<arg>
235 {
236     static const type_index_t value = arg;
237 };
238 
239 template <type_index_t arg1, type_index_t arg2, type_index_t... others>
240 struct static_max<arg1, arg2, others...>
241 {
242     static const type_index_t value = arg1 >= arg2 ? static_max<arg1, others...>::value : static_max<arg2, others...>::value;
243 };
244 
245 template <typename... Types>
246 struct variant_helper;
247 
248 template <typename T, typename... Types>
249 struct variant_helper<T, Types...>
250 {
destroymapbox::util::detail::variant_helper251     VARIANT_INLINE static void destroy(const type_index_t type_index, void* data)
252     {
253         if (type_index == sizeof...(Types))
254         {
255             reinterpret_cast<T*>(data)->~T();
256         }
257         else
258         {
259             variant_helper<Types...>::destroy(type_index, data);
260         }
261     }
262 
movemapbox::util::detail::variant_helper263     VARIANT_INLINE static void move(const type_index_t old_type_index, void* old_value, void* new_value)
264     {
265         if (old_type_index == sizeof...(Types))
266         {
267             new (new_value) T(std::move(*reinterpret_cast<T*>(old_value)));
268         }
269         else
270         {
271             variant_helper<Types...>::move(old_type_index, old_value, new_value);
272         }
273     }
274 
copymapbox::util::detail::variant_helper275     VARIANT_INLINE static void copy(const type_index_t old_type_index, const void* old_value, void* new_value)
276     {
277         if (old_type_index == sizeof...(Types))
278         {
279             new (new_value) T(*reinterpret_cast<const T*>(old_value));
280         }
281         else
282         {
283             variant_helper<Types...>::copy(old_type_index, old_value, new_value);
284         }
285     }
286 };
287 
288 template <>
289 struct variant_helper<>
290 {
destroymapbox::util::detail::variant_helper291     VARIANT_INLINE static void destroy(const type_index_t, void*) {}
movemapbox::util::detail::variant_helper292     VARIANT_INLINE static void move(const type_index_t, void*, void*) {}
copymapbox::util::detail::variant_helper293     VARIANT_INLINE static void copy(const type_index_t, const void*, void*) {}
294 };
295 
296 template <typename T>
297 struct unwrapper
298 {
299     using value_type = T;
300 
301     template <typename V>
applymapbox::util::detail::unwrapper302     static auto apply(typename std::remove_reference<V>::type& var)
303         -> typename std::enable_if<std::is_lvalue_reference<V>::value,
304                     decltype(var.template get_unchecked<T>())>::type
305     {
306         return var.template get_unchecked<T>();
307     }
308 
309     template <typename V>
applymapbox::util::detail::unwrapper310     static auto apply(typename std::remove_reference<V>::type& var)
311         -> typename std::enable_if<!std::is_lvalue_reference<V>::value,
312                     decltype(std::move(var.template get_unchecked<T>()))>::type
313     {
314         return std::move(var.template get_unchecked<T>());
315     }
316 };
317 
318 template <typename T>
319 struct unwrapper<recursive_wrapper<T>> : unwrapper<T>
320 {};
321 
322 template <typename T>
323 struct unwrapper<std::reference_wrapper<T>> : unwrapper<T>
324 {};
325 
326 template <typename R, typename... Types>
327 struct dispatcher;
328 
329 template <typename R, typename T, typename... Types>
330 struct dispatcher<R, T, Types...>
331 {
332     template <typename V, typename F>
applymapbox::util::detail::dispatcher333     VARIANT_INLINE static R apply(V&& v, F&& f)
334     {
335         if (v.template is<T>())
336         {
337             return std::forward<F>(f)(unwrapper<T>::template apply<V>(v));
338         }
339         else
340         {
341             return dispatcher<R, Types...>::apply(std::forward<V>(v), std::forward<F>(f));
342         }
343     }
344 };
345 
346 template <typename R, typename T>
347 struct dispatcher<R, T>
348 {
349     template <typename V, typename F>
applymapbox::util::detail::dispatcher350     VARIANT_INLINE static R apply(V&& v, F&& f)
351     {
352         return std::forward<F>(f)(unwrapper<T>::template apply<V>(v));
353     }
354 };
355 
356 template <typename R, typename T, typename... Types>
357 struct binary_dispatcher_rhs;
358 
359 template <typename R, typename T0, typename T1, typename... Types>
360 struct binary_dispatcher_rhs<R, T0, T1, Types...>
361 {
362     template <typename V, typename F>
applymapbox::util::detail::binary_dispatcher_rhs363     VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f)
364     {
365         if (rhs.template is<T1>()) // call binary functor
366         {
367             return std::forward<F>(f)(unwrapper<T0>::template apply<V>(lhs),
368                                       unwrapper<T1>::template apply<V>(rhs));
369         }
370         else
371         {
372             return binary_dispatcher_rhs<R, T0, Types...>::apply(std::forward<V>(lhs),
373                                                                  std::forward<V>(rhs),
374                                                                  std::forward<F>(f));
375         }
376     }
377 };
378 
379 template <typename R, typename T0, typename T1>
380 struct binary_dispatcher_rhs<R, T0, T1>
381 {
382     template <typename V, typename F>
applymapbox::util::detail::binary_dispatcher_rhs383     VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f)
384     {
385         return std::forward<F>(f)(unwrapper<T0>::template apply<V>(lhs),
386                                   unwrapper<T1>::template apply<V>(rhs));
387     }
388 };
389 
390 template <typename R, typename T, typename... Types>
391 struct binary_dispatcher_lhs;
392 
393 template <typename R, typename T0, typename T1, typename... Types>
394 struct binary_dispatcher_lhs<R, T0, T1, Types...>
395 {
396     template <typename V, typename F>
applymapbox::util::detail::binary_dispatcher_lhs397     VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f)
398     {
399         if (lhs.template is<T1>()) // call binary functor
400         {
401             return std::forward<F>(f)(unwrapper<T1>::template apply<V>(lhs),
402                                       unwrapper<T0>::template apply<V>(rhs));
403         }
404         else
405         {
406             return binary_dispatcher_lhs<R, T0, Types...>::apply(std::forward<V>(lhs),
407                                                                  std::forward<V>(rhs),
408                                                                  std::forward<F>(f));
409         }
410     }
411 };
412 
413 template <typename R, typename T0, typename T1>
414 struct binary_dispatcher_lhs<R, T0, T1>
415 {
416     template <typename V, typename F>
applymapbox::util::detail::binary_dispatcher_lhs417     VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f)
418     {
419         return std::forward<F>(f)(unwrapper<T1>::template apply<V>(lhs),
420                                   unwrapper<T0>::template apply<V>(rhs));
421     }
422 };
423 
424 template <typename R, typename... Types>
425 struct binary_dispatcher;
426 
427 template <typename R, typename T, typename... Types>
428 struct binary_dispatcher<R, T, Types...>
429 {
430     template <typename V, typename F>
applymapbox::util::detail::binary_dispatcher431     VARIANT_INLINE static R apply(V&& v0, V&& v1, F&& f)
432     {
433         if (v0.template is<T>())
434         {
435             if (v1.template is<T>())
436             {
437                 return std::forward<F>(f)(unwrapper<T>::template apply<V>(v0),
438                                           unwrapper<T>::template apply<V>(v1)); // call binary functor
439             }
440             else
441             {
442                 return binary_dispatcher_rhs<R, T, Types...>::apply(std::forward<V>(v0),
443                                                                     std::forward<V>(v1),
444                                                                     std::forward<F>(f));
445             }
446         }
447         else if (v1.template is<T>())
448         {
449             return binary_dispatcher_lhs<R, T, Types...>::apply(std::forward<V>(v0),
450                                                                 std::forward<V>(v1),
451                                                                 std::forward<F>(f));
452         }
453         return binary_dispatcher<R, Types...>::apply(std::forward<V>(v0),
454                                                      std::forward<V>(v1),
455                                                      std::forward<F>(f));
456     }
457 };
458 
459 template <typename R, typename T>
460 struct binary_dispatcher<R, T>
461 {
462     template <typename V, typename F>
applymapbox::util::detail::binary_dispatcher463     VARIANT_INLINE static R apply(V&& v0, V&& v1, F&& f)
464     {
465         return std::forward<F>(f)(unwrapper<T>::template apply<V>(v0),
466                                   unwrapper<T>::template apply<V>(v1)); // call binary functor
467     }
468 };
469 
470 // comparator functors
471 struct equal_comp
472 {
473     template <typename T>
operator ()mapbox::util::detail::equal_comp474     bool operator()(T const& lhs, T const& rhs) const
475     {
476         return lhs == rhs;
477     }
478 };
479 
480 struct less_comp
481 {
482     template <typename T>
operator ()mapbox::util::detail::less_comp483     bool operator()(T const& lhs, T const& rhs) const
484     {
485         return lhs < rhs;
486     }
487 };
488 
489 template <typename Variant, typename Comp>
490 class comparer
491 {
492 public:
comparer(Variant const & lhs)493     explicit comparer(Variant const& lhs) noexcept
494         : lhs_(lhs) {}
495     comparer& operator=(comparer const&) = delete;
496     // visitor
497     template <typename T>
operator ()(T const & rhs_content) const498     bool operator()(T const& rhs_content) const
499     {
500         T const& lhs_content = lhs_.template get_unchecked<T>();
501         return Comp()(lhs_content, rhs_content);
502     }
503 
504 private:
505     Variant const& lhs_;
506 };
507 
508 // hashing visitor
509 struct hasher
510 {
511     template <typename T>
operator ()mapbox::util::detail::hasher512     std::size_t operator()(const T& hashable) const
513     {
514         return std::hash<T>{}(hashable);
515     }
516 };
517 
518 } // namespace detail
519 
520 struct no_init {};
521 
522 template <typename... Types>
523 class variant
524 {
525     static_assert(sizeof...(Types) > 0, "Template parameter type list of variant can not be empty.");
526     static_assert(!detail::disjunction<std::is_reference<Types>...>::value, "Variant can not hold reference types. Maybe use std::reference_wrapper?");
527     static_assert(!detail::disjunction<std::is_array<Types>...>::value, "Variant can not hold array types.");
528     static_assert(sizeof...(Types) < std::numeric_limits<type_index_t>::max(), "Internal index type must be able to accommodate all alternatives.");
529 private:
530     static const std::size_t data_size = detail::static_max<sizeof(Types)...>::value;
531     static const std::size_t data_align = detail::static_max<alignof(Types)...>::value;
532 public:
533     struct adapted_variant_tag;
534     using types = std::tuple<Types...>;
535 private:
536     using first_type = typename std::tuple_element<0, types>::type;
537     using unwrap_first_type = typename detail::unwrapper<first_type>::value_type;
538     using data_type = typename std::aligned_storage<data_size, data_align>::type;
539     using helper_type = detail::variant_helper<Types...>;
540 
541     template <typename V, typename T = unwrap_first_type>
542         using alternative_ref = typename detail::copy_cvref<V, T>::type;
543 
544     type_index_t type_index;
545 #ifdef __clang_analyzer__
546     data_type data {};
547 #else
548     data_type data;
549 #endif
550 
551 public:
variant()552     VARIANT_INLINE variant() noexcept(std::is_nothrow_default_constructible<first_type>::value)
553         : type_index(sizeof...(Types)-1)
554     {
555         static_assert(std::is_default_constructible<first_type>::value, "First type in variant must be default constructible to allow default construction of variant.");
556         new (&data) first_type();
557     }
558 
variant(no_init)559     VARIANT_INLINE variant(no_init) noexcept
560         : type_index(detail::invalid_value) {}
561 
562     // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
563     template <typename T, typename Traits = detail::value_traits<T, Types...>,
564               typename Enable = typename std::enable_if<Traits::is_valid && !std::is_same<variant<Types...>, typename Traits::value_type>::value>::type >
variant(T && val)565     VARIANT_INLINE variant(T&& val) noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value)
566         : type_index(Traits::index)
567     {
568         new (&data) typename Traits::target_type(std::forward<T>(val));
569     }
570 
variant(variant<Types...> const & old)571     VARIANT_INLINE variant(variant<Types...> const& old)
572         : type_index(old.type_index)
573     {
574         helper_type::copy(old.type_index, &old.data, &data);
575     }
576 
variant(variant<Types...> && old)577     VARIANT_INLINE variant(variant<Types...>&& old)
578         noexcept(detail::conjunction<std::is_nothrow_move_constructible<Types>...>::value)
579         : type_index(old.type_index)
580     {
581         helper_type::move(old.type_index, &old.data, &data);
582     }
583 
584 private:
copy_assign(variant<Types...> const & rhs)585     VARIANT_INLINE void copy_assign(variant<Types...> const& rhs)
586     {
587         helper_type::destroy(type_index, &data);
588         type_index = detail::invalid_value;
589         helper_type::copy(rhs.type_index, &rhs.data, &data);
590         type_index = rhs.type_index;
591     }
592 
move_assign(variant<Types...> && rhs)593     VARIANT_INLINE void move_assign(variant<Types...>&& rhs)
594     {
595         helper_type::destroy(type_index, &data);
596         type_index = detail::invalid_value;
597         helper_type::move(rhs.type_index, &rhs.data, &data);
598         type_index = rhs.type_index;
599     }
600 
601 public:
operator =(variant<Types...> && other)602     VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other)
603         // note we check for nothrow-constructible, not nothrow-assignable, since
604         // move_assign uses move-construction via placement new.
605         noexcept(detail::conjunction<std::is_nothrow_move_constructible<Types>...>::value)
606     {
607         if (this == &other) { // playing safe in release mode, hit assertion in debug.
608             assert(false);
609             return *this;
610         }
611         move_assign(std::move(other));
612         return *this;
613     }
614 
operator =(variant<Types...> const & other)615     VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other)
616     {
617         if (this != &other)
618             copy_assign(other);
619         return *this;
620     }
621 
622     // conversions
623     // move-assign
624     template <typename T, typename Traits = detail::value_traits<T, Types...>,
625               typename Enable = typename std::enable_if<Traits::is_valid && !std::is_same<variant<Types...>, typename Traits::value_type>::value>::type >
operator =(T && rhs)626     VARIANT_INLINE variant<Types...>& operator=(T&& rhs)
627         // not that we check is_nothrow_constructible<T>, not is_nothrow_move_assignable<T>,
628         // since we construct a temporary
629         noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value
630                  && std::is_nothrow_move_assignable<variant<Types...>>::value)
631     {
632         variant<Types...> temp(std::forward<T>(rhs));
633         move_assign(std::move(temp));
634         return *this;
635     }
636 
637     // copy-assign
638     template <typename T>
operator =(T const & rhs)639     VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
640     {
641         variant<Types...> temp(rhs);
642         copy_assign(temp);
643         return *this;
644     }
645 
646     template <typename T, typename std::enable_if<
647                           (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
is() const648     VARIANT_INLINE bool is() const
649     {
650         return type_index == detail::direct_type<T, Types...>::index;
651     }
652 
653     template <typename T,typename std::enable_if<
654                          (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
is() const655     VARIANT_INLINE bool is() const
656     {
657         return type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index;
658     }
659 
valid() const660     VARIANT_INLINE bool valid() const
661     {
662         return type_index != detail::invalid_value;
663     }
664 
665     template <typename T, typename... Args>
set(Args &&...args)666     VARIANT_INLINE void set(Args&&... args)
667     {
668         helper_type::destroy(type_index, &data);
669         type_index = detail::invalid_value;
670         new (&data) T(std::forward<Args>(args)...);
671         type_index = detail::direct_type<T, Types...>::index;
672     }
673 
674     // get_unchecked<T>()
675     template <typename T, typename std::enable_if<
676                           (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
get_unchecked()677     VARIANT_INLINE T& get_unchecked()
678     {
679         return *reinterpret_cast<T*>(&data);
680     }
681 
682 #ifdef HAS_EXCEPTIONS
683     // get<T>()
684     template <typename T, typename std::enable_if<
685                           (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
get()686     VARIANT_INLINE T& get()
687     {
688         if (type_index == detail::direct_type<T, Types...>::index)
689         {
690             return *reinterpret_cast<T*>(&data);
691         }
692         else
693         {
694             throw bad_variant_access("in get<T>()");
695         }
696     }
697 #endif
698 
699     template <typename T, typename std::enable_if<
700                           (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
get_unchecked() const701     VARIANT_INLINE T const& get_unchecked() const
702     {
703         return *reinterpret_cast<T const*>(&data);
704     }
705 
706 #ifdef HAS_EXCEPTIONS
707     template <typename T, typename std::enable_if<
708                           (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
get() const709     VARIANT_INLINE T const& get() const
710     {
711         if (type_index == detail::direct_type<T, Types...>::index)
712         {
713             return *reinterpret_cast<T const*>(&data);
714         }
715         else
716         {
717             throw bad_variant_access("in get<T>()");
718         }
719     }
720 #endif
721 
722     // get_unchecked<T>() - T stored as recursive_wrapper<T>
723     template <typename T, typename std::enable_if<
724                           (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
get_unchecked()725     VARIANT_INLINE T& get_unchecked()
726     {
727         return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
728     }
729 
730 #ifdef HAS_EXCEPTIONS
731     // get<T>() - T stored as recursive_wrapper<T>
732     template <typename T, typename std::enable_if<
733                           (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
get()734     VARIANT_INLINE T& get()
735     {
736         if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
737         {
738             return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
739         }
740         else
741         {
742             throw bad_variant_access("in get<T>()");
743         }
744     }
745 #endif
746 
747     template <typename T, typename std::enable_if<
748                           (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
get_unchecked() const749     VARIANT_INLINE T const& get_unchecked() const
750     {
751         return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
752     }
753 
754 #ifdef HAS_EXCEPTIONS
755     template <typename T, typename std::enable_if<
756                           (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
get() const757     VARIANT_INLINE T const& get() const
758     {
759         if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
760         {
761             return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
762         }
763         else
764         {
765             throw bad_variant_access("in get<T>()");
766         }
767     }
768 #endif
769 
770     // get_unchecked<T>() - T stored as std::reference_wrapper<T>
771     template <typename T, typename std::enable_if<
772                           (detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
get_unchecked()773     VARIANT_INLINE T& get_unchecked()
774     {
775         return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
776     }
777 
778 #ifdef HAS_EXCEPTIONS
779     // get<T>() - T stored as std::reference_wrapper<T>
780     template <typename T, typename std::enable_if<
781                           (detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
get()782     VARIANT_INLINE T& get()
783     {
784         if (type_index == detail::direct_type<std::reference_wrapper<T>, Types...>::index)
785         {
786             return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
787         }
788         else
789         {
790             throw bad_variant_access("in get<T>()");
791         }
792     }
793 #endif
794 
795     template <typename T, typename std::enable_if<
796                           (detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr>
get_unchecked() const797     VARIANT_INLINE T const& get_unchecked() const
798     {
799         return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get();
800     }
801 
802 #ifdef HAS_EXCEPTIONS
803     template <typename T, typename std::enable_if<
804                           (detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr>
get() const805     VARIANT_INLINE T const& get() const
806     {
807         if (type_index == detail::direct_type<std::reference_wrapper<T const>, Types...>::index)
808         {
809             return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get();
810         }
811         else
812         {
813             throw bad_variant_access("in get<T>()");
814         }
815     }
816 #endif
817 
818     // This function is deprecated because it returns an internal index field.
819     // Use which() instead.
get_type_index() const820     MAPBOX_VARIANT_DEPRECATED VARIANT_INLINE type_index_t get_type_index() const
821     {
822         return type_index;
823     }
824 
which() const825     VARIANT_INLINE int which() const noexcept
826     {
827         return static_cast<int>(sizeof...(Types) - type_index - 1);
828     }
829 
830     template <typename T, typename std::enable_if<
831                           (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
which()832     VARIANT_INLINE static constexpr int which() noexcept
833     {
834         return static_cast<int>(sizeof...(Types)-detail::direct_type<T, Types...>::index - 1);
835     }
836 
837     // visitor
838     // unary
839     template <typename F, typename V, typename T0 = alternative_ref<V>,
840               typename R = detail::result_of_unary_visit<F, T0>>
visit(V && v,F && f)841     VARIANT_INLINE static R visit(V&& v, F&& f)
842     {
843         return detail::dispatcher<R, Types...>::apply(std::forward<V>(v), std::forward<F>(f));
844     }
845 
846     // binary
847     template <typename F, typename V, typename T0 = alternative_ref<V>,
848               typename R = detail::result_of_binary_visit<F, T0>>
binary_visit(V && v0,V && v1,F && f)849     VARIANT_INLINE static R binary_visit(V&& v0, V&& v1, F&& f)
850     {
851         return detail::binary_dispatcher<R, Types...>::apply(std::forward<V>(v0),
852                                                              std::forward<V>(v1),
853                                                              std::forward<F>(f));
854     }
855 
856     // match
857     // unary
858     template <typename... Fs>
match(Fs &&...fs) const859     auto VARIANT_INLINE match(Fs&&... fs) const&
860         -> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)))
861     {
862         return variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...));
863     }
864     // non-const
865     template <typename... Fs>
match(Fs &&...fs)866     auto VARIANT_INLINE match(Fs&&... fs) &
867         -> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)))
868     {
869         return variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...));
870     }
871     template <typename... Fs>
match(Fs &&...fs)872     auto VARIANT_INLINE match(Fs&&... fs) &&
873         -> decltype(variant::visit(std::move(*this), ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)))
874     {
875         return variant::visit(std::move(*this), ::mapbox::util::make_visitor(std::forward<Fs>(fs)...));
876     }
877 
~variant()878     ~variant() noexcept // no-throw destructor
879     {
880         helper_type::destroy(type_index, &data);
881     }
882 
883     // comparison operators
884     // equality
operator ==(variant const & rhs) const885     VARIANT_INLINE bool operator==(variant const& rhs) const
886     {
887         assert(valid() && rhs.valid());
888         if (this->which() != rhs.which())
889         {
890             return false;
891         }
892         detail::comparer<variant, detail::equal_comp> visitor(*this);
893         return visit(rhs, visitor);
894     }
895 
operator !=(variant const & rhs) const896     VARIANT_INLINE bool operator!=(variant const& rhs) const
897     {
898         return !(*this == rhs);
899     }
900 
901     // less than
operator <(variant const & rhs) const902     VARIANT_INLINE bool operator<(variant const& rhs) const
903     {
904         assert(valid() && rhs.valid());
905         if (this->which() != rhs.which())
906         {
907             return this->which() < rhs.which();
908         }
909         detail::comparer<variant, detail::less_comp> visitor(*this);
910         return visit(rhs, visitor);
911     }
operator >(variant const & rhs) const912     VARIANT_INLINE bool operator>(variant const& rhs) const
913     {
914         return rhs < *this;
915     }
operator <=(variant const & rhs) const916     VARIANT_INLINE bool operator<=(variant const& rhs) const
917     {
918         return !(*this > rhs);
919     }
operator >=(variant const & rhs) const920     VARIANT_INLINE bool operator>=(variant const& rhs) const
921     {
922         return !(*this < rhs);
923     }
924 };
925 
926 // unary visitor interface
927 template <typename F, typename V>
apply_visitor(F && f,V && v)928 auto VARIANT_INLINE apply_visitor(F&& f, V&& v)
929     -> decltype(v.visit(std::forward<V>(v), std::forward<F>(f)))
930 {
931     return v.visit(std::forward<V>(v), std::forward<F>(f));
932 }
933 
934 // binary visitor interface
935 template <typename F, typename V>
apply_visitor(F && f,V && v0,V && v1)936 auto VARIANT_INLINE apply_visitor(F&& f, V&& v0, V&& v1)
937     -> decltype(v0.binary_visit(std::forward<V>(v0), std::forward<V>(v1), std::forward<F>(f)))
938 {
939     return v0.binary_visit(std::forward<V>(v0), std::forward<V>(v1), std::forward<F>(f));
940 }
941 
942 // getter interface
943 
944 #ifdef HAS_EXCEPTIONS
945 template <typename ResultType, typename T>
get(T & var)946 auto get(T& var)->decltype(var.template get<ResultType>())
947 {
948     return var.template get<ResultType>();
949 }
950 #endif
951 
952 template <typename ResultType, typename T>
get_unchecked(T & var)953 ResultType& get_unchecked(T& var)
954 {
955     return var.template get_unchecked<ResultType>();
956 }
957 
958 #ifdef HAS_EXCEPTIONS
959 template <typename ResultType, typename T>
get(T const & var)960 auto get(T const& var)->decltype(var.template get<ResultType>())
961 {
962     return var.template get<ResultType>();
963 }
964 #endif
965 
966 template <typename ResultType, typename T>
get_unchecked(T const & var)967 ResultType const& get_unchecked(T const& var)
968 {
969     return var.template get_unchecked<ResultType>();
970 }
971 // variant_size
972 template <typename T>
973 struct variant_size;
974 
975 //variable templates is c++14
976 //template <typename T>
977 //constexpr std::size_t variant_size_v = variant_size<T>::value;
978 
979 template <typename T>
980 struct variant_size<const T>
981     : variant_size<T> {};
982 
983 template <typename T>
984 struct variant_size<volatile T>
985     : variant_size<T> {};
986 
987 template <typename T>
988 struct variant_size<const volatile T>
989     : variant_size<T> {};
990 
991 template <typename... Types>
992 struct variant_size<variant<Types...>>
993     : std::integral_constant<std::size_t, sizeof...(Types)> {};
994 
995 // variant_alternative
996 template <std::size_t Index, typename T>
997 struct variant_alternative;
998 
999 #if defined(__clang__)
1000 #if __has_builtin(__type_pack_element)
1001 #define has_type_pack_element
1002 #endif
1003 #endif
1004 
1005 #if defined(has_type_pack_element)
1006 template <std::size_t Index, typename ...Types>
1007 struct variant_alternative<Index, variant<Types...>>
1008 {
1009     static_assert(sizeof...(Types) > Index , "Index out of range");
1010     using type = __type_pack_element<Index, Types...>;
1011 };
1012 #else
1013 template <std::size_t Index, typename First, typename...Types>
1014 struct variant_alternative<Index, variant<First, Types...>>
1015     : variant_alternative<Index - 1, variant<Types...>>
1016 {
1017     static_assert(sizeof...(Types) > Index -1 , "Index out of range");
1018 };
1019 
1020 template <typename First, typename...Types>
1021 struct variant_alternative<0, variant<First, Types...>>
1022 {
1023     using type = First;
1024 };
1025 
1026 #endif
1027 
1028 template <size_t Index, typename T>
1029 using variant_alternative_t = typename variant_alternative<Index, T>::type;
1030 
1031 template <size_t Index, typename T>
1032 struct variant_alternative<Index, const T>
1033     : std::add_const<variant_alternative<Index, T>> {};
1034 
1035 template <size_t Index, typename T>
1036 struct variant_alternative<Index, volatile T>
1037     : std::add_volatile<variant_alternative<Index, T>> {};
1038 
1039 template <size_t Index, typename T>
1040 struct variant_alternative<Index, const volatile T>
1041     : std::add_cv<variant_alternative<Index, T>> {};
1042 
1043 } // namespace util
1044 } // namespace mapbox
1045 
1046 // hashable iff underlying types are hashable
1047 namespace std {
1048 template <typename... Types>
1049 struct hash< ::mapbox::util::variant<Types...>> {
operator ()std::hash1050     std::size_t operator()(const ::mapbox::util::variant<Types...>& v) const noexcept
1051     {
1052         return ::mapbox::util::apply_visitor(::mapbox::util::detail::hasher{}, v);
1053     }
1054 };
1055 
1056 }
1057 
1058 #endif // MAPBOX_UTIL_VARIANT_HPP
1059