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