blob: 71108572e24913fbc8f6cebc6071598f2ef15866 [file] [log] [blame]
Jim Flynn6217c3d2022-06-14 10:58:23 +01001//
2// Copyright (c) MapBox All rights reserved.
3// SPDX-License-Identifier: BSD-3-Clause
4//
5
James Ward22a4e152020-09-25 11:43:21 +01006#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
66namespace mapbox {
67namespace 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.
71class bad_variant_access : public std::runtime_error
72{
73
74public:
75 explicit bad_variant_access(const std::string& what_arg)
76 : runtime_error(what_arg) {}
77
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)
84using type_index_t = unsigned int;
85#else
86#if defined(MAPBOX_VARIANT_OPTIMIZE_FOR_SPEED)
87using type_index_t = std::uint_fast8_t;
88#else
89using type_index_t = std::uint_least8_t;
90#endif
91#endif
92
93namespace detail {
94
95static constexpr type_index_t invalid_value = type_index_t(-1);
96
97template <typename T, typename... Types>
98struct direct_type;
99
100template <typename T, typename First, typename... Types>
101struct 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
108template <typename T>
109struct direct_type<T>
110{
111 static constexpr type_index_t index = invalid_value;
112};
113
114#if __cpp_lib_logical_traits >= 201510L
115
116using std::conjunction;
117using std::disjunction;
118
119#else
120
121template <typename...>
122struct conjunction : std::true_type {};
123
124template <typename B1>
125struct conjunction<B1> : B1 {};
126
127template <typename B1, typename B2>
128struct conjunction<B1, B2> : std::conditional<B1::value, B2, B1>::type {};
129
130template <typename B1, typename... Bs>
131struct conjunction<B1, Bs...> : std::conditional<B1::value, conjunction<Bs...>, B1>::type {};
132
133template <typename...>
134struct disjunction : std::false_type {};
135
136template <typename B1>
137struct disjunction<B1> : B1 {};
138
139template <typename B1, typename B2>
140struct disjunction<B1, B2> : std::conditional<B1::value, B1, B2>::type {};
141
142template <typename B1, typename... Bs>
143struct disjunction<B1, Bs...> : std::conditional<B1::value, B1, disjunction<Bs...>>::type {};
144
145#endif
146
147template <typename T, typename... Types>
148struct convertible_type;
149
150template <typename T, typename First, typename... Types>
151struct 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
158template <typename T>
159struct convertible_type<T>
160{
161 static constexpr type_index_t index = invalid_value;
162};
163
164template <typename T, typename... Types>
165struct 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
179template <typename Src, typename Dest>
180struct copy_cvref
181{
182 using type = Dest;
183};
184
185template <typename Src, typename Dest>
186struct copy_cvref<Src const&, Dest>
187{
188 using type = Dest const&;
189};
190
191template <typename Src, typename Dest>
192struct copy_cvref<Src&, Dest>
193{
194 using type = Dest&;
195};
196
197template <typename Src, typename Dest>
198struct copy_cvref<Src&&, Dest>
199{
200 using type = Dest&&;
201};
202
203template <typename F, typename = void>
204struct deduced_result_type
205{};
206
207template <typename F, typename... Args>
208struct 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
213template <typename F, typename = void>
214struct visitor_result_type : deduced_result_type<F>
215{};
216
217// specialization for explicit result_type member in visitor class
218template <typename F, typename... Args>
219struct 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
224template <typename F, typename T>
225using result_of_unary_visit = typename visitor_result_type<F&&(T&&)>::type;
226
227template <typename F, typename T>
228using result_of_binary_visit = typename visitor_result_type<F&&(T&&, T&&)>::type;
229
230template <type_index_t arg1, type_index_t... others>
231struct static_max;
232
233template <type_index_t arg>
234struct static_max<arg>
235{
236 static const type_index_t value = arg;
237};
238
239template <type_index_t arg1, type_index_t arg2, type_index_t... others>
240struct 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
245template <typename... Types>
246struct variant_helper;
247
248template <typename T, typename... Types>
249struct variant_helper<T, Types...>
250{
251 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
263 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
275 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
288template <>
289struct variant_helper<>
290{
291 VARIANT_INLINE static void destroy(const type_index_t, void*) {}
292 VARIANT_INLINE static void move(const type_index_t, void*, void*) {}
293 VARIANT_INLINE static void copy(const type_index_t, const void*, void*) {}
294};
295
296template <typename T>
297struct unwrapper
298{
299 using value_type = T;
300
301 template <typename V>
302 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>
310 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
318template <typename T>
319struct unwrapper<recursive_wrapper<T>> : unwrapper<T>
320{};
321
322template <typename T>
323struct unwrapper<std::reference_wrapper<T>> : unwrapper<T>
324{};
325
326template <typename R, typename... Types>
327struct dispatcher;
328
329template <typename R, typename T, typename... Types>
330struct dispatcher<R, T, Types...>
331{
332 template <typename V, typename F>
333 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
346template <typename R, typename T>
347struct dispatcher<R, T>
348{
349 template <typename V, typename F>
350 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
356template <typename R, typename T, typename... Types>
357struct binary_dispatcher_rhs;
358
359template <typename R, typename T0, typename T1, typename... Types>
360struct binary_dispatcher_rhs<R, T0, T1, Types...>
361{
362 template <typename V, typename F>
363 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
379template <typename R, typename T0, typename T1>
380struct binary_dispatcher_rhs<R, T0, T1>
381{
382 template <typename V, typename F>
383 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
390template <typename R, typename T, typename... Types>
391struct binary_dispatcher_lhs;
392
393template <typename R, typename T0, typename T1, typename... Types>
394struct binary_dispatcher_lhs<R, T0, T1, Types...>
395{
396 template <typename V, typename F>
397 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
413template <typename R, typename T0, typename T1>
414struct binary_dispatcher_lhs<R, T0, T1>
415{
416 template <typename V, typename F>
417 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
424template <typename R, typename... Types>
425struct binary_dispatcher;
426
427template <typename R, typename T, typename... Types>
428struct binary_dispatcher<R, T, Types...>
429{
430 template <typename V, typename F>
431 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
459template <typename R, typename T>
460struct binary_dispatcher<R, T>
461{
462 template <typename V, typename F>
463 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
471struct equal_comp
472{
473 template <typename T>
474 bool operator()(T const& lhs, T const& rhs) const
475 {
476 return lhs == rhs;
477 }
478};
479
480struct less_comp
481{
482 template <typename T>
483 bool operator()(T const& lhs, T const& rhs) const
484 {
485 return lhs < rhs;
486 }
487};
488
489template <typename Variant, typename Comp>
490class comparer
491{
492public:
493 explicit comparer(Variant const& lhs) noexcept
494 : lhs_(lhs) {}
495 comparer& operator=(comparer const&) = delete;
496 // visitor
497 template <typename T>
498 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
504private:
505 Variant const& lhs_;
506};
507
508// hashing visitor
509struct hasher
510{
511 template <typename T>
512 std::size_t operator()(const T& hashable) const
513 {
514 return std::hash<T>{}(hashable);
515 }
516};
517
518} // namespace detail
519
520struct no_init {};
521
522template <typename... Types>
523class 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.");
529private:
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;
532public:
533 struct adapted_variant_tag;
534 using types = std::tuple<Types...>;
535private:
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
551public:
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
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 >
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
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
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
584private:
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
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
601public:
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
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 >
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>
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>
648 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>
655 VARIANT_INLINE bool is() const
656 {
657 return type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index;
658 }
659
660 VARIANT_INLINE bool valid() const
661 {
662 return type_index != detail::invalid_value;
663 }
664
665 template <typename T, typename... 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>
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>
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>
701 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>
709 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>
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>
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>
749 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>
757 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>
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>
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>
797 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>
805 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.
820 MAPBOX_VARIANT_DEPRECATED VARIANT_INLINE type_index_t get_type_index() const
821 {
822 return type_index;
823 }
824
825 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>
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>>
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>>
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>
859 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>
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>
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
878 ~variant() noexcept // no-throw destructor
879 {
880 helper_type::destroy(type_index, &data);
881 }
882
883 // comparison operators
884 // equality
885 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
896 VARIANT_INLINE bool operator!=(variant const& rhs) const
897 {
898 return !(*this == rhs);
899 }
900
901 // less than
902 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 }
912 VARIANT_INLINE bool operator>(variant const& rhs) const
913 {
914 return rhs < *this;
915 }
916 VARIANT_INLINE bool operator<=(variant const& rhs) const
917 {
918 return !(*this > rhs);
919 }
920 VARIANT_INLINE bool operator>=(variant const& rhs) const
921 {
922 return !(*this < rhs);
923 }
924};
925
926// unary visitor interface
927template <typename F, typename V>
928auto 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
935template <typename F, typename V>
936auto 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
945template <typename ResultType, typename T>
946auto get(T& var)->decltype(var.template get<ResultType>())
947{
948 return var.template get<ResultType>();
949}
950#endif
951
952template <typename ResultType, typename T>
953ResultType& get_unchecked(T& var)
954{
955 return var.template get_unchecked<ResultType>();
956}
957
958#ifdef HAS_EXCEPTIONS
959template <typename ResultType, typename T>
960auto get(T const& var)->decltype(var.template get<ResultType>())
961{
962 return var.template get<ResultType>();
963}
964#endif
965
966template <typename ResultType, typename T>
967ResultType const& get_unchecked(T const& var)
968{
969 return var.template get_unchecked<ResultType>();
970}
971// variant_size
972template <typename T>
973struct 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
979template <typename T>
980struct variant_size<const T>
981 : variant_size<T> {};
982
983template <typename T>
984struct variant_size<volatile T>
985 : variant_size<T> {};
986
987template <typename T>
988struct variant_size<const volatile T>
989 : variant_size<T> {};
990
991template <typename... Types>
992struct variant_size<variant<Types...>>
993 : std::integral_constant<std::size_t, sizeof...(Types)> {};
994
995// variant_alternative
996template <std::size_t Index, typename T>
997struct 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)
1006template <std::size_t Index, typename ...Types>
1007struct 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
1013template <std::size_t Index, typename First, typename...Types>
1014struct 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
1020template <typename First, typename...Types>
1021struct variant_alternative<0, variant<First, Types...>>
1022{
1023 using type = First;
1024};
1025
1026#endif
1027
1028template <size_t Index, typename T>
1029using variant_alternative_t = typename variant_alternative<Index, T>::type;
1030
1031template <size_t Index, typename T>
1032struct variant_alternative<Index, const T>
1033 : std::add_const<variant_alternative<Index, T>> {};
1034
1035template <size_t Index, typename T>
1036struct variant_alternative<Index, volatile T>
1037 : std::add_volatile<variant_alternative<Index, T>> {};
1038
1039template <size_t Index, typename T>
1040struct 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
1047namespace std {
1048template <typename... Types>
1049struct hash< ::mapbox::util::variant<Types...>> {
1050 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