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