blob: 9f039bcebf56d6986362898576087b21a76ef396 [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>
Patrick Venture95269db2018-08-31 09:19:17 -07005#include <cstddef> // size_t
6#include <mapbox/recursive_wrapper.hpp>
Patrick Williamsceefb312016-09-11 21:12:42 -05007#include <new> // operator new
8#include <stdexcept> // runtime_error
9#include <string>
10#include <tuple>
11#include <type_traits>
12#include <typeinfo>
13#include <utility>
14
Patrick Williamsceefb312016-09-11 21:12:42 -050015// clang-format off
16// [[deprecated]] is only available in C++14, use this for the time being
17#if __cplusplus <= 201103L
18# ifdef __GNUC__
19# define MAPBOX_VARIANT_DEPRECATED __attribute__((deprecated))
20# elif defined(_MSC_VER)
21# define MAPBOX_VARIANT_DEPRECATED __declspec(deprecated)
22# else
23# define MAPBOX_VARIANT_DEPRECATED
24# endif
25#else
26# define MAPBOX_VARIANT_DEPRECATED [[deprecated]]
27#endif
28
29
30#ifdef _MSC_VER
31// https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx
32# ifdef NDEBUG
33# define VARIANT_INLINE __forceinline
34# else
35# define VARIANT_INLINE //__declspec(noinline)
36# endif
37#else
38# ifdef NDEBUG
39# define VARIANT_INLINE //inline __attribute__((always_inline))
40# else
41# define VARIANT_INLINE __attribute__((noinline))
42# endif
43#endif
44// clang-format on
45
46// Exceptions
Andrew Geissler072da3e2018-01-18 07:21:42 -080047#if defined(__EXCEPTIONS) || defined(_MSC_VER)
Patrick Williamsceefb312016-09-11 21:12:42 -050048#define HAS_EXCEPTIONS
49#endif
50
51#define VARIANT_MAJOR_VERSION 1
52#define VARIANT_MINOR_VERSION 1
53#define VARIANT_PATCH_VERSION 0
54
Andrew Geissler072da3e2018-01-18 07:21:42 -080055#define VARIANT_VERSION \
56 (VARIANT_MAJOR_VERSION * 100000) + (VARIANT_MINOR_VERSION * 100) + \
57 (VARIANT_PATCH_VERSION)
Patrick Williamsceefb312016-09-11 21:12:42 -050058
Andrew Geissler072da3e2018-01-18 07:21:42 -080059namespace mapbox
60{
61namespace util
62{
Patrick Williamsceefb312016-09-11 21:12:42 -050063
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
Andrew Geissler072da3e2018-01-18 07:21:42 -080069 public:
70 explicit bad_variant_access(const std::string& what_arg) :
71 runtime_error(what_arg)
72 {
73 }
Patrick Williamsceefb312016-09-11 21:12:42 -050074
Andrew Geissler072da3e2018-01-18 07:21:42 -080075 explicit bad_variant_access(const char* what_arg) : runtime_error(what_arg)
76 {
77 }
Patrick Williamsceefb312016-09-11 21:12:42 -050078
79}; // class bad_variant_access
80
Patrick Venture2b238af2018-08-31 12:45:01 -070081template <typename R = void>
82struct MAPBOX_VARIANT_DEPRECATED static_visitor
Patrick Williamsceefb312016-09-11 21:12:42 -050083{
84 using result_type = R;
85
Andrew Geissler072da3e2018-01-18 07:21:42 -080086 protected:
87 static_visitor()
88 {
89 }
90 ~static_visitor()
91 {
92 }
Patrick Williamsceefb312016-09-11 21:12:42 -050093};
94
Andrew Geissler072da3e2018-01-18 07:21:42 -080095namespace detail
96{
Patrick Williamsceefb312016-09-11 21:12:42 -050097
98static constexpr std::size_t invalid_value = std::size_t(-1);
99
Patrick Venture2b238af2018-08-31 12:45:01 -0700100template <typename T, typename... Types>
101struct direct_type;
Patrick Williamsceefb312016-09-11 21:12:42 -0500102
103template <typename T, typename First, typename... Types>
104struct direct_type<T, First, Types...>
105{
106 static constexpr std::size_t index = std::is_same<T, First>::value
Andrew Geissler072da3e2018-01-18 07:21:42 -0800107 ? sizeof...(Types)
108 : direct_type<T, Types...>::index;
Patrick Williamsceefb312016-09-11 21:12:42 -0500109};
110
Patrick Venture2b238af2018-08-31 12:45:01 -0700111template <typename T>
112struct direct_type<T>
Patrick Williamsceefb312016-09-11 21:12:42 -0500113{
114 static constexpr std::size_t index = invalid_value;
115};
116
117#if __cpp_lib_logical_traits >= 201510L
118
119using std::disjunction;
120
121#else
122
Patrick Venture2b238af2018-08-31 12:45:01 -0700123template <typename...>
124struct disjunction : std::false_type
Andrew Geissler072da3e2018-01-18 07:21:42 -0800125{
126};
Patrick Williamsceefb312016-09-11 21:12:42 -0500127
Patrick Venture2b238af2018-08-31 12:45:01 -0700128template <typename B1>
129struct disjunction<B1> : B1
Andrew Geissler072da3e2018-01-18 07:21:42 -0800130{
131};
Patrick Williamsceefb312016-09-11 21:12:42 -0500132
133template <typename B1, typename B2>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800134struct disjunction<B1, B2> : std::conditional<B1::value, B1, B2>::type
135{
136};
Patrick Williamsceefb312016-09-11 21:12:42 -0500137
138template <typename B1, typename... Bs>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800139struct disjunction<B1, Bs...>
140 : std::conditional<B1::value, B1, disjunction<Bs...>>::type
141{
142};
Patrick Williamsceefb312016-09-11 21:12:42 -0500143
144#endif
145
Patrick Venture2b238af2018-08-31 12:45:01 -0700146template <typename T, typename... Types>
147struct convertible_type;
Patrick Williamsceefb312016-09-11 21:12:42 -0500148
149template <typename T, typename First, typename... Types>
150struct convertible_type<T, First, Types...>
151{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800152 static constexpr std::size_t index =
153 std::is_convertible<T, First>::value
154 ? disjunction<std::is_convertible<T, Types>...>::value
155 ? invalid_value
156 : sizeof...(Types)
157 : convertible_type<T, Types...>::index;
Patrick Williamsceefb312016-09-11 21:12:42 -0500158};
159
Patrick Venture2b238af2018-08-31 12:45:01 -0700160template <typename T>
161struct convertible_type<T>
Patrick Williamsceefb312016-09-11 21:12:42 -0500162{
163 static constexpr std::size_t index = invalid_value;
164};
165
Patrick Venture2b238af2018-08-31 12:45:01 -0700166template <typename T, typename... Types>
167struct value_traits
Patrick Williamsceefb312016-09-11 21:12:42 -0500168{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800169 using value_type = typename std::remove_const<
170 typename std::remove_reference<T>::type>::type;
171 static constexpr std::size_t direct_index =
172 direct_type<value_type, Types...>::index;
Patrick Williamsceefb312016-09-11 21:12:42 -0500173 static constexpr bool is_direct = direct_index != invalid_value;
Andrew Geissler072da3e2018-01-18 07:21:42 -0800174 static constexpr std::size_t index =
175 is_direct ? direct_index
176 : convertible_type<value_type, Types...>::index;
Patrick Williamsceefb312016-09-11 21:12:42 -0500177 static constexpr bool is_valid = index != invalid_value;
Andrew Geissler072da3e2018-01-18 07:21:42 -0800178 static constexpr std::size_t tindex =
179 is_valid ? sizeof...(Types) - index : 0;
180 using target_type =
181 typename std::tuple_element<tindex, std::tuple<void, Types...>>::type;
Patrick Williamsceefb312016-09-11 21:12:42 -0500182};
183
Patrick Venture2b238af2018-08-31 12:45:01 -0700184template <typename T, typename R = void>
185struct enable_if_type
Patrick Williamsceefb312016-09-11 21:12:42 -0500186{
187 using type = R;
188};
189
190template <typename F, typename V, typename Enable = void>
191struct result_of_unary_visit
192{
193 using type = typename std::result_of<F(V&)>::type;
194};
195
196template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800197struct result_of_unary_visit<
198 F, V, typename enable_if_type<typename F::result_type>::type>
Patrick Williamsceefb312016-09-11 21:12:42 -0500199{
200 using type = typename F::result_type;
201};
202
203template <typename F, typename V, typename Enable = void>
204struct result_of_binary_visit
205{
206 using type = typename std::result_of<F(V&, V&)>::type;
207};
208
209template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800210struct result_of_binary_visit<
211 F, V, typename enable_if_type<typename F::result_type>::type>
Patrick Williamsceefb312016-09-11 21:12:42 -0500212{
213 using type = typename F::result_type;
214};
215
Patrick Venture2b238af2018-08-31 12:45:01 -0700216template <std::size_t arg1, std::size_t... others>
217struct static_max;
Patrick Williamsceefb312016-09-11 21:12:42 -0500218
Patrick Venture2b238af2018-08-31 12:45:01 -0700219template <std::size_t arg>
220struct static_max<arg>
Patrick Williamsceefb312016-09-11 21:12:42 -0500221{
222 static const std::size_t value = arg;
223};
224
225template <std::size_t arg1, std::size_t arg2, std::size_t... others>
226struct static_max<arg1, arg2, others...>
227{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800228 static const std::size_t value = arg1 >= arg2
229 ? static_max<arg1, others...>::value
230 : static_max<arg2, others...>::value;
Patrick Williamsceefb312016-09-11 21:12:42 -0500231};
232
Patrick Venture2b238af2018-08-31 12:45:01 -0700233template <typename... Types>
234struct variant_helper;
Patrick Williamsceefb312016-09-11 21:12:42 -0500235
Patrick Venture2b238af2018-08-31 12:45:01 -0700236template <typename T, typename... Types>
237struct variant_helper<T, Types...>
Patrick Williamsceefb312016-09-11 21:12:42 -0500238{
239 VARIANT_INLINE static void destroy(const std::size_t type_index, void* data)
240 {
241 if (type_index == sizeof...(Types))
242 {
243 reinterpret_cast<T*>(data)->~T();
244 }
245 else
246 {
247 variant_helper<Types...>::destroy(type_index, data);
248 }
249 }
250
Andrew Geissler072da3e2018-01-18 07:21:42 -0800251 VARIANT_INLINE static void move(const std::size_t old_type_index,
252 void* old_value, void* new_value)
Patrick Williamsceefb312016-09-11 21:12:42 -0500253 {
254 if (old_type_index == sizeof...(Types))
255 {
256 new (new_value) T(std::move(*reinterpret_cast<T*>(old_value)));
257 }
258 else
259 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800260 variant_helper<Types...>::move(old_type_index, old_value,
261 new_value);
Patrick Williamsceefb312016-09-11 21:12:42 -0500262 }
263 }
264
Andrew Geissler072da3e2018-01-18 07:21:42 -0800265 VARIANT_INLINE static void copy(const std::size_t old_type_index,
266 const void* old_value, void* new_value)
Patrick Williamsceefb312016-09-11 21:12:42 -0500267 {
268 if (old_type_index == sizeof...(Types))
269 {
270 new (new_value) T(*reinterpret_cast<const T*>(old_value));
271 }
272 else
273 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800274 variant_helper<Types...>::copy(old_type_index, old_value,
275 new_value);
Patrick Williamsceefb312016-09-11 21:12:42 -0500276 }
277 }
278};
279
Patrick Venture2b238af2018-08-31 12:45:01 -0700280template <>
281struct variant_helper<>
Patrick Williamsceefb312016-09-11 21:12:42 -0500282{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800283 VARIANT_INLINE static void destroy(const std::size_t, void*)
284 {
285 }
286 VARIANT_INLINE static void move(const std::size_t, void*, void*)
287 {
288 }
289 VARIANT_INLINE static void copy(const std::size_t, const void*, void*)
290 {
291 }
Patrick Williamsceefb312016-09-11 21:12:42 -0500292};
293
Patrick Venture2b238af2018-08-31 12:45:01 -0700294template <typename T>
295struct unwrapper
Patrick Williamsceefb312016-09-11 21:12:42 -0500296{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800297 static T const& apply_const(T const& obj)
298 {
299 return obj;
300 }
301 static T& apply(T& obj)
302 {
303 return obj;
304 }
Patrick Williamsceefb312016-09-11 21:12:42 -0500305};
306
Patrick Venture2b238af2018-08-31 12:45:01 -0700307template <typename T>
308struct unwrapper<recursive_wrapper<T>>
Patrick Williamsceefb312016-09-11 21:12:42 -0500309{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800310 static auto apply_const(recursive_wrapper<T> const& obj) ->
311 typename recursive_wrapper<T>::type const&
Patrick Williamsceefb312016-09-11 21:12:42 -0500312 {
313 return obj.get();
314 }
Andrew Geissler072da3e2018-01-18 07:21:42 -0800315 static auto apply(recursive_wrapper<T>& obj) ->
316 typename recursive_wrapper<T>::type&
Patrick Williamsceefb312016-09-11 21:12:42 -0500317 {
318 return obj.get();
319 }
320};
321
Patrick Venture2b238af2018-08-31 12:45:01 -0700322template <typename T>
323struct unwrapper<std::reference_wrapper<T>>
Patrick Williamsceefb312016-09-11 21:12:42 -0500324{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800325 static auto apply_const(std::reference_wrapper<T> const& obj) ->
326 typename std::reference_wrapper<T>::type const&
Patrick Williamsceefb312016-09-11 21:12:42 -0500327 {
328 return obj.get();
329 }
Andrew Geissler072da3e2018-01-18 07:21:42 -0800330 static auto apply(std::reference_wrapper<T>& obj) ->
331 typename std::reference_wrapper<T>::type&
Patrick Williamsceefb312016-09-11 21:12:42 -0500332 {
333 return obj.get();
334 }
335};
336
337template <typename F, typename V, typename R, typename... Types>
338struct dispatcher;
339
340template <typename F, typename V, typename R, typename T, typename... Types>
341struct dispatcher<F, V, R, T, Types...>
342{
343 VARIANT_INLINE static R apply_const(V const& v, F&& f)
344 {
345 if (v.template is<T>())
346 {
347 return f(unwrapper<T>::apply_const(v.template get_unchecked<T>()));
348 }
349 else
350 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800351 return dispatcher<F, V, R, Types...>::apply_const(
352 v, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500353 }
354 }
355
356 VARIANT_INLINE static R apply(V& v, F&& f)
357 {
358 if (v.template is<T>())
359 {
360 return f(unwrapper<T>::apply(v.template get_unchecked<T>()));
361 }
362 else
363 {
364 return dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
365 }
366 }
367};
368
369template <typename F, typename V, typename R, typename T>
370struct dispatcher<F, V, R, T>
371{
372 VARIANT_INLINE static R apply_const(V const& v, F&& f)
373 {
374 return f(unwrapper<T>::apply_const(v.template get_unchecked<T>()));
375 }
376
377 VARIANT_INLINE static R apply(V& v, F&& f)
378 {
379 return f(unwrapper<T>::apply(v.template get_unchecked<T>()));
380 }
381};
382
383template <typename F, typename V, typename R, typename T, typename... Types>
384struct binary_dispatcher_rhs;
385
Andrew Geissler072da3e2018-01-18 07:21:42 -0800386template <typename F, typename V, typename R, typename T0, typename T1,
387 typename... Types>
Patrick Williamsceefb312016-09-11 21:12:42 -0500388struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
389{
390 VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
391 {
392 if (rhs.template is<T1>()) // call binary functor
393 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800394 return f(
395 unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()),
396 unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>()));
Patrick Williamsceefb312016-09-11 21:12:42 -0500397 }
398 else
399 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800400 return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(
401 lhs, rhs, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500402 }
403 }
404
405 VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
406 {
407 if (rhs.template is<T1>()) // call binary functor
408 {
409 return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()),
410 unwrapper<T1>::apply(rhs.template get_unchecked<T1>()));
411 }
412 else
413 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800414 return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(
415 lhs, rhs, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500416 }
417 }
418};
419
420template <typename F, typename V, typename R, typename T0, typename T1>
421struct binary_dispatcher_rhs<F, V, R, T0, T1>
422{
423 VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
424 {
425 return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()),
426 unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>()));
427 }
428
429 VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
430 {
431 return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()),
432 unwrapper<T1>::apply(rhs.template get_unchecked<T1>()));
433 }
434};
435
436template <typename F, typename V, typename R, typename T, typename... Types>
437struct binary_dispatcher_lhs;
438
Andrew Geissler072da3e2018-01-18 07:21:42 -0800439template <typename F, typename V, typename R, typename T0, typename T1,
440 typename... Types>
Patrick Williamsceefb312016-09-11 21:12:42 -0500441struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
442{
443 VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
444 {
445 if (lhs.template is<T1>()) // call binary functor
446 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800447 return f(
448 unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()),
449 unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>()));
Patrick Williamsceefb312016-09-11 21:12:42 -0500450 }
451 else
452 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800453 return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(
454 lhs, rhs, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500455 }
456 }
457
458 VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
459 {
460 if (lhs.template is<T1>()) // call binary functor
461 {
462 return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()),
463 unwrapper<T0>::apply(rhs.template get_unchecked<T0>()));
464 }
465 else
466 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800467 return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(
468 lhs, rhs, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500469 }
470 }
471};
472
473template <typename F, typename V, typename R, typename T0, typename T1>
474struct binary_dispatcher_lhs<F, V, R, T0, T1>
475{
476 VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
477 {
478 return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()),
479 unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>()));
480 }
481
482 VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
483 {
484 return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()),
485 unwrapper<T0>::apply(rhs.template get_unchecked<T0>()));
486 }
487};
488
489template <typename F, typename V, typename R, typename... Types>
490struct binary_dispatcher;
491
492template <typename F, typename V, typename R, typename T, typename... Types>
493struct binary_dispatcher<F, V, R, T, Types...>
494{
495 VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
496 {
497 if (v0.template is<T>())
498 {
499 if (v1.template is<T>())
500 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800501 return f(
502 unwrapper<T>::apply_const(v0.template get_unchecked<T>()),
503 unwrapper<T>::apply_const(
504 v1.template get_unchecked<T>())); // call binary functor
Patrick Williamsceefb312016-09-11 21:12:42 -0500505 }
506 else
507 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800508 return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(
509 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500510 }
511 }
512 else if (v1.template is<T>())
513 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800514 return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(
515 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500516 }
Andrew Geissler072da3e2018-01-18 07:21:42 -0800517 return binary_dispatcher<F, V, R, Types...>::apply_const(
518 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500519 }
520
521 VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
522 {
523 if (v0.template is<T>())
524 {
525 if (v1.template is<T>())
526 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800527 return f(
528 unwrapper<T>::apply(v0.template get_unchecked<T>()),
529 unwrapper<T>::apply(
530 v1.template get_unchecked<T>())); // call binary functor
Patrick Williamsceefb312016-09-11 21:12:42 -0500531 }
532 else
533 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800534 return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(
535 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500536 }
537 }
538 else if (v1.template is<T>())
539 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800540 return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(
541 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500542 }
Andrew Geissler072da3e2018-01-18 07:21:42 -0800543 return binary_dispatcher<F, V, R, Types...>::apply(v0, v1,
544 std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500545 }
546};
547
548template <typename F, typename V, typename R, typename T>
549struct binary_dispatcher<F, V, R, T>
550{
551 VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
552 {
553 return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()),
Andrew Geissler072da3e2018-01-18 07:21:42 -0800554 unwrapper<T>::apply_const(
555 v1.template get_unchecked<T>())); // call binary functor
Patrick Williamsceefb312016-09-11 21:12:42 -0500556 }
557
558 VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
559 {
560 return f(unwrapper<T>::apply(v0.template get_unchecked<T>()),
Andrew Geissler072da3e2018-01-18 07:21:42 -0800561 unwrapper<T>::apply(
562 v1.template get_unchecked<T>())); // call binary functor
Patrick Williamsceefb312016-09-11 21:12:42 -0500563 }
564};
565
566// comparator functors
567struct equal_comp
568{
Patrick Venture2b238af2018-08-31 12:45:01 -0700569 template <typename T>
570 bool operator()(T const& lhs, T const& rhs) const
Patrick Williamsceefb312016-09-11 21:12:42 -0500571 {
572 return lhs == rhs;
573 }
574};
575
576struct less_comp
577{
Patrick Venture2b238af2018-08-31 12:45:01 -0700578 template <typename T>
579 bool operator()(T const& lhs, T const& rhs) const
Patrick Williamsceefb312016-09-11 21:12:42 -0500580 {
581 return lhs < rhs;
582 }
583};
584
Patrick Venture2b238af2018-08-31 12:45:01 -0700585template <typename Variant, typename Comp>
586class comparer
Patrick Williamsceefb312016-09-11 21:12:42 -0500587{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800588 public:
589 explicit comparer(Variant const& lhs) noexcept : lhs_(lhs)
590 {
591 }
Patrick Williamsceefb312016-09-11 21:12:42 -0500592 comparer& operator=(comparer const&) = delete;
593 // visitor
Patrick Venture2b238af2018-08-31 12:45:01 -0700594 template <typename T>
595 bool operator()(T const& rhs_content) const
Patrick Williamsceefb312016-09-11 21:12:42 -0500596 {
597 T const& lhs_content = lhs_.template get_unchecked<T>();
598 return Comp()(lhs_content, rhs_content);
599 }
600
Andrew Geissler072da3e2018-01-18 07:21:42 -0800601 private:
Patrick Williamsceefb312016-09-11 21:12:42 -0500602 Variant const& lhs_;
603};
604
605} // namespace detail
606
607struct no_init
608{
609};
610
Patrick Venture2b238af2018-08-31 12:45:01 -0700611template <typename... Types>
612class variant
Patrick Williamsceefb312016-09-11 21:12:42 -0500613{
Andrew Geissler072da3e2018-01-18 07:21:42 -0800614 static_assert(sizeof...(Types) > 0,
615 "Template parameter type list of variant can not be empty");
616 static_assert(!detail::disjunction<std::is_reference<Types>...>::value,
617 "Variant can not hold reference types. Maybe use "
618 "std::reference_wrapper?");
Patrick Williamsceefb312016-09-11 21:12:42 -0500619
Andrew Geissler072da3e2018-01-18 07:21:42 -0800620 private:
621 static const std::size_t data_size =
622 detail::static_max<sizeof(Types)...>::value;
623 static const std::size_t data_align =
624 detail::static_max<alignof(Types)...>::value;
Patrick Williamsceefb312016-09-11 21:12:42 -0500625
Andrew Geissler072da3e2018-01-18 07:21:42 -0800626 using first_type =
627 typename std::tuple_element<0, std::tuple<Types...>>::type;
628 using data_type =
629 typename std::aligned_storage<data_size, data_align>::type;
Patrick Williamsceefb312016-09-11 21:12:42 -0500630 using helper_type = detail::variant_helper<Types...>;
631
632 std::size_t type_index;
633 data_type data;
634
Andrew Geissler072da3e2018-01-18 07:21:42 -0800635 public:
636 VARIANT_INLINE variant() noexcept(
637 std::is_nothrow_default_constructible<first_type>::value) :
638 type_index(sizeof...(Types) - 1)
Patrick Williamsceefb312016-09-11 21:12:42 -0500639 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800640 static_assert(std::is_default_constructible<first_type>::value,
641 "First type in variant must be default constructible to "
642 "allow default construction of variant");
Patrick Williamsceefb312016-09-11 21:12:42 -0500643 new (&data) first_type();
644 }
645
Andrew Geissler072da3e2018-01-18 07:21:42 -0800646 VARIANT_INLINE variant(no_init) noexcept : type_index(detail::invalid_value)
647 {
648 }
Patrick Williamsceefb312016-09-11 21:12:42 -0500649
650 // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
651 template <typename T, typename Traits = detail::value_traits<T, Types...>,
652 typename Enable = typename std::enable_if<Traits::is_valid>::type>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800653 VARIANT_INLINE variant(T&& val) noexcept(
654 std::is_nothrow_constructible<typename Traits::target_type,
655 T&&>::value) :
656 type_index(Traits::index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500657 {
658 new (&data) typename Traits::target_type(std::forward<T>(val));
659 }
660
Andrew Geissler072da3e2018-01-18 07:21:42 -0800661 VARIANT_INLINE variant(variant<Types...> const& old) :
662 type_index(old.type_index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500663 {
664 helper_type::copy(old.type_index, &old.data, &data);
665 }
666
Andrew Geissler072da3e2018-01-18 07:21:42 -0800667 VARIANT_INLINE variant(variant<Types...>&& old) noexcept(
668 std::is_nothrow_move_constructible<std::tuple<Types...>>::value) :
669 type_index(old.type_index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500670 {
671 helper_type::move(old.type_index, &old.data, &data);
672 }
673
Andrew Geissler072da3e2018-01-18 07:21:42 -0800674 private:
Patrick Williamsceefb312016-09-11 21:12:42 -0500675 VARIANT_INLINE void copy_assign(variant<Types...> const& rhs)
676 {
677 helper_type::destroy(type_index, &data);
678 type_index = detail::invalid_value;
679 helper_type::copy(rhs.type_index, &rhs.data, &data);
680 type_index = rhs.type_index;
681 }
682
683 VARIANT_INLINE void move_assign(variant<Types...>&& rhs)
684 {
685 helper_type::destroy(type_index, &data);
686 type_index = detail::invalid_value;
687 helper_type::move(rhs.type_index, &rhs.data, &data);
688 type_index = rhs.type_index;
689 }
690
Andrew Geissler072da3e2018-01-18 07:21:42 -0800691 public:
Patrick Williamsceefb312016-09-11 21:12:42 -0500692 VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other)
693 {
694 move_assign(std::move(other));
695 return *this;
696 }
697
698 VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other)
699 {
700 copy_assign(other);
701 return *this;
702 }
703
704 // conversions
705 // move-assign
706 template <typename T>
707 VARIANT_INLINE variant<Types...>& operator=(T&& rhs) noexcept
708 {
709 variant<Types...> temp(std::forward<T>(rhs));
710 move_assign(std::move(temp));
711 return *this;
712 }
713
714 // copy-assign
715 template <typename T>
716 VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
717 {
718 variant<Types...> temp(rhs);
719 copy_assign(temp);
720 return *this;
721 }
722
723 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800724 (detail::direct_type<T, Types...>::index !=
725 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500726 VARIANT_INLINE bool is() const
727 {
728 return type_index == detail::direct_type<T, Types...>::index;
729 }
730
Andrew Geissler072da3e2018-01-18 07:21:42 -0800731 template <typename T,
732 typename std::enable_if<
733 (detail::direct_type<recursive_wrapper<T>, Types...>::index !=
734 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500735 VARIANT_INLINE bool is() const
736 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800737 return type_index ==
738 detail::direct_type<recursive_wrapper<T>, Types...>::index;
Patrick Williamsceefb312016-09-11 21:12:42 -0500739 }
740
741 VARIANT_INLINE bool valid() const
742 {
743 return type_index != detail::invalid_value;
744 }
745
746 template <typename T, typename... Args>
747 VARIANT_INLINE void set(Args&&... args)
748 {
749 helper_type::destroy(type_index, &data);
750 type_index = detail::invalid_value;
751 new (&data) T(std::forward<Args>(args)...);
752 type_index = detail::direct_type<T, Types...>::index;
753 }
754
755 // get_unchecked<T>()
756 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800757 (detail::direct_type<T, Types...>::index !=
758 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500759 VARIANT_INLINE T& get_unchecked()
760 {
761 return *reinterpret_cast<T*>(&data);
762 }
763
764#ifdef HAS_EXCEPTIONS
765 // get<T>()
766 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800767 (detail::direct_type<T, Types...>::index !=
768 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500769 VARIANT_INLINE T& get()
770 {
771 if (type_index == detail::direct_type<T, Types...>::index)
772 {
773 return *reinterpret_cast<T*>(&data);
774 }
775 else
776 {
777 throw bad_variant_access("in get<T>()");
778 }
779 }
780#endif
781
782 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800783 (detail::direct_type<T, Types...>::index !=
784 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500785 VARIANT_INLINE T const& get_unchecked() const
786 {
787 return *reinterpret_cast<T const*>(&data);
788 }
789
790#ifdef HAS_EXCEPTIONS
791 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800792 (detail::direct_type<T, Types...>::index !=
793 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500794 VARIANT_INLINE T const& get() const
795 {
796 if (type_index == detail::direct_type<T, Types...>::index)
797 {
798 return *reinterpret_cast<T const*>(&data);
799 }
800 else
801 {
802 throw bad_variant_access("in get<T>()");
803 }
804 }
805#endif
806
807 // get_unchecked<T>() - T stored as recursive_wrapper<T>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800808 template <typename T,
809 typename std::enable_if<
810 (detail::direct_type<recursive_wrapper<T>, Types...>::index !=
811 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500812 VARIANT_INLINE T& get_unchecked()
813 {
814 return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
815 }
816
817#ifdef HAS_EXCEPTIONS
818 // get<T>() - T stored as recursive_wrapper<T>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800819 template <typename T,
820 typename std::enable_if<
821 (detail::direct_type<recursive_wrapper<T>, Types...>::index !=
822 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500823 VARIANT_INLINE T& get()
824 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800825 if (type_index ==
826 detail::direct_type<recursive_wrapper<T>, Types...>::index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500827 {
828 return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
829 }
830 else
831 {
832 throw bad_variant_access("in get<T>()");
833 }
834 }
835#endif
836
Andrew Geissler072da3e2018-01-18 07:21:42 -0800837 template <typename T,
838 typename std::enable_if<
839 (detail::direct_type<recursive_wrapper<T>, Types...>::index !=
840 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500841 VARIANT_INLINE T const& get_unchecked() const
842 {
843 return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
844 }
845
846#ifdef HAS_EXCEPTIONS
Andrew Geissler072da3e2018-01-18 07:21:42 -0800847 template <typename T,
848 typename std::enable_if<
849 (detail::direct_type<recursive_wrapper<T>, Types...>::index !=
850 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500851 VARIANT_INLINE T const& get() const
852 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800853 if (type_index ==
854 detail::direct_type<recursive_wrapper<T>, Types...>::index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500855 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800856 return (*reinterpret_cast<recursive_wrapper<T> const*>(&data))
857 .get();
Patrick Williamsceefb312016-09-11 21:12:42 -0500858 }
859 else
860 {
861 throw bad_variant_access("in get<T>()");
862 }
863 }
864#endif
865
866 // get_unchecked<T>() - T stored as std::reference_wrapper<T>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800867 template <
868 typename T,
869 typename std::enable_if<
870 (detail::direct_type<std::reference_wrapper<T>, Types...>::index !=
871 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500872 VARIANT_INLINE T& get_unchecked()
873 {
874 return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
875 }
876
877#ifdef HAS_EXCEPTIONS
878 // get<T>() - T stored as std::reference_wrapper<T>
Andrew Geissler072da3e2018-01-18 07:21:42 -0800879 template <
880 typename T,
881 typename std::enable_if<
882 (detail::direct_type<std::reference_wrapper<T>, Types...>::index !=
883 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500884 VARIANT_INLINE T& get()
885 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800886 if (type_index ==
887 detail::direct_type<std::reference_wrapper<T>, Types...>::index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500888 {
889 return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
890 }
891 else
892 {
893 throw bad_variant_access("in get<T>()");
894 }
895 }
896#endif
897
Andrew Geissler072da3e2018-01-18 07:21:42 -0800898 template <typename T,
899 typename std::enable_if<
900 (detail::direct_type<std::reference_wrapper<T const>,
901 Types...>::index !=
902 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500903 VARIANT_INLINE T const& get_unchecked() const
904 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800905 return (*reinterpret_cast<std::reference_wrapper<T const> const*>(
906 &data))
907 .get();
Patrick Williamsceefb312016-09-11 21:12:42 -0500908 }
909
910#ifdef HAS_EXCEPTIONS
Andrew Geissler072da3e2018-01-18 07:21:42 -0800911 template <typename T,
912 typename std::enable_if<
913 (detail::direct_type<std::reference_wrapper<T const>,
914 Types...>::index !=
915 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500916 VARIANT_INLINE T const& get() const
917 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800918 if (type_index == detail::direct_type<std::reference_wrapper<T const>,
919 Types...>::index)
Patrick Williamsceefb312016-09-11 21:12:42 -0500920 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800921 return (*reinterpret_cast<std::reference_wrapper<T const> const*>(
922 &data))
923 .get();
Patrick Williamsceefb312016-09-11 21:12:42 -0500924 }
925 else
926 {
927 throw bad_variant_access("in get<T>()");
928 }
929 }
930#endif
931
932 // This function is deprecated because it returns an internal index field.
933 // Use which() instead.
934 MAPBOX_VARIANT_DEPRECATED VARIANT_INLINE std::size_t get_type_index() const
935 {
936 return type_index;
937 }
938
939 VARIANT_INLINE int which() const noexcept
940 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800941 return static_cast<int>(sizeof...(Types) - type_index - 1);
Patrick Williamsceefb312016-09-11 21:12:42 -0500942 }
943
944 template <typename T, typename std::enable_if<
Andrew Geissler072da3e2018-01-18 07:21:42 -0800945 (detail::direct_type<T, Types...>::index !=
946 detail::invalid_value)>::type* = nullptr>
Patrick Williamsceefb312016-09-11 21:12:42 -0500947 VARIANT_INLINE static constexpr int which() noexcept
948 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800949 return static_cast<int>(sizeof...(Types) -
950 detail::direct_type<T, Types...>::index - 1);
Patrick Williamsceefb312016-09-11 21:12:42 -0500951 }
952
953 // visitor
954 // unary
Andrew Geissler072da3e2018-01-18 07:21:42 -0800955 template <typename F, typename V,
956 typename R =
957 typename detail::result_of_unary_visit<F, first_type>::type>
Patrick Williamsceefb312016-09-11 21:12:42 -0500958 auto VARIANT_INLINE static visit(V const& v, F&& f)
Andrew Geissler072da3e2018-01-18 07:21:42 -0800959 -> decltype(detail::dispatcher<F, V, R, Types...>::apply_const(
960 v, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -0500961 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800962 return detail::dispatcher<F, V, R, Types...>::apply_const(
963 v, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500964 }
965 // non-const
Andrew Geissler072da3e2018-01-18 07:21:42 -0800966 template <typename F, typename V,
967 typename R =
968 typename detail::result_of_unary_visit<F, first_type>::type>
969 auto VARIANT_INLINE static visit(V& v, F&& f) -> decltype(
970 detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -0500971 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800972 return detail::dispatcher<F, V, R, Types...>::apply(v,
973 std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500974 }
975
976 // binary
977 // const
Andrew Geissler072da3e2018-01-18 07:21:42 -0800978 template <typename F, typename V,
979 typename R =
980 typename detail::result_of_binary_visit<F, first_type>::type>
Patrick Williamsceefb312016-09-11 21:12:42 -0500981 auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F&& f)
Andrew Geissler072da3e2018-01-18 07:21:42 -0800982 -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply_const(
983 v0, v1, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -0500984 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800985 return detail::binary_dispatcher<F, V, R, Types...>::apply_const(
986 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500987 }
988 // non-const
Andrew Geissler072da3e2018-01-18 07:21:42 -0800989 template <typename F, typename V,
990 typename R =
991 typename detail::result_of_binary_visit<F, first_type>::type>
Patrick Williamsceefb312016-09-11 21:12:42 -0500992 auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F&& f)
Andrew Geissler072da3e2018-01-18 07:21:42 -0800993 -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply(
994 v0, v1, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -0500995 {
Andrew Geissler072da3e2018-01-18 07:21:42 -0800996 return detail::binary_dispatcher<F, V, R, Types...>::apply(
997 v0, v1, std::forward<F>(f));
Patrick Williamsceefb312016-09-11 21:12:42 -0500998 }
999
1000 ~variant() noexcept // no-throw destructor
1001 {
1002 helper_type::destroy(type_index, &data);
1003 }
1004
1005 // comparison operators
1006 // equality
1007 VARIANT_INLINE bool operator==(variant const& rhs) const
1008 {
1009 assert(valid() && rhs.valid());
1010 if (this->which() != rhs.which())
1011 {
1012 return false;
1013 }
1014 detail::comparer<variant, detail::equal_comp> visitor(*this);
1015 return visit(rhs, visitor);
1016 }
1017
1018 VARIANT_INLINE bool operator!=(variant const& rhs) const
1019 {
1020 return !(*this == rhs);
1021 }
1022
1023 // less than
1024 VARIANT_INLINE bool operator<(variant const& rhs) const
1025 {
1026 assert(valid() && rhs.valid());
1027 if (this->which() != rhs.which())
1028 {
1029 return this->which() < rhs.which();
1030 }
1031 detail::comparer<variant, detail::less_comp> visitor(*this);
1032 return visit(rhs, visitor);
1033 }
1034 VARIANT_INLINE bool operator>(variant const& rhs) const
1035 {
1036 return rhs < *this;
1037 }
1038 VARIANT_INLINE bool operator<=(variant const& rhs) const
1039 {
1040 return !(*this > rhs);
1041 }
1042 VARIANT_INLINE bool operator>=(variant const& rhs) const
1043 {
1044 return !(*this < rhs);
1045 }
1046};
1047
1048// unary visitor interface
1049// const
1050template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001051auto VARIANT_INLINE apply_visitor(F&& f, V const& v)
1052 -> decltype(V::visit(v, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -05001053{
1054 return V::visit(v, std::forward<F>(f));
1055}
1056
1057// non-const
1058template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001059auto VARIANT_INLINE apply_visitor(F&& f, V& v)
1060 -> decltype(V::visit(v, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -05001061{
1062 return V::visit(v, std::forward<F>(f));
1063}
1064
1065// binary visitor interface
1066// const
1067template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001068auto VARIANT_INLINE apply_visitor(F&& f, V const& v0, V const& v1)
1069 -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -05001070{
1071 return V::binary_visit(v0, v1, std::forward<F>(f));
1072}
1073
1074// non-const
1075template <typename F, typename V>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001076auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1)
1077 -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
Patrick Williamsceefb312016-09-11 21:12:42 -05001078{
1079 return V::binary_visit(v0, v1, std::forward<F>(f));
1080}
1081
William A. Kennington IIIb2cb9332018-10-04 16:01:53 -07001082// is interface
1083
1084#ifdef HAS_EXCEPTIONS
1085template <typename ResultType, typename T>
1086auto holds_alternative(T const& var) -> decltype(var.template is<ResultType>())
1087{
1088 return var.template is<ResultType>();
1089}
1090#endif
1091
Patrick Venture0b5d1e02018-08-31 09:12:15 -07001092// getter interface
Patrick Williamsceefb312016-09-11 21:12:42 -05001093
1094#ifdef HAS_EXCEPTIONS
1095template <typename ResultType, typename T>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001096auto get(T& var) -> decltype(var.template get<ResultType>())
Patrick Williamsceefb312016-09-11 21:12:42 -05001097{
1098 return var.template get<ResultType>();
1099}
1100#endif
1101
Patrick Venture2b238af2018-08-31 12:45:01 -07001102template <typename ResultType, typename T>
1103ResultType& get_unchecked(T& var)
Patrick Williamsceefb312016-09-11 21:12:42 -05001104{
1105 return var.template get_unchecked<ResultType>();
1106}
1107
1108#ifdef HAS_EXCEPTIONS
1109template <typename ResultType, typename T>
Andrew Geissler072da3e2018-01-18 07:21:42 -08001110auto get(T const& var) -> decltype(var.template get<ResultType>())
Patrick Williamsceefb312016-09-11 21:12:42 -05001111{
1112 return var.template get<ResultType>();
1113}
1114#endif
1115
1116template <typename ResultType, typename T>
1117ResultType const& get_unchecked(T const& var)
1118{
1119 return var.template get_unchecked<ResultType>();
1120}
1121} // namespace util
1122} // namespace mapbox
1123
1124#endif // MAPBOX_UTIL_VARIANT_HPP