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