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