1 | // MPark.Variant |
2 | // |
3 | // Copyright Michael Park, 2015-2017 |
4 | // |
5 | // Distributed under the Boost Software License, Version 1.0. |
6 | // (See accompanying file LICENSE.md or copy at |
7 | // http://boost.org/LICENSE_1_0.txt) |
8 | // |
9 | // From https://github.com/mpark/variant |
10 | // |
11 | // C10 |
12 | // - Move to `c10` namespace. |
13 | // - Rename namespace `detail` to `detail_`, to not conflict with existing |
14 | // c10 implementations in `detail` namespace. |
15 | // - In two functions, the template name reference `I` is changed to |
16 | // `detail_::best_match<Arg, Ts...>::value` to work around gcc 7.3.1 bug. |
17 | // However, this workaround also limits the use cases of `c10::variant`. |
18 | // Please see NOTE [gcc 7.3.1 bug workaround] for details. |
19 | // - The following code is moved to `c10/util/in_place.h`: |
20 | // ``` |
21 | // struct in_place_t { explicit in_place_t() = default; }; |
22 | // |
23 | // template <std::size_t I> |
24 | // struct in_place_index_t { explicit in_place_index_t() = default; }; |
25 | // |
26 | // template <typename T> |
27 | // struct in_place_type_t { explicit in_place_type_t() = default; }; |
28 | // |
29 | // constexpr in_place_t in_place{}; |
30 | // ``` |
31 | // so that they can also be used in `c10/util/Optional.h`. |
32 | |
33 | #ifndef C10_UTIL_VARIANT_H_ |
34 | #define C10_UTIL_VARIANT_H_ |
35 | |
36 | /* |
37 | variant synopsis |
38 | |
39 | namespace std { |
40 | |
41 | // 20.7.2, class template variant |
42 | template <class... Types> |
43 | class variant { |
44 | public: |
45 | |
46 | // 20.7.2.1, constructors |
47 | constexpr variant() noexcept(see below); |
48 | variant(const variant&); |
49 | variant(variant&&) noexcept(see below); |
50 | |
51 | template <class T> constexpr variant(T&&) noexcept(see below); |
52 | |
53 | template <class T, class... Args> |
54 | constexpr explicit variant(in_place_type_t<T>, Args&&...); |
55 | |
56 | template <class T, class U, class... Args> |
57 | constexpr explicit variant( |
58 | in_place_type_t<T>, initializer_list<U>, Args&&...); |
59 | |
60 | template <size_t I, class... Args> |
61 | constexpr explicit variant(in_place_index_t<I>, Args&&...); |
62 | |
63 | template <size_t I, class U, class... Args> |
64 | constexpr explicit variant( |
65 | in_place_index_t<I>, initializer_list<U>, Args&&...); |
66 | |
67 | // 20.7.2.2, destructor |
68 | ~variant(); |
69 | |
70 | // 20.7.2.3, assignment |
71 | variant& operator=(const variant&); |
72 | variant& operator=(variant&&) noexcept(see below); |
73 | |
74 | template <class T> variant& operator=(T&&) noexcept(see below); |
75 | |
76 | // 20.7.2.4, modifiers |
77 | template <class T, class... Args> |
78 | T& emplace(Args&&...); |
79 | |
80 | template <class T, class U, class... Args> |
81 | T& emplace(initializer_list<U>, Args&&...); |
82 | |
83 | template <size_t I, class... Args> |
84 | variant_alternative<I, variant>& emplace(Args&&...); |
85 | |
86 | template <size_t I, class U, class... Args> |
87 | variant_alternative<I, variant>& emplace(initializer_list<U>, Args&&...); |
88 | |
89 | // 20.7.2.5, value status |
90 | constexpr bool valueless_by_exception() const noexcept; |
91 | constexpr size_t index() const noexcept; |
92 | |
93 | // 20.7.2.6, swap |
94 | void swap(variant&) noexcept(see below); |
95 | }; |
96 | |
97 | // 20.7.3, variant helper classes |
98 | template <class T> struct variant_size; // undefined |
99 | |
100 | template <class T> |
101 | constexpr size_t variant_size_v = variant_size<T>::value; |
102 | |
103 | template <class T> struct variant_size<const T>; |
104 | template <class T> struct variant_size<volatile T>; |
105 | template <class T> struct variant_size<const volatile T>; |
106 | |
107 | template <class... Types> |
108 | struct variant_size<variant<Types...>>; |
109 | |
110 | template <size_t I, class T> struct variant_alternative; // undefined |
111 | |
112 | template <size_t I, class T> |
113 | using variant_alternative_t = typename variant_alternative<I, T>::type; |
114 | |
115 | template <size_t I, class T> struct variant_alternative<I, const T>; |
116 | template <size_t I, class T> struct variant_alternative<I, volatile T>; |
117 | template <size_t I, class T> struct variant_alternative<I, const volatile T>; |
118 | |
119 | template <size_t I, class... Types> |
120 | struct variant_alternative<I, variant<Types...>>; |
121 | |
122 | constexpr size_t variant_npos = -1; |
123 | |
124 | // 20.7.4, value access |
125 | template <class T, class... Types> |
126 | constexpr bool holds_alternative(const variant<Types...>&) noexcept; |
127 | |
128 | template <size_t I, class... Types> |
129 | constexpr variant_alternative_t<I, variant<Types...>>& |
130 | get(variant<Types...>&); |
131 | |
132 | template <size_t I, class... Types> |
133 | constexpr variant_alternative_t<I, variant<Types...>>&& |
134 | get(variant<Types...>&&); |
135 | |
136 | template <size_t I, class... Types> |
137 | constexpr variant_alternative_t<I, variant<Types...>> const& |
138 | get(const variant<Types...>&); |
139 | |
140 | template <size_t I, class... Types> |
141 | constexpr variant_alternative_t<I, variant<Types...>> const&& |
142 | get(const variant<Types...>&&); |
143 | |
144 | template <class T, class... Types> |
145 | constexpr T& get(variant<Types...>&); |
146 | |
147 | template <class T, class... Types> |
148 | constexpr T&& get(variant<Types...>&&); |
149 | |
150 | template <class T, class... Types> |
151 | constexpr const T& get(const variant<Types...>&); |
152 | |
153 | template <class T, class... Types> |
154 | constexpr const T&& get(const variant<Types...>&&); |
155 | |
156 | template <size_t I, class... Types> |
157 | constexpr add_pointer_t<variant_alternative_t<I, variant<Types...>>> |
158 | get_if(variant<Types...>*) noexcept; |
159 | |
160 | template <size_t I, class... Types> |
161 | constexpr add_pointer_t<const variant_alternative_t<I, variant<Types...>>> |
162 | get_if(const variant<Types...>*) noexcept; |
163 | |
164 | template <class T, class... Types> |
165 | constexpr add_pointer_t<T> |
166 | get_if(variant<Types...>*) noexcept; |
167 | |
168 | template <class T, class... Types> |
169 | constexpr add_pointer_t<const T> |
170 | get_if(const variant<Types...>*) noexcept; |
171 | |
172 | // 20.7.5, relational operators |
173 | template <class... Types> |
174 | constexpr bool operator==(const variant<Types...>&, const variant<Types...>&); |
175 | |
176 | template <class... Types> |
177 | constexpr bool operator!=(const variant<Types...>&, const variant<Types...>&); |
178 | |
179 | template <class... Types> |
180 | constexpr bool operator<(const variant<Types...>&, const variant<Types...>&); |
181 | |
182 | template <class... Types> |
183 | constexpr bool operator>(const variant<Types...>&, const variant<Types...>&); |
184 | |
185 | template <class... Types> |
186 | constexpr bool operator<=(const variant<Types...>&, const variant<Types...>&); |
187 | |
188 | template <class... Types> |
189 | constexpr bool operator>=(const variant<Types...>&, const variant<Types...>&); |
190 | |
191 | // 20.7.6, visitation |
192 | template <class Visitor, class... Variants> |
193 | constexpr see below visit(Visitor&&, Variants&&...); |
194 | |
195 | // 20.7.7, class monostate |
196 | struct monostate; |
197 | |
198 | // 20.7.8, monostate relational operators |
199 | constexpr bool operator<(monostate, monostate) noexcept; |
200 | constexpr bool operator>(monostate, monostate) noexcept; |
201 | constexpr bool operator<=(monostate, monostate) noexcept; |
202 | constexpr bool operator>=(monostate, monostate) noexcept; |
203 | constexpr bool operator==(monostate, monostate) noexcept; |
204 | constexpr bool operator!=(monostate, monostate) noexcept; |
205 | |
206 | // 20.7.9, specialized algorithms |
207 | template <class... Types> |
208 | void swap(variant<Types...>&, variant<Types...>&) noexcept(see below); |
209 | |
210 | // 20.7.10, class bad_variant_access |
211 | class bad_variant_access; |
212 | |
213 | // 20.7.11, hash support |
214 | template <class T> struct hash; |
215 | template <class... Types> struct hash<variant<Types...>>; |
216 | template <> struct hash<monostate>; |
217 | |
218 | } // namespace std |
219 | |
220 | */ |
221 | |
222 | #include <cstddef> |
223 | #include <exception> |
224 | #include <functional> |
225 | #include <initializer_list> |
226 | #include <new> |
227 | #include <type_traits> |
228 | #include <utility> |
229 | |
230 | // MPark.Variant |
231 | // |
232 | // Copyright Michael Park, 2015-2017 |
233 | // |
234 | // Distributed under the Boost Software License, Version 1.0. |
235 | // (See accompanying file LICENSE.md or copy at |
236 | // http://boost.org/LICENSE_1_0.txt) |
237 | |
238 | #ifndef C10_MPARK_CONFIG_HPP |
239 | #define C10_MPARK_CONFIG_HPP |
240 | |
241 | // MSVC 2015 Update 3. |
242 | #if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_FULL_VER < 190024210) |
243 | #error "MPark.Variant requires C++11 support." |
244 | #endif |
245 | |
246 | #ifndef __has_attribute |
247 | #define __has_attribute(x) 0 |
248 | #endif |
249 | |
250 | #ifndef __has_builtin |
251 | #define __has_builtin(x) 0 |
252 | #endif |
253 | |
254 | #ifndef __has_include |
255 | #define __has_include(x) 0 |
256 | #endif |
257 | |
258 | #ifndef __has_feature |
259 | #define __has_feature(x) 0 |
260 | #endif |
261 | |
262 | #if __has_attribute(always_inline) || defined(__GNUC__) |
263 | #define C10_MPARK_ALWAYS_INLINE __attribute__((__always_inline__)) inline |
264 | #elif defined(_MSC_VER) |
265 | #define C10_MPARK_ALWAYS_INLINE __forceinline |
266 | #else |
267 | #define C10_MPARK_ALWAYS_INLINE inline |
268 | #endif |
269 | |
270 | #if __has_builtin(__builtin_addressof) || \ |
271 | (defined(__GNUC__) && __GNUC__ >= 7) || defined(_MSC_VER) |
272 | #define C10_MPARK_BUILTIN_ADDRESSOF |
273 | #endif |
274 | |
275 | #if __has_builtin(__builtin_unreachable) || defined(__GNUC__) |
276 | #define C10_MPARK_BUILTIN_UNREACHABLE __builtin_unreachable() |
277 | #elif defined(_MSC_VER) |
278 | #define C10_MPARK_BUILTIN_UNREACHABLE __assume(false) |
279 | #else |
280 | #define C10_MPARK_BUILTIN_UNREACHABLE |
281 | #endif |
282 | |
283 | // NOTE [nvcc bug workaround] |
284 | // |
285 | // The original line `typename Front = lib::type_pack_element_t<0, Ts...>,` |
286 | // throws the following compiler error on nvcc: |
287 | // ``` |
288 | // c10/util/variant.h(2367): error: parameter pack "Ts" was referenced but not |
289 | // expanded |
290 | // ``` |
291 | // As a workaround, we skip defining C10_MPARK_TYPE_PACK_ELEMENT for nvcc |
292 | // compiler |
293 | // |
294 | // See the following issues for more context: |
295 | // https://github.com/pytorch/extension-cpp/issues/58 |
296 | // https://github.com/mpark/variant/issues/77 |
297 | #if __has_builtin(__type_pack_element) && !defined(__CUDACC__) |
298 | #define C10_MPARK_TYPE_PACK_ELEMENT |
299 | #endif |
300 | |
301 | #if defined(__cpp_constexpr) && __cpp_constexpr >= 200704 && \ |
302 | !(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 9) |
303 | #define C10_MPARK_CPP11_CONSTEXPR |
304 | #endif |
305 | |
306 | #if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 |
307 | #define C10_MPARK_CPP14_CONSTEXPR |
308 | #endif |
309 | |
310 | #if __has_feature(cxx_exceptions) || defined(__cpp_exceptions) || \ |
311 | (defined(_MSC_VER) && defined(_CPPUNWIND)) |
312 | #define C10_MPARK_EXCEPTIONS |
313 | #endif |
314 | |
315 | #if defined(__cpp_generic_lambdas) || defined(_MSC_VER) |
316 | #define C10_MPARK_GENERIC_LAMBDAS |
317 | #endif |
318 | |
319 | #if defined(__cpp_lib_integer_sequence) |
320 | #define C10_MPARK_INTEGER_SEQUENCE |
321 | #endif |
322 | |
323 | #if defined(__cpp_return_type_deduction) || defined(_MSC_VER) |
324 | #define C10_MPARK_RETURN_TYPE_DEDUCTION |
325 | #endif |
326 | |
327 | #if defined(__cpp_lib_transparent_operators) || defined(_MSC_VER) |
328 | #define C10_MPARK_TRANSPARENT_OPERATORS |
329 | #endif |
330 | |
331 | #if defined(__cpp_variable_templates) || defined(_MSC_VER) |
332 | #define C10_MPARK_VARIABLE_TEMPLATES |
333 | #endif |
334 | |
335 | #if !defined(__GLIBCXX__) || __has_include(<codecvt>) // >= libstdc++-5 |
336 | #define C10_MPARK_TRIVIALITY_TYPE_TRAITS |
337 | #define C10_MPARK_INCOMPLETE_TYPE_TRAITS |
338 | #endif |
339 | |
340 | #ifdef _WIN32 |
341 | #define C10_MPARK_VISIBILITY_HIDDEN |
342 | #else |
343 | #define C10_MPARK_VISIBILITY_HIDDEN __attribute__((visibility("hidden"))) |
344 | #endif |
345 | |
346 | #endif // C10_MPARK_CONFIG_HPP |
347 | |
348 | // MPark.Variant |
349 | // |
350 | // Copyright Michael Park, 2015-2017 |
351 | // |
352 | // Distributed under the Boost Software License, Version 1.0. |
353 | // (See accompanying file LICENSE.md or copy at |
354 | // http://boost.org/LICENSE_1_0.txt) |
355 | |
356 | #ifndef C10_MPARK_IN_PLACE_HPP |
357 | #define C10_MPARK_IN_PLACE_HPP |
358 | |
359 | #include <c10/util/in_place.h> |
360 | |
361 | #include <cstddef> |
362 | |
363 | namespace c10 { |
364 | |
365 | #ifdef C10_MPARK_VARIABLE_TEMPLATES |
366 | template <std::size_t I> |
367 | constexpr in_place_index_t<I> in_place_index{}; |
368 | |
369 | template <typename T> |
370 | constexpr in_place_type_t<T> in_place_type{}; |
371 | #endif |
372 | |
373 | } // namespace c10 |
374 | |
375 | #endif // C10_MPARK_IN_PLACE_HPP |
376 | |
377 | // MPark.Variant |
378 | // |
379 | // Copyright Michael Park, 2015-2017 |
380 | // |
381 | // Distributed under the Boost Software License, Version 1.0. |
382 | // (See accompanying file LICENSE.md or copy at |
383 | // http://boost.org/LICENSE_1_0.txt) |
384 | |
385 | #ifndef C10_MPARK_LIB_HPP |
386 | #define C10_MPARK_LIB_HPP |
387 | |
388 | #include <functional> |
389 | #include <memory> |
390 | #include <type_traits> |
391 | #include <utility> |
392 | |
393 | #define C10_MPARK_RETURN(...) \ |
394 | noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) { \ |
395 | return __VA_ARGS__; \ |
396 | } |
397 | |
398 | namespace c10 { |
399 | namespace lib { |
400 | template <typename T> |
401 | struct identity { |
402 | using type = T; |
403 | }; |
404 | |
405 | inline namespace cpp14 { |
406 | template <typename T, std::size_t N> |
407 | struct array { |
408 | constexpr const T& operator[](std::size_t index) const { |
409 | return data[index]; |
410 | } |
411 | |
412 | T data[N == 0 ? 1 : N]; |
413 | }; |
414 | |
415 | template <typename T> |
416 | using add_pointer_t = typename std::add_pointer<T>::type; |
417 | |
418 | template <typename... Ts> |
419 | using common_type_t = typename std::common_type<Ts...>::type; |
420 | |
421 | template <typename T> |
422 | using decay_t = typename std::decay<T>::type; |
423 | |
424 | template <bool B, typename T = void> |
425 | using enable_if_t = typename std::enable_if<B, T>::type; |
426 | |
427 | template <typename T> |
428 | using remove_const_t = typename std::remove_const<T>::type; |
429 | |
430 | template <typename T> |
431 | using remove_reference_t = typename std::remove_reference<T>::type; |
432 | |
433 | template <typename T> |
434 | inline constexpr T&& forward(remove_reference_t<T>& t) noexcept { |
435 | return static_cast<T&&>(t); |
436 | } |
437 | |
438 | template <typename T> |
439 | inline constexpr T&& forward(remove_reference_t<T>&& t) noexcept { |
440 | static_assert( |
441 | !std::is_lvalue_reference<T>::value, |
442 | "can not forward an rvalue as an lvalue" ); |
443 | return static_cast<T&&>(t); |
444 | } |
445 | |
446 | template <typename T> |
447 | inline constexpr remove_reference_t<T>&& move(T&& t) noexcept { |
448 | return static_cast<remove_reference_t<T>&&>(t); |
449 | } |
450 | |
451 | #ifdef C10_MPARK_INTEGER_SEQUENCE |
452 | using std::index_sequence; |
453 | using std::index_sequence_for; |
454 | using std::integer_sequence; |
455 | using std::make_index_sequence; |
456 | #else |
457 | template <typename T, T... Is> |
458 | struct integer_sequence { |
459 | using value_type = T; |
460 | static constexpr std::size_t size() noexcept { |
461 | return sizeof...(Is); |
462 | } |
463 | }; |
464 | |
465 | template <std::size_t... Is> |
466 | using index_sequence = integer_sequence<std::size_t, Is...>; |
467 | |
468 | template <typename Lhs, typename Rhs> |
469 | struct make_index_sequence_concat; |
470 | |
471 | template <std::size_t... Lhs, std::size_t... Rhs> |
472 | struct make_index_sequence_concat< |
473 | index_sequence<Lhs...>, |
474 | index_sequence<Rhs...>> |
475 | : identity<index_sequence<Lhs..., (sizeof...(Lhs) + Rhs)...>> {}; |
476 | |
477 | template <std::size_t N> |
478 | struct make_index_sequence_impl; |
479 | |
480 | template <std::size_t N> |
481 | using make_index_sequence = typename make_index_sequence_impl<N>::type; |
482 | |
483 | template <std::size_t N> |
484 | struct make_index_sequence_impl : make_index_sequence_concat< |
485 | make_index_sequence<N / 2>, |
486 | make_index_sequence<N - (N / 2)>> {}; |
487 | |
488 | template <> |
489 | struct make_index_sequence_impl<0> : identity<index_sequence<>> {}; |
490 | |
491 | template <> |
492 | struct make_index_sequence_impl<1> : identity<index_sequence<0>> {}; |
493 | |
494 | template <typename... Ts> |
495 | using index_sequence_for = make_index_sequence<sizeof...(Ts)>; |
496 | #endif |
497 | |
498 | // <functional> |
499 | #ifdef C10_MPARK_TRANSPARENT_OPERATORS |
500 | using equal_to = std::equal_to<>; |
501 | #else |
502 | struct equal_to { |
503 | template <typename Lhs, typename Rhs> |
504 | inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const |
505 | C10_MPARK_RETURN(lib::forward<Lhs>(lhs) == lib::forward<Rhs>(rhs)) |
506 | }; |
507 | #endif |
508 | |
509 | #ifdef C10_MPARK_TRANSPARENT_OPERATORS |
510 | using not_equal_to = std::not_equal_to<>; |
511 | #else |
512 | struct not_equal_to { |
513 | template <typename Lhs, typename Rhs> |
514 | inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const |
515 | C10_MPARK_RETURN(lib::forward<Lhs>(lhs) != lib::forward<Rhs>(rhs)) |
516 | }; |
517 | #endif |
518 | |
519 | #ifdef C10_MPARK_TRANSPARENT_OPERATORS |
520 | using less = std::less<>; |
521 | #else |
522 | struct less { |
523 | template <typename Lhs, typename Rhs> |
524 | inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const |
525 | C10_MPARK_RETURN(lib::forward<Lhs>(lhs) < lib::forward<Rhs>(rhs)) |
526 | }; |
527 | #endif |
528 | |
529 | #ifdef C10_MPARK_TRANSPARENT_OPERATORS |
530 | using greater = std::greater<>; |
531 | #else |
532 | struct greater { |
533 | template <typename Lhs, typename Rhs> |
534 | inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const |
535 | C10_MPARK_RETURN(lib::forward<Lhs>(lhs) > lib::forward<Rhs>(rhs)) |
536 | }; |
537 | #endif |
538 | |
539 | #ifdef C10_MPARK_TRANSPARENT_OPERATORS |
540 | using less_equal = std::less_equal<>; |
541 | #else |
542 | struct less_equal { |
543 | template <typename Lhs, typename Rhs> |
544 | inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const |
545 | C10_MPARK_RETURN(lib::forward<Lhs>(lhs) <= lib::forward<Rhs>(rhs)) |
546 | }; |
547 | #endif |
548 | |
549 | #ifdef C10_MPARK_TRANSPARENT_OPERATORS |
550 | using greater_equal = std::greater_equal<>; |
551 | #else |
552 | struct greater_equal { |
553 | template <typename Lhs, typename Rhs> |
554 | inline constexpr auto operator()(Lhs&& lhs, Rhs&& rhs) const |
555 | C10_MPARK_RETURN(lib::forward<Lhs>(lhs) >= lib::forward<Rhs>(rhs)) |
556 | }; |
557 | #endif |
558 | } // namespace cpp14 |
559 | |
560 | inline namespace cpp17 { |
561 | |
562 | // <type_traits> |
563 | template <bool B> |
564 | using bool_constant = std::integral_constant<bool, B>; |
565 | |
566 | template <typename...> |
567 | struct voider : identity<void> {}; |
568 | |
569 | template <typename... Ts> |
570 | using void_t = typename voider<Ts...>::type; |
571 | |
572 | namespace detail_ { |
573 | namespace swappable { |
574 | |
575 | using std::swap; |
576 | |
577 | template <typename T> |
578 | struct is_swappable { |
579 | private: |
580 | template < |
581 | typename U, |
582 | typename = decltype(swap(std::declval<U&>(), std::declval<U&>()))> |
583 | inline static std::true_type test(int); |
584 | |
585 | template <typename U> |
586 | inline static std::false_type test(...); |
587 | |
588 | public: |
589 | static constexpr bool value = decltype(test<T>(0))::value; |
590 | }; |
591 | |
592 | template <bool IsSwappable, typename T> |
593 | struct is_nothrow_swappable { |
594 | static constexpr bool value = |
595 | noexcept(swap(std::declval<T&>(), std::declval<T&>())); |
596 | }; |
597 | |
598 | template <typename T> |
599 | struct is_nothrow_swappable<false, T> : std::false_type {}; |
600 | |
601 | } // namespace swappable |
602 | } // namespace detail_ |
603 | |
604 | using detail_::swappable::is_swappable; |
605 | |
606 | template <typename T> |
607 | using is_nothrow_swappable = |
608 | detail_::swappable::is_nothrow_swappable<is_swappable<T>::value, T>; |
609 | |
610 | // <functional> |
611 | namespace detail_ { |
612 | |
613 | template <typename T> |
614 | struct is_reference_wrapper : std::false_type {}; |
615 | |
616 | template <typename T> |
617 | struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {}; |
618 | |
619 | template <bool, int> |
620 | struct Invoke; |
621 | |
622 | template <> |
623 | struct Invoke<true /* pmf */, 0 /* is_base_of */> { |
624 | template <typename R, typename T, typename Arg, typename... Args> |
625 | inline static constexpr auto invoke(R T::*pmf, Arg&& arg, Args&&... args) |
626 | C10_MPARK_RETURN( |
627 | (lib::forward<Arg>(arg).*pmf)(lib::forward<Args>(args)...)) |
628 | }; |
629 | |
630 | template <> |
631 | struct Invoke<true /* pmf */, 1 /* is_reference_wrapper */> { |
632 | template <typename R, typename T, typename Arg, typename... Args> |
633 | inline static constexpr auto invoke(R T::*pmf, Arg&& arg, Args&&... args) |
634 | C10_MPARK_RETURN( |
635 | (lib::forward<Arg>(arg).get().*pmf)(lib::forward<Args>(args)...)) |
636 | }; |
637 | |
638 | template <> |
639 | struct Invoke<true /* pmf */, 2 /* otherwise */> { |
640 | template <typename R, typename T, typename Arg, typename... Args> |
641 | inline static constexpr auto invoke(R T::*pmf, Arg&& arg, Args&&... args) |
642 | C10_MPARK_RETURN( |
643 | ((*lib::forward<Arg>(arg)).*pmf)(lib::forward<Args>(args)...)) |
644 | }; |
645 | |
646 | template <> |
647 | struct Invoke<false /* pmo */, 0 /* is_base_of */> { |
648 | template <typename R, typename T, typename Arg> |
649 | inline static constexpr auto invoke(R T::*pmo, Arg&& arg) |
650 | C10_MPARK_RETURN(lib::forward<Arg>(arg).*pmo) |
651 | }; |
652 | |
653 | template <> |
654 | struct Invoke<false /* pmo */, 1 /* is_reference_wrapper */> { |
655 | template <typename R, typename T, typename Arg> |
656 | inline static constexpr auto invoke(R T::*pmo, Arg&& arg) |
657 | C10_MPARK_RETURN(lib::forward<Arg>(arg).get().*pmo) |
658 | }; |
659 | |
660 | template <> |
661 | struct Invoke<false /* pmo */, 2 /* otherwise */> { |
662 | template <typename R, typename T, typename Arg> |
663 | inline static constexpr auto invoke(R T::*pmo, Arg&& arg) |
664 | C10_MPARK_RETURN((*lib::forward<Arg>(arg)).*pmo) |
665 | }; |
666 | |
667 | template <typename R, typename T, typename Arg, typename... Args> |
668 | inline constexpr auto invoke(R T::*f, Arg&& arg, Args&&... args) |
669 | C10_MPARK_RETURN( |
670 | Invoke< |
671 | std::is_function<R>::value, |
672 | (std::is_base_of<T, lib::decay_t<Arg>>::value ? 0 |
673 | : is_reference_wrapper<lib::decay_t<Arg>>::value ? 1 |
674 | : 2)>:: |
675 | invoke(f, lib::forward<Arg>(arg), lib::forward<Args>(args)...)) |
676 | |
677 | #ifdef _MSC_VER |
678 | #pragma warning(push) |
679 | #pragma warning(disable : 4100) |
680 | #endif |
681 | template <typename F, typename... Args> |
682 | inline constexpr auto invoke(F&& f, Args&&... args) |
683 | C10_MPARK_RETURN(lib::forward<F>(f)(lib::forward<Args>(args)...)) |
684 | #ifdef _MSC_VER |
685 | #pragma warning(pop) |
686 | #endif |
687 | } // namespace detail_ |
688 | |
689 | template <typename F, typename... Args> |
690 | inline constexpr auto invoke(F&& f, Args&&... args) C10_MPARK_RETURN( |
691 | detail_::invoke(lib::forward<F>(f), lib::forward<Args>(args)...)) |
692 | |
693 | namespace detail_ { |
694 | template <typename Void, typename, typename...> |
695 | struct invoke_result {}; |
696 | |
697 | template <typename F, typename... Args> |
698 | struct invoke_result< |
699 | void_t<decltype(lib::invoke(std::declval<F>(), std::declval<Args>()...))>, |
700 | F, |
701 | Args...> |
702 | : identity<decltype(lib::invoke( |
703 | std::declval<F>(), std::declval<Args>()...))> {}; |
704 | |
705 | } // namespace detail_ |
706 | |
707 | template <typename F, typename... Args> |
708 | using invoke_result = detail_::invoke_result<void, F, Args...>; |
709 | |
710 | template <typename F, typename... Args> |
711 | using invoke_result_t = typename invoke_result<F, Args...>::type; |
712 | |
713 | namespace detail_ { |
714 | |
715 | template <typename Void, typename, typename...> |
716 | struct is_invocable : std::false_type {}; |
717 | |
718 | template <typename F, typename... Args> |
719 | struct is_invocable<void_t<invoke_result_t<F, Args...>>, F, Args...> |
720 | : std::true_type {}; |
721 | |
722 | template <typename Void, typename, typename, typename...> |
723 | struct is_invocable_r : std::false_type {}; |
724 | |
725 | template <typename R, typename F, typename... Args> |
726 | struct is_invocable_r<void_t<invoke_result_t<F, Args...>>, R, F, Args...> |
727 | : std::is_convertible<invoke_result_t<F, Args...>, R> {}; |
728 | |
729 | } // namespace detail_ |
730 | |
731 | template <typename F, typename... Args> |
732 | using is_invocable = detail_::is_invocable<void, F, Args...>; |
733 | |
734 | template <typename R, typename F, typename... Args> |
735 | using is_invocable_r = detail_::is_invocable_r<void, R, F, Args...>; |
736 | |
737 | namespace detail_ { |
738 | |
739 | template <bool Invocable, typename F, typename... Args> |
740 | struct is_nothrow_invocable { |
741 | static constexpr bool value = |
742 | noexcept(lib::invoke(std::declval<F>(), std::declval<Args>()...)); |
743 | }; |
744 | |
745 | template <typename F, typename... Args> |
746 | struct is_nothrow_invocable<false, F, Args...> : std::false_type {}; |
747 | |
748 | template <bool Invocable, typename R, typename F, typename... Args> |
749 | struct is_nothrow_invocable_r { |
750 | private: |
751 | inline static R impl() { |
752 | return lib::invoke(std::declval<F>(), std::declval<Args>()...); |
753 | } |
754 | |
755 | public: |
756 | static constexpr bool value = noexcept(impl()); |
757 | }; |
758 | |
759 | template <typename R, typename F, typename... Args> |
760 | struct is_nothrow_invocable_r<false, R, F, Args...> : std::false_type {}; |
761 | |
762 | } // namespace detail_ |
763 | |
764 | template <typename F, typename... Args> |
765 | using is_nothrow_invocable = |
766 | detail_::is_nothrow_invocable<is_invocable<F, Args...>::value, F, Args...>; |
767 | |
768 | template <typename R, typename F, typename... Args> |
769 | using is_nothrow_invocable_r = detail_:: |
770 | is_nothrow_invocable_r<is_invocable_r<R, F, Args...>::value, R, F, Args...>; |
771 | |
772 | // <memory> |
773 | #ifdef C10_MPARK_BUILTIN_ADDRESSOF |
774 | template <typename T> |
775 | inline constexpr T* addressof(T& arg) noexcept { |
776 | return __builtin_addressof(arg); |
777 | } |
778 | #else |
779 | namespace detail_ { |
780 | |
781 | namespace has_addressof_impl { |
782 | |
783 | struct fail; |
784 | |
785 | template <typename T> |
786 | inline fail operator&(T&&); |
787 | |
788 | template <typename T> |
789 | inline static constexpr bool impl() { |
790 | return (std::is_class<T>::value || std::is_union<T>::value) && |
791 | !std::is_same<decltype(&std::declval<T&>()), fail>::value; |
792 | } |
793 | |
794 | } // namespace has_addressof_impl |
795 | |
796 | template <typename T> |
797 | using has_addressof = bool_constant<has_addressof_impl::impl<T>()>; |
798 | |
799 | template <typename T> |
800 | inline constexpr T* addressof(T& arg, std::true_type) noexcept { |
801 | return std::addressof(arg); |
802 | } |
803 | |
804 | template <typename T> |
805 | inline constexpr T* addressof(T& arg, std::false_type) noexcept { |
806 | return &arg; |
807 | } |
808 | |
809 | } // namespace detail_ |
810 | |
811 | template <typename T> |
812 | inline constexpr T* addressof(T& arg) noexcept { |
813 | return detail_::addressof(arg, detail_::has_addressof<T>{}); |
814 | } |
815 | #endif |
816 | |
817 | template <typename T> |
818 | inline constexpr T* addressof(const T&&) = delete; |
819 | |
820 | } // namespace cpp17 |
821 | |
822 | template <typename T> |
823 | struct remove_all_extents : identity<T> {}; |
824 | |
825 | template <typename T, std::size_t N> |
826 | struct remove_all_extents<array<T, N>> : remove_all_extents<T> {}; |
827 | |
828 | template <typename T> |
829 | using remove_all_extents_t = typename remove_all_extents<T>::type; |
830 | |
831 | template <std::size_t N> |
832 | using size_constant = std::integral_constant<std::size_t, N>; |
833 | |
834 | template <std::size_t I, typename T> |
835 | struct indexed_type : size_constant<I> { |
836 | using type = T; |
837 | }; |
838 | |
839 | template <bool... Bs> |
840 | using all = std::is_same< |
841 | integer_sequence<bool, true, Bs...>, |
842 | integer_sequence<bool, Bs..., true>>; |
843 | |
844 | #ifdef C10_MPARK_TYPE_PACK_ELEMENT |
845 | template <std::size_t I, typename... Ts> |
846 | using type_pack_element_t = __type_pack_element<I, Ts...>; |
847 | #else |
848 | template <std::size_t I, typename... Ts> |
849 | struct type_pack_element_impl { |
850 | private: |
851 | template <typename> |
852 | struct set; |
853 | |
854 | template <std::size_t... Is> |
855 | struct set<index_sequence<Is...>> : indexed_type<Is, Ts>... {}; |
856 | |
857 | template <typename T> |
858 | inline static std::enable_if<true, T> impl(indexed_type<I, T>); |
859 | |
860 | inline static std::enable_if<false> impl(...); |
861 | |
862 | public: |
863 | using type = decltype(impl(set<index_sequence_for<Ts...>>{})); |
864 | }; |
865 | |
866 | template <std::size_t I, typename... Ts> |
867 | using type_pack_element = typename type_pack_element_impl<I, Ts...>::type; |
868 | |
869 | template <std::size_t I, typename... Ts> |
870 | using type_pack_element_t = typename type_pack_element<I, Ts...>::type; |
871 | #endif |
872 | |
873 | #ifdef C10_MPARK_TRIVIALITY_TYPE_TRAITS |
874 | using std::is_trivially_copy_assignable; |
875 | using std::is_trivially_copy_constructible; |
876 | using std::is_trivially_move_assignable; |
877 | using std::is_trivially_move_constructible; |
878 | #else |
879 | template <typename T> |
880 | struct is_trivially_copy_constructible |
881 | : bool_constant<std::is_copy_constructible<T>::value&& __has_trivial_copy( |
882 | T)> {}; |
883 | |
884 | template <typename T> |
885 | struct is_trivially_move_constructible : bool_constant<__is_trivial(T)> {}; |
886 | |
887 | template <typename T> |
888 | struct is_trivially_copy_assignable |
889 | : bool_constant<std::is_copy_assignable<T>::value&& __has_trivial_assign( |
890 | T)> {}; |
891 | |
892 | template <typename T> |
893 | struct is_trivially_move_assignable : bool_constant<__is_trivial(T)> {}; |
894 | #endif |
895 | |
896 | template <typename T, bool> |
897 | struct dependent_type : T {}; |
898 | |
899 | template <typename Is, std::size_t J> |
900 | struct push_back; |
901 | |
902 | template <typename Is, std::size_t J> |
903 | using push_back_t = typename push_back<Is, J>::type; |
904 | |
905 | template <std::size_t... Is, std::size_t J> |
906 | struct push_back<index_sequence<Is...>, J> { |
907 | using type = index_sequence<Is..., J>; |
908 | }; |
909 | |
910 | } // namespace lib |
911 | } // namespace c10 |
912 | |
913 | #undef C10_MPARK_RETURN |
914 | |
915 | #endif // C10_MPARK_LIB_HPP |
916 | |
917 | namespace c10 { |
918 | |
919 | #ifdef C10_MPARK_RETURN_TYPE_DEDUCTION |
920 | |
921 | #define AUTO auto |
922 | #define AUTO_RETURN(...) \ |
923 | { return __VA_ARGS__; } |
924 | |
925 | #define AUTO_REFREF auto&& |
926 | #define AUTO_REFREF_RETURN(...) \ |
927 | { return __VA_ARGS__; } |
928 | |
929 | #define DECLTYPE_AUTO decltype(auto) |
930 | #define DECLTYPE_AUTO_RETURN(...) \ |
931 | { return __VA_ARGS__; } |
932 | |
933 | #else |
934 | |
935 | #define AUTO auto |
936 | #define AUTO_RETURN(...) \ |
937 | ->lib::decay_t<decltype(__VA_ARGS__)> { \ |
938 | return __VA_ARGS__; \ |
939 | } |
940 | |
941 | #define AUTO_REFREF auto |
942 | #define AUTO_REFREF_RETURN(...) \ |
943 | ->decltype((__VA_ARGS__)) { \ |
944 | static_assert(std::is_reference<decltype((__VA_ARGS__))>::value, ""); \ |
945 | return __VA_ARGS__; \ |
946 | } |
947 | |
948 | #define DECLTYPE_AUTO auto |
949 | #define DECLTYPE_AUTO_RETURN(...) \ |
950 | ->decltype(__VA_ARGS__) { \ |
951 | return __VA_ARGS__; \ |
952 | } |
953 | |
954 | #endif |
955 | |
956 | class bad_variant_access : public std::exception { |
957 | public: |
958 | const char* what() const noexcept override { |
959 | return "bad_variant_access" ; |
960 | } |
961 | }; |
962 | |
963 | [[noreturn]] inline void throw_bad_variant_access() { |
964 | #ifdef C10_MPARK_EXCEPTIONS |
965 | throw bad_variant_access{}; |
966 | #else |
967 | std::terminate(); |
968 | C10_MPARK_BUILTIN_UNREACHABLE; |
969 | #endif |
970 | } |
971 | |
972 | template <typename... Ts> |
973 | class variant; |
974 | |
975 | template <typename T> |
976 | struct variant_size; |
977 | |
978 | #ifdef C10_MPARK_VARIABLE_TEMPLATES |
979 | template <typename T> |
980 | constexpr std::size_t variant_size_v = variant_size<T>::value; |
981 | #endif |
982 | |
983 | template <typename T> |
984 | struct variant_size<const T> : variant_size<T> {}; |
985 | |
986 | template <typename T> |
987 | struct variant_size<volatile T> : variant_size<T> {}; |
988 | |
989 | template <typename T> |
990 | struct variant_size<const volatile T> : variant_size<T> {}; |
991 | |
992 | template <typename... Ts> |
993 | struct variant_size<variant<Ts...>> : lib::size_constant<sizeof...(Ts)> {}; |
994 | |
995 | template <std::size_t I, typename T> |
996 | struct variant_alternative; |
997 | |
998 | template <std::size_t I, typename T> |
999 | using variant_alternative_t = typename variant_alternative<I, T>::type; |
1000 | |
1001 | template <std::size_t I, typename T> |
1002 | struct variant_alternative<I, const T> |
1003 | : std::add_const<variant_alternative_t<I, T>> {}; |
1004 | |
1005 | template <std::size_t I, typename T> |
1006 | struct variant_alternative<I, volatile T> |
1007 | : std::add_volatile<variant_alternative_t<I, T>> {}; |
1008 | |
1009 | template <std::size_t I, typename T> |
1010 | struct variant_alternative<I, const volatile T> |
1011 | : std::add_cv<variant_alternative_t<I, T>> {}; |
1012 | |
1013 | template <std::size_t I, typename... Ts> |
1014 | struct variant_alternative<I, variant<Ts...>> { |
1015 | static_assert( |
1016 | I < sizeof...(Ts), |
1017 | "index out of bounds in `std::variant_alternative<>`" ); |
1018 | using type = lib::type_pack_element_t<I, Ts...>; |
1019 | }; |
1020 | |
1021 | constexpr std::size_t variant_npos = static_cast<std::size_t>(-1); |
1022 | |
1023 | namespace detail_ { |
1024 | |
1025 | constexpr std::size_t not_found = static_cast<std::size_t>(-1); |
1026 | constexpr std::size_t ambiguous = static_cast<std::size_t>(-2); |
1027 | |
1028 | #ifdef C10_MPARK_CPP14_CONSTEXPR |
1029 | template <typename T, typename... Ts> |
1030 | inline constexpr std::size_t find_index() { |
1031 | constexpr lib::array<bool, sizeof...(Ts)> matches = { |
1032 | {std::is_same<T, Ts>::value...}}; |
1033 | std::size_t result = not_found; |
1034 | for (std::size_t i = 0; i < sizeof...(Ts); ++i) { |
1035 | if (matches[i]) { |
1036 | if (result != not_found) { |
1037 | return ambiguous; |
1038 | } |
1039 | result = i; |
1040 | } |
1041 | } |
1042 | return result; |
1043 | } |
1044 | #else |
1045 | inline constexpr std::size_t find_index_impl(std::size_t result, std::size_t) { |
1046 | return result; |
1047 | } |
1048 | |
1049 | template <typename... Bs> |
1050 | inline constexpr std::size_t find_index_impl( |
1051 | std::size_t result, |
1052 | std::size_t idx, |
1053 | bool b, |
1054 | Bs... bs) { |
1055 | return b |
1056 | ? (result != not_found ? ambiguous : find_index_impl(idx, idx + 1, bs...)) |
1057 | : find_index_impl(result, idx + 1, bs...); |
1058 | } |
1059 | |
1060 | template <typename T, typename... Ts> |
1061 | inline constexpr std::size_t find_index() { |
1062 | return find_index_impl(not_found, 0, std::is_same<T, Ts>::value...); |
1063 | } |
1064 | #endif |
1065 | |
1066 | template <std::size_t I> |
1067 | using find_index_sfinae_impl = |
1068 | lib::enable_if_t<I != not_found && I != ambiguous, lib::size_constant<I>>; |
1069 | |
1070 | template <typename T, typename... Ts> |
1071 | using find_index_sfinae = find_index_sfinae_impl<find_index<T, Ts...>()>; |
1072 | |
1073 | template <std::size_t I> |
1074 | struct find_index_checked_impl : lib::size_constant<I> { |
1075 | static_assert(I != not_found, "the specified type is not found." ); |
1076 | static_assert(I != ambiguous, "the specified type is ambiguous." ); |
1077 | }; |
1078 | |
1079 | template <typename T, typename... Ts> |
1080 | using find_index_checked = find_index_checked_impl<find_index<T, Ts...>()>; |
1081 | |
1082 | struct valueless_t {}; |
1083 | |
1084 | enum class Trait { TriviallyAvailable, Available, Unavailable }; |
1085 | |
1086 | template < |
1087 | typename T, |
1088 | template <typename> |
1089 | class IsTriviallyAvailable, |
1090 | template <typename> |
1091 | class IsAvailable> |
1092 | inline constexpr Trait trait() { |
1093 | return IsTriviallyAvailable<T>::value ? Trait::TriviallyAvailable |
1094 | : IsAvailable<T>::value ? Trait::Available |
1095 | : Trait::Unavailable; |
1096 | } |
1097 | |
1098 | #ifdef C10_MPARK_CPP14_CONSTEXPR |
1099 | template <typename... Traits> |
1100 | inline constexpr Trait common_trait(Traits... traits_) { |
1101 | Trait result = Trait::TriviallyAvailable; |
1102 | lib::array<Trait, sizeof...(Traits)> traits = {{traits_...}}; |
1103 | for (std::size_t i = 0; i < sizeof...(Traits); ++i) { |
1104 | Trait t = traits[i]; |
1105 | if (static_cast<int>(t) > static_cast<int>(result)) { |
1106 | result = t; |
1107 | } |
1108 | } |
1109 | return result; |
1110 | } |
1111 | #else |
1112 | inline constexpr Trait common_trait_impl(Trait result) { |
1113 | return result; |
1114 | } |
1115 | |
1116 | template <typename... Traits> |
1117 | inline constexpr Trait common_trait_impl(Trait result, Trait t, Traits... ts) { |
1118 | return static_cast<int>(t) > static_cast<int>(result) |
1119 | ? common_trait_impl(t, ts...) |
1120 | : common_trait_impl(result, ts...); |
1121 | } |
1122 | |
1123 | template <typename... Traits> |
1124 | inline constexpr Trait common_trait(Traits... ts) { |
1125 | return common_trait_impl(Trait::TriviallyAvailable, ts...); |
1126 | } |
1127 | #endif |
1128 | |
1129 | template <typename... Ts> |
1130 | struct traits { |
1131 | static constexpr Trait copy_constructible_trait = |
1132 | common_trait(trait< |
1133 | Ts, |
1134 | lib::is_trivially_copy_constructible, |
1135 | std::is_copy_constructible>()...); |
1136 | |
1137 | static constexpr Trait move_constructible_trait = |
1138 | common_trait(trait< |
1139 | Ts, |
1140 | lib::is_trivially_move_constructible, |
1141 | std::is_move_constructible>()...); |
1142 | |
1143 | static constexpr Trait copy_assignable_trait = common_trait( |
1144 | copy_constructible_trait, |
1145 | trait< |
1146 | Ts, |
1147 | lib::is_trivially_copy_assignable, |
1148 | std::is_copy_assignable>()...); |
1149 | |
1150 | static constexpr Trait move_assignable_trait = common_trait( |
1151 | move_constructible_trait, |
1152 | trait< |
1153 | Ts, |
1154 | lib::is_trivially_move_assignable, |
1155 | std::is_move_assignable>()...); |
1156 | |
1157 | static constexpr Trait destructible_trait = common_trait( |
1158 | trait<Ts, std::is_trivially_destructible, std::is_destructible>()...); |
1159 | }; |
1160 | |
1161 | namespace access { |
1162 | |
1163 | struct recursive_union { |
1164 | #ifdef C10_MPARK_RETURN_TYPE_DEDUCTION |
1165 | template <typename V> |
1166 | inline static constexpr auto&& get_alt(V&& v, in_place_index_t<0>) { |
1167 | return lib::forward<V>(v).head_; |
1168 | } |
1169 | |
1170 | template <typename V, std::size_t I> |
1171 | inline static constexpr auto&& get_alt(V&& v, in_place_index_t<I>) { |
1172 | return get_alt(lib::forward<V>(v).tail_, in_place_index_t<I - 1>{}); |
1173 | } |
1174 | #else |
1175 | template <std::size_t I, bool Dummy = true> |
1176 | struct get_alt_impl { |
1177 | template <typename V> |
1178 | inline constexpr AUTO_REFREF operator()(V&& v) const |
1179 | AUTO_REFREF_RETURN(get_alt_impl<I - 1>{}(lib::forward<V>(v).tail_)) |
1180 | }; |
1181 | |
1182 | template <bool Dummy> |
1183 | struct get_alt_impl<0, Dummy> { |
1184 | template <typename V> |
1185 | inline constexpr AUTO_REFREF operator()(V&& v) const |
1186 | AUTO_REFREF_RETURN(lib::forward<V>(v).head_) |
1187 | }; |
1188 | |
1189 | template <typename V, std::size_t I> |
1190 | inline static constexpr AUTO_REFREF get_alt(V&& v, in_place_index_t<I>) |
1191 | AUTO_REFREF_RETURN(get_alt_impl<I>{}(lib::forward<V>(v))) |
1192 | #endif |
1193 | }; |
1194 | |
1195 | struct base { |
1196 | template <std::size_t I, typename V> |
1197 | inline static constexpr AUTO_REFREF get_alt(V&& v) |
1198 | #ifdef _MSC_VER |
1199 | AUTO_REFREF_RETURN(recursive_union::get_alt( |
1200 | lib::forward<V>(v).data_, |
1201 | in_place_index_t<I>{})) |
1202 | #else |
1203 | AUTO_REFREF_RETURN(recursive_union::get_alt( |
1204 | data(lib::forward<V>(v)), |
1205 | in_place_index_t<I>{})) |
1206 | #endif |
1207 | }; |
1208 | |
1209 | struct variant { |
1210 | template <std::size_t I, typename V> |
1211 | inline static constexpr AUTO_REFREF get_alt(V&& v) |
1212 | AUTO_REFREF_RETURN(base::get_alt<I>(lib::forward<V>(v).impl_)) |
1213 | }; |
1214 | |
1215 | } // namespace access |
1216 | |
1217 | namespace visitation { |
1218 | |
1219 | #if defined(C10_MPARK_CPP14_CONSTEXPR) && !defined(_MSC_VER) |
1220 | #define C10_MPARK_VARIANT_SWITCH_VISIT |
1221 | #endif |
1222 | |
1223 | struct base { |
1224 | template <typename Visitor, typename... Vs> |
1225 | using dispatch_result_t = decltype(lib::invoke( |
1226 | std::declval<Visitor>(), |
1227 | access::base::get_alt<0>(std::declval<Vs>())...)); |
1228 | |
1229 | template <typename Expected> |
1230 | struct expected { |
1231 | template <typename Actual> |
1232 | inline static constexpr bool but_got() { |
1233 | return std::is_same<Expected, Actual>::value; |
1234 | } |
1235 | }; |
1236 | |
1237 | template <typename Expected, typename Actual> |
1238 | struct visit_return_type_check { |
1239 | static_assert( |
1240 | expected<Expected>::template but_got<Actual>(), |
1241 | "`visit` requires the visitor to have a single return type" ); |
1242 | |
1243 | template <typename Visitor, typename... Alts> |
1244 | inline static constexpr DECLTYPE_AUTO invoke( |
1245 | Visitor&& visitor, |
1246 | Alts&&... alts) |
1247 | DECLTYPE_AUTO_RETURN(lib::invoke( |
1248 | lib::forward<Visitor>(visitor), |
1249 | lib::forward<Alts>(alts)...)) |
1250 | }; |
1251 | |
1252 | #ifdef C10_MPARK_VARIANT_SWITCH_VISIT |
1253 | template <bool B, typename R, typename... ITs> |
1254 | struct dispatcher; |
1255 | |
1256 | template <typename R, typename... ITs> |
1257 | struct dispatcher<false, R, ITs...> { |
1258 | template <std::size_t B, typename F, typename... Vs> |
1259 | C10_MPARK_ALWAYS_INLINE static constexpr R dispatch( |
1260 | F&&, |
1261 | typename ITs::type&&..., |
1262 | Vs&&...) { |
1263 | C10_MPARK_BUILTIN_UNREACHABLE; |
1264 | } |
1265 | |
1266 | template <std::size_t I, typename F, typename... Vs> |
1267 | C10_MPARK_ALWAYS_INLINE static constexpr R dispatch_case(F&&, Vs&&...) { |
1268 | C10_MPARK_BUILTIN_UNREACHABLE; |
1269 | } |
1270 | |
1271 | template <std::size_t B, typename F, typename... Vs> |
1272 | C10_MPARK_ALWAYS_INLINE static constexpr R dispatch_at( |
1273 | std::size_t, |
1274 | F&&, |
1275 | Vs&&...) { |
1276 | C10_MPARK_BUILTIN_UNREACHABLE; |
1277 | } |
1278 | }; |
1279 | |
1280 | template <typename R, typename... ITs> |
1281 | struct dispatcher<true, R, ITs...> { |
1282 | template <std::size_t B, typename F> |
1283 | C10_MPARK_ALWAYS_INLINE static constexpr R dispatch( |
1284 | F&& f, |
1285 | typename ITs::type&&... visited_vs) { |
1286 | using Expected = R; |
1287 | using Actual = decltype(lib::invoke( |
1288 | lib::forward<F>(f), |
1289 | access::base::get_alt<ITs::value>( |
1290 | lib::forward<typename ITs::type>(visited_vs))...)); |
1291 | return visit_return_type_check<Expected, Actual>::invoke( |
1292 | lib::forward<F>(f), |
1293 | access::base::get_alt<ITs::value>( |
1294 | lib::forward<typename ITs::type>(visited_vs))...); |
1295 | } |
1296 | |
1297 | template <std::size_t B, typename F, typename V, typename... Vs> |
1298 | C10_MPARK_ALWAYS_INLINE static constexpr R dispatch( |
1299 | F&& f, |
1300 | typename ITs::type&&... visited_vs, |
1301 | V&& v, |
1302 | Vs&&... vs) { |
1303 | #define C10_MPARK_DISPATCH(I) \ |
1304 | dispatcher< \ |
1305 | (I < lib::decay_t<V>::size()), \ |
1306 | R, \ |
1307 | ITs..., \ |
1308 | lib::indexed_type<I, V>>:: \ |
1309 | template dispatch<0>( \ |
1310 | lib::forward<F>(f), \ |
1311 | lib::forward<typename ITs::type>(visited_vs)..., \ |
1312 | lib::forward<V>(v), \ |
1313 | lib::forward<Vs>(vs)...) |
1314 | |
1315 | #define C10_MPARK_DEFAULT(I) \ |
1316 | dispatcher<(I < lib::decay_t<V>::size()), R, ITs...>::template dispatch<I>( \ |
1317 | lib::forward<F>(f), \ |
1318 | lib::forward<typename ITs::type>(visited_vs)..., \ |
1319 | lib::forward<V>(v), \ |
1320 | lib::forward<Vs>(vs)...) |
1321 | |
1322 | switch (v.index()) { |
1323 | case B + 0: |
1324 | return C10_MPARK_DISPATCH(B + 0); |
1325 | case B + 1: |
1326 | return C10_MPARK_DISPATCH(B + 1); |
1327 | case B + 2: |
1328 | return C10_MPARK_DISPATCH(B + 2); |
1329 | case B + 3: |
1330 | return C10_MPARK_DISPATCH(B + 3); |
1331 | case B + 4: |
1332 | return C10_MPARK_DISPATCH(B + 4); |
1333 | case B + 5: |
1334 | return C10_MPARK_DISPATCH(B + 5); |
1335 | case B + 6: |
1336 | return C10_MPARK_DISPATCH(B + 6); |
1337 | case B + 7: |
1338 | return C10_MPARK_DISPATCH(B + 7); |
1339 | case B + 8: |
1340 | return C10_MPARK_DISPATCH(B + 8); |
1341 | case B + 9: |
1342 | return C10_MPARK_DISPATCH(B + 9); |
1343 | case B + 10: |
1344 | return C10_MPARK_DISPATCH(B + 10); |
1345 | case B + 11: |
1346 | return C10_MPARK_DISPATCH(B + 11); |
1347 | case B + 12: |
1348 | return C10_MPARK_DISPATCH(B + 12); |
1349 | case B + 13: |
1350 | return C10_MPARK_DISPATCH(B + 13); |
1351 | case B + 14: |
1352 | return C10_MPARK_DISPATCH(B + 14); |
1353 | case B + 15: |
1354 | return C10_MPARK_DISPATCH(B + 15); |
1355 | case B + 16: |
1356 | return C10_MPARK_DISPATCH(B + 16); |
1357 | case B + 17: |
1358 | return C10_MPARK_DISPATCH(B + 17); |
1359 | case B + 18: |
1360 | return C10_MPARK_DISPATCH(B + 18); |
1361 | case B + 19: |
1362 | return C10_MPARK_DISPATCH(B + 19); |
1363 | case B + 20: |
1364 | return C10_MPARK_DISPATCH(B + 20); |
1365 | case B + 21: |
1366 | return C10_MPARK_DISPATCH(B + 21); |
1367 | case B + 22: |
1368 | return C10_MPARK_DISPATCH(B + 22); |
1369 | case B + 23: |
1370 | return C10_MPARK_DISPATCH(B + 23); |
1371 | case B + 24: |
1372 | return C10_MPARK_DISPATCH(B + 24); |
1373 | case B + 25: |
1374 | return C10_MPARK_DISPATCH(B + 25); |
1375 | case B + 26: |
1376 | return C10_MPARK_DISPATCH(B + 26); |
1377 | case B + 27: |
1378 | return C10_MPARK_DISPATCH(B + 27); |
1379 | case B + 28: |
1380 | return C10_MPARK_DISPATCH(B + 28); |
1381 | case B + 29: |
1382 | return C10_MPARK_DISPATCH(B + 29); |
1383 | case B + 30: |
1384 | return C10_MPARK_DISPATCH(B + 30); |
1385 | case B + 31: |
1386 | return C10_MPARK_DISPATCH(B + 31); |
1387 | default: |
1388 | return C10_MPARK_DEFAULT(B + 32); |
1389 | } |
1390 | |
1391 | #undef C10_MPARK_DEFAULT |
1392 | #undef C10_MPARK_DISPATCH |
1393 | } |
1394 | |
1395 | template <std::size_t I, typename F, typename... Vs> |
1396 | C10_MPARK_ALWAYS_INLINE static constexpr R dispatch_case( |
1397 | F&& f, |
1398 | Vs&&... vs) { |
1399 | using Expected = R; |
1400 | using Actual = decltype(lib::invoke( |
1401 | lib::forward<F>(f), |
1402 | access::base::get_alt<I>(lib::forward<Vs>(vs))...)); |
1403 | return visit_return_type_check<Expected, Actual>::invoke( |
1404 | lib::forward<F>(f), |
1405 | access::base::get_alt<I>(lib::forward<Vs>(vs))...); |
1406 | } |
1407 | |
1408 | template <std::size_t B, typename F, typename V, typename... Vs> |
1409 | C10_MPARK_ALWAYS_INLINE static constexpr R dispatch_at( |
1410 | std::size_t index, |
1411 | F&& f, |
1412 | V&& v, |
1413 | Vs&&... vs) { |
1414 | static_assert( |
1415 | lib::all<( |
1416 | lib::decay_t<V>::size() == lib::decay_t<Vs>::size())...>::value, |
1417 | "all of the variants must be the same size." ); |
1418 | #define C10_MPARK_DISPATCH_AT(I) \ |
1419 | dispatcher<(I < lib::decay_t<V>::size()), R>::template dispatch_case<I>( \ |
1420 | lib::forward<F>(f), lib::forward<V>(v), lib::forward<Vs>(vs)...) |
1421 | |
1422 | #define C10_MPARK_DEFAULT(I) \ |
1423 | dispatcher<(I < lib::decay_t<V>::size()), R>::template dispatch_at<I>( \ |
1424 | index, lib::forward<F>(f), lib::forward<V>(v), lib::forward<Vs>(vs)...) |
1425 | |
1426 | switch (index) { |
1427 | case B + 0: |
1428 | return C10_MPARK_DISPATCH_AT(B + 0); |
1429 | case B + 1: |
1430 | return C10_MPARK_DISPATCH_AT(B + 1); |
1431 | case B + 2: |
1432 | return C10_MPARK_DISPATCH_AT(B + 2); |
1433 | case B + 3: |
1434 | return C10_MPARK_DISPATCH_AT(B + 3); |
1435 | case B + 4: |
1436 | return C10_MPARK_DISPATCH_AT(B + 4); |
1437 | case B + 5: |
1438 | return C10_MPARK_DISPATCH_AT(B + 5); |
1439 | case B + 6: |
1440 | return C10_MPARK_DISPATCH_AT(B + 6); |
1441 | case B + 7: |
1442 | return C10_MPARK_DISPATCH_AT(B + 7); |
1443 | case B + 8: |
1444 | return C10_MPARK_DISPATCH_AT(B + 8); |
1445 | case B + 9: |
1446 | return C10_MPARK_DISPATCH_AT(B + 9); |
1447 | case B + 10: |
1448 | return C10_MPARK_DISPATCH_AT(B + 10); |
1449 | case B + 11: |
1450 | return C10_MPARK_DISPATCH_AT(B + 11); |
1451 | case B + 12: |
1452 | return C10_MPARK_DISPATCH_AT(B + 12); |
1453 | case B + 13: |
1454 | return C10_MPARK_DISPATCH_AT(B + 13); |
1455 | case B + 14: |
1456 | return C10_MPARK_DISPATCH_AT(B + 14); |
1457 | case B + 15: |
1458 | return C10_MPARK_DISPATCH_AT(B + 15); |
1459 | case B + 16: |
1460 | return C10_MPARK_DISPATCH_AT(B + 16); |
1461 | case B + 17: |
1462 | return C10_MPARK_DISPATCH_AT(B + 17); |
1463 | case B + 18: |
1464 | return C10_MPARK_DISPATCH_AT(B + 18); |
1465 | case B + 19: |
1466 | return C10_MPARK_DISPATCH_AT(B + 19); |
1467 | case B + 20: |
1468 | return C10_MPARK_DISPATCH_AT(B + 20); |
1469 | case B + 21: |
1470 | return C10_MPARK_DISPATCH_AT(B + 21); |
1471 | case B + 22: |
1472 | return C10_MPARK_DISPATCH_AT(B + 22); |
1473 | case B + 23: |
1474 | return C10_MPARK_DISPATCH_AT(B + 23); |
1475 | case B + 24: |
1476 | return C10_MPARK_DISPATCH_AT(B + 24); |
1477 | case B + 25: |
1478 | return C10_MPARK_DISPATCH_AT(B + 25); |
1479 | case B + 26: |
1480 | return C10_MPARK_DISPATCH_AT(B + 26); |
1481 | case B + 27: |
1482 | return C10_MPARK_DISPATCH_AT(B + 27); |
1483 | case B + 28: |
1484 | return C10_MPARK_DISPATCH_AT(B + 28); |
1485 | case B + 29: |
1486 | return C10_MPARK_DISPATCH_AT(B + 29); |
1487 | case B + 30: |
1488 | return C10_MPARK_DISPATCH_AT(B + 30); |
1489 | case B + 31: |
1490 | return C10_MPARK_DISPATCH_AT(B + 31); |
1491 | default: |
1492 | return C10_MPARK_DEFAULT(B + 32); |
1493 | } |
1494 | |
1495 | #undef C10_MPARK_DEFAULT |
1496 | #undef C10_MPARK_DISPATCH_AT |
1497 | } |
1498 | }; |
1499 | #else |
1500 | template <typename T> |
1501 | inline static constexpr const T& at(const T& elem) noexcept { |
1502 | return elem; |
1503 | } |
1504 | |
1505 | template <typename T, std::size_t N, typename... Is> |
1506 | inline static constexpr const lib::remove_all_extents_t<T>& at( |
1507 | const lib::array<T, N>& elems, |
1508 | std::size_t i, |
1509 | Is... is) noexcept { |
1510 | return at(elems[i], is...); |
1511 | } |
1512 | |
1513 | template <typename F, typename... Fs> |
1514 | inline static constexpr lib::array<lib::decay_t<F>, sizeof...(Fs) + 1> |
1515 | make_farray(F&& f, Fs&&... fs) { |
1516 | return {{lib::forward<F>(f), lib::forward<Fs>(fs)...}}; |
1517 | } |
1518 | |
1519 | template <typename F, typename... Vs> |
1520 | struct make_fmatrix_impl { |
1521 | template <std::size_t... Is> |
1522 | inline static constexpr dispatch_result_t<F, Vs...> dispatch( |
1523 | F&& f, |
1524 | Vs&&... vs) { |
1525 | using Expected = dispatch_result_t<F, Vs...>; |
1526 | using Actual = decltype(lib::invoke( |
1527 | lib::forward<F>(f), |
1528 | access::base::get_alt<Is>(lib::forward<Vs>(vs))...)); |
1529 | return visit_return_type_check<Expected, Actual>::invoke( |
1530 | lib::forward<F>(f), |
1531 | access::base::get_alt<Is>(lib::forward<Vs>(vs))...); |
1532 | } |
1533 | |
1534 | #ifdef C10_MPARK_RETURN_TYPE_DEDUCTION |
1535 | template <std::size_t... Is> |
1536 | inline static constexpr auto impl(lib::index_sequence<Is...>) { |
1537 | return &dispatch<Is...>; |
1538 | } |
1539 | |
1540 | template <typename Is, std::size_t... Js, typename... Ls> |
1541 | inline static constexpr auto impl( |
1542 | Is, |
1543 | lib::index_sequence<Js...>, |
1544 | Ls... ls) { |
1545 | return make_farray(impl(lib::push_back_t<Is, Js>{}, ls...)...); |
1546 | } |
1547 | #else |
1548 | template <typename...> |
1549 | struct impl; |
1550 | |
1551 | template <std::size_t... Is> |
1552 | struct impl<lib::index_sequence<Is...>> { |
1553 | inline constexpr AUTO operator()() const AUTO_RETURN(&dispatch<Is...>) |
1554 | }; |
1555 | |
1556 | template <typename Is, std::size_t... Js, typename... Ls> |
1557 | struct impl<Is, lib::index_sequence<Js...>, Ls...> { |
1558 | inline constexpr AUTO operator()() const |
1559 | AUTO_RETURN(make_farray(impl<lib::push_back_t<Is, Js>, Ls...>{}()...)) |
1560 | }; |
1561 | #endif |
1562 | }; |
1563 | |
1564 | #ifdef C10_MPARK_RETURN_TYPE_DEDUCTION |
1565 | template <typename F, typename... Vs> |
1566 | inline static constexpr auto make_fmatrix() { |
1567 | return make_fmatrix_impl<F, Vs...>::impl( |
1568 | lib::index_sequence<>{}, |
1569 | lib::make_index_sequence<lib::decay_t<Vs>::size()>{}...); |
1570 | } |
1571 | #else |
1572 | template <typename F, typename... Vs> |
1573 | inline static constexpr AUTO make_fmatrix() |
1574 | AUTO_RETURN(typename make_fmatrix_impl<F, Vs...>::template impl< |
1575 | lib::index_sequence<>, |
1576 | lib::make_index_sequence<lib::decay_t<Vs>::size()>...>{}()) |
1577 | #endif |
1578 | |
1579 | template <typename F, typename... Vs> |
1580 | struct make_fdiagonal_impl { |
1581 | template <std::size_t I> |
1582 | inline static constexpr dispatch_result_t<F, Vs...> dispatch( |
1583 | F&& f, |
1584 | Vs&&... vs) { |
1585 | using Expected = dispatch_result_t<F, Vs...>; |
1586 | using Actual = decltype(lib::invoke( |
1587 | lib::forward<F>(f), |
1588 | access::base::get_alt<I>(lib::forward<Vs>(vs))...)); |
1589 | return visit_return_type_check<Expected, Actual>::invoke( |
1590 | lib::forward<F>(f), |
1591 | access::base::get_alt<I>(lib::forward<Vs>(vs))...); |
1592 | } |
1593 | |
1594 | template <std::size_t... Is> |
1595 | inline static constexpr AUTO impl(lib::index_sequence<Is...>) |
1596 | AUTO_RETURN(make_farray(&dispatch<Is>...)) |
1597 | }; |
1598 | |
1599 | template <typename F, typename V, typename... Vs> |
1600 | inline static constexpr auto make_fdiagonal() |
1601 | -> decltype(make_fdiagonal_impl<F, V, Vs...>::impl( |
1602 | lib::make_index_sequence<lib::decay_t<V>::size()>{})) { |
1603 | static_assert( |
1604 | lib::all<( |
1605 | lib::decay_t<V>::size() == lib::decay_t<Vs>::size())...>::value, |
1606 | "all of the variants must be the same size." ); |
1607 | return make_fdiagonal_impl<F, V, Vs...>::impl( |
1608 | lib::make_index_sequence<lib::decay_t<V>::size()>{}); |
1609 | } |
1610 | #endif |
1611 | }; |
1612 | |
1613 | #if !defined(C10_MPARK_VARIANT_SWITCH_VISIT) && \ |
1614 | (!defined(_MSC_VER) || _MSC_VER >= 1910) |
1615 | template <typename F, typename... Vs> |
1616 | using fmatrix_t = decltype(base::make_fmatrix<F, Vs...>()); |
1617 | |
1618 | template <typename F, typename... Vs> |
1619 | struct fmatrix { |
1620 | static constexpr fmatrix_t<F, Vs...> value = base::make_fmatrix<F, Vs...>(); |
1621 | }; |
1622 | |
1623 | template <typename F, typename... Vs> |
1624 | constexpr fmatrix_t<F, Vs...> fmatrix<F, Vs...>::value; |
1625 | |
1626 | template <typename F, typename... Vs> |
1627 | using fdiagonal_t = decltype(base::make_fdiagonal<F, Vs...>()); |
1628 | |
1629 | template <typename F, typename... Vs> |
1630 | struct fdiagonal { |
1631 | static constexpr fdiagonal_t<F, Vs...> value = |
1632 | base::make_fdiagonal<F, Vs...>(); |
1633 | }; |
1634 | |
1635 | template <typename F, typename... Vs> |
1636 | constexpr fdiagonal_t<F, Vs...> fdiagonal<F, Vs...>::value; |
1637 | #endif |
1638 | |
1639 | struct alt { |
1640 | template <typename Visitor, typename... Vs> |
1641 | inline static constexpr DECLTYPE_AUTO visit_alt(Visitor&& visitor, Vs&&... vs) |
1642 | #ifdef C10_MPARK_VARIANT_SWITCH_VISIT |
1643 | DECLTYPE_AUTO_RETURN(base::dispatcher< |
1644 | true, |
1645 | base::dispatch_result_t< |
1646 | Visitor, |
1647 | decltype(as_base(lib::forward<Vs>(vs)))...>>:: |
1648 | template dispatch<0>( |
1649 | lib::forward<Visitor>(visitor), |
1650 | as_base(lib::forward<Vs>(vs))...)) |
1651 | #elif !defined(_MSC_VER) || _MSC_VER >= 1910 |
1652 | DECLTYPE_AUTO_RETURN(base::at( |
1653 | fmatrix<Visitor&&, decltype(as_base(lib::forward<Vs>(vs)))...>::value, |
1654 | vs.index()...)( |
1655 | lib::forward<Visitor>(visitor), |
1656 | as_base(lib::forward<Vs>(vs))...)) |
1657 | #else |
1658 | DECLTYPE_AUTO_RETURN(base::at( |
1659 | base::make_fmatrix< |
1660 | Visitor&&, |
1661 | decltype(as_base(lib::forward<Vs>(vs)))...>(), |
1662 | vs.index()...)( |
1663 | lib::forward<Visitor>(visitor), |
1664 | as_base(lib::forward<Vs>(vs))...)) |
1665 | #endif |
1666 | |
1667 | template <typename Visitor, typename... Vs> |
1668 | inline static constexpr DECLTYPE_AUTO |
1669 | visit_alt_at(std::size_t index, Visitor&& visitor, Vs&&... vs) |
1670 | #ifdef C10_MPARK_VARIANT_SWITCH_VISIT |
1671 | DECLTYPE_AUTO_RETURN( |
1672 | base::dispatcher< |
1673 | true, |
1674 | base::dispatch_result_t< |
1675 | Visitor, |
1676 | decltype(as_base(lib::forward<Vs>(vs)))...>>:: |
1677 | template dispatch_at<0>( |
1678 | index, |
1679 | lib::forward<Visitor>(visitor), |
1680 | as_base(lib::forward<Vs>(vs))...)) |
1681 | #elif !defined(_MSC_VER) || _MSC_VER >= 1910 |
1682 | DECLTYPE_AUTO_RETURN(base::at( |
1683 | fdiagonal<Visitor&&, decltype(as_base(lib::forward<Vs>(vs)))...>:: |
1684 | value, |
1685 | index)( |
1686 | lib::forward<Visitor>(visitor), |
1687 | as_base(lib::forward<Vs>(vs))...)) |
1688 | #else |
1689 | DECLTYPE_AUTO_RETURN(base::at( |
1690 | base::make_fdiagonal< |
1691 | Visitor&&, |
1692 | decltype(as_base(lib::forward<Vs>(vs)))...>(), |
1693 | index)( |
1694 | lib::forward<Visitor>(visitor), |
1695 | as_base(lib::forward<Vs>(vs))...)) |
1696 | #endif |
1697 | }; |
1698 | |
1699 | struct variant { |
1700 | private: |
1701 | template <typename Visitor> |
1702 | struct visitor { |
1703 | template <typename... Values> |
1704 | inline static constexpr bool does_not_handle() { |
1705 | return lib::is_invocable<Visitor, Values...>::value; |
1706 | } |
1707 | }; |
1708 | |
1709 | template <typename Visitor, typename... Values> |
1710 | struct visit_exhaustiveness_check { |
1711 | static_assert( |
1712 | visitor<Visitor>::template does_not_handle<Values...>(), |
1713 | "`visit` requires the visitor to be exhaustive." ); |
1714 | |
1715 | inline static constexpr DECLTYPE_AUTO invoke( |
1716 | Visitor&& visitor, |
1717 | Values&&... values) |
1718 | DECLTYPE_AUTO_RETURN(lib::invoke( |
1719 | lib::forward<Visitor>(visitor), |
1720 | lib::forward<Values>(values)...)) |
1721 | }; |
1722 | |
1723 | template <typename Visitor> |
1724 | struct C10_MPARK_VISIBILITY_HIDDEN value_visitor { |
1725 | Visitor&& visitor_; |
1726 | |
1727 | template <typename... Alts> |
1728 | inline constexpr DECLTYPE_AUTO operator()(Alts&&... alts) const |
1729 | DECLTYPE_AUTO_RETURN(visit_exhaustiveness_check< |
1730 | Visitor, |
1731 | decltype((lib::forward<Alts>(alts).value))...>:: |
1732 | invoke( |
1733 | lib::forward<Visitor>(visitor_), |
1734 | lib::forward<Alts>(alts).value...)) |
1735 | }; |
1736 | |
1737 | template <typename Visitor> |
1738 | inline static constexpr AUTO make_value_visitor(Visitor&& visitor) |
1739 | AUTO_RETURN(value_visitor<Visitor>{lib::forward<Visitor>(visitor)}) |
1740 | |
1741 | public |
1742 | : template <typename Visitor, typename... Vs> |
1743 | inline static constexpr DECLTYPE_AUTO |
1744 | visit_alt(Visitor&& visitor, Vs&&... vs) |
1745 | DECLTYPE_AUTO_RETURN(alt::visit_alt( |
1746 | lib::forward<Visitor>(visitor), |
1747 | lib::forward<Vs>(vs).impl_...)) |
1748 | |
1749 | template <typename Visitor, typename... Vs> |
1750 | inline static constexpr DECLTYPE_AUTO |
1751 | visit_alt_at(std::size_t index, Visitor&& visitor, Vs&&... vs) |
1752 | DECLTYPE_AUTO_RETURN(alt::visit_alt_at( |
1753 | index, |
1754 | lib::forward<Visitor>(visitor), |
1755 | lib::forward<Vs>(vs).impl_...)) |
1756 | |
1757 | template <typename Visitor, typename... Vs> |
1758 | inline static constexpr DECLTYPE_AUTO |
1759 | visit_value(Visitor&& visitor, Vs&&... vs) |
1760 | DECLTYPE_AUTO_RETURN(visit_alt( |
1761 | make_value_visitor(lib::forward<Visitor>(visitor)), |
1762 | lib::forward<Vs>(vs)...)) |
1763 | |
1764 | template <typename Visitor, typename... Vs> |
1765 | inline static constexpr DECLTYPE_AUTO |
1766 | visit_value_at(std::size_t index, Visitor&& visitor, Vs&&... vs) |
1767 | DECLTYPE_AUTO_RETURN(visit_alt_at( |
1768 | index, |
1769 | make_value_visitor(lib::forward<Visitor>(visitor)), |
1770 | lib::forward<Vs>(vs)...)) |
1771 | }; |
1772 | |
1773 | } // namespace visitation |
1774 | |
1775 | template <std::size_t Index, typename T> |
1776 | struct alt { |
1777 | using value_type = T; |
1778 | |
1779 | #ifdef _MSC_VER |
1780 | #pragma warning(push) |
1781 | #pragma warning(disable : 4244) |
1782 | #endif |
1783 | template <typename... Args> |
1784 | inline explicit constexpr alt(in_place_t, Args&&... args) |
1785 | : value(lib::forward<Args>(args)...) {} |
1786 | #ifdef _MSC_VER |
1787 | #pragma warning(pop) |
1788 | #endif |
1789 | |
1790 | T value; |
1791 | }; |
1792 | |
1793 | template <Trait DestructibleTrait, std::size_t Index, typename... Ts> |
1794 | union recursive_union; |
1795 | |
1796 | template <Trait DestructibleTrait, std::size_t Index> |
1797 | union recursive_union<DestructibleTrait, Index> {}; |
1798 | |
1799 | #define C10_MPARK_VARIANT_RECURSIVE_UNION(destructible_trait, destructor) \ |
1800 | template <std::size_t Index, typename T, typename... Ts> \ |
1801 | union recursive_union<destructible_trait, Index, T, Ts...> { \ |
1802 | public: \ |
1803 | inline explicit constexpr recursive_union(valueless_t) noexcept \ |
1804 | : dummy_{} {} \ |
1805 | \ |
1806 | template <typename... Args> \ |
1807 | inline explicit constexpr recursive_union( \ |
1808 | in_place_index_t<0>, \ |
1809 | Args&&... args) \ |
1810 | : head_(in_place_t{}, lib::forward<Args>(args)...) {} \ |
1811 | \ |
1812 | template <std::size_t I, typename... Args> \ |
1813 | inline explicit constexpr recursive_union( \ |
1814 | in_place_index_t<I>, \ |
1815 | Args&&... args) \ |
1816 | : tail_(in_place_index_t<I - 1>{}, lib::forward<Args>(args)...) {} \ |
1817 | \ |
1818 | recursive_union(const recursive_union&) = default; \ |
1819 | recursive_union(recursive_union&&) = default; \ |
1820 | \ |
1821 | destructor \ |
1822 | \ |
1823 | recursive_union& \ |
1824 | operator=(const recursive_union&) = default; \ |
1825 | recursive_union& operator=(recursive_union&&) = default; \ |
1826 | \ |
1827 | private: \ |
1828 | char dummy_; \ |
1829 | alt<Index, T> head_; \ |
1830 | recursive_union<destructible_trait, Index + 1, Ts...> tail_; \ |
1831 | \ |
1832 | friend struct access::recursive_union; \ |
1833 | } |
1834 | |
1835 | C10_MPARK_VARIANT_RECURSIVE_UNION(Trait::TriviallyAvailable, |
1836 | ~recursive_union() = default;); |
1837 | C10_MPARK_VARIANT_RECURSIVE_UNION(Trait::Available, ~recursive_union(){}); |
1838 | C10_MPARK_VARIANT_RECURSIVE_UNION(Trait::Unavailable, |
1839 | ~recursive_union() = delete;); |
1840 | |
1841 | #undef C10_MPARK_VARIANT_RECURSIVE_UNION |
1842 | |
1843 | using index_t = unsigned int; |
1844 | |
1845 | template <Trait DestructibleTrait, typename... Ts> |
1846 | class base { |
1847 | public: |
1848 | inline explicit constexpr base(valueless_t tag) noexcept |
1849 | : data_(tag), index_(static_cast<index_t>(-1)) {} |
1850 | |
1851 | template <std::size_t I, typename... Args> |
1852 | inline explicit constexpr base(in_place_index_t<I>, Args&&... args) |
1853 | : data_(in_place_index_t<I>{}, lib::forward<Args>(args)...), index_(I) {} |
1854 | |
1855 | inline constexpr bool valueless_by_exception() const noexcept { |
1856 | return index_ == static_cast<index_t>(-1); |
1857 | } |
1858 | |
1859 | inline constexpr std::size_t index() const noexcept { |
1860 | return valueless_by_exception() ? variant_npos : index_; |
1861 | } |
1862 | |
1863 | protected: |
1864 | using data_t = recursive_union<DestructibleTrait, 0, Ts...>; |
1865 | |
1866 | friend inline constexpr base& as_base(base& b) { |
1867 | return b; |
1868 | } |
1869 | friend inline constexpr const base& as_base(const base& b) { |
1870 | return b; |
1871 | } |
1872 | friend inline constexpr base&& as_base(base&& b) { |
1873 | return lib::move(b); |
1874 | } |
1875 | friend inline constexpr const base&& as_base(const base&& b) { |
1876 | return lib::move(b); |
1877 | } |
1878 | |
1879 | friend inline constexpr data_t& data(base& b) { |
1880 | return b.data_; |
1881 | } |
1882 | friend inline constexpr const data_t& data(const base& b) { |
1883 | return b.data_; |
1884 | } |
1885 | friend inline constexpr data_t&& data(base&& b) { |
1886 | return lib::move(b).data_; |
1887 | } |
1888 | friend inline constexpr const data_t&& data(const base&& b) { |
1889 | return lib::move(b).data_; |
1890 | } |
1891 | |
1892 | inline static constexpr std::size_t size() { |
1893 | return sizeof...(Ts); |
1894 | } |
1895 | |
1896 | data_t data_; |
1897 | index_t index_; |
1898 | |
1899 | friend struct access::base; |
1900 | friend struct visitation::base; |
1901 | }; |
1902 | |
1903 | struct dtor { |
1904 | #ifdef _MSC_VER |
1905 | #pragma warning(push) |
1906 | #pragma warning(disable : 4100) |
1907 | #endif |
1908 | template <typename Alt> |
1909 | inline void operator()(Alt& alt) const noexcept { |
1910 | alt.~Alt(); |
1911 | } |
1912 | #ifdef _MSC_VER |
1913 | #pragma warning(pop) |
1914 | #endif |
1915 | }; |
1916 | |
1917 | #if !defined(_MSC_VER) || _MSC_VER >= 1910 |
1918 | #define C10_MPARK_INHERITING_CTOR(type, base) using base::base; |
1919 | #else |
1920 | #define C10_MPARK_INHERITING_CTOR(type, base) \ |
1921 | template <typename... Args> \ |
1922 | inline explicit constexpr type(Args&&... args) \ |
1923 | : base(lib::forward<Args>(args)...) {} |
1924 | #endif |
1925 | |
1926 | template <typename Traits, Trait = Traits::destructible_trait> |
1927 | class destructor; |
1928 | |
1929 | #define C10_MPARK_VARIANT_DESTRUCTOR(destructible_trait, definition, destroy) \ |
1930 | template <typename... Ts> \ |
1931 | class destructor<traits<Ts...>, destructible_trait> \ |
1932 | : public base<destructible_trait, Ts...> { \ |
1933 | using super = base<destructible_trait, Ts...>; \ |
1934 | \ |
1935 | public: \ |
1936 | C10_MPARK_INHERITING_CTOR(destructor, super) \ |
1937 | using super::operator=; \ |
1938 | \ |
1939 | destructor(const destructor&) = default; \ |
1940 | destructor(destructor&&) = default; \ |
1941 | definition destructor& operator=(const destructor&) = default; \ |
1942 | destructor& operator=(destructor&&) = default; \ |
1943 | \ |
1944 | protected: \ |
1945 | destroy \ |
1946 | } |
1947 | |
1948 | C10_MPARK_VARIANT_DESTRUCTOR( |
1949 | Trait::TriviallyAvailable, ~destructor() = default; |
1950 | , inline void destroy() noexcept { |
1951 | this->index_ = static_cast<index_t>(-1); |
1952 | }); |
1953 | |
1954 | C10_MPARK_VARIANT_DESTRUCTOR( |
1955 | Trait::Available, |
1956 | ~destructor() { destroy(); }, |
1957 | inline void destroy() noexcept { |
1958 | if (!this->valueless_by_exception()) { |
1959 | visitation::alt::visit_alt(dtor{}, *this); |
1960 | } |
1961 | this->index_ = static_cast<index_t>(-1); |
1962 | }); |
1963 | |
1964 | C10_MPARK_VARIANT_DESTRUCTOR(Trait::Unavailable, ~destructor() = delete; |
1965 | , inline void destroy() noexcept = delete;); |
1966 | |
1967 | #undef C10_MPARK_VARIANT_DESTRUCTOR |
1968 | |
1969 | template <typename Traits> |
1970 | class constructor : public destructor<Traits> { |
1971 | using super = destructor<Traits>; |
1972 | |
1973 | public: |
1974 | C10_MPARK_INHERITING_CTOR(constructor, super) |
1975 | using super::operator=; |
1976 | |
1977 | protected: |
1978 | #ifndef C10_MPARK_GENERIC_LAMBDAS |
1979 | struct ctor { |
1980 | template <typename LhsAlt, typename RhsAlt> |
1981 | inline void operator()(LhsAlt& lhs_alt, RhsAlt&& rhs_alt) const { |
1982 | constructor::construct_alt(lhs_alt, lib::forward<RhsAlt>(rhs_alt).value); |
1983 | } |
1984 | }; |
1985 | #endif |
1986 | |
1987 | template <std::size_t I, typename T, typename... Args> |
1988 | inline static T& construct_alt(alt<I, T>& a, Args&&... args) { |
1989 | auto* result = ::new (static_cast<void*>(lib::addressof(a))) |
1990 | alt<I, T>(in_place_t{}, lib::forward<Args>(args)...); |
1991 | return result->value; |
1992 | } |
1993 | |
1994 | template <typename Rhs> |
1995 | inline static void generic_construct(constructor& lhs, Rhs&& rhs) { |
1996 | lhs.destroy(); |
1997 | if (!rhs.valueless_by_exception()) { |
1998 | visitation::alt::visit_alt_at( |
1999 | rhs.index(), |
2000 | #ifdef C10_MPARK_GENERIC_LAMBDAS |
2001 | [](auto& lhs_alt, auto&& rhs_alt) { |
2002 | constructor::construct_alt( |
2003 | lhs_alt, lib::forward<decltype(rhs_alt)>(rhs_alt).value); |
2004 | } |
2005 | #else |
2006 | ctor {} |
2007 | #endif |
2008 | , |
2009 | lhs, |
2010 | lib::forward<Rhs>(rhs)); |
2011 | lhs.index_ = rhs.index_; |
2012 | } |
2013 | } |
2014 | }; |
2015 | |
2016 | template <typename Traits, Trait = Traits::move_constructible_trait> |
2017 | class move_constructor; |
2018 | |
2019 | #define C10_MPARK_VARIANT_MOVE_CONSTRUCTOR( \ |
2020 | move_constructible_trait, definition) \ |
2021 | template <typename... Ts> \ |
2022 | class move_constructor<traits<Ts...>, move_constructible_trait> \ |
2023 | : public constructor<traits<Ts...>> { \ |
2024 | using super = constructor<traits<Ts...>>; \ |
2025 | \ |
2026 | public: \ |
2027 | C10_MPARK_INHERITING_CTOR(move_constructor, super) \ |
2028 | using super::operator=; \ |
2029 | \ |
2030 | move_constructor(const move_constructor&) = default; \ |
2031 | definition ~move_constructor() = default; \ |
2032 | move_constructor& operator=(const move_constructor&) = default; \ |
2033 | move_constructor& operator=(move_constructor&&) = default; \ |
2034 | } |
2035 | |
2036 | C10_MPARK_VARIANT_MOVE_CONSTRUCTOR( |
2037 | Trait::TriviallyAvailable, |
2038 | move_constructor(move_constructor&& that) = default;); |
2039 | |
2040 | C10_MPARK_VARIANT_MOVE_CONSTRUCTOR( |
2041 | Trait::Available, |
2042 | move_constructor(move_constructor&& that) noexcept( |
2043 | lib::all<std::is_nothrow_move_constructible<Ts>::value...>::value) |
2044 | : move_constructor(valueless_t{}) { |
2045 | this->generic_construct(*this, lib::move(that)); |
2046 | }); |
2047 | |
2048 | C10_MPARK_VARIANT_MOVE_CONSTRUCTOR( |
2049 | Trait::Unavailable, move_constructor(move_constructor&&) = delete;); |
2050 | |
2051 | #undef C10_MPARK_VARIANT_MOVE_CONSTRUCTOR |
2052 | |
2053 | template <typename Traits, Trait = Traits::copy_constructible_trait> |
2054 | class copy_constructor; |
2055 | |
2056 | #define C10_MPARK_VARIANT_COPY_CONSTRUCTOR( \ |
2057 | copy_constructible_trait, definition) \ |
2058 | template <typename... Ts> \ |
2059 | class copy_constructor<traits<Ts...>, copy_constructible_trait> \ |
2060 | : public move_constructor<traits<Ts...>> { \ |
2061 | using super = move_constructor<traits<Ts...>>; \ |
2062 | \ |
2063 | public: \ |
2064 | C10_MPARK_INHERITING_CTOR(copy_constructor, super) \ |
2065 | using super::operator=; \ |
2066 | \ |
2067 | definition copy_constructor(copy_constructor&&) = default; \ |
2068 | ~copy_constructor() = default; \ |
2069 | copy_constructor& operator=(const copy_constructor&) = default; \ |
2070 | copy_constructor& operator=(copy_constructor&&) = default; \ |
2071 | } |
2072 | |
2073 | C10_MPARK_VARIANT_COPY_CONSTRUCTOR( |
2074 | Trait::TriviallyAvailable, |
2075 | copy_constructor(const copy_constructor& that) = default;); |
2076 | |
2077 | C10_MPARK_VARIANT_COPY_CONSTRUCTOR( |
2078 | Trait::Available, copy_constructor(const copy_constructor& that) |
2079 | : copy_constructor(valueless_t{}) { |
2080 | this->generic_construct(*this, that); |
2081 | }); |
2082 | |
2083 | C10_MPARK_VARIANT_COPY_CONSTRUCTOR( |
2084 | Trait::Unavailable, copy_constructor(const copy_constructor&) = delete;); |
2085 | |
2086 | #undef C10_MPARK_VARIANT_COPY_CONSTRUCTOR |
2087 | |
2088 | template <typename Traits> |
2089 | class assignment : public copy_constructor<Traits> { |
2090 | using super = copy_constructor<Traits>; |
2091 | |
2092 | public: |
2093 | C10_MPARK_INHERITING_CTOR(assignment, super) |
2094 | using super::operator=; |
2095 | |
2096 | template <std::size_t I, typename... Args> |
2097 | inline /* auto & */ auto emplace(Args&&... args) |
2098 | -> decltype(this->construct_alt( |
2099 | access::base::get_alt<I>(*this), |
2100 | lib::forward<Args>(args)...)) { |
2101 | this->destroy(); |
2102 | auto& result = this->construct_alt( |
2103 | access::base::get_alt<I>(*this), lib::forward<Args>(args)...); |
2104 | this->index_ = I; |
2105 | return result; |
2106 | } |
2107 | |
2108 | protected: |
2109 | #ifndef C10_MPARK_GENERIC_LAMBDAS |
2110 | template <typename That> |
2111 | struct assigner { |
2112 | template <typename ThisAlt, typename ThatAlt> |
2113 | inline void operator()(ThisAlt& this_alt, ThatAlt&& that_alt) const { |
2114 | self->assign_alt(this_alt, lib::forward<ThatAlt>(that_alt).value); |
2115 | } |
2116 | assignment* self; |
2117 | }; |
2118 | #endif |
2119 | |
2120 | template <std::size_t I, typename T, typename Arg> |
2121 | inline void assign_alt(alt<I, T>& a, Arg&& arg) { |
2122 | if (this->index() == I) { |
2123 | #ifdef _MSC_VER |
2124 | #pragma warning(push) |
2125 | #pragma warning(disable : 4244) |
2126 | #endif |
2127 | a.value = lib::forward<Arg>(arg); |
2128 | #ifdef _MSC_VER |
2129 | #pragma warning(pop) |
2130 | #endif |
2131 | } else { |
2132 | struct { |
2133 | void operator()(std::true_type) const { |
2134 | this_->emplace<I>(lib::forward<Arg>(arg_)); |
2135 | } |
2136 | void operator()(std::false_type) const { |
2137 | this_->emplace<I>(T(lib::forward<Arg>(arg_))); |
2138 | } |
2139 | assignment* this_; |
2140 | Arg&& arg_; |
2141 | } impl{this, lib::forward<Arg>(arg)}; |
2142 | impl( |
2143 | lib::bool_constant < std::is_nothrow_constructible<T, Arg>::value || |
2144 | !std::is_nothrow_move_constructible<T>::value > {}); |
2145 | } |
2146 | } |
2147 | |
2148 | template <typename That> |
2149 | inline void generic_assign(That&& that) { |
2150 | if (this->valueless_by_exception() && that.valueless_by_exception()) { |
2151 | // do nothing. |
2152 | } else if (that.valueless_by_exception()) { |
2153 | this->destroy(); |
2154 | } else { |
2155 | visitation::alt::visit_alt_at( |
2156 | that.index(), |
2157 | #ifdef C10_MPARK_GENERIC_LAMBDAS |
2158 | [this](auto& this_alt, auto&& that_alt) { |
2159 | this->assign_alt( |
2160 | this_alt, lib::forward<decltype(that_alt)>(that_alt).value); |
2161 | } |
2162 | #else |
2163 | assigner<That> { this } |
2164 | #endif |
2165 | , |
2166 | *this, |
2167 | lib::forward<That>(that)); |
2168 | } |
2169 | } |
2170 | }; |
2171 | |
2172 | template <typename Traits, Trait = Traits::move_assignable_trait> |
2173 | class move_assignment; |
2174 | |
2175 | #define C10_MPARK_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, definition) \ |
2176 | template <typename... Ts> \ |
2177 | class move_assignment<traits<Ts...>, move_assignable_trait> \ |
2178 | : public assignment<traits<Ts...>> { \ |
2179 | using super = assignment<traits<Ts...>>; \ |
2180 | \ |
2181 | public: \ |
2182 | C10_MPARK_INHERITING_CTOR(move_assignment, super) \ |
2183 | using super::operator=; \ |
2184 | \ |
2185 | move_assignment(const move_assignment&) = default; \ |
2186 | move_assignment(move_assignment&&) = default; \ |
2187 | ~move_assignment() = default; \ |
2188 | move_assignment& operator=(const move_assignment&) = default; \ |
2189 | definition \ |
2190 | } |
2191 | |
2192 | C10_MPARK_VARIANT_MOVE_ASSIGNMENT( |
2193 | Trait::TriviallyAvailable, |
2194 | move_assignment& operator=(move_assignment&& that) = default;); |
2195 | |
2196 | C10_MPARK_VARIANT_MOVE_ASSIGNMENT( |
2197 | Trait::Available, |
2198 | move_assignment& |
2199 | operator=(move_assignment&& that) noexcept( |
2200 | lib::all< |
2201 | (std::is_nothrow_move_constructible<Ts>::value && |
2202 | std::is_nothrow_move_assignable<Ts>::value)...>::value) { |
2203 | this->generic_assign(lib::move(that)); |
2204 | return *this; |
2205 | }); |
2206 | |
2207 | C10_MPARK_VARIANT_MOVE_ASSIGNMENT( |
2208 | Trait::Unavailable, |
2209 | move_assignment& operator=(move_assignment&&) = delete;); |
2210 | |
2211 | #undef C10_MPARK_VARIANT_MOVE_ASSIGNMENT |
2212 | |
2213 | template <typename Traits, Trait = Traits::copy_assignable_trait> |
2214 | class copy_assignment; |
2215 | |
2216 | #define C10_MPARK_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, definition) \ |
2217 | template <typename... Ts> \ |
2218 | class copy_assignment<traits<Ts...>, copy_assignable_trait> \ |
2219 | : public move_assignment<traits<Ts...>> { \ |
2220 | using super = move_assignment<traits<Ts...>>; \ |
2221 | \ |
2222 | public: \ |
2223 | C10_MPARK_INHERITING_CTOR(copy_assignment, super) \ |
2224 | using super::operator=; \ |
2225 | \ |
2226 | copy_assignment(const copy_assignment&) = default; \ |
2227 | copy_assignment(copy_assignment&&) = default; \ |
2228 | ~copy_assignment() = default; \ |
2229 | definition copy_assignment& operator=(copy_assignment&&) = default; \ |
2230 | } |
2231 | |
2232 | C10_MPARK_VARIANT_COPY_ASSIGNMENT( |
2233 | Trait::TriviallyAvailable, |
2234 | copy_assignment& operator=(const copy_assignment& that) = default;); |
2235 | |
2236 | C10_MPARK_VARIANT_COPY_ASSIGNMENT( |
2237 | Trait::Available, |
2238 | copy_assignment& |
2239 | operator=(const copy_assignment& that) { |
2240 | this->generic_assign(that); |
2241 | return *this; |
2242 | }); |
2243 | |
2244 | C10_MPARK_VARIANT_COPY_ASSIGNMENT( |
2245 | Trait::Unavailable, |
2246 | copy_assignment& operator=(const copy_assignment&) = delete;); |
2247 | |
2248 | #undef C10_MPARK_VARIANT_COPY_ASSIGNMENT |
2249 | |
2250 | template <typename... Ts> |
2251 | class impl : public copy_assignment<traits<Ts...>> { |
2252 | using super = copy_assignment<traits<Ts...>>; |
2253 | |
2254 | public: |
2255 | C10_MPARK_INHERITING_CTOR(impl, super) |
2256 | |
2257 | template <std::size_t I, typename Arg> |
2258 | inline void assign(Arg&& arg) { |
2259 | this->assign_alt(access::base::get_alt<I>(*this), lib::forward<Arg>(arg)); |
2260 | } |
2261 | |
2262 | inline void swap(impl& that) { |
2263 | if (this->valueless_by_exception() && that.valueless_by_exception()) { |
2264 | // do nothing. |
2265 | } else if (this->index() == that.index()) { |
2266 | visitation::alt::visit_alt_at( |
2267 | this->index(), |
2268 | #ifdef C10_MPARK_GENERIC_LAMBDAS |
2269 | [](auto& this_alt, auto& that_alt) { |
2270 | using std::swap; |
2271 | swap(this_alt.value, that_alt.value); |
2272 | } |
2273 | #else |
2274 | swapper {} |
2275 | #endif |
2276 | , |
2277 | *this, |
2278 | that); |
2279 | } else { |
2280 | impl* lhs = this; |
2281 | impl* rhs = lib::addressof(that); |
2282 | if (lhs->move_nothrow() && !rhs->move_nothrow()) { |
2283 | std::swap(lhs, rhs); |
2284 | } |
2285 | impl tmp(lib::move(*rhs)); |
2286 | #ifdef C10_MPARK_EXCEPTIONS |
2287 | // EXTENSION: When the move construction of `lhs` into `rhs` throws |
2288 | // and `tmp` is nothrow move constructible then we move `tmp` back |
2289 | // into `rhs` and provide the strong exception safety guarantee. |
2290 | try { |
2291 | this->generic_construct(*rhs, lib::move(*lhs)); |
2292 | } catch (...) { |
2293 | if (tmp.move_nothrow()) { |
2294 | this->generic_construct(*rhs, lib::move(tmp)); |
2295 | } |
2296 | throw; |
2297 | } |
2298 | #else |
2299 | this->generic_construct(*rhs, lib::move(*lhs)); |
2300 | #endif |
2301 | this->generic_construct(*lhs, lib::move(tmp)); |
2302 | } |
2303 | } |
2304 | |
2305 | private: |
2306 | #ifndef C10_MPARK_GENERIC_LAMBDAS |
2307 | struct swapper { |
2308 | template <typename ThisAlt, typename ThatAlt> |
2309 | inline void operator()(ThisAlt& this_alt, ThatAlt& that_alt) const { |
2310 | using std::swap; |
2311 | swap(this_alt.value, that_alt.value); |
2312 | } |
2313 | }; |
2314 | #endif |
2315 | |
2316 | inline constexpr bool move_nothrow() const { |
2317 | return this->valueless_by_exception() || |
2318 | lib::array<bool, sizeof...(Ts)>{ |
2319 | {std::is_nothrow_move_constructible<Ts>::value...}}[this->index()]; |
2320 | } |
2321 | }; |
2322 | |
2323 | #undef C10_MPARK_INHERITING_CTOR |
2324 | |
2325 | template <std::size_t I, typename T> |
2326 | struct overload_leaf { |
2327 | using F = lib::size_constant<I> (*)(T); |
2328 | operator F() const { |
2329 | return nullptr; |
2330 | } |
2331 | }; |
2332 | |
2333 | template <typename... Ts> |
2334 | struct overload_impl { |
2335 | private: |
2336 | template <typename> |
2337 | struct impl; |
2338 | |
2339 | template <std::size_t... Is> |
2340 | struct impl<lib::index_sequence<Is...>> : overload_leaf<Is, Ts>... {}; |
2341 | |
2342 | public: |
2343 | using type = impl<lib::index_sequence_for<Ts...>>; |
2344 | }; |
2345 | |
2346 | template <typename... Ts> |
2347 | using overload = typename overload_impl<Ts...>::type; |
2348 | |
2349 | template <typename T, typename... Ts> |
2350 | using best_match = lib::invoke_result_t<overload<Ts...>, T&&>; |
2351 | |
2352 | template <typename T> |
2353 | struct is_in_place_index : std::false_type {}; |
2354 | |
2355 | template <std::size_t I> |
2356 | struct is_in_place_index<in_place_index_t<I>> : std::true_type {}; |
2357 | |
2358 | template <typename T> |
2359 | struct is_in_place_type : std::false_type {}; |
2360 | |
2361 | template <typename T> |
2362 | struct is_in_place_type<in_place_type_t<T>> : std::true_type {}; |
2363 | |
2364 | } // namespace detail_ |
2365 | |
2366 | template <typename... Ts> |
2367 | class variant { |
2368 | static_assert( |
2369 | 0 < sizeof...(Ts), |
2370 | "variant must consist of at least one alternative." ); |
2371 | |
2372 | static_assert( |
2373 | lib::all<!std::is_array<Ts>::value...>::value, |
2374 | "variant can not have an array type as an alternative." ); |
2375 | |
2376 | static_assert( |
2377 | lib::all<!std::is_reference<Ts>::value...>::value, |
2378 | "variant can not have a reference type as an alternative." ); |
2379 | |
2380 | static_assert( |
2381 | lib::all<!std::is_void<Ts>::value...>::value, |
2382 | "variant can not have a void type as an alternative." ); |
2383 | |
2384 | public: |
2385 | template < |
2386 | typename Front = lib::type_pack_element_t<0, Ts...>, |
2387 | lib::enable_if_t<std::is_default_constructible<Front>::value, int> = 0> |
2388 | inline constexpr variant() noexcept( |
2389 | std::is_nothrow_default_constructible<Front>::value) |
2390 | : impl_(in_place_index_t<0>{}) {} |
2391 | |
2392 | variant(const variant&) = default; |
2393 | variant(variant&&) = default; |
2394 | |
2395 | // NOTE [gcc 7.3.1 bug workaround] |
2396 | // |
2397 | // The original line `typename T = lib::type_pack_element_t<I, Ts...>` |
2398 | // throws the following compiler error on gcc 7.3.1: |
2399 | // ``` |
2400 | // ../c10/util/variant.h:2250:9: internal compiler error: |
2401 | // unexpected expression ‘I’ of kind template_parm_index |
2402 | // typename T = lib::type_pack_element_t<I, Ts...>, |
2403 | // ^~~~~~~~ |
2404 | // ``` |
2405 | // As a workaround, `I` is changed to `detail_::best_match<Arg, |
2406 | // Ts...>::value`, which is the default value for `I` in this template. Note |
2407 | // that this workaround effectively disallows setting `I` to any other |
2408 | // non-default value, and we add a `static_assert` in the function body to |
2409 | // check for this. |
2410 | // |
2411 | // See the following issues for more context: |
2412 | // - https://github.com/mpark/variant/issues/43 |
2413 | // - https://github.com/eggs-cpp/variant/issues/31 |
2414 | template < |
2415 | typename Arg, |
2416 | typename Decayed = lib::decay_t<Arg>, |
2417 | lib::enable_if_t<!std::is_same<Decayed, variant>::value, int> = 0, |
2418 | lib::enable_if_t<!detail_::is_in_place_index<Decayed>::value, int> = 0, |
2419 | lib::enable_if_t<!detail_::is_in_place_type<Decayed>::value, int> = 0, |
2420 | std::size_t I = detail_::best_match<Arg, Ts...>::value, |
2421 | typename T = lib:: |
2422 | type_pack_element_t<detail_::best_match<Arg, Ts...>::value, Ts...>, |
2423 | lib::enable_if_t<std::is_constructible<T, Arg>::value, int> = 0> |
2424 | inline constexpr variant(Arg&& arg) noexcept( |
2425 | std::is_nothrow_constructible<T, Arg>::value) |
2426 | : impl_(in_place_index_t<I>{}, lib::forward<Arg>(arg)) { |
2427 | static_assert( |
2428 | I == detail_::best_match<Arg, Ts...>::value, |
2429 | "Setting template parameter `I` to a custom non-default value is not supported. " |
2430 | "Please file a feature request if you see this." ); |
2431 | } |
2432 | |
2433 | template < |
2434 | std::size_t I, |
2435 | typename... Args, |
2436 | typename T = lib::type_pack_element_t<I, Ts...>, |
2437 | lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> |
2438 | inline explicit constexpr variant( |
2439 | in_place_index_t<I>, |
2440 | Args&&... args) noexcept(std::is_nothrow_constructible<T, Args...>::value) |
2441 | : impl_(in_place_index_t<I>{}, lib::forward<Args>(args)...) {} |
2442 | |
2443 | template < |
2444 | std::size_t I, |
2445 | typename Up, |
2446 | typename... Args, |
2447 | typename T = lib::type_pack_element_t<I, Ts...>, |
2448 | lib::enable_if_t< |
2449 | std::is_constructible<T, std::initializer_list<Up>&, Args...>::value, |
2450 | int> = 0> |
2451 | inline explicit constexpr variant( |
2452 | in_place_index_t<I>, |
2453 | std::initializer_list<Up> il, |
2454 | Args&&... args) noexcept(std:: |
2455 | is_nothrow_constructible< |
2456 | T, |
2457 | std::initializer_list<Up>&, |
2458 | Args...>::value) |
2459 | : impl_(in_place_index_t<I>{}, il, lib::forward<Args>(args)...) {} |
2460 | |
2461 | template < |
2462 | typename T, |
2463 | typename... Args, |
2464 | std::size_t I = detail_::find_index_sfinae<T, Ts...>::value, |
2465 | lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> |
2466 | inline explicit constexpr variant( |
2467 | in_place_type_t<T>, |
2468 | Args&&... args) noexcept(std::is_nothrow_constructible<T, Args...>::value) |
2469 | : impl_(in_place_index_t<I>{}, lib::forward<Args>(args)...) {} |
2470 | |
2471 | template < |
2472 | typename T, |
2473 | typename Up, |
2474 | typename... Args, |
2475 | std::size_t I = detail_::find_index_sfinae<T, Ts...>::value, |
2476 | lib::enable_if_t< |
2477 | std::is_constructible<T, std::initializer_list<Up>&, Args...>::value, |
2478 | int> = 0> |
2479 | inline explicit constexpr variant( |
2480 | in_place_type_t<T>, |
2481 | std::initializer_list<Up> il, |
2482 | Args&&... args) noexcept(std:: |
2483 | is_nothrow_constructible< |
2484 | T, |
2485 | std::initializer_list<Up>&, |
2486 | Args...>::value) |
2487 | : impl_(in_place_index_t<I>{}, il, lib::forward<Args>(args)...) {} |
2488 | |
2489 | ~variant() = default; |
2490 | |
2491 | variant& operator=(const variant&) = default; |
2492 | variant& operator=(variant&&) = default; |
2493 | |
2494 | // NOTE: See NOTE [gcc 7.3.1 bug workaround] for the changes made to this |
2495 | // function. |
2496 | template < |
2497 | typename Arg, |
2498 | lib::enable_if_t<!std::is_same<lib::decay_t<Arg>, variant>::value, int> = |
2499 | 0, |
2500 | std::size_t I = detail_::best_match<Arg, Ts...>::value, |
2501 | typename T = lib:: |
2502 | type_pack_element_t<detail_::best_match<Arg, Ts...>::value, Ts...>, |
2503 | lib::enable_if_t< |
2504 | (std::is_assignable<T&, Arg>::value && |
2505 | std::is_constructible<T, Arg>::value), |
2506 | int> = 0> |
2507 | inline variant& operator=(Arg&& arg) noexcept( |
2508 | (std::is_nothrow_assignable<T&, Arg>::value && |
2509 | std::is_nothrow_constructible<T, Arg>::value)) { |
2510 | static_assert( |
2511 | I == detail_::best_match<Arg, Ts...>::value, |
2512 | "Setting template parameter `I` to a custom non-default value is not supported. " |
2513 | "Please file a feature request if you see this." ); |
2514 | impl_.template assign<I>(lib::forward<Arg>(arg)); |
2515 | return *this; |
2516 | } |
2517 | |
2518 | template < |
2519 | std::size_t I, |
2520 | typename... Args, |
2521 | typename T = lib::type_pack_element_t<I, Ts...>, |
2522 | lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> |
2523 | inline T& emplace(Args&&... args) { |
2524 | return impl_.template emplace<I>(lib::forward<Args>(args)...); |
2525 | } |
2526 | |
2527 | template < |
2528 | std::size_t I, |
2529 | typename Up, |
2530 | typename... Args, |
2531 | typename T = lib::type_pack_element_t<I, Ts...>, |
2532 | lib::enable_if_t< |
2533 | std::is_constructible<T, std::initializer_list<Up>&, Args...>::value, |
2534 | int> = 0> |
2535 | inline T& emplace(std::initializer_list<Up> il, Args&&... args) { |
2536 | return impl_.template emplace<I>(il, lib::forward<Args>(args)...); |
2537 | } |
2538 | |
2539 | template < |
2540 | typename T, |
2541 | typename... Args, |
2542 | std::size_t I = detail_::find_index_sfinae<T, Ts...>::value, |
2543 | lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> |
2544 | inline T& emplace(Args&&... args) { |
2545 | return impl_.template emplace<I>(lib::forward<Args>(args)...); |
2546 | } |
2547 | |
2548 | template < |
2549 | typename T, |
2550 | typename Up, |
2551 | typename... Args, |
2552 | std::size_t I = detail_::find_index_sfinae<T, Ts...>::value, |
2553 | lib::enable_if_t< |
2554 | std::is_constructible<T, std::initializer_list<Up>&, Args...>::value, |
2555 | int> = 0> |
2556 | inline T& emplace(std::initializer_list<Up> il, Args&&... args) { |
2557 | return impl_.template emplace<I>(il, lib::forward<Args>(args)...); |
2558 | } |
2559 | |
2560 | inline constexpr bool valueless_by_exception() const noexcept { |
2561 | return impl_.valueless_by_exception(); |
2562 | } |
2563 | |
2564 | inline constexpr std::size_t index() const noexcept { |
2565 | return impl_.index(); |
2566 | } |
2567 | |
2568 | template < |
2569 | bool Dummy = true, |
2570 | lib::enable_if_t< |
2571 | lib::all< |
2572 | Dummy, |
2573 | (lib::dependent_type<std::is_move_constructible<Ts>, Dummy>:: |
2574 | value && |
2575 | lib::dependent_type<lib::is_swappable<Ts>, Dummy>::value)...>:: |
2576 | value, |
2577 | int> = 0> |
2578 | inline void swap(variant& that) noexcept( |
2579 | lib::all< |
2580 | (std::is_nothrow_move_constructible<Ts>::value && |
2581 | lib::is_nothrow_swappable<Ts>::value)...>::value) { |
2582 | impl_.swap(that.impl_); |
2583 | } |
2584 | |
2585 | private: |
2586 | detail_::impl<Ts...> impl_; |
2587 | |
2588 | friend struct detail_::access::variant; |
2589 | friend struct detail_::visitation::variant; |
2590 | }; |
2591 | |
2592 | template <std::size_t I, typename... Ts> |
2593 | inline constexpr bool holds_alternative(const variant<Ts...>& v) noexcept { |
2594 | return v.index() == I; |
2595 | } |
2596 | |
2597 | template <typename T, typename... Ts> |
2598 | inline constexpr bool holds_alternative(const variant<Ts...>& v) noexcept { |
2599 | return holds_alternative<detail_::find_index_checked<T, Ts...>::value>(v); |
2600 | } |
2601 | |
2602 | namespace detail_ { |
2603 | template <std::size_t I, typename V> |
2604 | struct generic_get_impl { |
2605 | constexpr generic_get_impl(int) noexcept {} |
2606 | |
2607 | constexpr AUTO_REFREF operator()(V&& v) const |
2608 | AUTO_REFREF_RETURN(access::variant::get_alt<I>(lib::forward<V>(v)).value) |
2609 | }; |
2610 | |
2611 | template <std::size_t I, typename V> |
2612 | inline constexpr AUTO_REFREF generic_get(V&& v) |
2613 | AUTO_REFREF_RETURN(generic_get_impl<I, V>( |
2614 | holds_alternative<I>(v) |
2615 | ? 0 |
2616 | : (throw_bad_variant_access(), 0))(lib::forward<V>(v))) |
2617 | } // namespace detail_ |
2618 | |
2619 | template <std::size_t I, typename... Ts> |
2620 | inline constexpr variant_alternative_t<I, variant<Ts...>>& get( |
2621 | variant<Ts...>& v) { |
2622 | return detail_::generic_get<I>(v); |
2623 | } |
2624 | |
2625 | template <std::size_t I, typename... Ts> |
2626 | inline constexpr variant_alternative_t<I, variant<Ts...>>&& get( |
2627 | variant<Ts...>&& v) { |
2628 | return detail_::generic_get<I>(lib::move(v)); |
2629 | } |
2630 | |
2631 | template <std::size_t I, typename... Ts> |
2632 | inline constexpr const variant_alternative_t<I, variant<Ts...>>& get( |
2633 | const variant<Ts...>& v) { |
2634 | return detail_::generic_get<I>(v); |
2635 | } |
2636 | |
2637 | template <std::size_t I, typename... Ts> |
2638 | inline constexpr const variant_alternative_t<I, variant<Ts...>>&& get( |
2639 | const variant<Ts...>&& v) { |
2640 | return detail_::generic_get<I>(lib::move(v)); |
2641 | } |
2642 | |
2643 | template <typename T, typename... Ts> |
2644 | inline constexpr T& get(variant<Ts...>& v) { |
2645 | return get<detail_::find_index_checked<T, Ts...>::value>(v); |
2646 | } |
2647 | |
2648 | template <typename T, typename... Ts> |
2649 | inline constexpr T&& get(variant<Ts...>&& v) { |
2650 | return get<detail_::find_index_checked<T, Ts...>::value>(lib::move(v)); |
2651 | } |
2652 | |
2653 | template <typename T, typename... Ts> |
2654 | inline constexpr const T& get(const variant<Ts...>& v) { |
2655 | return get<detail_::find_index_checked<T, Ts...>::value>(v); |
2656 | } |
2657 | |
2658 | template <typename T, typename... Ts> |
2659 | inline constexpr const T&& get(const variant<Ts...>&& v) { |
2660 | return get<detail_::find_index_checked<T, Ts...>::value>(lib::move(v)); |
2661 | } |
2662 | |
2663 | namespace detail_ { |
2664 | |
2665 | template <std::size_t I, typename V> |
2666 | inline constexpr /* auto * */ AUTO generic_get_if(V* v) noexcept AUTO_RETURN( |
2667 | v&& holds_alternative<I>(*v) |
2668 | ? lib::addressof(access::variant::get_alt<I>(*v).value) |
2669 | : nullptr) |
2670 | |
2671 | } // namespace detail_ |
2672 | |
2673 | template <std::size_t I, typename... Ts> |
2674 | inline constexpr lib::add_pointer_t<variant_alternative_t<I, variant<Ts...>>> |
2675 | get_if(variant<Ts...>* v) noexcept { |
2676 | return detail_::generic_get_if<I>(v); |
2677 | } |
2678 | |
2679 | template <std::size_t I, typename... Ts> |
2680 | inline constexpr lib::add_pointer_t< |
2681 | const variant_alternative_t<I, variant<Ts...>>> |
2682 | get_if(const variant<Ts...>* v) noexcept { |
2683 | return detail_::generic_get_if<I>(v); |
2684 | } |
2685 | |
2686 | template <typename T, typename... Ts> |
2687 | inline constexpr lib::add_pointer_t<T> get_if(variant<Ts...>* v) noexcept { |
2688 | return get_if<detail_::find_index_checked<T, Ts...>::value>(v); |
2689 | } |
2690 | |
2691 | template <typename T, typename... Ts> |
2692 | inline constexpr lib::add_pointer_t<const T> get_if( |
2693 | const variant<Ts...>* v) noexcept { |
2694 | return get_if<detail_::find_index_checked<T, Ts...>::value>(v); |
2695 | } |
2696 | |
2697 | namespace detail_ { |
2698 | template <typename RelOp> |
2699 | struct convert_to_bool { |
2700 | template <typename Lhs, typename Rhs> |
2701 | inline constexpr bool operator()(Lhs&& lhs, Rhs&& rhs) const { |
2702 | static_assert( |
2703 | std::is_convertible<lib::invoke_result_t<RelOp, Lhs, Rhs>, bool>::value, |
2704 | "relational operators must return a type" |
2705 | " implicitly convertible to bool" ); |
2706 | return lib::invoke(RelOp{}, lib::forward<Lhs>(lhs), lib::forward<Rhs>(rhs)); |
2707 | } |
2708 | }; |
2709 | } // namespace detail_ |
2710 | |
2711 | template <typename... Ts> |
2712 | inline constexpr bool operator==( |
2713 | const variant<Ts...>& lhs, |
2714 | const variant<Ts...>& rhs) { |
2715 | using detail_::visitation::variant; |
2716 | using equal_to = detail_::convert_to_bool<lib::equal_to>; |
2717 | #ifdef C10_MPARK_CPP14_CONSTEXPR |
2718 | if (lhs.index() != rhs.index()) |
2719 | return false; |
2720 | if (lhs.valueless_by_exception()) |
2721 | return true; |
2722 | return variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs); |
2723 | #else |
2724 | return lhs.index() == rhs.index() && |
2725 | (lhs.valueless_by_exception() || |
2726 | variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs)); |
2727 | #endif |
2728 | } |
2729 | |
2730 | template <typename... Ts> |
2731 | inline constexpr bool operator!=( |
2732 | const variant<Ts...>& lhs, |
2733 | const variant<Ts...>& rhs) { |
2734 | using detail_::visitation::variant; |
2735 | using not_equal_to = detail_::convert_to_bool<lib::not_equal_to>; |
2736 | #ifdef C10_MPARK_CPP14_CONSTEXPR |
2737 | if (lhs.index() != rhs.index()) |
2738 | return true; |
2739 | if (lhs.valueless_by_exception()) |
2740 | return false; |
2741 | return variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs); |
2742 | #else |
2743 | return lhs.index() != rhs.index() || |
2744 | (!lhs.valueless_by_exception() && |
2745 | variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs)); |
2746 | #endif |
2747 | } |
2748 | |
2749 | template <typename... Ts> |
2750 | inline constexpr bool operator<( |
2751 | const variant<Ts...>& lhs, |
2752 | const variant<Ts...>& rhs) { |
2753 | using detail_::visitation::variant; |
2754 | using less = detail_::convert_to_bool<lib::less>; |
2755 | #ifdef C10_MPARK_CPP14_CONSTEXPR |
2756 | if (rhs.valueless_by_exception()) |
2757 | return false; |
2758 | if (lhs.valueless_by_exception()) |
2759 | return true; |
2760 | if (lhs.index() < rhs.index()) |
2761 | return true; |
2762 | if (lhs.index() > rhs.index()) |
2763 | return false; |
2764 | return variant::visit_value_at(lhs.index(), less{}, lhs, rhs); |
2765 | #else |
2766 | return !rhs.valueless_by_exception() && |
2767 | (lhs.valueless_by_exception() || lhs.index() < rhs.index() || |
2768 | (lhs.index() == rhs.index() && |
2769 | variant::visit_value_at(lhs.index(), less{}, lhs, rhs))); |
2770 | #endif |
2771 | } |
2772 | |
2773 | template <typename... Ts> |
2774 | inline constexpr bool operator>( |
2775 | const variant<Ts...>& lhs, |
2776 | const variant<Ts...>& rhs) { |
2777 | using detail_::visitation::variant; |
2778 | using greater = detail_::convert_to_bool<lib::greater>; |
2779 | #ifdef C10_MPARK_CPP14_CONSTEXPR |
2780 | if (lhs.valueless_by_exception()) |
2781 | return false; |
2782 | if (rhs.valueless_by_exception()) |
2783 | return true; |
2784 | if (lhs.index() > rhs.index()) |
2785 | return true; |
2786 | if (lhs.index() < rhs.index()) |
2787 | return false; |
2788 | return variant::visit_value_at(lhs.index(), greater{}, lhs, rhs); |
2789 | #else |
2790 | return !lhs.valueless_by_exception() && |
2791 | (rhs.valueless_by_exception() || lhs.index() > rhs.index() || |
2792 | (lhs.index() == rhs.index() && |
2793 | variant::visit_value_at(lhs.index(), greater{}, lhs, rhs))); |
2794 | #endif |
2795 | } |
2796 | |
2797 | template <typename... Ts> |
2798 | inline constexpr bool operator<=( |
2799 | const variant<Ts...>& lhs, |
2800 | const variant<Ts...>& rhs) { |
2801 | using detail_::visitation::variant; |
2802 | using less_equal = detail_::convert_to_bool<lib::less_equal>; |
2803 | #ifdef C10_MPARK_CPP14_CONSTEXPR |
2804 | if (lhs.valueless_by_exception()) |
2805 | return true; |
2806 | if (rhs.valueless_by_exception()) |
2807 | return false; |
2808 | if (lhs.index() < rhs.index()) |
2809 | return true; |
2810 | if (lhs.index() > rhs.index()) |
2811 | return false; |
2812 | return variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs); |
2813 | #else |
2814 | return lhs.valueless_by_exception() || |
2815 | (!rhs.valueless_by_exception() && |
2816 | (lhs.index() < rhs.index() || |
2817 | (lhs.index() == rhs.index() && |
2818 | variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs)))); |
2819 | #endif |
2820 | } |
2821 | |
2822 | template <typename... Ts> |
2823 | inline constexpr bool operator>=( |
2824 | const variant<Ts...>& lhs, |
2825 | const variant<Ts...>& rhs) { |
2826 | using detail_::visitation::variant; |
2827 | using greater_equal = detail_::convert_to_bool<lib::greater_equal>; |
2828 | #ifdef C10_MPARK_CPP14_CONSTEXPR |
2829 | if (rhs.valueless_by_exception()) |
2830 | return true; |
2831 | if (lhs.valueless_by_exception()) |
2832 | return false; |
2833 | if (lhs.index() > rhs.index()) |
2834 | return true; |
2835 | if (lhs.index() < rhs.index()) |
2836 | return false; |
2837 | return variant::visit_value_at(lhs.index(), greater_equal{}, lhs, rhs); |
2838 | #else |
2839 | return rhs.valueless_by_exception() || |
2840 | (!lhs.valueless_by_exception() && |
2841 | (lhs.index() > rhs.index() || |
2842 | (lhs.index() == rhs.index() && |
2843 | variant::visit_value_at(lhs.index(), greater_equal{}, lhs, rhs)))); |
2844 | #endif |
2845 | } |
2846 | |
2847 | struct monostate {}; |
2848 | |
2849 | inline constexpr bool operator<(monostate, monostate) noexcept { |
2850 | return false; |
2851 | } |
2852 | |
2853 | inline constexpr bool operator>(monostate, monostate) noexcept { |
2854 | return false; |
2855 | } |
2856 | |
2857 | inline constexpr bool operator<=(monostate, monostate) noexcept { |
2858 | return true; |
2859 | } |
2860 | |
2861 | inline constexpr bool operator>=(monostate, monostate) noexcept { |
2862 | return true; |
2863 | } |
2864 | |
2865 | inline constexpr bool operator==(monostate, monostate) noexcept { |
2866 | return true; |
2867 | } |
2868 | |
2869 | inline constexpr bool operator!=(monostate, monostate) noexcept { |
2870 | return false; |
2871 | } |
2872 | |
2873 | #ifdef C10_MPARK_CPP14_CONSTEXPR |
2874 | namespace detail_ { |
2875 | |
2876 | inline constexpr bool any(std::initializer_list<bool> bs) { |
2877 | for (bool b : bs) { |
2878 | if (b) { |
2879 | return true; |
2880 | } |
2881 | } |
2882 | return false; |
2883 | } |
2884 | |
2885 | } // namespace detail_ |
2886 | |
2887 | template <typename Visitor, typename... Vs> |
2888 | inline constexpr decltype(auto) visit(Visitor&& visitor, Vs&&... vs) { |
2889 | return (!detail_::any({vs.valueless_by_exception()...}) |
2890 | ? (void)0 |
2891 | : throw_bad_variant_access()), |
2892 | detail_::visitation::variant::visit_value( |
2893 | lib::forward<Visitor>(visitor), lib::forward<Vs>(vs)...); |
2894 | } |
2895 | #else |
2896 | namespace detail_ { |
2897 | |
2898 | template <std::size_t N> |
2899 | inline constexpr bool all_impl(const lib::array<bool, N>& bs, std::size_t idx) { |
2900 | return idx >= N || (bs[idx] && all_impl(bs, idx + 1)); |
2901 | } |
2902 | |
2903 | template <std::size_t N> |
2904 | inline constexpr bool all(const lib::array<bool, N>& bs) { |
2905 | return all_impl(bs, 0); |
2906 | } |
2907 | |
2908 | } // namespace detail_ |
2909 | |
2910 | template <typename Visitor, typename... Vs> |
2911 | inline constexpr DECLTYPE_AUTO visit(Visitor&& visitor, Vs&&... vs) |
2912 | DECLTYPE_AUTO_RETURN( |
2913 | (detail_::all(lib::array<bool, sizeof...(Vs)>{ |
2914 | {!vs.valueless_by_exception()...}}) |
2915 | ? (void)0 |
2916 | : throw_bad_variant_access()), |
2917 | detail_::visitation::variant::visit_value( |
2918 | lib::forward<Visitor>(visitor), |
2919 | lib::forward<Vs>(vs)...)) |
2920 | #endif |
2921 | |
2922 | template <typename... Ts> |
2923 | inline auto swap(variant<Ts...>& lhs, variant<Ts...>& rhs) noexcept( |
2924 | noexcept(lhs.swap(rhs))) -> decltype(lhs.swap(rhs)) { |
2925 | lhs.swap(rhs); |
2926 | } |
2927 | |
2928 | namespace detail_ { |
2929 | |
2930 | template <typename T, typename...> |
2931 | using enabled_type = T; |
2932 | |
2933 | namespace hash { |
2934 | |
2935 | template <typename H, typename K> |
2936 | constexpr bool meets_requirements() noexcept { |
2937 | return std::is_copy_constructible<H>::value && |
2938 | std::is_move_constructible<H>::value && |
2939 | lib::is_invocable_r<std::size_t, H, const K&>::value; |
2940 | } |
2941 | |
2942 | template <typename K> |
2943 | constexpr bool is_enabled() noexcept { |
2944 | using H = std::hash<K>; |
2945 | return meets_requirements<H, K>() && |
2946 | std::is_default_constructible<H>::value && |
2947 | std::is_copy_assignable<H>::value && std::is_move_assignable<H>::value; |
2948 | } |
2949 | |
2950 | } // namespace hash |
2951 | |
2952 | } // namespace detail_ |
2953 | |
2954 | #undef AUTO |
2955 | #undef AUTO_RETURN |
2956 | |
2957 | #undef AUTO_REFREF |
2958 | #undef AUTO_REFREF_RETURN |
2959 | |
2960 | #undef DECLTYPE_AUTO |
2961 | #undef DECLTYPE_AUTO_RETURN |
2962 | |
2963 | } // namespace c10 |
2964 | |
2965 | namespace std { |
2966 | |
2967 | template <typename... Ts> |
2968 | struct hash<c10::detail_::enabled_type< |
2969 | c10::variant<Ts...>, |
2970 | c10::lib::enable_if_t<c10::lib::all<c10::detail_::hash::is_enabled< |
2971 | c10::lib::remove_const_t<Ts>>()...>::value>>> { |
2972 | using argument_type = c10::variant<Ts...>; |
2973 | using result_type = std::size_t; |
2974 | |
2975 | inline result_type operator()(const argument_type& v) const { |
2976 | using c10::detail_::visitation::variant; |
2977 | std::size_t result = v.valueless_by_exception() |
2978 | ? 299792458 // Random value chosen by the universe upon creation |
2979 | : variant::visit_alt( |
2980 | #ifdef C10_MPARK_GENERIC_LAMBDAS |
2981 | [](const auto& alt) { |
2982 | using alt_type = c10::lib::decay_t<decltype(alt)>; |
2983 | using value_type = |
2984 | c10::lib::remove_const_t<typename alt_type::value_type>; |
2985 | return hash<value_type>{}(alt.value); |
2986 | } |
2987 | #else |
2988 | hasher {} |
2989 | #endif |
2990 | , |
2991 | v); |
2992 | return hash_combine(result, hash<std::size_t>{}(v.index())); |
2993 | } |
2994 | |
2995 | private: |
2996 | #ifndef C10_MPARK_GENERIC_LAMBDAS |
2997 | struct hasher { |
2998 | template <typename Alt> |
2999 | inline std::size_t operator()(const Alt& alt) const { |
3000 | using alt_type = c10::lib::decay_t<Alt>; |
3001 | using value_type = |
3002 | c10::lib::remove_const_t<typename alt_type::value_type>; |
3003 | return hash<value_type>{}(alt.value); |
3004 | } |
3005 | }; |
3006 | #endif |
3007 | |
3008 | static std::size_t hash_combine(std::size_t lhs, std::size_t rhs) { |
3009 | return lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2); |
3010 | } |
3011 | }; |
3012 | |
3013 | template <> |
3014 | struct hash<c10::monostate> { |
3015 | using argument_type = c10::monostate; |
3016 | using result_type = std::size_t; |
3017 | |
3018 | inline result_type operator()(const argument_type&) const noexcept { |
3019 | return 66740831; // return a fundamentally attractive random value. |
3020 | } |
3021 | }; |
3022 | |
3023 | } // namespace std |
3024 | |
3025 | #endif // C10_UTIL_VARIANT_H_ |
3026 | |