| #ifndef MAPBOX_UTIL_VARIANT_HPP |
| #define MAPBOX_UTIL_VARIANT_HPP |
| |
| #include <cassert> |
| #include <cstddef> // size_t |
| #include <new> // operator new |
| #include <stdexcept> // runtime_error |
| #include <string> |
| #include <tuple> |
| #include <type_traits> |
| #include <typeinfo> |
| #include <utility> |
| |
| #include <mapbox/recursive_wrapper.hpp> |
| |
| // clang-format off |
| // [[deprecated]] is only available in C++14, use this for the time being |
| #if __cplusplus <= 201103L |
| # ifdef __GNUC__ |
| # define MAPBOX_VARIANT_DEPRECATED __attribute__((deprecated)) |
| # elif defined(_MSC_VER) |
| # define MAPBOX_VARIANT_DEPRECATED __declspec(deprecated) |
| # else |
| # define MAPBOX_VARIANT_DEPRECATED |
| # endif |
| #else |
| # define MAPBOX_VARIANT_DEPRECATED [[deprecated]] |
| #endif |
| |
| |
| #ifdef _MSC_VER |
| // https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx |
| # ifdef NDEBUG |
| # define VARIANT_INLINE __forceinline |
| # else |
| # define VARIANT_INLINE //__declspec(noinline) |
| # endif |
| #else |
| # ifdef NDEBUG |
| # define VARIANT_INLINE //inline __attribute__((always_inline)) |
| # else |
| # define VARIANT_INLINE __attribute__((noinline)) |
| # endif |
| #endif |
| // clang-format on |
| |
| // Exceptions |
| #if defined(__EXCEPTIONS) || defined(_MSC_VER) |
| #define HAS_EXCEPTIONS |
| #endif |
| |
| #define VARIANT_MAJOR_VERSION 1 |
| #define VARIANT_MINOR_VERSION 1 |
| #define VARIANT_PATCH_VERSION 0 |
| |
| #define VARIANT_VERSION \ |
| (VARIANT_MAJOR_VERSION * 100000) + (VARIANT_MINOR_VERSION * 100) + \ |
| (VARIANT_PATCH_VERSION) |
| |
| namespace mapbox |
| { |
| namespace util |
| { |
| |
| // XXX This should derive from std::logic_error instead of std::runtime_error. |
| // See https://github.com/mapbox/variant/issues/48 for details. |
| class bad_variant_access : public std::runtime_error |
| { |
| |
| public: |
| explicit bad_variant_access(const std::string& what_arg) : |
| runtime_error(what_arg) |
| { |
| } |
| |
| explicit bad_variant_access(const char* what_arg) : runtime_error(what_arg) |
| { |
| } |
| |
| }; // class bad_variant_access |
| |
| template <typename R = void> struct MAPBOX_VARIANT_DEPRECATED static_visitor |
| { |
| using result_type = R; |
| |
| protected: |
| static_visitor() |
| { |
| } |
| ~static_visitor() |
| { |
| } |
| }; |
| |
| namespace detail |
| { |
| |
| static constexpr std::size_t invalid_value = std::size_t(-1); |
| |
| template <typename T, typename... Types> struct direct_type; |
| |
| template <typename T, typename First, typename... Types> |
| struct direct_type<T, First, Types...> |
| { |
| static constexpr std::size_t index = std::is_same<T, First>::value |
| ? sizeof...(Types) |
| : direct_type<T, Types...>::index; |
| }; |
| |
| template <typename T> struct direct_type<T> |
| { |
| static constexpr std::size_t index = invalid_value; |
| }; |
| |
| #if __cpp_lib_logical_traits >= 201510L |
| |
| using std::disjunction; |
| |
| #else |
| |
| template <typename...> struct disjunction : std::false_type |
| { |
| }; |
| |
| template <typename B1> struct disjunction<B1> : B1 |
| { |
| }; |
| |
| template <typename B1, typename B2> |
| struct disjunction<B1, B2> : std::conditional<B1::value, B1, B2>::type |
| { |
| }; |
| |
| template <typename B1, typename... Bs> |
| struct disjunction<B1, Bs...> |
| : std::conditional<B1::value, B1, disjunction<Bs...>>::type |
| { |
| }; |
| |
| #endif |
| |
| template <typename T, typename... Types> struct convertible_type; |
| |
| template <typename T, typename First, typename... Types> |
| struct convertible_type<T, First, Types...> |
| { |
| static constexpr std::size_t index = |
| std::is_convertible<T, First>::value |
| ? disjunction<std::is_convertible<T, Types>...>::value |
| ? invalid_value |
| : sizeof...(Types) |
| : convertible_type<T, Types...>::index; |
| }; |
| |
| template <typename T> struct convertible_type<T> |
| { |
| static constexpr std::size_t index = invalid_value; |
| }; |
| |
| template <typename T, typename... Types> struct value_traits |
| { |
| using value_type = typename std::remove_const< |
| typename std::remove_reference<T>::type>::type; |
| static constexpr std::size_t direct_index = |
| direct_type<value_type, Types...>::index; |
| static constexpr bool is_direct = direct_index != invalid_value; |
| static constexpr std::size_t index = |
| is_direct ? direct_index |
| : convertible_type<value_type, Types...>::index; |
| static constexpr bool is_valid = index != invalid_value; |
| static constexpr std::size_t tindex = |
| is_valid ? sizeof...(Types) - index : 0; |
| using target_type = |
| typename std::tuple_element<tindex, std::tuple<void, Types...>>::type; |
| }; |
| |
| template <typename T, typename R = void> struct enable_if_type |
| { |
| using type = R; |
| }; |
| |
| template <typename F, typename V, typename Enable = void> |
| struct result_of_unary_visit |
| { |
| using type = typename std::result_of<F(V&)>::type; |
| }; |
| |
| template <typename F, typename V> |
| struct result_of_unary_visit< |
| F, V, typename enable_if_type<typename F::result_type>::type> |
| { |
| using type = typename F::result_type; |
| }; |
| |
| template <typename F, typename V, typename Enable = void> |
| struct result_of_binary_visit |
| { |
| using type = typename std::result_of<F(V&, V&)>::type; |
| }; |
| |
| template <typename F, typename V> |
| struct result_of_binary_visit< |
| F, V, typename enable_if_type<typename F::result_type>::type> |
| { |
| using type = typename F::result_type; |
| }; |
| |
| template <std::size_t arg1, std::size_t... others> struct static_max; |
| |
| template <std::size_t arg> struct static_max<arg> |
| { |
| static const std::size_t value = arg; |
| }; |
| |
| template <std::size_t arg1, std::size_t arg2, std::size_t... others> |
| struct static_max<arg1, arg2, others...> |
| { |
| static const std::size_t value = arg1 >= arg2 |
| ? static_max<arg1, others...>::value |
| : static_max<arg2, others...>::value; |
| }; |
| |
| template <typename... Types> struct variant_helper; |
| |
| template <typename T, typename... Types> struct variant_helper<T, Types...> |
| { |
| VARIANT_INLINE static void destroy(const std::size_t type_index, void* data) |
| { |
| if (type_index == sizeof...(Types)) |
| { |
| reinterpret_cast<T*>(data)->~T(); |
| } |
| else |
| { |
| variant_helper<Types...>::destroy(type_index, data); |
| } |
| } |
| |
| VARIANT_INLINE static void move(const std::size_t old_type_index, |
| void* old_value, void* new_value) |
| { |
| if (old_type_index == sizeof...(Types)) |
| { |
| new (new_value) T(std::move(*reinterpret_cast<T*>(old_value))); |
| } |
| else |
| { |
| variant_helper<Types...>::move(old_type_index, old_value, |
| new_value); |
| } |
| } |
| |
| VARIANT_INLINE static void copy(const std::size_t old_type_index, |
| const void* old_value, void* new_value) |
| { |
| if (old_type_index == sizeof...(Types)) |
| { |
| new (new_value) T(*reinterpret_cast<const T*>(old_value)); |
| } |
| else |
| { |
| variant_helper<Types...>::copy(old_type_index, old_value, |
| new_value); |
| } |
| } |
| }; |
| |
| template <> struct variant_helper<> |
| { |
| VARIANT_INLINE static void destroy(const std::size_t, void*) |
| { |
| } |
| VARIANT_INLINE static void move(const std::size_t, void*, void*) |
| { |
| } |
| VARIANT_INLINE static void copy(const std::size_t, const void*, void*) |
| { |
| } |
| }; |
| |
| template <typename T> struct unwrapper |
| { |
| static T const& apply_const(T const& obj) |
| { |
| return obj; |
| } |
| static T& apply(T& obj) |
| { |
| return obj; |
| } |
| }; |
| |
| template <typename T> struct unwrapper<recursive_wrapper<T>> |
| { |
| static auto apply_const(recursive_wrapper<T> const& obj) -> |
| typename recursive_wrapper<T>::type const& |
| { |
| return obj.get(); |
| } |
| static auto apply(recursive_wrapper<T>& obj) -> |
| typename recursive_wrapper<T>::type& |
| { |
| return obj.get(); |
| } |
| }; |
| |
| template <typename T> struct unwrapper<std::reference_wrapper<T>> |
| { |
| static auto apply_const(std::reference_wrapper<T> const& obj) -> |
| typename std::reference_wrapper<T>::type const& |
| { |
| return obj.get(); |
| } |
| static auto apply(std::reference_wrapper<T>& obj) -> |
| typename std::reference_wrapper<T>::type& |
| { |
| return obj.get(); |
| } |
| }; |
| |
| template <typename F, typename V, typename R, typename... Types> |
| struct dispatcher; |
| |
| template <typename F, typename V, typename R, typename T, typename... Types> |
| struct dispatcher<F, V, R, T, Types...> |
| { |
| VARIANT_INLINE static R apply_const(V const& v, F&& f) |
| { |
| if (v.template is<T>()) |
| { |
| return f(unwrapper<T>::apply_const(v.template get_unchecked<T>())); |
| } |
| else |
| { |
| return dispatcher<F, V, R, Types...>::apply_const( |
| v, std::forward<F>(f)); |
| } |
| } |
| |
| VARIANT_INLINE static R apply(V& v, F&& f) |
| { |
| if (v.template is<T>()) |
| { |
| return f(unwrapper<T>::apply(v.template get_unchecked<T>())); |
| } |
| else |
| { |
| return dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)); |
| } |
| } |
| }; |
| |
| template <typename F, typename V, typename R, typename T> |
| struct dispatcher<F, V, R, T> |
| { |
| VARIANT_INLINE static R apply_const(V const& v, F&& f) |
| { |
| return f(unwrapper<T>::apply_const(v.template get_unchecked<T>())); |
| } |
| |
| VARIANT_INLINE static R apply(V& v, F&& f) |
| { |
| return f(unwrapper<T>::apply(v.template get_unchecked<T>())); |
| } |
| }; |
| |
| template <typename F, typename V, typename R, typename T, typename... Types> |
| struct binary_dispatcher_rhs; |
| |
| template <typename F, typename V, typename R, typename T0, typename T1, |
| typename... Types> |
| struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...> |
| { |
| VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) |
| { |
| if (rhs.template is<T1>()) // call binary functor |
| { |
| return f( |
| unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()), |
| unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>())); |
| } |
| else |
| { |
| return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const( |
| lhs, rhs, std::forward<F>(f)); |
| } |
| } |
| |
| VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) |
| { |
| if (rhs.template is<T1>()) // call binary functor |
| { |
| return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()), |
| unwrapper<T1>::apply(rhs.template get_unchecked<T1>())); |
| } |
| else |
| { |
| return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply( |
| lhs, rhs, std::forward<F>(f)); |
| } |
| } |
| }; |
| |
| template <typename F, typename V, typename R, typename T0, typename T1> |
| struct binary_dispatcher_rhs<F, V, R, T0, T1> |
| { |
| VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) |
| { |
| return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()), |
| unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>())); |
| } |
| |
| VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) |
| { |
| return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()), |
| unwrapper<T1>::apply(rhs.template get_unchecked<T1>())); |
| } |
| }; |
| |
| template <typename F, typename V, typename R, typename T, typename... Types> |
| struct binary_dispatcher_lhs; |
| |
| template <typename F, typename V, typename R, typename T0, typename T1, |
| typename... Types> |
| struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...> |
| { |
| VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) |
| { |
| if (lhs.template is<T1>()) // call binary functor |
| { |
| return f( |
| unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()), |
| unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>())); |
| } |
| else |
| { |
| return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const( |
| lhs, rhs, std::forward<F>(f)); |
| } |
| } |
| |
| VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) |
| { |
| if (lhs.template is<T1>()) // call binary functor |
| { |
| return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()), |
| unwrapper<T0>::apply(rhs.template get_unchecked<T0>())); |
| } |
| else |
| { |
| return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply( |
| lhs, rhs, std::forward<F>(f)); |
| } |
| } |
| }; |
| |
| template <typename F, typename V, typename R, typename T0, typename T1> |
| struct binary_dispatcher_lhs<F, V, R, T0, T1> |
| { |
| VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) |
| { |
| return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()), |
| unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>())); |
| } |
| |
| VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) |
| { |
| return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()), |
| unwrapper<T0>::apply(rhs.template get_unchecked<T0>())); |
| } |
| }; |
| |
| template <typename F, typename V, typename R, typename... Types> |
| struct binary_dispatcher; |
| |
| template <typename F, typename V, typename R, typename T, typename... Types> |
| struct binary_dispatcher<F, V, R, T, Types...> |
| { |
| VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f) |
| { |
| if (v0.template is<T>()) |
| { |
| if (v1.template is<T>()) |
| { |
| return f( |
| unwrapper<T>::apply_const(v0.template get_unchecked<T>()), |
| unwrapper<T>::apply_const( |
| v1.template get_unchecked<T>())); // call binary functor |
| } |
| else |
| { |
| return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const( |
| v0, v1, std::forward<F>(f)); |
| } |
| } |
| else if (v1.template is<T>()) |
| { |
| return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const( |
| v0, v1, std::forward<F>(f)); |
| } |
| return binary_dispatcher<F, V, R, Types...>::apply_const( |
| v0, v1, std::forward<F>(f)); |
| } |
| |
| VARIANT_INLINE static R apply(V& v0, V& v1, F&& f) |
| { |
| if (v0.template is<T>()) |
| { |
| if (v1.template is<T>()) |
| { |
| return f( |
| unwrapper<T>::apply(v0.template get_unchecked<T>()), |
| unwrapper<T>::apply( |
| v1.template get_unchecked<T>())); // call binary functor |
| } |
| else |
| { |
| return binary_dispatcher_rhs<F, V, R, T, Types...>::apply( |
| v0, v1, std::forward<F>(f)); |
| } |
| } |
| else if (v1.template is<T>()) |
| { |
| return binary_dispatcher_lhs<F, V, R, T, Types...>::apply( |
| v0, v1, std::forward<F>(f)); |
| } |
| return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, |
| std::forward<F>(f)); |
| } |
| }; |
| |
| template <typename F, typename V, typename R, typename T> |
| struct binary_dispatcher<F, V, R, T> |
| { |
| VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f) |
| { |
| return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()), |
| unwrapper<T>::apply_const( |
| v1.template get_unchecked<T>())); // call binary functor |
| } |
| |
| VARIANT_INLINE static R apply(V& v0, V& v1, F&& f) |
| { |
| return f(unwrapper<T>::apply(v0.template get_unchecked<T>()), |
| unwrapper<T>::apply( |
| v1.template get_unchecked<T>())); // call binary functor |
| } |
| }; |
| |
| // comparator functors |
| struct equal_comp |
| { |
| template <typename T> bool operator()(T const& lhs, T const& rhs) const |
| { |
| return lhs == rhs; |
| } |
| }; |
| |
| struct less_comp |
| { |
| template <typename T> bool operator()(T const& lhs, T const& rhs) const |
| { |
| return lhs < rhs; |
| } |
| }; |
| |
| template <typename Variant, typename Comp> class comparer |
| { |
| public: |
| explicit comparer(Variant const& lhs) noexcept : lhs_(lhs) |
| { |
| } |
| comparer& operator=(comparer const&) = delete; |
| // visitor |
| template <typename T> bool operator()(T const& rhs_content) const |
| { |
| T const& lhs_content = lhs_.template get_unchecked<T>(); |
| return Comp()(lhs_content, rhs_content); |
| } |
| |
| private: |
| Variant const& lhs_; |
| }; |
| |
| } // namespace detail |
| |
| struct no_init |
| { |
| }; |
| |
| template <typename... Types> class variant |
| { |
| static_assert(sizeof...(Types) > 0, |
| "Template parameter type list of variant can not be empty"); |
| static_assert(!detail::disjunction<std::is_reference<Types>...>::value, |
| "Variant can not hold reference types. Maybe use " |
| "std::reference_wrapper?"); |
| |
| private: |
| static const std::size_t data_size = |
| detail::static_max<sizeof(Types)...>::value; |
| static const std::size_t data_align = |
| detail::static_max<alignof(Types)...>::value; |
| |
| using first_type = |
| typename std::tuple_element<0, std::tuple<Types...>>::type; |
| using data_type = |
| typename std::aligned_storage<data_size, data_align>::type; |
| using helper_type = detail::variant_helper<Types...>; |
| |
| std::size_t type_index; |
| data_type data; |
| |
| public: |
| VARIANT_INLINE variant() noexcept( |
| std::is_nothrow_default_constructible<first_type>::value) : |
| type_index(sizeof...(Types) - 1) |
| { |
| static_assert(std::is_default_constructible<first_type>::value, |
| "First type in variant must be default constructible to " |
| "allow default construction of variant"); |
| new (&data) first_type(); |
| } |
| |
| VARIANT_INLINE variant(no_init) noexcept : type_index(detail::invalid_value) |
| { |
| } |
| |
| // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers |
| template <typename T, typename Traits = detail::value_traits<T, Types...>, |
| typename Enable = typename std::enable_if<Traits::is_valid>::type> |
| VARIANT_INLINE variant(T&& val) noexcept( |
| std::is_nothrow_constructible<typename Traits::target_type, |
| T&&>::value) : |
| type_index(Traits::index) |
| { |
| new (&data) typename Traits::target_type(std::forward<T>(val)); |
| } |
| |
| VARIANT_INLINE variant(variant<Types...> const& old) : |
| type_index(old.type_index) |
| { |
| helper_type::copy(old.type_index, &old.data, &data); |
| } |
| |
| VARIANT_INLINE variant(variant<Types...>&& old) noexcept( |
| std::is_nothrow_move_constructible<std::tuple<Types...>>::value) : |
| type_index(old.type_index) |
| { |
| helper_type::move(old.type_index, &old.data, &data); |
| } |
| |
| private: |
| VARIANT_INLINE void copy_assign(variant<Types...> const& rhs) |
| { |
| helper_type::destroy(type_index, &data); |
| type_index = detail::invalid_value; |
| helper_type::copy(rhs.type_index, &rhs.data, &data); |
| type_index = rhs.type_index; |
| } |
| |
| VARIANT_INLINE void move_assign(variant<Types...>&& rhs) |
| { |
| helper_type::destroy(type_index, &data); |
| type_index = detail::invalid_value; |
| helper_type::move(rhs.type_index, &rhs.data, &data); |
| type_index = rhs.type_index; |
| } |
| |
| public: |
| VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other) |
| { |
| move_assign(std::move(other)); |
| return *this; |
| } |
| |
| VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other) |
| { |
| copy_assign(other); |
| return *this; |
| } |
| |
| // conversions |
| // move-assign |
| template <typename T> |
| VARIANT_INLINE variant<Types...>& operator=(T&& rhs) noexcept |
| { |
| variant<Types...> temp(std::forward<T>(rhs)); |
| move_assign(std::move(temp)); |
| return *this; |
| } |
| |
| // copy-assign |
| template <typename T> |
| VARIANT_INLINE variant<Types...>& operator=(T const& rhs) |
| { |
| variant<Types...> temp(rhs); |
| copy_assign(temp); |
| return *this; |
| } |
| |
| template <typename T, typename std::enable_if< |
| (detail::direct_type<T, Types...>::index != |
| detail::invalid_value)>::type* = nullptr> |
| VARIANT_INLINE bool is() const |
| { |
| return type_index == detail::direct_type<T, Types...>::index; |
| } |
| |
| template <typename T, |
| typename std::enable_if< |
| (detail::direct_type<recursive_wrapper<T>, Types...>::index != |
| detail::invalid_value)>::type* = nullptr> |
| VARIANT_INLINE bool is() const |
| { |
| return type_index == |
| detail::direct_type<recursive_wrapper<T>, Types...>::index; |
| } |
| |
| VARIANT_INLINE bool valid() const |
| { |
| return type_index != detail::invalid_value; |
| } |
| |
| template <typename T, typename... Args> |
| VARIANT_INLINE void set(Args&&... args) |
| { |
| helper_type::destroy(type_index, &data); |
| type_index = detail::invalid_value; |
| new (&data) T(std::forward<Args>(args)...); |
| type_index = detail::direct_type<T, Types...>::index; |
| } |
| |
| // get_unchecked<T>() |
| template <typename T, typename std::enable_if< |
| (detail::direct_type<T, Types...>::index != |
| detail::invalid_value)>::type* = nullptr> |
| VARIANT_INLINE T& get_unchecked() |
| { |
| return *reinterpret_cast<T*>(&data); |
| } |
| |
| #ifdef HAS_EXCEPTIONS |
| // get<T>() |
| template <typename T, typename std::enable_if< |
| (detail::direct_type<T, Types...>::index != |
| detail::invalid_value)>::type* = nullptr> |
| VARIANT_INLINE T& get() |
| { |
| if (type_index == detail::direct_type<T, Types...>::index) |
| { |
| return *reinterpret_cast<T*>(&data); |
| } |
| else |
| { |
| throw bad_variant_access("in get<T>()"); |
| } |
| } |
| #endif |
| |
| template <typename T, typename std::enable_if< |
| (detail::direct_type<T, Types...>::index != |
| detail::invalid_value)>::type* = nullptr> |
| VARIANT_INLINE T const& get_unchecked() const |
| { |
| return *reinterpret_cast<T const*>(&data); |
| } |
| |
| #ifdef HAS_EXCEPTIONS |
| template <typename T, typename std::enable_if< |
| (detail::direct_type<T, Types...>::index != |
| detail::invalid_value)>::type* = nullptr> |
| VARIANT_INLINE T const& get() const |
| { |
| if (type_index == detail::direct_type<T, Types...>::index) |
| { |
| return *reinterpret_cast<T const*>(&data); |
| } |
| else |
| { |
| throw bad_variant_access("in get<T>()"); |
| } |
| } |
| #endif |
| |
| // get_unchecked<T>() - T stored as recursive_wrapper<T> |
| template <typename T, |
| typename std::enable_if< |
| (detail::direct_type<recursive_wrapper<T>, Types...>::index != |
| detail::invalid_value)>::type* = nullptr> |
| VARIANT_INLINE T& get_unchecked() |
| { |
| return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get(); |
| } |
| |
| #ifdef HAS_EXCEPTIONS |
| // get<T>() - T stored as recursive_wrapper<T> |
| template <typename T, |
| typename std::enable_if< |
| (detail::direct_type<recursive_wrapper<T>, Types...>::index != |
| detail::invalid_value)>::type* = nullptr> |
| VARIANT_INLINE T& get() |
| { |
| if (type_index == |
| detail::direct_type<recursive_wrapper<T>, Types...>::index) |
| { |
| return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get(); |
| } |
| else |
| { |
| throw bad_variant_access("in get<T>()"); |
| } |
| } |
| #endif |
| |
| template <typename T, |
| typename std::enable_if< |
| (detail::direct_type<recursive_wrapper<T>, Types...>::index != |
| detail::invalid_value)>::type* = nullptr> |
| VARIANT_INLINE T const& get_unchecked() const |
| { |
| return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get(); |
| } |
| |
| #ifdef HAS_EXCEPTIONS |
| template <typename T, |
| typename std::enable_if< |
| (detail::direct_type<recursive_wrapper<T>, Types...>::index != |
| detail::invalid_value)>::type* = nullptr> |
| VARIANT_INLINE T const& get() const |
| { |
| if (type_index == |
| detail::direct_type<recursive_wrapper<T>, Types...>::index) |
| { |
| return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)) |
| .get(); |
| } |
| else |
| { |
| throw bad_variant_access("in get<T>()"); |
| } |
| } |
| #endif |
| |
| // get_unchecked<T>() - T stored as std::reference_wrapper<T> |
| template < |
| typename T, |
| typename std::enable_if< |
| (detail::direct_type<std::reference_wrapper<T>, Types...>::index != |
| detail::invalid_value)>::type* = nullptr> |
| VARIANT_INLINE T& get_unchecked() |
| { |
| return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get(); |
| } |
| |
| #ifdef HAS_EXCEPTIONS |
| // get<T>() - T stored as std::reference_wrapper<T> |
| template < |
| typename T, |
| typename std::enable_if< |
| (detail::direct_type<std::reference_wrapper<T>, Types...>::index != |
| detail::invalid_value)>::type* = nullptr> |
| VARIANT_INLINE T& get() |
| { |
| if (type_index == |
| detail::direct_type<std::reference_wrapper<T>, Types...>::index) |
| { |
| return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get(); |
| } |
| else |
| { |
| throw bad_variant_access("in get<T>()"); |
| } |
| } |
| #endif |
| |
| template <typename T, |
| typename std::enable_if< |
| (detail::direct_type<std::reference_wrapper<T const>, |
| Types...>::index != |
| detail::invalid_value)>::type* = nullptr> |
| VARIANT_INLINE T const& get_unchecked() const |
| { |
| return (*reinterpret_cast<std::reference_wrapper<T const> const*>( |
| &data)) |
| .get(); |
| } |
| |
| #ifdef HAS_EXCEPTIONS |
| template <typename T, |
| typename std::enable_if< |
| (detail::direct_type<std::reference_wrapper<T const>, |
| Types...>::index != |
| detail::invalid_value)>::type* = nullptr> |
| VARIANT_INLINE T const& get() const |
| { |
| if (type_index == detail::direct_type<std::reference_wrapper<T const>, |
| Types...>::index) |
| { |
| return (*reinterpret_cast<std::reference_wrapper<T const> const*>( |
| &data)) |
| .get(); |
| } |
| else |
| { |
| throw bad_variant_access("in get<T>()"); |
| } |
| } |
| #endif |
| |
| // This function is deprecated because it returns an internal index field. |
| // Use which() instead. |
| MAPBOX_VARIANT_DEPRECATED VARIANT_INLINE std::size_t get_type_index() const |
| { |
| return type_index; |
| } |
| |
| VARIANT_INLINE int which() const noexcept |
| { |
| return static_cast<int>(sizeof...(Types) - type_index - 1); |
| } |
| |
| template <typename T, typename std::enable_if< |
| (detail::direct_type<T, Types...>::index != |
| detail::invalid_value)>::type* = nullptr> |
| VARIANT_INLINE static constexpr int which() noexcept |
| { |
| return static_cast<int>(sizeof...(Types) - |
| detail::direct_type<T, Types...>::index - 1); |
| } |
| |
| // visitor |
| // unary |
| template <typename F, typename V, |
| typename R = |
| typename detail::result_of_unary_visit<F, first_type>::type> |
| auto VARIANT_INLINE static visit(V const& v, F&& f) |
| -> decltype(detail::dispatcher<F, V, R, Types...>::apply_const( |
| v, std::forward<F>(f))) |
| { |
| return detail::dispatcher<F, V, R, Types...>::apply_const( |
| v, std::forward<F>(f)); |
| } |
| // non-const |
| template <typename F, typename V, |
| typename R = |
| typename detail::result_of_unary_visit<F, first_type>::type> |
| auto VARIANT_INLINE static visit(V& v, F&& f) -> decltype( |
| detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f))) |
| { |
| return detail::dispatcher<F, V, R, Types...>::apply(v, |
| std::forward<F>(f)); |
| } |
| |
| // binary |
| // const |
| template <typename F, typename V, |
| typename R = |
| typename detail::result_of_binary_visit<F, first_type>::type> |
| auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F&& f) |
| -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply_const( |
| v0, v1, std::forward<F>(f))) |
| { |
| return detail::binary_dispatcher<F, V, R, Types...>::apply_const( |
| v0, v1, std::forward<F>(f)); |
| } |
| // non-const |
| template <typename F, typename V, |
| typename R = |
| typename detail::result_of_binary_visit<F, first_type>::type> |
| auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F&& f) |
| -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply( |
| v0, v1, std::forward<F>(f))) |
| { |
| return detail::binary_dispatcher<F, V, R, Types...>::apply( |
| v0, v1, std::forward<F>(f)); |
| } |
| |
| ~variant() noexcept // no-throw destructor |
| { |
| helper_type::destroy(type_index, &data); |
| } |
| |
| // comparison operators |
| // equality |
| VARIANT_INLINE bool operator==(variant const& rhs) const |
| { |
| assert(valid() && rhs.valid()); |
| if (this->which() != rhs.which()) |
| { |
| return false; |
| } |
| detail::comparer<variant, detail::equal_comp> visitor(*this); |
| return visit(rhs, visitor); |
| } |
| |
| VARIANT_INLINE bool operator!=(variant const& rhs) const |
| { |
| return !(*this == rhs); |
| } |
| |
| // less than |
| VARIANT_INLINE bool operator<(variant const& rhs) const |
| { |
| assert(valid() && rhs.valid()); |
| if (this->which() != rhs.which()) |
| { |
| return this->which() < rhs.which(); |
| } |
| detail::comparer<variant, detail::less_comp> visitor(*this); |
| return visit(rhs, visitor); |
| } |
| VARIANT_INLINE bool operator>(variant const& rhs) const |
| { |
| return rhs < *this; |
| } |
| VARIANT_INLINE bool operator<=(variant const& rhs) const |
| { |
| return !(*this > rhs); |
| } |
| VARIANT_INLINE bool operator>=(variant const& rhs) const |
| { |
| return !(*this < rhs); |
| } |
| }; |
| |
| // unary visitor interface |
| // const |
| template <typename F, typename V> |
| auto VARIANT_INLINE apply_visitor(F&& f, V const& v) |
| -> decltype(V::visit(v, std::forward<F>(f))) |
| { |
| return V::visit(v, std::forward<F>(f)); |
| } |
| |
| // non-const |
| template <typename F, typename V> |
| auto VARIANT_INLINE apply_visitor(F&& f, V& v) |
| -> decltype(V::visit(v, std::forward<F>(f))) |
| { |
| return V::visit(v, std::forward<F>(f)); |
| } |
| |
| // binary visitor interface |
| // const |
| template <typename F, typename V> |
| auto VARIANT_INLINE apply_visitor(F&& f, V const& v0, V const& v1) |
| -> decltype(V::binary_visit(v0, v1, std::forward<F>(f))) |
| { |
| return V::binary_visit(v0, v1, std::forward<F>(f)); |
| } |
| |
| // non-const |
| template <typename F, typename V> |
| auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1) |
| -> decltype(V::binary_visit(v0, v1, std::forward<F>(f))) |
| { |
| return V::binary_visit(v0, v1, std::forward<F>(f)); |
| } |
| |
| // getter interface |
| |
| #ifdef HAS_EXCEPTIONS |
| template <typename ResultType, typename T> |
| auto get(T& var) -> decltype(var.template get<ResultType>()) |
| { |
| return var.template get<ResultType>(); |
| } |
| #endif |
| |
| template <typename ResultType, typename T> ResultType& get_unchecked(T& var) |
| { |
| return var.template get_unchecked<ResultType>(); |
| } |
| |
| #ifdef HAS_EXCEPTIONS |
| template <typename ResultType, typename T> |
| auto get(T const& var) -> decltype(var.template get<ResultType>()) |
| { |
| return var.template get<ResultType>(); |
| } |
| #endif |
| |
| template <typename ResultType, typename T> |
| ResultType const& get_unchecked(T const& var) |
| { |
| return var.template get_unchecked<ResultType>(); |
| } |
| } // namespace util |
| } // namespace mapbox |
| |
| #endif // MAPBOX_UTIL_VARIANT_HPP |