| /* |
| * Copyright (C) 2025 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #pragma once |
| |
| // MPark.Variant |
| // |
| // Copyright Michael Park, 2015-2017 |
| // |
| // Distributed under the Boost Software License, Version 1.0. |
| /* |
| Boost Software License - Version 1.0 - August 17th, 2003 |
| |
| Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: |
| |
| The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #ifndef MPARK_VARIANT_HPP |
| #define MPARK_VARIANT_HPP |
| |
| /* |
| variant synopsis |
| |
| namespace std { |
| |
| // 20.7.2, class template variant |
| template <class... Types> |
| class variant { |
| public: |
| |
| // 20.7.2.1, constructors |
| constexpr variant() noexcept(see below); |
| variant(const variant&); |
| variant(variant&&) noexcept(see below); |
| |
| template <class T> constexpr variant(T&&) noexcept(see below); |
| |
| template <class T, class... Args> |
| constexpr explicit variant(in_place_type_t<T>, Args&&...); |
| |
| template <class T, class U, class... Args> |
| constexpr explicit variant( |
| in_place_type_t<T>, initializer_list<U>, Args&&...); |
| |
| template <size_t I, class... Args> |
| constexpr explicit variant(in_place_index_t<I>, Args&&...); |
| |
| template <size_t I, class U, class... Args> |
| constexpr explicit variant( |
| in_place_index_t<I>, initializer_list<U>, Args&&...); |
| |
| // 20.7.2.2, destructor |
| ~variant(); |
| |
| // 20.7.2.3, assignment |
| variant& operator=(const variant&); |
| variant& operator=(variant&&) noexcept(see below); |
| |
| template <class T> variant& operator=(T&&) noexcept(see below); |
| |
| // 20.7.2.4, modifiers |
| template <class T, class... Args> |
| T& emplace(Args&&...); |
| |
| template <class T, class U, class... Args> |
| T& emplace(initializer_list<U>, Args&&...); |
| |
| template <size_t I, class... Args> |
| variant_alternative<I, variant>& emplace(Args&&...); |
| |
| template <size_t I, class U, class... Args> |
| variant_alternative<I, variant>& emplace(initializer_list<U>, Args&&...); |
| |
| // 20.7.2.5, value status |
| constexpr bool valueless_by_exception() const noexcept; |
| constexpr size_t index() const noexcept; |
| |
| // 20.7.2.6, swap |
| void swap(variant&) noexcept(see below); |
| }; |
| |
| // 20.7.3, variant helper classes |
| template <class T> struct variant_size; // undefined |
| |
| template <class T> |
| constexpr size_t variant_size_v = variant_size<T>::value; |
| |
| template <class T> struct variant_size<const T>; |
| template <class T> struct variant_size<volatile T>; |
| template <class T> struct variant_size<const volatile T>; |
| |
| template <class... Types> |
| struct variant_size<variant<Types...>>; |
| |
| template <size_t I, class T> struct variant_alternative; // undefined |
| |
| template <size_t I, class T> |
| using variant_alternative_t = typename variant_alternative<I, T>::type; |
| |
| template <size_t I, class T> struct variant_alternative<I, const T>; |
| template <size_t I, class T> struct variant_alternative<I, volatile T>; |
| template <size_t I, class T> struct variant_alternative<I, const volatile T>; |
| |
| template <size_t I, class... Types> |
| struct variant_alternative<I, variant<Types...>>; |
| |
| constexpr size_t variant_npos = -1; |
| |
| // 20.7.4, value access |
| template <class T, class... Types> |
| constexpr bool holds_alternative(const variant<Types...>&) noexcept; |
| |
| template <size_t I, class... Types> |
| constexpr variant_alternative_t<I, variant<Types...>>& |
| get(variant<Types...>&); |
| |
| template <size_t I, class... Types> |
| constexpr variant_alternative_t<I, variant<Types...>>&& |
| get(variant<Types...>&&); |
| |
| template <size_t I, class... Types> |
| constexpr variant_alternative_t<I, variant<Types...>> const& |
| get(const variant<Types...>&); |
| |
| template <size_t I, class... Types> |
| constexpr variant_alternative_t<I, variant<Types...>> const&& |
| get(const variant<Types...>&&); |
| |
| template <class T, class... Types> |
| constexpr T& get(variant<Types...>&); |
| |
| template <class T, class... Types> |
| constexpr T&& get(variant<Types...>&&); |
| |
| template <class T, class... Types> |
| constexpr const T& get(const variant<Types...>&); |
| |
| template <class T, class... Types> |
| constexpr const T&& get(const variant<Types...>&&); |
| |
| template <size_t I, class... Types> |
| constexpr add_pointer_t<variant_alternative_t<I, variant<Types...>>> |
| get_if(variant<Types...>*) noexcept; |
| |
| template <size_t I, class... Types> |
| constexpr add_pointer_t<const variant_alternative_t<I, variant<Types...>>> |
| get_if(const variant<Types...>*) noexcept; |
| |
| template <class T, class... Types> |
| constexpr add_pointer_t<T> |
| get_if(variant<Types...>*) noexcept; |
| |
| template <class T, class... Types> |
| constexpr add_pointer_t<const T> |
| get_if(const variant<Types...>*) noexcept; |
| |
| // 20.7.5, relational operators |
| template <class... Types> |
| constexpr bool operator==(const variant<Types...>&, const variant<Types...>&); |
| |
| template <class... Types> |
| constexpr bool operator!=(const variant<Types...>&, const variant<Types...>&); |
| |
| template <class... Types> |
| constexpr bool operator<(const variant<Types...>&, const variant<Types...>&); |
| |
| template <class... Types> |
| constexpr bool operator>(const variant<Types...>&, const variant<Types...>&); |
| |
| template <class... Types> |
| constexpr bool operator<=(const variant<Types...>&, const variant<Types...>&); |
| |
| template <class... Types> |
| constexpr bool operator>=(const variant<Types...>&, const variant<Types...>&); |
| |
| // 20.7.6, visitation |
| template <class Visitor, class... Variants> |
| constexpr see below visit(Visitor&&, Variants&&...); |
| |
| // 20.7.7, class monostate |
| struct monostate; |
| |
| // 20.7.8, monostate relational operators |
| constexpr bool operator<(monostate, monostate) noexcept; |
| constexpr bool operator>(monostate, monostate) noexcept; |
| constexpr bool operator<=(monostate, monostate) noexcept; |
| constexpr bool operator>=(monostate, monostate) noexcept; |
| constexpr bool operator==(monostate, monostate) noexcept; |
| constexpr bool operator!=(monostate, monostate) noexcept; |
| |
| // 20.7.9, specialized algorithms |
| template <class... Types> |
| void swap(variant<Types...>&, variant<Types...>&) noexcept(see below); |
| |
| // 20.7.10, class bad_variant_access |
| class bad_variant_access; |
| |
| // 20.7.11, hash support |
| template <class T> struct hash; |
| template <class... Types> struct hash<variant<Types...>>; |
| template <> struct hash<monostate>; |
| |
| } // namespace std |
| |
| */ |
| |
| #include <cstddef> |
| #include <exception> |
| #include <functional> |
| #include <initializer_list> |
| #include <limits> |
| #include <new> |
| #include <type_traits> |
| #include <utility> |
| |
| // MPark.Variant |
| // |
| // Copyright Michael Park, 2015-2017 |
| // |
| // Distributed under the Boost Software License, Version 1.0. |
| /* |
| Boost Software License - Version 1.0 - August 17th, 2003 |
| |
| Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: |
| |
| The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #ifndef MPARK_CONFIG_HPP |
| #define MPARK_CONFIG_HPP |
| |
| // MSVC 2015 Update 3. |
| #if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_FULL_VER < 190024210) |
| #error "MPark.Variant requires C++11 support." |
| #endif |
| |
| #ifndef __has_attribute |
| #define __has_attribute(x) 0 |
| #endif |
| |
| #ifndef __has_builtin |
| #define __has_builtin(x) 0 |
| #endif |
| |
| #ifndef __has_include |
| #define __has_include(x) 0 |
| #endif |
| |
| #ifndef __has_feature |
| #define __has_feature(x) 0 |
| #endif |
| |
| #if __has_attribute(always_inline) || defined(__GNUC__) |
| #define MPARK_ALWAYS_INLINE __attribute__((__always_inline__)) inline |
| #elif defined(_MSC_VER) |
| #define MPARK_ALWAYS_INLINE __forceinline |
| #else |
| #define MPARK_ALWAYS_INLINE inline |
| #endif |
| |
| #if __has_builtin(__builtin_addressof) || \ |
| (defined(__GNUC__) && __GNUC__ >= 7) || defined(_MSC_VER) |
| #define MPARK_BUILTIN_ADDRESSOF |
| #endif |
| |
| #if __has_builtin(__builtin_unreachable) || defined(__GNUC__) |
| #define MPARK_BUILTIN_UNREACHABLE __builtin_unreachable() |
| #elif defined(_MSC_VER) |
| #define MPARK_BUILTIN_UNREACHABLE __assume(false) |
| #else |
| #define MPARK_BUILTIN_UNREACHABLE |
| #endif |
| |
| #if __has_builtin(__type_pack_element) && !(defined(__ICC)) |
| #define MPARK_TYPE_PACK_ELEMENT |
| #endif |
| |
| #if defined(__cpp_constexpr) && __cpp_constexpr >= 200704 && \ |
| !(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 9) |
| #define MPARK_CPP11_CONSTEXPR |
| #endif |
| |
| #if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 |
| #define MPARK_CPP14_CONSTEXPR |
| #endif |
| |
| #if 0 |
| #define MPARK_EXCEPTIONS |
| #endif |
| |
| #if defined(__cpp_generic_lambdas) || defined(_MSC_VER) |
| #define MPARK_GENERIC_LAMBDAS |
| #endif |
| |
| #if defined(__cpp_lib_integer_sequence) |
| #define MPARK_INTEGER_SEQUENCE |
| #endif |
| |
| #if (defined(__cpp_decltype_auto) && defined(__cpp_return_type_deduction)) || defined(_MSC_VER) |
| #define MPARK_RETURN_TYPE_DEDUCTION |
| #endif |
| |
| #if defined(__cpp_lib_transparent_operators) || defined(_MSC_VER) |
| #define MPARK_TRANSPARENT_OPERATORS |
| #endif |
| |
| #if defined(__cpp_variable_templates) || defined(_MSC_VER) |
| #define MPARK_VARIABLE_TEMPLATES |
| #endif |
| |
| #if !defined(__GLIBCXX__) || __has_include(<codecvt>) // >= libstdc++-5 |
| #define MPARK_TRIVIALITY_TYPE_TRAITS |
| #define MPARK_INCOMPLETE_TYPE_TRAITS |
| #endif |
| |
| #endif // MPARK_CONFIG_HPP |
| // MPark.Variant |
| // |
| // Copyright Michael Park, 2015-2017 |
| // |
| // Distributed under the Boost Software License, Version 1.0. |
| /* |
| Boost Software License - Version 1.0 - August 17th, 2003 |
| |
| Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: |
| |
| The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #ifndef MPARK_IN_PLACE_HPP |
| #define MPARK_IN_PLACE_HPP |
| |
| #include <cstddef> |
| |
| namespace mpark { |
| |
| struct in_place_t { explicit in_place_t() = default; }; |
| |
| template <std::size_t I> |
| struct in_place_index_t { explicit in_place_index_t() = default; }; |
| |
| template <typename T> |
| struct in_place_type_t { explicit in_place_type_t() = default; }; |
| |
| #ifdef MPARK_VARIABLE_TEMPLATES |
| constexpr in_place_t in_place{}; |
| |
| template <std::size_t I> constexpr in_place_index_t<I> in_place_index{}; |
| |
| template <typename T> constexpr in_place_type_t<T> in_place_type{}; |
| #endif |
| |
| } // namespace mpark |
| |
| #endif // MPARK_IN_PLACE_HPP |
| // MPark.Variant |
| // |
| // Copyright Michael Park, 2015-2017 |
| // |
| // Distributed under the Boost Software License, Version 1.0. |
| /* |
| Boost Software License - Version 1.0 - August 17th, 2003 |
| |
| Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: |
| |
| The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #ifndef MPARK_LIB_HPP |
| #define MPARK_LIB_HPP |
| |
| #include <array> |
| #include <memory> |
| #include <functional> |
| #include <type_traits> |
| #include <utility> |
| #include <wtf/Assertions.h> |
| |
| #define MPARK_RETURN(...) \ |
| noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { return __VA_ARGS__; } |
| |
| namespace mpark { |
| namespace lib { |
| template <typename T> |
| struct identity { using type = T; }; |
| |
| inline namespace cpp14 { |
| template <typename T, std::size_t N> |
| struct array { |
| constexpr const T &operator[](std::size_t index) const { |
| return data[index]; |
| } |
| |
| std::array<T, N == 0 ? 1 : N> data; |
| }; |
| |
| template <typename T> |
| using add_pointer_t = typename std::add_pointer<T>::type; |
| |
| template <typename... Ts> |
| using common_type_t = typename std::common_type<Ts...>::type; |
| |
| template <typename T> |
| using decay_t = typename std::decay<T>::type; |
| |
| template <bool B, typename T = void> |
| using enable_if_t = typename std::enable_if<B, T>::type; |
| |
| template <typename T> |
| using remove_const_t = typename std::remove_const<T>::type; |
| |
| template <typename T> |
| using remove_reference_t = typename std::remove_reference<T>::type; |
| |
| template <typename T> |
| using remove_cvref_t = |
| typename std::remove_cv<remove_reference_t<T>>::type; |
| |
| template <typename T> |
| inline constexpr T &&forward(remove_reference_t<T> &t) noexcept { |
| return static_cast<T &&>(t); |
| } |
| |
| template <typename T> |
| inline constexpr T &&forward(remove_reference_t<T> &&t) noexcept { |
| static_assert(!std::is_lvalue_reference<T>::value, |
| "can not forward an rvalue as an lvalue"); |
| return static_cast<T &&>(t); |
| } |
| |
| template <typename T> |
| inline constexpr remove_reference_t<T> &&move(T &&t) noexcept { |
| return static_cast<remove_reference_t<T> &&>(t); |
| } |
| |
| #ifdef MPARK_INTEGER_SEQUENCE |
| using std::integer_sequence; |
| using std::index_sequence; |
| using std::make_index_sequence; |
| using std::index_sequence_for; |
| #else |
| template <typename T, T... Is> |
| struct integer_sequence { |
| using value_type = T; |
| static constexpr std::size_t size() noexcept { return sizeof...(Is); } |
| }; |
| |
| template <std::size_t... Is> |
| using index_sequence = integer_sequence<std::size_t, Is...>; |
| |
| template <typename Lhs, typename Rhs> |
| struct make_index_sequence_concat; |
| |
| template <std::size_t... Lhs, std::size_t... Rhs> |
| struct make_index_sequence_concat<index_sequence<Lhs...>, |
| index_sequence<Rhs...>> |
| : identity<index_sequence<Lhs..., (sizeof...(Lhs) + Rhs)...>> {}; |
| |
| template <std::size_t N> |
| struct make_index_sequence_impl; |
| |
| template <std::size_t N> |
| using make_index_sequence = typename make_index_sequence_impl<N>::type; |
| |
| template <std::size_t N> |
| struct make_index_sequence_impl |
| : make_index_sequence_concat<make_index_sequence<N / 2>, |
| make_index_sequence<N - (N / 2)>> {}; |
| |
| template <> |
| struct make_index_sequence_impl<0> : identity<index_sequence<>> {}; |
| |
| template <> |
| struct make_index_sequence_impl<1> : identity<index_sequence<0>> {}; |
| |
| template <typename... Ts> |
| using index_sequence_for = make_index_sequence<sizeof...(Ts)>; |
| #endif |
| |
| // <functional> |
| #ifdef MPARK_TRANSPARENT_OPERATORS |
| using equal_to = std::equal_to<>; |
| #else |
| struct equal_to { |
| template <typename Lhs, typename Rhs> |
| inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const |
| MPARK_RETURN(lib::forward<Lhs>(lhs) == lib::forward<Rhs>(rhs)) |
| }; |
| #endif |
| |
| #ifdef MPARK_TRANSPARENT_OPERATORS |
| using not_equal_to = std::not_equal_to<>; |
| #else |
| struct not_equal_to { |
| template <typename Lhs, typename Rhs> |
| inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const |
| MPARK_RETURN(lib::forward<Lhs>(lhs) != lib::forward<Rhs>(rhs)) |
| }; |
| #endif |
| |
| #ifdef MPARK_TRANSPARENT_OPERATORS |
| using less = std::less<>; |
| #else |
| struct less { |
| template <typename Lhs, typename Rhs> |
| inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const |
| MPARK_RETURN(lib::forward<Lhs>(lhs) < lib::forward<Rhs>(rhs)) |
| }; |
| #endif |
| |
| #ifdef MPARK_TRANSPARENT_OPERATORS |
| using greater = std::greater<>; |
| #else |
| struct greater { |
| template <typename Lhs, typename Rhs> |
| inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const |
| MPARK_RETURN(lib::forward<Lhs>(lhs) > lib::forward<Rhs>(rhs)) |
| }; |
| #endif |
| |
| #ifdef MPARK_TRANSPARENT_OPERATORS |
| using less_equal = std::less_equal<>; |
| #else |
| struct less_equal { |
| template <typename Lhs, typename Rhs> |
| inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const |
| MPARK_RETURN(lib::forward<Lhs>(lhs) <= lib::forward<Rhs>(rhs)) |
| }; |
| #endif |
| |
| #ifdef MPARK_TRANSPARENT_OPERATORS |
| using greater_equal = std::greater_equal<>; |
| #else |
| struct greater_equal { |
| template <typename Lhs, typename Rhs> |
| inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const |
| MPARK_RETURN(lib::forward<Lhs>(lhs) >= lib::forward<Rhs>(rhs)) |
| }; |
| #endif |
| } // namespace cpp14 |
| |
| inline namespace cpp17 { |
| |
| // <type_traits> |
| template <bool B> |
| using bool_constant = std::integral_constant<bool, B>; |
| |
| template <typename...> |
| struct voider : identity<void> {}; |
| |
| template <typename... Ts> |
| using void_t = typename voider<Ts...>::type; |
| |
| namespace detail { |
| namespace swappable { |
| |
| using std::swap; |
| |
| template <typename T> |
| struct is_swappable { |
| private: |
| template <typename U, |
| typename = decltype(swap(std::declval<U &>(), |
| std::declval<U &>()))> |
| inline static std::true_type test(int); |
| |
| template <typename U> |
| inline static std::false_type test(...); |
| |
| public: |
| static constexpr bool value = decltype(test<T>(0))::value; |
| }; |
| |
| template <bool IsSwappable, typename T> |
| struct is_nothrow_swappable { |
| static constexpr bool value = |
| noexcept(swap(std::declval<T &>(), std::declval<T &>())); |
| }; |
| |
| template <typename T> |
| struct is_nothrow_swappable<false, T> : std::false_type {}; |
| |
| } // namespace swappable |
| } // namespace detail |
| |
| using detail::swappable::is_swappable; |
| |
| template <typename T> |
| using is_nothrow_swappable = |
| detail::swappable::is_nothrow_swappable<is_swappable<T>::value, T>; |
| |
| // <functional> |
| namespace detail { |
| |
| template <typename T> |
| struct is_reference_wrapper : std::false_type {}; |
| |
| template <typename T> |
| struct is_reference_wrapper<std::reference_wrapper<T>> |
| : std::true_type {}; |
| |
| template <bool, int> |
| struct Invoke; |
| |
| template <> |
| struct Invoke<true /* pmf */, 0 /* is_base_of */> { |
| template <typename R, typename T, typename Arg, typename... Args> |
| inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) |
| MPARK_RETURN((lib::forward<Arg>(arg).*pmf)(lib::forward<Args>(args)...)) |
| }; |
| |
| template <> |
| struct Invoke<true /* pmf */, 1 /* is_reference_wrapper */> { |
| template <typename R, typename T, typename Arg, typename... Args> |
| inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) |
| MPARK_RETURN((lib::forward<Arg>(arg).get().*pmf)(lib::forward<Args>(args)...)) |
| }; |
| |
| template <> |
| struct Invoke<true /* pmf */, 2 /* otherwise */> { |
| template <typename R, typename T, typename Arg, typename... Args> |
| inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) |
| MPARK_RETURN(((*lib::forward<Arg>(arg)).*pmf)(lib::forward<Args>(args)...)) |
| }; |
| |
| template <> |
| struct Invoke<false /* pmo */, 0 /* is_base_of */> { |
| template <typename R, typename T, typename Arg> |
| inline static constexpr auto invoke(R T::*pmo, Arg &&arg) |
| MPARK_RETURN(lib::forward<Arg>(arg).*pmo) |
| }; |
| |
| template <> |
| struct Invoke<false /* pmo */, 1 /* is_reference_wrapper */> { |
| template <typename R, typename T, typename Arg> |
| inline static constexpr auto invoke(R T::*pmo, Arg &&arg) |
| MPARK_RETURN(lib::forward<Arg>(arg).get().*pmo) |
| }; |
| |
| template <> |
| struct Invoke<false /* pmo */, 2 /* otherwise */> { |
| template <typename R, typename T, typename Arg> |
| inline static constexpr auto invoke(R T::*pmo, Arg &&arg) |
| MPARK_RETURN((*lib::forward<Arg>(arg)).*pmo) |
| }; |
| |
| template <typename R, typename T, typename Arg, typename... Args> |
| inline constexpr auto invoke(R T::*f, Arg &&arg, Args &&... args) |
| MPARK_RETURN( |
| Invoke<std::is_function<R>::value, |
| (std::is_base_of<T, lib::decay_t<Arg>>::value |
| ? 0 |
| : is_reference_wrapper<lib::decay_t<Arg>>::value |
| ? 1 |
| : 2)>::invoke(f, |
| lib::forward<Arg>(arg), |
| lib::forward<Args>(args)...)) |
| |
| #ifdef _MSC_VER |
| #pragma warning(push) |
| #pragma warning(disable : 4100) |
| #endif |
| template <typename F, typename... Args> |
| inline constexpr auto invoke(F &&f, Args &&... args) |
| MPARK_RETURN(lib::forward<F>(f)(lib::forward<Args>(args)...)) |
| #ifdef _MSC_VER |
| #pragma warning(pop) |
| #endif |
| } // namespace detail |
| |
| template <typename F, typename... Args> |
| inline constexpr auto invoke(F &&f, Args &&... args) |
| MPARK_RETURN(detail::invoke(lib::forward<F>(f), |
| lib::forward<Args>(args)...)) |
| |
| namespace detail { |
| |
| template <typename Void, typename, typename...> |
| struct invoke_result {}; |
| |
| template <typename F, typename... Args> |
| struct invoke_result<void_t<decltype(lib::invoke( |
| std::declval<F>(), std::declval<Args>()...))>, |
| F, |
| Args...> |
| : identity<decltype( |
| lib::invoke(std::declval<F>(), std::declval<Args>()...))> {}; |
| |
| } // namespace detail |
| |
| template <typename F, typename... Args> |
| using invoke_result = detail::invoke_result<void, F, Args...>; |
| |
| template <typename F, typename... Args> |
| using invoke_result_t = typename invoke_result<F, Args...>::type; |
| |
| namespace detail { |
| |
| template <typename Void, typename, typename...> |
| struct is_invocable : std::false_type {}; |
| |
| template <typename F, typename... Args> |
| struct is_invocable<void_t<invoke_result_t<F, Args...>>, F, Args...> |
| : std::true_type {}; |
| |
| template <typename Void, typename, typename, typename...> |
| struct is_invocable_r : std::false_type {}; |
| |
| template <typename R, typename F, typename... Args> |
| struct is_invocable_r<void_t<invoke_result_t<F, Args...>>, |
| R, |
| F, |
| Args...> |
| : std::is_convertible<invoke_result_t<F, Args...>, R> {}; |
| |
| } // namespace detail |
| |
| template <typename F, typename... Args> |
| using is_invocable = detail::is_invocable<void, F, Args...>; |
| |
| template <typename R, typename F, typename... Args> |
| using is_invocable_r = detail::is_invocable_r<void, R, F, Args...>; |
| |
| // <memory> |
| #ifdef MPARK_BUILTIN_ADDRESSOF |
| template <typename T> |
| inline constexpr T *addressof(T &arg) noexcept { |
| return __builtin_addressof(arg); |
| } |
| #else |
| namespace detail { |
| |
| namespace has_addressof_impl { |
| |
| struct fail; |
| |
| template <typename T> |
| inline fail operator&(T &&); |
| |
| template <typename T> |
| inline static constexpr bool impl() { |
| return (std::is_class<T>::value || std::is_union<T>::value) && |
| !std::is_same<decltype(&std::declval<T &>()), fail>::value; |
| } |
| |
| } // namespace has_addressof_impl |
| |
| template <typename T> |
| using has_addressof = bool_constant<has_addressof_impl::impl<T>()>; |
| |
| template <typename T> |
| inline constexpr T *addressof(T &arg, std::true_type) noexcept { |
| return std::addressof(arg); |
| } |
| |
| template <typename T> |
| inline constexpr T *addressof(T &arg, std::false_type) noexcept { |
| return &arg; |
| } |
| |
| } // namespace detail |
| |
| template <typename T> |
| inline constexpr T *addressof(T &arg) noexcept { |
| return detail::addressof(arg, detail::has_addressof<T>{}); |
| } |
| #endif |
| |
| template <typename T> |
| inline constexpr T *addressof(const T &&) = delete; |
| |
| } // namespace cpp17 |
| |
| template <typename T> |
| struct remove_all_extents : identity<T> {}; |
| |
| template <typename T, std::size_t N> |
| struct remove_all_extents<array<T, N>> : remove_all_extents<T> {}; |
| |
| template <typename T> |
| using remove_all_extents_t = typename remove_all_extents<T>::type; |
| |
| template <std::size_t N> |
| using size_constant = std::integral_constant<std::size_t, N>; |
| |
| template <std::size_t I, typename T> |
| struct indexed_type : size_constant<I> { using type = T; }; |
| |
| template <bool... Bs> |
| using all = std::is_same<integer_sequence<bool, true, Bs...>, |
| integer_sequence<bool, Bs..., true>>; |
| |
| #ifdef MPARK_TYPE_PACK_ELEMENT |
| #ifdef __clang__ |
| template <std::size_t I, typename... Ts> |
| using type_pack_element_t = __type_pack_element<I, Ts...>; |
| #else |
| template <std::size_t I, typename... Ts> |
| struct type_pack_element_impl { |
| using type = __type_pack_element<I, Ts...>; |
| }; |
| |
| template <std::size_t I, typename... Ts> |
| using type_pack_element_t = typename type_pack_element_impl<I, Ts...>::type; |
| #endif |
| #else |
| template <std::size_t I, typename... Ts> |
| struct type_pack_element_impl { |
| private: |
| template <typename> |
| struct set; |
| |
| template <std::size_t... Is> |
| struct set<index_sequence<Is...>> : indexed_type<Is, Ts>... {}; |
| |
| template <typename T> |
| inline static std::enable_if<true, T> impl(indexed_type<I, T>); |
| |
| inline static std::enable_if<false> impl(...); |
| |
| public: |
| using type = decltype(impl(set<index_sequence_for<Ts...>>{})); |
| }; |
| |
| template <std::size_t I, typename... Ts> |
| using type_pack_element = typename type_pack_element_impl<I, Ts...>::type; |
| |
| template <std::size_t I, typename... Ts> |
| using type_pack_element_t = typename type_pack_element<I, Ts...>::type; |
| #endif |
| |
| template <typename T, bool> |
| struct dependent_type : T {}; |
| |
| template <typename Is, std::size_t J> |
| struct push_back; |
| |
| template <typename Is, std::size_t J> |
| using push_back_t = typename push_back<Is, J>::type; |
| |
| template <std::size_t... Is, std::size_t J> |
| struct push_back<index_sequence<Is...>, J> { |
| using type = index_sequence<Is..., J>; |
| }; |
| |
| } // namespace lib |
| } // namespace mpark |
| |
| #undef MPARK_RETURN |
| |
| #endif // MPARK_LIB_HPP |
| |
| namespace mpark { |
| |
| #ifdef MPARK_RETURN_TYPE_DEDUCTION |
| |
| #define AUTO auto |
| #define AUTO_RETURN(...) { return __VA_ARGS__; } |
| |
| #define AUTO_REFREF auto && |
| #define AUTO_REFREF_RETURN(...) { return __VA_ARGS__; } |
| |
| #define DECLTYPE_AUTO decltype(auto) |
| #define DECLTYPE_AUTO_RETURN(...) { return __VA_ARGS__; } |
| |
| #else |
| |
| #define AUTO auto |
| #define AUTO_RETURN(...) \ |
| -> lib::decay_t<decltype(__VA_ARGS__)> { return __VA_ARGS__; } |
| |
| #define AUTO_REFREF auto |
| #define AUTO_REFREF_RETURN(...) \ |
| -> decltype((__VA_ARGS__)) { \ |
| static_assert(std::is_reference<decltype((__VA_ARGS__))>::value, ""); \ |
| return __VA_ARGS__; \ |
| } |
| |
| #define DECLTYPE_AUTO auto |
| #define DECLTYPE_AUTO_RETURN(...) \ |
| -> decltype(__VA_ARGS__) { return __VA_ARGS__; } |
| |
| #endif |
| |
| class bad_variant_access : public std::exception { |
| public: |
| [[nodiscard]] virtual const char *what() const noexcept override { return "bad_variant_access"; } |
| }; |
| |
| [[noreturn]] inline void throw_bad_variant_access() { |
| #ifdef MPARK_EXCEPTIONS |
| throw bad_variant_access{}; |
| #else |
| std::terminate(); |
| MPARK_BUILTIN_UNREACHABLE; |
| #endif |
| } |
| |
| template <typename... Ts> |
| class variant; |
| |
| template <typename T> |
| struct variant_size; |
| |
| #ifdef MPARK_VARIABLE_TEMPLATES |
| template <typename T> |
| constexpr std::size_t variant_size_v = variant_size<T>::value; |
| #endif |
| |
| template <typename T> |
| struct variant_size<const T> : variant_size<T> {}; |
| |
| template <typename T> |
| struct variant_size<volatile T> : variant_size<T> {}; |
| |
| template <typename T> |
| struct variant_size<const volatile T> : variant_size<T> {}; |
| |
| template <typename... Ts> |
| struct variant_size<variant<Ts...>> : lib::size_constant<sizeof...(Ts)> {}; |
| |
| template <std::size_t I, typename T> |
| struct variant_alternative; |
| |
| template <std::size_t I, typename T> |
| using variant_alternative_t = typename variant_alternative<I, T>::type; |
| |
| template <std::size_t I, typename T> |
| struct variant_alternative<I, const T> |
| : std::add_const<variant_alternative_t<I, T>> {}; |
| |
| template <std::size_t I, typename T> |
| struct variant_alternative<I, volatile T> |
| : std::add_volatile<variant_alternative_t<I, T>> {}; |
| |
| template <std::size_t I, typename T> |
| struct variant_alternative<I, const volatile T> |
| : std::add_cv<variant_alternative_t<I, T>> {}; |
| |
| template <std::size_t I, typename... Ts> |
| struct variant_alternative<I, variant<Ts...>> { |
| static_assert(I < sizeof...(Ts), |
| "index out of bounds in `std::variant_alternative<>`"); |
| using type = lib::type_pack_element_t<I, Ts...>; |
| }; |
| |
| constexpr std::size_t variant_npos = static_cast<std::size_t>(-1); |
| |
| namespace detail { |
| |
| constexpr std::size_t not_found = static_cast<std::size_t>(-1); |
| constexpr std::size_t ambiguous = static_cast<std::size_t>(-2); |
| |
| #ifdef MPARK_CPP14_CONSTEXPR |
| template <typename T, typename... Ts> |
| inline constexpr std::size_t find_index() { |
| constexpr lib::array<bool, sizeof...(Ts)> matches = { |
| {std::is_same<T, Ts>::value...} |
| }; |
| std::size_t result = not_found; |
| for (std::size_t i = 0; i < sizeof...(Ts); ++i) { |
| if (matches[i]) { |
| if (result != not_found) { |
| return ambiguous; |
| } |
| result = i; |
| } |
| } |
| return result; |
| } |
| #else |
| inline constexpr std::size_t find_index_impl(std::size_t result, |
| std::size_t) { |
| return result; |
| } |
| |
| template <typename... Bs> |
| inline constexpr std::size_t find_index_impl(std::size_t result, |
| std::size_t idx, |
| bool b, |
| Bs... bs) { |
| return b ? (result != not_found ? ambiguous |
| : find_index_impl(idx, idx + 1, bs...)) |
| : find_index_impl(result, idx + 1, bs...); |
| } |
| |
| template <typename T, typename... Ts> |
| inline constexpr std::size_t find_index() { |
| return find_index_impl(not_found, 0, std::is_same<T, Ts>::value...); |
| } |
| #endif |
| |
| template <std::size_t I> |
| using find_index_sfinae_impl = |
| lib::enable_if_t<I != not_found && I != ambiguous, |
| lib::size_constant<I>>; |
| |
| template <typename T, typename... Ts> |
| using find_index_sfinae = find_index_sfinae_impl<find_index<T, Ts...>()>; |
| |
| template <std::size_t I> |
| struct find_index_checked_impl : lib::size_constant<I> { |
| static_assert(I != not_found, "the specified type is not found."); |
| static_assert(I != ambiguous, "the specified type is ambiguous."); |
| }; |
| |
| template <typename T, typename... Ts> |
| using find_index_checked = find_index_checked_impl<find_index<T, Ts...>()>; |
| |
| struct valueless_t {}; |
| |
| namespace access { |
| |
| struct base { |
| template <std::size_t I, typename V> |
| inline static constexpr decltype(auto) get_alt(V &&v) { |
| return as_base(lib::forward<V>(v)).template get_alt<I>(); |
| } |
| }; |
| |
| struct variant { |
| template <std::size_t I, typename V> |
| inline static constexpr AUTO_REFREF get_alt(V &&v) |
| AUTO_REFREF_RETURN(base::get_alt<I>(lib::forward<V>(v).impl_)) |
| }; |
| |
| } // namespace access |
| |
| namespace visitation { |
| |
| #if defined(MPARK_CPP14_CONSTEXPR) && !defined(_MSC_VER) |
| #define MPARK_VARIANT_SWITCH_VISIT |
| #endif |
| |
| struct base { |
| template <typename Visitor, typename... Vs> |
| using dispatch_result_t = decltype( |
| lib::invoke(std::declval<Visitor>(), |
| access::base::get_alt<0>(std::declval<Vs>())...)); |
| |
| template <typename Expected> |
| struct expected { |
| template <typename Actual> |
| inline static constexpr bool but_got() { |
| return std::is_same<Expected, Actual>::value; |
| } |
| }; |
| |
| template <typename Expected, typename Actual> |
| struct visit_return_type_check { |
| static_assert( |
| expected<Expected>::template but_got<Actual>(), |
| "`visit` requires the visitor to have a single return type"); |
| |
| template <typename Visitor, typename... Alts> |
| inline static constexpr DECLTYPE_AUTO invoke(Visitor &&visitor, |
| Alts &&... alts) |
| DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward<Visitor>(visitor), |
| lib::forward<Alts>(alts)...)) |
| }; |
| |
| #ifdef MPARK_VARIANT_SWITCH_VISIT |
| template <bool B, typename R, typename... ITs> |
| struct dispatcher; |
| |
| template <typename R, typename... ITs> |
| struct dispatcher<false, R, ITs...> { |
| template <std::size_t B, typename F, typename... Vs> |
| MPARK_ALWAYS_INLINE static constexpr R dispatch( |
| F &&, typename ITs::type &&..., Vs &&...) { |
| MPARK_BUILTIN_UNREACHABLE; |
| } |
| }; |
| |
| template <typename R, typename... ITs> |
| struct dispatcher<true, R, ITs...> { |
| template <std::size_t B, typename F> |
| MPARK_ALWAYS_INLINE static constexpr R dispatch( |
| F &&f, typename ITs::type &&... visited_vs) { |
| using Expected = R; |
| using Actual = decltype(lib::invoke( |
| lib::forward<F>(f), |
| access::base::get_alt<ITs::value>( |
| lib::forward<typename ITs::type>(visited_vs))...)); |
| return visit_return_type_check<Expected, Actual>::invoke( |
| lib::forward<F>(f), |
| access::base::get_alt<ITs::value>( |
| lib::forward<typename ITs::type>(visited_vs))...); |
| } |
| |
| template <std::size_t B, typename F, typename V, typename... Vs> |
| MPARK_ALWAYS_INLINE static constexpr R dispatch( |
| F &&f, typename ITs::type &&... visited_vs, V &&v, Vs &&... vs) { |
| #define MPARK_DISPATCH(I) \ |
| dispatcher<(I < lib::decay_t<V>::size()), \ |
| R, \ |
| ITs..., \ |
| lib::indexed_type<I, V>>:: \ |
| template dispatch<0>(lib::forward<F>(f), \ |
| lib::forward<typename ITs::type>(visited_vs)..., \ |
| lib::forward<V>(v), \ |
| lib::forward<Vs>(vs)...) |
| |
| #define MPARK_DEFAULT(I) \ |
| dispatcher<(I < lib::decay_t<V>::size()), R, ITs...>::template dispatch<I>( \ |
| lib::forward<F>(f), \ |
| lib::forward<typename ITs::type>(visited_vs)..., \ |
| lib::forward<V>(v), \ |
| lib::forward<Vs>(vs)...) |
| |
| switch (v.index()) { |
| case B + 0: return MPARK_DISPATCH(B + 0); |
| case B + 1: return MPARK_DISPATCH(B + 1); |
| case B + 2: return MPARK_DISPATCH(B + 2); |
| case B + 3: return MPARK_DISPATCH(B + 3); |
| case B + 4: return MPARK_DISPATCH(B + 4); |
| case B + 5: return MPARK_DISPATCH(B + 5); |
| case B + 6: return MPARK_DISPATCH(B + 6); |
| case B + 7: return MPARK_DISPATCH(B + 7); |
| case B + 8: return MPARK_DISPATCH(B + 8); |
| case B + 9: return MPARK_DISPATCH(B + 9); |
| case B + 10: return MPARK_DISPATCH(B + 10); |
| case B + 11: return MPARK_DISPATCH(B + 11); |
| case B + 12: return MPARK_DISPATCH(B + 12); |
| case B + 13: return MPARK_DISPATCH(B + 13); |
| case B + 14: return MPARK_DISPATCH(B + 14); |
| case B + 15: return MPARK_DISPATCH(B + 15); |
| case B + 16: return MPARK_DISPATCH(B + 16); |
| case B + 17: return MPARK_DISPATCH(B + 17); |
| case B + 18: return MPARK_DISPATCH(B + 18); |
| case B + 19: return MPARK_DISPATCH(B + 19); |
| case B + 20: return MPARK_DISPATCH(B + 20); |
| case B + 21: return MPARK_DISPATCH(B + 21); |
| case B + 22: return MPARK_DISPATCH(B + 22); |
| case B + 23: return MPARK_DISPATCH(B + 23); |
| case B + 24: return MPARK_DISPATCH(B + 24); |
| case B + 25: return MPARK_DISPATCH(B + 25); |
| case B + 26: return MPARK_DISPATCH(B + 26); |
| case B + 27: return MPARK_DISPATCH(B + 27); |
| case B + 28: return MPARK_DISPATCH(B + 28); |
| case B + 29: return MPARK_DISPATCH(B + 29); |
| case B + 30: return MPARK_DISPATCH(B + 30); |
| case B + 31: return MPARK_DISPATCH(B + 31); |
| default: return MPARK_DEFAULT(B + 32); |
| } |
| |
| #undef MPARK_DEFAULT |
| #undef MPARK_DISPATCH |
| } |
| }; |
| #else |
| template <typename T> |
| inline static constexpr const T &at(const T &elem) noexcept { |
| return elem; |
| } |
| |
| template <typename T, std::size_t N, typename... Is> |
| inline static constexpr const lib::remove_all_extents_t<T> &at( |
| const lib::array<T, N> &elems, std::size_t i, Is... is) noexcept { |
| return at(elems[i], is...); |
| } |
| |
| template <typename F, typename... Fs> |
| inline static constexpr lib::array<lib::decay_t<F>, sizeof...(Fs) + 1> |
| make_farray(F &&f, Fs &&... fs) { |
| return {{lib::forward<F>(f), lib::forward<Fs>(fs)...}}; |
| } |
| |
| template <typename F, typename... Vs> |
| struct make_fmatrix_impl { |
| |
| template <std::size_t... Is> |
| inline static constexpr dispatch_result_t<F, Vs...> dispatch( |
| F &&f, Vs &&... vs) { |
| using Expected = dispatch_result_t<F, Vs...>; |
| using Actual = decltype(lib::invoke( |
| lib::forward<F>(f), |
| access::base::get_alt<Is>(lib::forward<Vs>(vs))...)); |
| return visit_return_type_check<Expected, Actual>::invoke( |
| lib::forward<F>(f), |
| access::base::get_alt<Is>(lib::forward<Vs>(vs))...); |
| } |
| |
| #ifdef MPARK_RETURN_TYPE_DEDUCTION |
| template <std::size_t... Is> |
| inline static constexpr auto impl(lib::index_sequence<Is...>) { |
| return &dispatch<Is...>; |
| } |
| |
| template <typename Is, std::size_t... Js, typename... Ls> |
| inline static constexpr auto impl(Is, |
| lib::index_sequence<Js...>, |
| Ls... ls) { |
| return make_farray(impl(lib::push_back_t<Is, Js>{}, ls...)...); |
| } |
| #else |
| template <typename...> |
| struct impl; |
| |
| template <std::size_t... Is> |
| struct impl<lib::index_sequence<Is...>> { |
| inline constexpr AUTO operator()() const |
| AUTO_RETURN(&dispatch<Is...>) |
| }; |
| |
| template <typename Is, std::size_t... Js, typename... Ls> |
| struct impl<Is, lib::index_sequence<Js...>, Ls...> { |
| inline constexpr AUTO operator()() const |
| AUTO_RETURN( |
| make_farray(impl<lib::push_back_t<Is, Js>, Ls...>{}()...)) |
| }; |
| #endif |
| }; |
| |
| #ifdef MPARK_RETURN_TYPE_DEDUCTION |
| template <typename F, typename... Vs> |
| inline static constexpr auto make_fmatrix() { |
| return make_fmatrix_impl<F, Vs...>::impl( |
| lib::index_sequence<>{}, |
| lib::make_index_sequence<lib::decay_t<Vs>::size()>{}...); |
| } |
| #else |
| template <typename F, typename... Vs> |
| inline static constexpr AUTO make_fmatrix() |
| AUTO_RETURN( |
| typename make_fmatrix_impl<F, Vs...>::template impl< |
| lib::index_sequence<>, |
| lib::make_index_sequence<lib::decay_t<Vs>::size()>...>{}()) |
| #endif |
| #endif |
| }; |
| |
| #if !defined(MPARK_VARIANT_SWITCH_VISIT) && \ |
| (!defined(_MSC_VER) || _MSC_VER >= 1910) |
| template <typename F, typename... Vs> |
| using fmatrix_t = decltype(base::make_fmatrix<F, Vs...>()); |
| |
| template <typename F, typename... Vs> |
| struct fmatrix { |
| static constexpr fmatrix_t<F, Vs...> value = |
| base::make_fmatrix<F, Vs...>(); |
| }; |
| |
| template <typename F, typename... Vs> |
| constexpr fmatrix_t<F, Vs...> fmatrix<F, Vs...>::value; |
| #endif |
| |
| template <typename R> |
| inline constexpr bool can_fold_result_v = std::is_void_v<R> |
| || (!std::is_reference_v<R> |
| && std::is_default_constructible_v<R> |
| && std::is_move_assignable_v<R>); |
| |
| struct alt { |
| template <typename Visitor, typename V> |
| requires can_fold_result_v<base::dispatch_result_t<Visitor, V>> |
| inline static constexpr decltype(auto) visit_alt(Visitor &&visitor, V &&v) { |
| return visit_alt_at(v.index(), lib::forward<Visitor>(visitor), lib::forward<V>(v)); |
| } |
| |
| template <typename Visitor, typename... Vs> |
| requires (sizeof...(Vs) != 1 |
| || !can_fold_result_v<base::dispatch_result_t<Visitor, Vs...>>) |
| inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, |
| Vs &&... vs) |
| #ifdef MPARK_VARIANT_SWITCH_VISIT |
| DECLTYPE_AUTO_RETURN( |
| base::dispatcher< |
| true, |
| base::dispatch_result_t<Visitor, |
| decltype(as_base( |
| lib::forward<Vs>(vs)))...>>:: |
| template dispatch<0>(lib::forward<Visitor>(visitor), |
| as_base(lib::forward<Vs>(vs))...)) |
| #elif !defined(_MSC_VER) || _MSC_VER >= 1910 |
| DECLTYPE_AUTO_RETURN(base::at( |
| fmatrix<Visitor &&, |
| decltype(as_base(lib::forward<Vs>(vs)))...>::value, |
| vs.index()...)(lib::forward<Visitor>(visitor), |
| as_base(lib::forward<Vs>(vs))...)) |
| #else |
| DECLTYPE_AUTO_RETURN(base::at( |
| base::make_fmatrix<Visitor &&, |
| decltype(as_base(lib::forward<Vs>(vs)))...>(), |
| vs.index()...)(lib::forward<Visitor>(visitor), |
| as_base(lib::forward<Vs>(vs))...)) |
| #endif |
| |
| template <typename Visitor, typename... Vs> |
| inline static constexpr base::dispatch_result_t<Visitor, Vs...> |
| visit_alt_at(std::size_t index, Visitor &&visitor, Vs &&... vs) { |
| #if defined(__GNUC__) && !defined(__clang__) |
| constexpr std::size_t N = lib::decay_t< |
| lib::type_pack_element_t<0, Vs...>>::size(); |
| return switch_at<0, N>(index, lib::forward<Visitor>(visitor), |
| lib::forward<Vs>(vs)...); |
| #else |
| return fold_at(std::make_index_sequence<lib::decay_t< |
| lib::type_pack_element_t<0, Vs...>>::size()>{}, |
| index, lib::forward<Visitor>(visitor), |
| lib::forward<Vs>(vs)...); |
| #endif |
| } |
| |
| private: |
| template <std::size_t I, typename Visitor, typename... Vs> |
| inline static constexpr base::dispatch_result_t<Visitor, Vs...> |
| step_at(Visitor &&visitor, Vs &&... vs) { |
| return lib::invoke(lib::forward<Visitor>(visitor), |
| access::base::get_alt<I>(as_base(lib::forward<Vs>(vs)))...); |
| } |
| |
| #if defined(__GNUC__) && !defined(__clang__) |
| // GCC does not reliably lower the comma-fold in fold_at() to a jump |
| // table and instead emits an O(N) cmp/branch cascade, which badly hurts |
| // visits over large variants such as DisplayList::Item (60+ |
| // alternatives). This is target-dependent: GCC 14 recovers a jump table |
| // on x86_64 but not on aarch64, where even 14.2 emits the cascade, so |
| // gate on the compiler rather than a version. An explicit switch is |
| // lowered to a jump table everywhere. Clang recovers a jump table from |
| // fold_at() on its own, so it keeps the fold (and its compile-time |
| // benefit). |
| template <std::size_t Base, std::size_t N, |
| typename Visitor, typename... Vs> |
| inline static constexpr base::dispatch_result_t<Visitor, Vs...> |
| switch_at(std::size_t index, Visitor &&visitor, Vs &&... vs) { |
| #define MPARK_CASE(I) \ |
| case Base + I: \ |
| if constexpr (Base + I < N) \ |
| return step_at<(Base + I < N ? Base + I : 0)>( \ |
| lib::forward<Visitor>(visitor), lib::forward<Vs>(vs)...); \ |
| else \ |
| MPARK_BUILTIN_UNREACHABLE; |
| switch (index) { |
| MPARK_CASE(0) MPARK_CASE(1) MPARK_CASE(2) MPARK_CASE(3) |
| MPARK_CASE(4) MPARK_CASE(5) MPARK_CASE(6) MPARK_CASE(7) |
| MPARK_CASE(8) MPARK_CASE(9) MPARK_CASE(10) MPARK_CASE(11) |
| MPARK_CASE(12) MPARK_CASE(13) MPARK_CASE(14) MPARK_CASE(15) |
| MPARK_CASE(16) MPARK_CASE(17) MPARK_CASE(18) MPARK_CASE(19) |
| MPARK_CASE(20) MPARK_CASE(21) MPARK_CASE(22) MPARK_CASE(23) |
| MPARK_CASE(24) MPARK_CASE(25) MPARK_CASE(26) MPARK_CASE(27) |
| MPARK_CASE(28) MPARK_CASE(29) MPARK_CASE(30) MPARK_CASE(31) |
| default: |
| if constexpr (Base + 32 < N) |
| return switch_at<Base + 32, N>( |
| index, lib::forward<Visitor>(visitor), |
| lib::forward<Vs>(vs)...); |
| else |
| MPARK_BUILTIN_UNREACHABLE; |
| } |
| #undef MPARK_CASE |
| } |
| #endif |
| |
| template <std::size_t... Is, typename Visitor, typename... Vs> |
| inline static constexpr base::dispatch_result_t<Visitor, Vs...> |
| fold_at(std::index_sequence<Is...>, std::size_t index, |
| Visitor &&visitor, Vs &&... vs) { |
| using R = base::dispatch_result_t<Visitor, Vs...>; |
| if constexpr (std::is_void_v<R>) |
| ((index == Is ? step_at<Is>(lib::forward<Visitor>(visitor), |
| lib::forward<Vs>(vs)...) : void()), ...); |
| else { |
| R r{}; |
| ((index == Is ? void(r = step_at<Is>(lib::forward<Visitor>(visitor), |
| lib::forward<Vs>(vs)...)) : void()), ...); |
| return r; |
| } |
| } |
| }; |
| |
| struct variant { |
| private: |
| template <typename Visitor> |
| struct visitor { |
| template <typename... Values> |
| inline static constexpr bool does_not_handle() { |
| return lib::is_invocable<Visitor, Values...>::value; |
| } |
| }; |
| |
| template <typename Visitor, typename... Values> |
| struct visit_exhaustiveness_check { |
| static_assert(visitor<Visitor>::template does_not_handle<Values...>(), |
| "`visit` requires the visitor to be exhaustive."); |
| |
| inline static constexpr DECLTYPE_AUTO invoke(Visitor &&visitor, |
| Values &&... values) |
| DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward<Visitor>(visitor), |
| lib::forward<Values>(values)...)) |
| }; |
| |
| template <typename Visitor> |
| struct value_visitor { |
| Visitor &&visitor_; |
| |
| template <typename... Alts> |
| inline constexpr DECLTYPE_AUTO operator()(Alts &&... alts) const |
| DECLTYPE_AUTO_RETURN( |
| visit_exhaustiveness_check< |
| Visitor, |
| decltype((lib::forward<Alts>(alts).value))...>:: |
| invoke(lib::forward<Visitor>(visitor_), |
| lib::forward<Alts>(alts).value...)) |
| }; |
| |
| template <typename Visitor> |
| inline static constexpr AUTO make_value_visitor(Visitor &&visitor) |
| AUTO_RETURN(value_visitor<Visitor>{lib::forward<Visitor>(visitor)}) |
| |
| public: |
| template <typename Visitor, typename... Vs> |
| inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, |
| Vs &&... vs) |
| DECLTYPE_AUTO_RETURN(alt::visit_alt(lib::forward<Visitor>(visitor), |
| lib::forward<Vs>(vs).impl_...)) |
| |
| template <typename Visitor, typename... Vs> |
| inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, |
| Visitor &&visitor, |
| Vs &&... vs) |
| DECLTYPE_AUTO_RETURN( |
| alt::visit_alt_at(index, |
| lib::forward<Visitor>(visitor), |
| lib::forward<Vs>(vs).impl_...)) |
| |
| template <typename Visitor, typename... Vs> |
| inline static constexpr DECLTYPE_AUTO visit_value(Visitor &&visitor, |
| Vs &&... vs) |
| DECLTYPE_AUTO_RETURN( |
| visit_alt(make_value_visitor(lib::forward<Visitor>(visitor)), |
| lib::forward<Vs>(vs)...)) |
| |
| template <typename Visitor, typename... Vs> |
| inline static constexpr DECLTYPE_AUTO visit_value_at(std::size_t index, |
| Visitor &&visitor, |
| Vs &&... vs) |
| DECLTYPE_AUTO_RETURN( |
| visit_alt_at(index, |
| make_value_visitor(lib::forward<Visitor>(visitor)), |
| lib::forward<Vs>(vs)...)) |
| }; |
| |
| } // namespace visitation |
| |
| template <std::size_t Index, typename T> |
| struct alt { |
| using value_type = T; |
| |
| #ifdef _MSC_VER |
| #pragma warning(push) |
| #pragma warning(disable : 4244) |
| #endif |
| template <typename... Args> |
| inline explicit constexpr alt(in_place_t, Args &&... args) |
| : value(lib::forward<Args>(args)...) {} |
| #ifdef _MSC_VER |
| #pragma warning(pop) |
| #endif |
| |
| T value; |
| }; |
| |
| template <typename... Ts> |
| using index_t = typename std::conditional< |
| sizeof...(Ts) < (std::numeric_limits<unsigned char>::max)(), |
| unsigned char, |
| typename std::conditional< |
| sizeof...(Ts) < (std::numeric_limits<unsigned short>::max)(), |
| unsigned short, |
| unsigned int>::type |
| >::type; |
| |
| template <typename... Ts> |
| class base { |
| public: |
| template <std::size_t I> |
| using alt_at = alt<I, lib::type_pack_element_t<I, Ts...>>; |
| |
| inline explicit constexpr base(valueless_t) noexcept |
| : index_(static_cast<index_t<Ts...>>(-1)) {} |
| |
| template <std::size_t I, typename... Args> |
| inline explicit constexpr base(in_place_index_t<I>, Args &&... args) |
| : index_(I) { |
| using T = lib::type_pack_element_t<I, Ts...>; |
| if constexpr (!(std::is_empty_v<T> && __is_trivially_constructible(T, Args...))) |
| ::new (static_cast<void *>(data_.storage_)) |
| alt_at<I>(in_place_t{}, lib::forward<Args>(args)...); |
| } |
| |
| // GCC 14 through 16 emit a bogus -Wuninitialized for index_ when these |
| // accessors are inlined into HashTable bucket teardown (e.g. |
| // HashMap<GenericHashKey<...>, ...>::remove()), even though index_ is set by |
| // every base constructor. Clang and GCC <= 13 are unaffected. |
| IGNORE_GCC_WARNINGS_BEGIN("uninitialized") |
| inline constexpr bool valueless_by_exception() const noexcept { |
| return index_ == static_cast<index_t<Ts...>>(-1); |
| } |
| |
| inline constexpr std::size_t index() const noexcept { |
| return valueless_by_exception() ? variant_npos : index_; |
| } |
| IGNORE_GCC_WARNINGS_END |
| |
| template <std::size_t I> inline constexpr alt_at<I> &get_alt() & noexcept { |
| return *std::launder(reinterpret_cast<alt_at<I> *>(data_.storage_)); |
| } |
| template <std::size_t I> inline constexpr const alt_at<I> &get_alt() const & noexcept { |
| return *std::launder(reinterpret_cast<const alt_at<I> *>(data_.storage_)); |
| } |
| template <std::size_t I> inline constexpr alt_at<I> &&get_alt() && noexcept { |
| return lib::move(*std::launder(reinterpret_cast<alt_at<I> *>(data_.storage_))); |
| } |
| template <std::size_t I> inline constexpr const alt_at<I> &&get_alt() const && noexcept { |
| return lib::move(*std::launder(reinterpret_cast<const alt_at<I> *>(data_.storage_))); |
| } |
| |
| inline static constexpr std::size_t size() { return sizeof...(Ts); } |
| |
| inline void destroy() noexcept { |
| if constexpr (!(... && std::is_trivially_destructible_v<Ts>)) |
| if (!valueless_by_exception()) |
| visitation::alt::visit_alt_at(index_, |
| [](auto &a) noexcept { using A = lib::decay_t<decltype(a)>; a.~A(); }, *this); |
| index_ = static_cast<index_t<Ts...>>(-1); |
| } |
| |
| template <std::size_t I, typename... Args> |
| inline static auto &construct_alt(base &self, Args &&... args) { |
| auto *result = ::new (static_cast<void *>(self.data_.storage_)) |
| alt_at<I>(in_place_t{}, lib::forward<Args>(args)...); |
| return result->value; |
| } |
| |
| template <typename Rhs> |
| inline static void generic_construct(base &lhs, Rhs &&rhs) { |
| lhs.destroy(); |
| if (!rhs.valueless_by_exception()) { |
| visitation::alt::visit_alt_at(rhs.index_, |
| [&lhs](auto &&rhs_alt) { |
| using A = lib::decay_t<decltype(rhs_alt)>; |
| ::new (static_cast<void *>(lhs.data_.storage_)) |
| A(in_place_t{}, lib::forward<decltype(rhs_alt)>(rhs_alt).value); |
| }, |
| lib::forward<Rhs>(rhs)); |
| lhs.index_ = rhs.index_; |
| } |
| } |
| |
| template <std::size_t I, typename... Args> |
| inline auto &emplace(Args &&... args) { |
| destroy(); |
| auto &result = construct_alt<I>(*this, lib::forward<Args>(args)...); |
| index_ = I; |
| return result; |
| } |
| |
| template <std::size_t I, typename T, typename Arg> |
| inline void assign_alt(alt<I, T> &a, Arg &&arg) { |
| if (index() == I) |
| a.value = lib::forward<Arg>(arg); |
| else if constexpr (std::is_nothrow_constructible_v<T, Arg> || |
| !std::is_nothrow_move_constructible_v<T>) |
| emplace<I>(lib::forward<Arg>(arg)); |
| else |
| emplace<I>(T(lib::forward<Arg>(arg))); |
| } |
| |
| template <typename That> |
| inline void generic_assign(That &&that) { |
| if (valueless_by_exception() && that.valueless_by_exception()) { |
| // do nothing. |
| } else if (that.valueless_by_exception()) { |
| destroy(); |
| } else { |
| visitation::alt::visit_alt_at(that.index(), |
| [this](auto &this_alt, auto &&that_alt) { |
| this->assign_alt(this_alt, lib::forward<decltype(that_alt)>(that_alt).value); |
| }, |
| *this, lib::forward<That>(that)); |
| } |
| } |
| |
| template <std::size_t I, typename Arg> |
| inline void assign(Arg &&arg) { |
| assign_alt(get_alt<I>(), lib::forward<Arg>(arg)); |
| } |
| |
| protected: |
| struct data_t { |
| static constexpr std::size_t size_ = []{ |
| std::size_t s = 1; |
| ((s = sizeof(Ts) > s ? sizeof(Ts) : s), ...); |
| return s; |
| }(); |
| static constexpr std::size_t align_ = []{ |
| std::size_t a = 1; |
| ((a = alignof(Ts) > a ? alignof(Ts) : a), ...); |
| return a; |
| }(); |
| constexpr data_t() noexcept { |
| if consteval { |
| for (auto& b : storage_) b = 0; |
| } |
| } |
| alignas(align_) unsigned char storage_[size_]; |
| }; |
| |
| friend inline constexpr base &as_base(base &b) { return b; } |
| friend inline constexpr const base &as_base(const base &b) { return b; } |
| friend inline constexpr base &&as_base(base &&b) { return lib::move(b); } |
| friend inline constexpr const base &&as_base(const base &&b) { return lib::move(b); } |
| |
| data_t data_; |
| index_t<Ts...> index_; |
| |
| friend struct access::base; |
| friend struct visitation::base; |
| }; |
| |
| template <typename... Ts> |
| inline constexpr bool variant_is_trivial_v = |
| (... && std::is_trivially_destructible_v<Ts>) |
| && (... && std::is_trivially_copy_constructible_v<Ts>) |
| && (... && std::is_trivially_move_constructible_v<Ts>) |
| && (... && std::is_trivially_copy_assignable_v<Ts>) |
| && (... && std::is_trivially_move_assignable_v<Ts>); |
| |
| template <bool Trivial, typename... Ts> |
| class impl_smf; |
| |
| template <typename... Ts> |
| class impl_smf<true, Ts...> : public base<Ts...> { |
| public: |
| using base<Ts...>::base; |
| |
| inline void swap(impl_smf &that) noexcept { std::swap(*this, that); } |
| }; |
| |
| template <typename... Ts> |
| class impl_smf<false, Ts...> : public base<Ts...> { |
| static_assert((... && std::is_destructible_v<Ts>), |
| "Variant<Ts...>: every alternative must be destructible"); |
| |
| public: |
| using base<Ts...>::base; |
| |
| ~impl_smf() { this->destroy(); } |
| |
| impl_smf(impl_smf &&that) noexcept((... && std::is_nothrow_move_constructible_v<Ts>)) |
| requires (... && std::is_move_constructible_v<Ts>) |
| : base<Ts...>(valueless_t{}) { |
| this->generic_construct(*this, lib::move(that)); |
| } |
| |
| impl_smf(const impl_smf &that) |
| requires (... && std::is_copy_constructible_v<Ts>) |
| : base<Ts...>(valueless_t{}) { |
| this->generic_construct(*this, that); |
| } |
| |
| impl_smf &operator=(impl_smf &&that) |
| noexcept((... && std::is_nothrow_move_constructible_v<Ts>) && |
| (... && std::is_nothrow_move_assignable_v<Ts>)) |
| requires (... && std::is_move_constructible_v<Ts>) { |
| if constexpr ((... && std::is_move_assignable_v<Ts>)) |
| this->generic_assign(lib::move(that)); |
| else if (this != &that) { |
| this->destroy(); |
| this->generic_construct(*this, lib::move(that)); |
| } |
| return *this; |
| } |
| |
| impl_smf &operator=(const impl_smf &that) |
| requires (... && std::is_copy_constructible_v<Ts>) { |
| if constexpr ((... && std::is_copy_assignable_v<Ts>)) |
| this->generic_assign(that); |
| else if (this != &that) { |
| this->destroy(); |
| this->generic_construct(*this, that); |
| } |
| return *this; |
| } |
| |
| inline void swap(impl_smf &that) { |
| if (this->valueless_by_exception() && that.valueless_by_exception()) { |
| // do nothing. |
| } else if (this->index() == that.index()) { |
| visitation::alt::visit_alt_at(this->index(), |
| [](auto &this_alt, auto &that_alt) { |
| using std::swap; |
| swap(this_alt.value, that_alt.value); |
| }, |
| *this, that); |
| } else { |
| impl_smf *lhs = this; |
| impl_smf *rhs = lib::addressof(that); |
| if (lhs->move_nothrow() && !rhs->move_nothrow()) |
| std::swap(lhs, rhs); |
| impl_smf tmp(lib::move(*rhs)); |
| #ifdef MPARK_EXCEPTIONS |
| try { |
| this->generic_construct(*rhs, lib::move(*lhs)); |
| } catch (...) { |
| if (tmp.move_nothrow()) |
| this->generic_construct(*rhs, lib::move(tmp)); |
| throw; |
| } |
| #else |
| this->generic_construct(*rhs, lib::move(*lhs)); |
| #endif |
| this->generic_construct(*lhs, lib::move(tmp)); |
| } |
| } |
| |
| private: |
| inline constexpr bool move_nothrow() const { |
| return this->valueless_by_exception() || |
| lib::array<bool, sizeof...(Ts)>{ |
| {std::is_nothrow_move_constructible<Ts>::value...} |
| }[this->index()]; |
| } |
| }; |
| |
| template <typename... Ts> |
| using impl = impl_smf<variant_is_trivial_v<Ts...>, Ts...>; |
| |
| template <typename From, typename To> |
| struct is_non_narrowing_convertible { |
| template <typename T> |
| static std::true_type test(T(&&)[1]); |
| |
| template <typename T> |
| static auto impl(int) -> decltype(test<T>({std::declval<From>()})); |
| |
| template <typename> |
| static auto impl(...) -> std::false_type; |
| |
| static constexpr bool value = decltype(impl<To>(0))::value; |
| }; |
| |
| template <typename Arg, |
| std::size_t I, |
| typename T, |
| bool = std::is_arithmetic<T>::value, |
| typename = void> |
| struct overload_leaf {}; |
| |
| template <typename Arg, std::size_t I, typename T> |
| struct overload_leaf<Arg, I, T, false> { |
| using impl = lib::size_constant<I> (*)(T); |
| operator impl() const { return nullptr; }; |
| }; |
| |
| template <typename Arg, std::size_t I, typename T> |
| struct overload_leaf< |
| Arg, |
| I, |
| T, |
| true |
| #if defined(__clang__) || !defined(__GNUC__) || __GNUC__ >= 5 |
| , |
| lib::enable_if_t< |
| std::is_same<lib::remove_cvref_t<T>, bool>::value |
| ? std::is_same<lib::remove_cvref_t<Arg>, bool>::value |
| : is_non_narrowing_convertible<Arg, T>::value> |
| #endif |
| > { |
| using impl = lib::size_constant<I> (*)(T); |
| operator impl() const { return nullptr; }; |
| }; |
| |
| template <typename Arg, typename... Ts> |
| struct overload_impl { |
| private: |
| template <typename> |
| struct impl; |
| |
| template <std::size_t... Is> |
| struct impl<lib::index_sequence<Is...>> : overload_leaf<Arg, Is, Ts>... {}; |
| |
| public: |
| using type = impl<lib::index_sequence_for<Ts...>>; |
| }; |
| |
| template <typename Arg, typename... Ts> |
| using overload = typename overload_impl<Arg, Ts...>::type; |
| |
| template <typename Arg, typename... Ts> |
| using best_match = lib::invoke_result_t<overload<Arg, Ts...>, Arg>; |
| |
| template <typename T> |
| struct is_in_place_index : std::false_type {}; |
| |
| template <std::size_t I> |
| struct is_in_place_index<in_place_index_t<I>> : std::true_type {}; |
| |
| template <typename T> |
| struct is_in_place_type : std::false_type {}; |
| |
| template <typename T> |
| struct is_in_place_type<in_place_type_t<T>> : std::true_type {}; |
| |
| } // detail |
| |
| template <typename... Ts> |
| class variant { |
| static_assert(0 < sizeof...(Ts), |
| "variant must consist of at least one alternative."); |
| |
| static_assert(lib::all<!std::is_array<Ts>::value...>::value, |
| "variant can not have an array type as an alternative."); |
| |
| static_assert(lib::all<!std::is_reference<Ts>::value...>::value, |
| "variant can not have a reference type as an alternative."); |
| |
| static_assert(lib::all<!std::is_void<Ts>::value...>::value, |
| "variant can not have a void type as an alternative."); |
| |
| public: |
| template < |
| typename Front = lib::type_pack_element_t<0, Ts...>, |
| lib::enable_if_t<std::is_default_constructible<Front>::value, int> = 0> |
| inline constexpr variant() noexcept( |
| std::is_nothrow_default_constructible<Front>::value) |
| : impl_(in_place_index_t<0>{}) {} |
| |
| variant(const variant &) = default; |
| variant(variant &&) = default; |
| |
| template < |
| typename Arg, |
| typename Decayed = lib::decay_t<Arg>, |
| lib::enable_if_t<!std::is_same<Decayed, variant>::value, int> = 0, |
| lib::enable_if_t<!detail::is_in_place_index<Decayed>::value, int> = 0, |
| lib::enable_if_t<!detail::is_in_place_type<Decayed>::value, int> = 0, |
| std::size_t I = detail::best_match<Arg, Ts...>::value, |
| typename T = lib::type_pack_element_t<I, Ts...>, |
| lib::enable_if_t<std::is_constructible<T, Arg>::value, int> = 0> |
| inline constexpr variant(Arg &&arg) noexcept( |
| std::is_nothrow_constructible<T, Arg>::value) |
| : impl_(in_place_index_t<I>{}, lib::forward<Arg>(arg)) {} |
| |
| template < |
| std::size_t I, |
| typename... Args, |
| typename T = lib::type_pack_element_t<I, Ts...>, |
| lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> |
| inline explicit constexpr variant( |
| in_place_index_t<I>, |
| Args &&... args) noexcept(std::is_nothrow_constructible<T, |
| Args...>::value) |
| : impl_(in_place_index_t<I>{}, lib::forward<Args>(args)...) {} |
| |
| template < |
| std::size_t I, |
| typename Up, |
| typename... Args, |
| typename T = lib::type_pack_element_t<I, Ts...>, |
| lib::enable_if_t<std::is_constructible<T, |
| std::initializer_list<Up> &, |
| Args...>::value, |
| int> = 0> |
| inline explicit constexpr variant( |
| in_place_index_t<I>, |
| std::initializer_list<Up> il, |
| Args &&... args) noexcept(std:: |
| is_nothrow_constructible< |
| T, |
| std::initializer_list<Up> &, |
| Args...>::value) |
| : impl_(in_place_index_t<I>{}, il, lib::forward<Args>(args)...) {} |
| |
| template < |
| typename T, |
| typename... Args, |
| std::size_t I = detail::find_index_sfinae<T, Ts...>::value, |
| lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> |
| inline explicit constexpr variant( |
| in_place_type_t<T>, |
| Args &&... args) noexcept(std::is_nothrow_constructible<T, |
| Args...>::value) |
| : impl_(in_place_index_t<I>{}, lib::forward<Args>(args)...) {} |
| |
| template < |
| typename T, |
| typename Up, |
| typename... Args, |
| std::size_t I = detail::find_index_sfinae<T, Ts...>::value, |
| lib::enable_if_t<std::is_constructible<T, |
| std::initializer_list<Up> &, |
| Args...>::value, |
| int> = 0> |
| inline explicit constexpr variant( |
| in_place_type_t<T>, |
| std::initializer_list<Up> il, |
| Args &&... args) noexcept(std:: |
| is_nothrow_constructible< |
| T, |
| std::initializer_list<Up> &, |
| Args...>::value) |
| : impl_(in_place_index_t<I>{}, il, lib::forward<Args>(args)...) {} |
| |
| ~variant() = default; |
| |
| variant &operator=(const variant &) = default; |
| variant &operator=(variant &&) = default; |
| |
| template <typename Arg, |
| lib::enable_if_t<!std::is_same<lib::decay_t<Arg>, variant>::value, |
| int> = 0, |
| std::size_t I = detail::best_match<Arg, Ts...>::value, |
| typename T = lib::type_pack_element_t<I, Ts...>, |
| lib::enable_if_t<(std::is_assignable<T &, Arg>::value && |
| std::is_constructible<T, Arg>::value), |
| int> = 0> |
| inline variant &operator=(Arg &&arg) noexcept( |
| (std::is_nothrow_assignable<T &, Arg>::value && |
| std::is_nothrow_constructible<T, Arg>::value)) { |
| impl_.template assign<I>(lib::forward<Arg>(arg)); |
| return *this; |
| } |
| |
| template < |
| std::size_t I, |
| typename... Args, |
| typename T = lib::type_pack_element_t<I, Ts...>, |
| lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> |
| inline T &emplace(Args &&... args) { |
| return impl_.template emplace<I>(lib::forward<Args>(args)...); |
| } |
| |
| template < |
| std::size_t I, |
| typename Up, |
| typename... Args, |
| typename T = lib::type_pack_element_t<I, Ts...>, |
| lib::enable_if_t<std::is_constructible<T, |
| std::initializer_list<Up> &, |
| Args...>::value, |
| int> = 0> |
| inline T &emplace(std::initializer_list<Up> il, Args &&... args) { |
| return impl_.template emplace<I>(il, lib::forward<Args>(args)...); |
| } |
| |
| template < |
| typename T, |
| typename... Args, |
| std::size_t I = detail::find_index_sfinae<T, Ts...>::value, |
| lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> |
| inline T &emplace(Args &&... args) { |
| return impl_.template emplace<I>(lib::forward<Args>(args)...); |
| } |
| |
| template < |
| typename T, |
| typename Up, |
| typename... Args, |
| std::size_t I = detail::find_index_sfinae<T, Ts...>::value, |
| lib::enable_if_t<std::is_constructible<T, |
| std::initializer_list<Up> &, |
| Args...>::value, |
| int> = 0> |
| inline T &emplace(std::initializer_list<Up> il, Args &&... args) { |
| return impl_.template emplace<I>(il, lib::forward<Args>(args)...); |
| } |
| |
| [[nodiscard]] inline constexpr bool valueless_by_exception() const noexcept { |
| return impl_.valueless_by_exception(); |
| } |
| |
| [[nodiscard]] inline constexpr std::size_t index() const noexcept { |
| return impl_.index(); |
| } |
| |
| template <bool Dummy = true, |
| lib::enable_if_t< |
| lib::all<Dummy, |
| (lib::dependent_type<std::is_move_constructible<Ts>, |
| Dummy>::value && |
| lib::dependent_type<lib::is_swappable<Ts>, |
| Dummy>::value)...>::value, |
| int> = 0> |
| inline void swap(variant &that) noexcept( |
| lib::all<(std::is_nothrow_move_constructible<Ts>::value && |
| lib::is_nothrow_swappable<Ts>::value)...>::value) { |
| impl_.swap(that.impl_); |
| } |
| |
| private: |
| detail::impl<Ts...> impl_; |
| |
| friend struct detail::access::variant; |
| friend struct detail::visitation::variant; |
| }; |
| |
| template <std::size_t I, typename... Ts> |
| [[nodiscard]] inline constexpr bool holds_alternative(const variant<Ts...> &v) noexcept { |
| return v.index() == I; |
| } |
| |
| template <typename T, typename... Ts> |
| [[nodiscard]] inline constexpr bool holds_alternative(const variant<Ts...> &v) noexcept { |
| return holds_alternative<detail::find_index_checked<T, Ts...>::value>(v); |
| } |
| |
| namespace detail { |
| template <std::size_t I, typename V> |
| struct generic_get_impl { |
| constexpr generic_get_impl(int) noexcept {} |
| |
| constexpr AUTO_REFREF operator()(V &&v) const |
| AUTO_REFREF_RETURN( |
| access::variant::get_alt<I>(lib::forward<V>(v)).value) |
| }; |
| |
| template <std::size_t I, typename V> |
| inline constexpr AUTO_REFREF generic_get(V &&v) |
| AUTO_REFREF_RETURN(generic_get_impl<I, V>( |
| holds_alternative<I>(v) ? 0 : (throw_bad_variant_access(), 0))( |
| lib::forward<V>(v))) |
| } // namespace detail |
| |
| template <std::size_t I, typename... Ts> |
| [[nodiscard]] inline constexpr variant_alternative_t<I, variant<Ts...>> &get( |
| variant<Ts...> &v) { |
| return detail::generic_get<I>(v); |
| } |
| |
| template <std::size_t I, typename... Ts> |
| [[nodiscard]] inline constexpr variant_alternative_t<I, variant<Ts...>> &&get( |
| variant<Ts...> &&v) { |
| return detail::generic_get<I>(lib::move(v)); |
| } |
| |
| template <std::size_t I, typename... Ts> |
| [[nodiscard]] inline constexpr const variant_alternative_t<I, variant<Ts...>> &get( |
| const variant<Ts...> &v) { |
| return detail::generic_get<I>(v); |
| } |
| |
| template <std::size_t I, typename... Ts> |
| [[nodiscard]] inline constexpr const variant_alternative_t<I, variant<Ts...>> &&get( |
| const variant<Ts...> &&v) { |
| return detail::generic_get<I>(lib::move(v)); |
| } |
| |
| template <typename T, typename... Ts> |
| [[nodiscard]] inline constexpr T &get(variant<Ts...> &v) { |
| return mpark::get<detail::find_index_checked<T, Ts...>::value>(v); |
| } |
| |
| template <typename T, typename... Ts> |
| [[nodiscard]] inline constexpr T &&get(variant<Ts...> &&v) { |
| return mpark::get<detail::find_index_checked<T, Ts...>::value>(lib::move(v)); |
| } |
| |
| template <typename T, typename... Ts> |
| [[nodiscard]] inline constexpr const T &get(const variant<Ts...> &v) { |
| return mpark::get<detail::find_index_checked<T, Ts...>::value>(v); |
| } |
| |
| template <typename T, typename... Ts> |
| [[nodiscard]] inline constexpr const T &&get(const variant<Ts...> &&v) { |
| return mpark::get<detail::find_index_checked<T, Ts...>::value>(lib::move(v)); |
| } |
| |
| namespace detail { |
| |
| template <std::size_t I, typename V> |
| inline constexpr /* auto * */ AUTO generic_get_if(V *v) noexcept |
| AUTO_RETURN(v && holds_alternative<I>(*v) |
| ? lib::addressof(access::variant::get_alt<I>(*v).value) |
| : nullptr) |
| |
| } // namespace detail |
| |
| template <std::size_t I, typename... Ts> |
| [[nodiscard]] inline constexpr lib::add_pointer_t<variant_alternative_t<I, variant<Ts...>>> |
| get_if(variant<Ts...> *v) noexcept { |
| return detail::generic_get_if<I>(v); |
| } |
| |
| template <std::size_t I, typename... Ts> |
| [[nodiscard]] inline constexpr lib::add_pointer_t< |
| const variant_alternative_t<I, variant<Ts...>>> |
| get_if(const variant<Ts...> *v) noexcept { |
| return detail::generic_get_if<I>(v); |
| } |
| |
| template <typename T, typename... Ts> |
| [[nodiscard]] inline constexpr lib::add_pointer_t<T> |
| get_if(variant<Ts...> *v) noexcept { |
| return mpark::get_if<detail::find_index_checked<T, Ts...>::value>(v); |
| } |
| |
| template <typename T, typename... Ts> |
| [[nodiscard]] inline constexpr lib::add_pointer_t<const T> |
| get_if(const variant<Ts...> *v) noexcept { |
| return mpark::get_if<detail::find_index_checked<T, Ts...>::value>(v); |
| } |
| |
| namespace detail { |
| template <typename RelOp> |
| struct convert_to_bool { |
| template <typename Lhs, typename Rhs> |
| inline constexpr bool operator()(Lhs &&lhs, Rhs &&rhs) const { |
| static_assert(std::is_convertible<lib::invoke_result_t<RelOp, Lhs, Rhs>, |
| bool>::value, |
| "relational operators must return a type" |
| " implicitly convertible to bool"); |
| return lib::invoke( |
| RelOp{}, lib::forward<Lhs>(lhs), lib::forward<Rhs>(rhs)); |
| } |
| }; |
| } // namespace detail |
| |
| template <typename... Ts> |
| inline constexpr bool operator==(const variant<Ts...> &lhs, |
| const variant<Ts...> &rhs) { |
| using detail::visitation::variant; |
| using equal_to = detail::convert_to_bool<lib::equal_to>; |
| #ifdef MPARK_CPP14_CONSTEXPR |
| if (lhs.index() != rhs.index()) return false; |
| if (lhs.valueless_by_exception()) return true; |
| return variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs); |
| #else |
| return lhs.index() == rhs.index() && |
| (lhs.valueless_by_exception() || |
| variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs)); |
| #endif |
| } |
| |
| template <typename... Ts> |
| inline constexpr bool operator!=(const variant<Ts...> &lhs, |
| const variant<Ts...> &rhs) { |
| using detail::visitation::variant; |
| using not_equal_to = detail::convert_to_bool<lib::not_equal_to>; |
| #ifdef MPARK_CPP14_CONSTEXPR |
| if (lhs.index() != rhs.index()) return true; |
| if (lhs.valueless_by_exception()) return false; |
| return variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs); |
| #else |
| return lhs.index() != rhs.index() || |
| (!lhs.valueless_by_exception() && |
| variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs)); |
| #endif |
| } |
| |
| template <typename... Ts> |
| inline constexpr bool operator<(const variant<Ts...> &lhs, |
| const variant<Ts...> &rhs) { |
| using detail::visitation::variant; |
| using less = detail::convert_to_bool<lib::less>; |
| #ifdef MPARK_CPP14_CONSTEXPR |
| if (rhs.valueless_by_exception()) return false; |
| if (lhs.valueless_by_exception()) return true; |
| if (lhs.index() < rhs.index()) return true; |
| if (lhs.index() > rhs.index()) return false; |
| return variant::visit_value_at(lhs.index(), less{}, lhs, rhs); |
| #else |
| return !rhs.valueless_by_exception() && |
| (lhs.valueless_by_exception() || lhs.index() < rhs.index() || |
| (lhs.index() == rhs.index() && |
| variant::visit_value_at(lhs.index(), less{}, lhs, rhs))); |
| #endif |
| } |
| |
| template <typename... Ts> |
| inline constexpr bool operator>(const variant<Ts...> &lhs, |
| const variant<Ts...> &rhs) { |
| using detail::visitation::variant; |
| using greater = detail::convert_to_bool<lib::greater>; |
| #ifdef MPARK_CPP14_CONSTEXPR |
| if (lhs.valueless_by_exception()) return false; |
| if (rhs.valueless_by_exception()) return true; |
| if (lhs.index() > rhs.index()) return true; |
| if (lhs.index() < rhs.index()) return false; |
| return variant::visit_value_at(lhs.index(), greater{}, lhs, rhs); |
| #else |
| return !lhs.valueless_by_exception() && |
| (rhs.valueless_by_exception() || lhs.index() > rhs.index() || |
| (lhs.index() == rhs.index() && |
| variant::visit_value_at(lhs.index(), greater{}, lhs, rhs))); |
| #endif |
| } |
| |
| template <typename... Ts> |
| inline constexpr bool operator<=(const variant<Ts...> &lhs, |
| const variant<Ts...> &rhs) { |
| using detail::visitation::variant; |
| using less_equal = detail::convert_to_bool<lib::less_equal>; |
| #ifdef MPARK_CPP14_CONSTEXPR |
| if (lhs.valueless_by_exception()) return true; |
| if (rhs.valueless_by_exception()) return false; |
| if (lhs.index() < rhs.index()) return true; |
| if (lhs.index() > rhs.index()) return false; |
| return variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs); |
| #else |
| return lhs.valueless_by_exception() || |
| (!rhs.valueless_by_exception() && |
| (lhs.index() < rhs.index() || |
| (lhs.index() == rhs.index() && |
| variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs)))); |
| #endif |
| } |
| |
| template <typename... Ts> |
| inline constexpr bool operator>=(const variant<Ts...> &lhs, |
| const variant<Ts...> &rhs) { |
| using detail::visitation::variant; |
| using greater_equal = detail::convert_to_bool<lib::greater_equal>; |
| #ifdef MPARK_CPP14_CONSTEXPR |
| if (rhs.valueless_by_exception()) return true; |
| if (lhs.valueless_by_exception()) return false; |
| if (lhs.index() > rhs.index()) return true; |
| if (lhs.index() < rhs.index()) return false; |
| return variant::visit_value_at(lhs.index(), greater_equal{}, lhs, rhs); |
| #else |
| return rhs.valueless_by_exception() || |
| (!lhs.valueless_by_exception() && |
| (lhs.index() > rhs.index() || |
| (lhs.index() == rhs.index() && |
| variant::visit_value_at( |
| lhs.index(), greater_equal{}, lhs, rhs)))); |
| #endif |
| } |
| |
| struct monostate {}; |
| |
| inline constexpr bool operator<(monostate, monostate) noexcept { |
| return false; |
| } |
| |
| inline constexpr bool operator>(monostate, monostate) noexcept { |
| return false; |
| } |
| |
| inline constexpr bool operator<=(monostate, monostate) noexcept { |
| return true; |
| } |
| |
| inline constexpr bool operator>=(monostate, monostate) noexcept { |
| return true; |
| } |
| |
| inline constexpr bool operator==(monostate, monostate) noexcept { |
| return true; |
| } |
| |
| inline constexpr bool operator!=(monostate, monostate) noexcept { |
| return false; |
| } |
| |
| #ifdef MPARK_CPP14_CONSTEXPR |
| namespace detail { |
| |
| inline constexpr bool any(std::initializer_list<bool> bs) { |
| for (bool b : bs) { |
| if (b) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| } // namespace detail |
| |
| template <typename Visitor, typename... Vs> |
| inline constexpr decltype(auto) visit(Visitor &&visitor, Vs &&... vs) { |
| return (!detail::any({vs.valueless_by_exception()...}) |
| ? (void)0 |
| : throw_bad_variant_access()), |
| detail::visitation::variant::visit_value( |
| lib::forward<Visitor>(visitor), lib::forward<Vs>(vs)...); |
| } |
| #else |
| namespace detail { |
| |
| template <std::size_t N> |
| inline constexpr bool all_impl(const lib::array<bool, N> &bs, |
| std::size_t idx) { |
| return idx >= N || (bs[idx] && all_impl(bs, idx + 1)); |
| } |
| |
| template <std::size_t N> |
| inline constexpr bool all(const lib::array<bool, N> &bs) { |
| return all_impl(bs, 0); |
| } |
| |
| } // namespace detail |
| |
| template <typename Visitor, typename... Vs> |
| inline constexpr DECLTYPE_AUTO visit(Visitor &&visitor, Vs &&... vs) |
| DECLTYPE_AUTO_RETURN( |
| (detail::all( |
| lib::array<bool, sizeof...(Vs)>{{!vs.valueless_by_exception()...}}) |
| ? (void)0 |
| : throw_bad_variant_access()), |
| detail::visitation::variant::visit_value(lib::forward<Visitor>(visitor), |
| lib::forward<Vs>(vs)...)) |
| #endif |
| |
| template <typename... Ts> |
| inline auto swap(variant<Ts...> &lhs, |
| variant<Ts...> &rhs) noexcept(noexcept(lhs.swap(rhs))) |
| -> decltype(lhs.swap(rhs)) { |
| lhs.swap(rhs); |
| } |
| |
| namespace detail { |
| |
| template <typename T, typename...> |
| using enabled_type = T; |
| |
| namespace hash { |
| |
| template <typename H, typename K> |
| constexpr bool meets_requirements() noexcept { |
| return std::is_copy_constructible<H>::value && |
| std::is_move_constructible<H>::value && |
| lib::is_invocable_r<std::size_t, H, const K &>::value; |
| } |
| |
| template <typename K> |
| constexpr bool is_enabled() noexcept { |
| using H = std::hash<K>; |
| return meets_requirements<H, K>() && |
| std::is_default_constructible<H>::value && |
| std::is_copy_assignable<H>::value && |
| std::is_move_assignable<H>::value; |
| } |
| |
| } // namespace hash |
| |
| } // namespace detail |
| |
| #undef AUTO |
| #undef AUTO_RETURN |
| |
| #undef AUTO_REFREF |
| #undef AUTO_REFREF_RETURN |
| |
| #undef DECLTYPE_AUTO |
| #undef DECLTYPE_AUTO_RETURN |
| |
| } // namespace mpark |
| |
| namespace std { |
| |
| template <typename... Ts> |
| struct hash<mpark::detail::enabled_type< |
| mpark::variant<Ts...>, |
| mpark::lib::enable_if_t<mpark::lib::all<mpark::detail::hash::is_enabled< |
| mpark::lib::remove_const_t<Ts>>()...>::value>>> { |
| using argument_type = mpark::variant<Ts...>; |
| using result_type = std::size_t; |
| |
| [[nodiscard]] inline result_type operator()(const argument_type &v) const { |
| using mpark::detail::visitation::variant; |
| std::size_t result = |
| v.valueless_by_exception() |
| ? 299792458 // Random value chosen by the universe upon creation |
| : variant::visit_alt( |
| #ifdef MPARK_GENERIC_LAMBDAS |
| [](const auto &alt) { |
| using alt_type = mpark::lib::decay_t<decltype(alt)>; |
| using value_type = mpark::lib::remove_const_t< |
| typename alt_type::value_type>; |
| return hash<value_type>{}(alt.value); |
| } |
| #else |
| hasher{} |
| #endif |
| , |
| v); |
| return hash_combine(result, hash<std::size_t>{}(v.index())); |
| } |
| |
| private: |
| #ifndef MPARK_GENERIC_LAMBDAS |
| struct hasher { |
| template <typename Alt> |
| inline std::size_t operator()(const Alt &alt) const { |
| using alt_type = mpark::lib::decay_t<Alt>; |
| using value_type = |
| mpark::lib::remove_const_t<typename alt_type::value_type>; |
| return hash<value_type>{}(alt.value); |
| } |
| }; |
| #endif |
| |
| static std::size_t hash_combine(std::size_t lhs, std::size_t rhs) { |
| return lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2); |
| } |
| }; |
| |
| template <> |
| struct hash<mpark::monostate> { |
| using argument_type = mpark::monostate; |
| using result_type = std::size_t; |
| |
| [[nodiscard]] inline result_type operator()(const argument_type &) const noexcept { |
| return 66740831; // return a fundamentally attractive random value. |
| } |
| }; |
| |
| } // namespace std |
| |
| #endif // MPARK_VARIANT_HPP |
| |
| namespace std { |
| |
| template<class T, class... Types> [[nodiscard]] constexpr bool holds_alternative(const mpark::variant<Types...>& v) noexcept { return mpark::holds_alternative<T>(v); } |
| |
| template<size_t I, class... Types> [[nodiscard]] constexpr mpark::variant_alternative_t<I, mpark::variant<Types...>>& get(mpark::variant<Types...>& v) { return mpark::get<I>(v); } |
| template<size_t I, class... Types> [[nodiscard]] constexpr mpark::variant_alternative_t<I, mpark::variant<Types...>>&& get(mpark::variant<Types...>&& v) { return mpark::get<I>(std::forward<mpark::variant<Types...>>(v)); } |
| template<size_t I, class... Types> [[nodiscard]] constexpr const mpark::variant_alternative_t<I, mpark::variant<Types...>>& get( const mpark::variant<Types...>& v ) { return mpark::get<I>(v); } |
| template<size_t I, class... Types> [[nodiscard]] constexpr const mpark::variant_alternative_t<I, mpark::variant<Types...>>&& get( const mpark::variant<Types...>&& v ) { return mpark::get<I>(std::forward<mpark::variant<Types...>>(v)); } |
| template<class T, class... Types> [[nodiscard]] constexpr T& get(mpark::variant<Types...>& v) { return mpark::get<T>(v); } |
| template<class T, class... Types> [[nodiscard]] constexpr T&& get(mpark::variant<Types...>&& v) { return mpark::get<T>(std::forward<mpark::variant<Types...>>(v)); } |
| template<class T, class... Types> [[nodiscard]] constexpr const T& get(const mpark::variant<Types...>& v) { return mpark::get<T>(v); } |
| template<class T, class... Types> [[nodiscard]] constexpr const T&& get(const mpark::variant<Types...>&& v) { return mpark::get<T>(std::forward<mpark::variant<Types...>>(v)); } |
| |
| template<size_t I, class... Types> [[nodiscard]] constexpr add_pointer_t<mpark::variant_alternative_t<I, mpark::variant<Types...>>> get_if( mpark::variant<Types...>* v ) noexcept { return mpark::get_if<I>(v); } |
| template<size_t I, class... Types> [[nodiscard]] constexpr add_pointer_t<const mpark::variant_alternative_t<I, mpark::variant<Types...>>> get_if(const mpark::variant<Types...>* v ) noexcept { return mpark::get_if<I>(v); } |
| template<class T, class... Types> [[nodiscard]] constexpr add_pointer_t<T> get_if(mpark::variant<Types...>* v ) noexcept { return mpark::get_if<T>(v); } |
| template<class T, class... Types> [[nodiscard]] constexpr add_pointer_t<const T> get_if(const mpark::variant<Types...>* v) noexcept { return mpark::get_if<T>(v); } |
| |
| } |
| |
| namespace WTF { |
| template<typename... Ts> using Variant = mpark::variant<Ts...>; |
| template<size_t I, class T> using variant_alternative_t = typename mpark::variant_alternative<I, T>::type; |
| template<typename T> constexpr mpark::in_place_type_t<T> InPlaceType { }; |
| template<typename T> using InPlaceTypeT = mpark::in_place_type_t<T>; |
| template<size_t I> constexpr mpark::in_place_index_t<I> InPlaceIndex { }; |
| template<size_t I> using InPlaceIndexT = mpark::in_place_index_t<I>; |
| template <size_t I, class T> struct VariantAlternative; |
| template<size_t I, typename... Types> struct VariantAlternative<I, Variant<Types...>> : mpark::variant_alternative<I, Variant<Types...>> { }; |
| template<size_t I, typename T> using VariantAlternativeT = typename VariantAlternative<I, T>::type; |
| template<typename T> struct VariantSize; |
| template<typename... Types> struct VariantSize<Variant<Types...>> : std::integral_constant<std::size_t, sizeof...(Types)> { }; |
| template<typename T> struct VariantSize<const T> : VariantSize<T> { }; |
| template<typename T> constexpr size_t VariantSizeV = VariantSize<T>::value; |
| |
| template<typename Visitor, typename... Variants> constexpr auto visit(Visitor&& v, Variants&&... values) |
| -> decltype(mpark::visit<Visitor, Variants...>(std::forward<Visitor>(v), std::forward<Variants>(values)...)) |
| { |
| return mpark::visit<Visitor, Variants...>(std::forward<Visitor>(v), std::forward<Variants>(values)...); |
| } |
| |
| } |
| |
| // The version of libstdc++ shipped with GCC 12 and older define std::monostate in |
| // the <variant> header, while newer versions define it in <utility>. The latter is |
| // included above, but the former should be included with older libstdc++ versions |
| // to ensure including this header also brings std::monostate into scope. |
| #if defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 13) |
| #include <variant> |
| #endif |
| |
| using WTF::Variant; |