#ifndef MAPBOX_UTIL_VARIANT_HPP #define MAPBOX_UTIL_VARIANT_HPP #include #include // size_t #include // operator new #include // runtime_error #include #include #include #include #include #include "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 #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 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 struct direct_type; template struct direct_type { static constexpr std::size_t index = std::is_same::value ? sizeof...(Types) : direct_type::index; }; template struct direct_type { static constexpr std::size_t index = invalid_value; }; template struct convertible_type; template struct convertible_type { static constexpr std::size_t index = std::is_convertible::value ? sizeof...(Types) : convertible_type::index; }; template struct convertible_type { static constexpr std::size_t index = invalid_value; }; template struct value_traits { using value_type = typename std::remove_reference::type; static constexpr std::size_t direct_index = direct_type::index; static constexpr bool is_direct = direct_index != invalid_value; static constexpr std::size_t index = is_direct ? direct_index : convertible_type::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>::type; }; // check if T is in Types... template struct has_type; template struct has_type { static constexpr bool value = std::is_same::value || has_type::value; }; template struct has_type : std::false_type { }; template struct is_valid_type; template struct is_valid_type { static constexpr bool value = std::is_convertible::value || is_valid_type::value; }; template struct is_valid_type : std::false_type { }; template struct enable_if_type { using type = R; }; template struct result_of_unary_visit { using type = typename std::result_of::type; }; template struct result_of_unary_visit::type> { using type = typename F::result_type; }; template struct result_of_binary_visit { using type = typename std::result_of::type; }; template struct result_of_binary_visit::type> { using type = typename F::result_type; }; template struct static_max; template struct static_max { static const std::size_t value = arg; }; template struct static_max { static const std::size_t value = arg1 >= arg2 ? static_max::value : static_max::value; }; template struct variant_helper; template struct variant_helper { VARIANT_INLINE static void destroy(const std::size_t type_index, void* data) { if (type_index == sizeof...(Types)) { reinterpret_cast(data)->~T(); } else { variant_helper::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(old_value))); } else { variant_helper::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(old_value)); } else { variant_helper::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 struct unwrapper { static T const& apply_const(T const& obj) { return obj; } static T& apply(T& obj) { return obj; } }; template struct unwrapper> { static auto apply_const(recursive_wrapper const& obj) -> typename recursive_wrapper::type const& { return obj.get(); } static auto apply(recursive_wrapper& obj) -> typename recursive_wrapper::type& { return obj.get(); } }; template struct unwrapper> { static auto apply_const(std::reference_wrapper const& obj) -> typename std::reference_wrapper::type const& { return obj.get(); } static auto apply(std::reference_wrapper& obj) -> typename std::reference_wrapper::type& { return obj.get(); } }; template struct dispatcher; template struct dispatcher { VARIANT_INLINE static R apply_const(V const& v, F&& f) { if (v.template is()) { return f(unwrapper::apply_const(v.template get())); } else { return dispatcher::apply_const(v, std::forward(f)); } } VARIANT_INLINE static R apply(V& v, F&& f) { if (v.template is()) { return f(unwrapper::apply(v.template get())); } else { return dispatcher::apply(v, std::forward(f)); } } }; template struct dispatcher { VARIANT_INLINE static R apply_const(V const& v, F&& f) { return f(unwrapper::apply_const(v.template get())); } VARIANT_INLINE static R apply(V& v, F&& f) { return f(unwrapper::apply(v.template get())); } }; template struct binary_dispatcher_rhs; template struct binary_dispatcher_rhs { VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) { if (rhs.template is()) // call binary functor { return f(unwrapper::apply_const(lhs.template get()), unwrapper::apply_const(rhs.template get())); } else { return binary_dispatcher_rhs::apply_const(lhs, rhs, std::forward(f)); } } VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) { if (rhs.template is()) // call binary functor { return f(unwrapper::apply(lhs.template get()), unwrapper::apply(rhs.template get())); } else { return binary_dispatcher_rhs::apply(lhs, rhs, std::forward(f)); } } }; template struct binary_dispatcher_rhs { VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) { return f(unwrapper::apply_const(lhs.template get()), unwrapper::apply_const(rhs.template get())); } VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) { return f(unwrapper::apply(lhs.template get()), unwrapper::apply(rhs.template get())); } }; template struct binary_dispatcher_lhs; template struct binary_dispatcher_lhs { VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) { if (lhs.template is()) // call binary functor { return f(unwrapper::apply_const(lhs.template get()), unwrapper::apply_const(rhs.template get())); } else { return binary_dispatcher_lhs::apply_const(lhs, rhs, std::forward(f)); } } VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) { if (lhs.template is()) // call binary functor { return f(unwrapper::apply(lhs.template get()), unwrapper::apply(rhs.template get())); } else { return binary_dispatcher_lhs::apply(lhs, rhs, std::forward(f)); } } }; template struct binary_dispatcher_lhs { VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) { return f(unwrapper::apply_const(lhs.template get()), unwrapper::apply_const(rhs.template get())); } VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) { return f(unwrapper::apply(lhs.template get()), unwrapper::apply(rhs.template get())); } }; template struct binary_dispatcher; template struct binary_dispatcher { VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f) { if (v0.template is()) { if (v1.template is()) { return f(unwrapper::apply_const(v0.template get()), unwrapper::apply_const(v1.template get())); // call binary functor } else { return binary_dispatcher_rhs::apply_const(v0, v1, std::forward(f)); } } else if (v1.template is()) { return binary_dispatcher_lhs::apply_const(v0, v1, std::forward(f)); } return binary_dispatcher::apply_const(v0, v1, std::forward(f)); } VARIANT_INLINE static R apply(V& v0, V& v1, F&& f) { if (v0.template is()) { if (v1.template is()) { return f(unwrapper::apply(v0.template get()), unwrapper::apply(v1.template get())); // call binary functor } else { return binary_dispatcher_rhs::apply(v0, v1, std::forward(f)); } } else if (v1.template is()) { return binary_dispatcher_lhs::apply(v0, v1, std::forward(f)); } return binary_dispatcher::apply(v0, v1, std::forward(f)); } }; template struct binary_dispatcher { VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f) { return f(unwrapper::apply_const(v0.template get()), unwrapper::apply_const(v1.template get())); // call binary functor } VARIANT_INLINE static R apply(V& v0, V& v1, F&& f) { return f(unwrapper::apply(v0.template get()), unwrapper::apply(v1.template get())); // call binary functor } }; // comparator functors struct equal_comp { template bool operator()(T const& lhs, T const& rhs) const { return lhs == rhs; } }; struct less_comp { template bool operator()(T const& lhs, T const& rhs) const { return lhs < rhs; } }; template class comparer { public: explicit comparer(Variant const& lhs) noexcept : lhs_(lhs) {} comparer& operator=(comparer const&) = delete; // visitor template bool operator()(T const& rhs_content) const { T const& lhs_content = lhs_.template get(); return Comp()(lhs_content, rhs_content); } private: Variant const& lhs_; }; // True if Predicate matches for all of the types Ts template