diff options
Diffstat (limited to 'src/mapbox')
-rw-r--r-- | src/mapbox/optional.hpp | 74 | ||||
-rw-r--r-- | src/mapbox/recursive_wrapper.hpp | 122 | ||||
-rw-r--r-- | src/mapbox/variant.hpp | 1053 | ||||
-rw-r--r-- | src/mapbox/variant_cast.hpp | 85 | ||||
-rw-r--r-- | src/mapbox/variant_io.hpp | 45 | ||||
-rw-r--r-- | src/mapbox/variant_visitor.hpp | 43 |
6 files changed, 1422 insertions, 0 deletions
diff --git a/src/mapbox/optional.hpp b/src/mapbox/optional.hpp new file mode 100644 index 0000000..d84705c --- /dev/null +++ b/src/mapbox/optional.hpp @@ -0,0 +1,74 @@ +#ifndef MAPBOX_UTIL_OPTIONAL_HPP +#define MAPBOX_UTIL_OPTIONAL_HPP + +#pragma message("This implementation of optional is deprecated. See https://github.com/mapbox/variant/issues/64.") + +#include <type_traits> +#include <utility> + +#include <mapbox/variant.hpp> + +namespace mapbox { +namespace util { + +template <typename T> +class optional +{ + static_assert(!std::is_reference<T>::value, "optional doesn't support references"); + + struct none_type + { + }; + + variant<none_type, T> variant_; + +public: + optional() = default; + + optional(optional const& rhs) + { + if (this != &rhs) + { // protect against invalid self-assignment + variant_ = rhs.variant_; + } + } + + optional(T const& v) { variant_ = v; } + + explicit operator bool() const noexcept { return variant_.template is<T>(); } + + T const& get() const { return variant_.template get<T>(); } + T& get() { return variant_.template get<T>(); } + + T const& operator*() const { return this->get(); } + T operator*() { return this->get(); } + + optional& operator=(T const& v) + { + variant_ = v; + return *this; + } + + optional& operator=(optional const& rhs) + { + if (this != &rhs) + { + variant_ = rhs.variant_; + } + return *this; + } + + template <typename... Args> + void emplace(Args&&... args) + { + variant_ = T{std::forward<Args>(args)...}; + } + + void reset() { variant_ = none_type{}; } + +}; // class optional + +} // namespace util +} // namespace mapbox + +#endif // MAPBOX_UTIL_OPTIONAL_HPP diff --git a/src/mapbox/recursive_wrapper.hpp b/src/mapbox/recursive_wrapper.hpp new file mode 100644 index 0000000..4ffcbd7 --- /dev/null +++ b/src/mapbox/recursive_wrapper.hpp @@ -0,0 +1,122 @@ +#ifndef MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP +#define MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP + +// Based on variant/recursive_wrapper.hpp from boost. +// +// Original license: +// +// Copyright (c) 2002-2003 +// Eric Friedman, Itay Maman +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <cassert> +#include <utility> + +namespace mapbox { +namespace util { + +template <typename T> +class recursive_wrapper +{ + + T* p_; + + void assign(T const& rhs) + { + this->get() = rhs; + } + +public: + using type = T; + + /** + * Default constructor default initializes the internally stored value. + * For POD types this means nothing is done and the storage is + * uninitialized. + * + * @throws std::bad_alloc if there is insufficient memory for an object + * of type T. + * @throws any exception thrown by the default constructur of T. + */ + recursive_wrapper() + : p_(new T){} + + ~recursive_wrapper() noexcept { delete p_; } + + recursive_wrapper(recursive_wrapper const& operand) + : p_(new T(operand.get())) {} + + recursive_wrapper(T const& operand) + : p_(new T(operand)) {} + + recursive_wrapper(recursive_wrapper&& operand) + : p_(new T(std::move(operand.get()))) {} + + recursive_wrapper(T&& operand) + : p_(new T(std::move(operand))) {} + + inline recursive_wrapper& operator=(recursive_wrapper const& rhs) + { + assign(rhs.get()); + return *this; + } + + inline recursive_wrapper& operator=(T const& rhs) + { + assign(rhs); + return *this; + } + + inline void swap(recursive_wrapper& operand) noexcept + { + T* temp = operand.p_; + operand.p_ = p_; + p_ = temp; + } + + recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept + { + swap(rhs); + return *this; + } + + recursive_wrapper& operator=(T&& rhs) + { + get() = std::move(rhs); + return *this; + } + + T& get() + { + assert(p_); + return *get_pointer(); + } + + T const& get() const + { + assert(p_); + return *get_pointer(); + } + + T* get_pointer() { return p_; } + + const T* get_pointer() const { return p_; } + + operator T const&() const { return this->get(); } + + operator T&() { return this->get(); } + +}; // class recursive_wrapper + +template <typename T> +inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept +{ + lhs.swap(rhs); +} +} // namespace util +} // namespace mapbox + +#endif // MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP diff --git a/src/mapbox/variant.hpp b/src/mapbox/variant.hpp new file mode 100644 index 0000000..06a46ab --- /dev/null +++ b/src/mapbox/variant.hpp @@ -0,0 +1,1053 @@ +#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 <functional> +#include <limits> + +#include <mapbox/recursive_wrapper.hpp> +#include <mapbox/variant_visitor.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 + +#if !defined(MAPBOX_VARIANT_MINIMIZE_SIZE) +using type_index_t = unsigned int; +#else +#if defined(MAPBOX_VARIANT_OPTIMIZE_FOR_SPEED) +using type_index_t = std::uint_fast8_t; +#else +using type_index_t = std::uint_least8_t; +#endif +#endif + +namespace detail { + +static constexpr type_index_t invalid_value = type_index_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 type_index_t index = std::is_same<T, First>::value + ? sizeof...(Types) + : direct_type<T, Types...>::index; +}; + +template <typename T> +struct direct_type<T> +{ + static constexpr type_index_t index = invalid_value; +}; + +#if __cpp_lib_logical_traits >= 201510L + +using std::conjunction; +using std::disjunction; + +#else + +template <typename...> +struct conjunction : std::true_type {}; + +template <typename B1> +struct conjunction<B1> : B1 {}; + +template <typename B1, typename B2> +struct conjunction<B1, B2> : std::conditional<B1::value, B2, B1>::type {}; + +template <typename B1, typename... Bs> +struct conjunction<B1, Bs...> : std::conditional<B1::value, conjunction<Bs...>, B1>::type {}; + +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 type_index_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 type_index_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; + using value_type_wrapper = recursive_wrapper<value_type>; + static constexpr type_index_t direct_index = direct_type<value_type, Types...>::index; + static constexpr bool is_direct = direct_index != invalid_value; + static constexpr type_index_t index_direct_or_wrapper = is_direct ? direct_index : direct_type<value_type_wrapper, Types...>::index; + static constexpr bool is_direct_or_wrapper = index_direct_or_wrapper != invalid_value; + static constexpr type_index_t index = is_direct_or_wrapper ? index_direct_or_wrapper : convertible_type<value_type, Types...>::index; + static constexpr bool is_valid = index != invalid_value; + static constexpr type_index_t tindex = is_valid ? sizeof...(Types)-index : 0; + using target_type = typename std::tuple_element<tindex, std::tuple<void, Types...>>::type; +}; + +template <typename Src, typename Dest> +struct copy_cvref +{ + using type = Dest; +}; + +template <typename Src, typename Dest> +struct copy_cvref<Src const&, Dest> +{ + using type = Dest const&; +}; + +template <typename Src, typename Dest> +struct copy_cvref<Src&, Dest> +{ + using type = Dest&; +}; + +template <typename Src, typename Dest> +struct copy_cvref<Src&&, Dest> +{ + using type = Dest&&; +}; + +template <typename F, typename = void> +struct deduced_result_type +{}; + +template <typename F, typename... Args> +struct deduced_result_type<F(Args...), decltype((void)std::declval<F>()(std::declval<Args>()...))> +{ + using type = decltype(std::declval<F>()(std::declval<Args>()...)); +}; + +template <typename F, typename = void> +struct visitor_result_type : deduced_result_type<F> +{}; + +// specialization for explicit result_type member in visitor class +template <typename F, typename... Args> +struct visitor_result_type<F(Args...), decltype((void)std::declval<typename std::decay<F>::type::result_type>())> +{ + using type = typename std::decay<F>::type::result_type; +}; + +template <typename F, typename T> +using result_of_unary_visit = typename visitor_result_type<F&&(T&&)>::type; + +template <typename F, typename T> +using result_of_binary_visit = typename visitor_result_type<F&&(T&&, T&&)>::type; + +template <type_index_t arg1, type_index_t... others> +struct static_max; + +template <type_index_t arg> +struct static_max<arg> +{ + static const type_index_t value = arg; +}; + +template <type_index_t arg1, type_index_t arg2, type_index_t... others> +struct static_max<arg1, arg2, others...> +{ + static const type_index_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 type_index_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 type_index_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 type_index_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 type_index_t, void*) {} + VARIANT_INLINE static void move(const type_index_t, void*, void*) {} + VARIANT_INLINE static void copy(const type_index_t, const void*, void*) {} +}; + +template <typename T> +struct unwrapper +{ + using value_type = T; + + template <typename V> + static auto apply(typename std::remove_reference<V>::type& var) + -> typename std::enable_if<std::is_lvalue_reference<V>::value, + decltype(var.template get_unchecked<T>())>::type + { + return var.template get_unchecked<T>(); + } + + template <typename V> + static auto apply(typename std::remove_reference<V>::type& var) + -> typename std::enable_if<!std::is_lvalue_reference<V>::value, + decltype(std::move(var.template get_unchecked<T>()))>::type + { + return std::move(var.template get_unchecked<T>()); + } +}; + +template <typename T> +struct unwrapper<recursive_wrapper<T>> : unwrapper<T> +{}; + +template <typename T> +struct unwrapper<std::reference_wrapper<T>> : unwrapper<T> +{}; + +template <typename R, typename... Types> +struct dispatcher; + +template <typename R, typename T, typename... Types> +struct dispatcher<R, T, Types...> +{ + template <typename V, typename F> + VARIANT_INLINE static R apply(V&& v, F&& f) + { + if (v.template is<T>()) + { + return std::forward<F>(f)(unwrapper<T>::template apply<V>(v)); + } + else + { + return dispatcher<R, Types...>::apply(std::forward<V>(v), std::forward<F>(f)); + } + } +}; + +template <typename R, typename T> +struct dispatcher<R, T> +{ + template <typename V, typename F> + VARIANT_INLINE static R apply(V&& v, F&& f) + { + return std::forward<F>(f)(unwrapper<T>::template apply<V>(v)); + } +}; + +template <typename R, typename T, typename... Types> +struct binary_dispatcher_rhs; + +template <typename R, typename T0, typename T1, typename... Types> +struct binary_dispatcher_rhs<R, T0, T1, Types...> +{ + template <typename V, typename F> + VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f) + { + if (rhs.template is<T1>()) // call binary functor + { + return std::forward<F>(f)(unwrapper<T0>::template apply<V>(lhs), + unwrapper<T1>::template apply<V>(rhs)); + } + else + { + return binary_dispatcher_rhs<R, T0, Types...>::apply(std::forward<V>(lhs), + std::forward<V>(rhs), + std::forward<F>(f)); + } + } +}; + +template <typename R, typename T0, typename T1> +struct binary_dispatcher_rhs<R, T0, T1> +{ + template <typename V, typename F> + VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f) + { + return std::forward<F>(f)(unwrapper<T0>::template apply<V>(lhs), + unwrapper<T1>::template apply<V>(rhs)); + } +}; + +template <typename R, typename T, typename... Types> +struct binary_dispatcher_lhs; + +template <typename R, typename T0, typename T1, typename... Types> +struct binary_dispatcher_lhs<R, T0, T1, Types...> +{ + template <typename V, typename F> + VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f) + { + if (lhs.template is<T1>()) // call binary functor + { + return std::forward<F>(f)(unwrapper<T1>::template apply<V>(lhs), + unwrapper<T0>::template apply<V>(rhs)); + } + else + { + return binary_dispatcher_lhs<R, T0, Types...>::apply(std::forward<V>(lhs), + std::forward<V>(rhs), + std::forward<F>(f)); + } + } +}; + +template <typename R, typename T0, typename T1> +struct binary_dispatcher_lhs<R, T0, T1> +{ + template <typename V, typename F> + VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f) + { + return std::forward<F>(f)(unwrapper<T1>::template apply<V>(lhs), + unwrapper<T0>::template apply<V>(rhs)); + } +}; + +template <typename R, typename... Types> +struct binary_dispatcher; + +template <typename R, typename T, typename... Types> +struct binary_dispatcher<R, T, Types...> +{ + template <typename V, typename F> + VARIANT_INLINE static R apply(V&& v0, V&& v1, F&& f) + { + if (v0.template is<T>()) + { + if (v1.template is<T>()) + { + return std::forward<F>(f)(unwrapper<T>::template apply<V>(v0), + unwrapper<T>::template apply<V>(v1)); // call binary functor + } + else + { + return binary_dispatcher_rhs<R, T, Types...>::apply(std::forward<V>(v0), + std::forward<V>(v1), + std::forward<F>(f)); + } + } + else if (v1.template is<T>()) + { + return binary_dispatcher_lhs<R, T, Types...>::apply(std::forward<V>(v0), + std::forward<V>(v1), + std::forward<F>(f)); + } + return binary_dispatcher<R, Types...>::apply(std::forward<V>(v0), + std::forward<V>(v1), + std::forward<F>(f)); + } +}; + +template <typename R, typename T> +struct binary_dispatcher<R, T> +{ + template <typename V, typename F> + VARIANT_INLINE static R apply(V&& v0, V&& v1, F&& f) + { + return std::forward<F>(f)(unwrapper<T>::template apply<V>(v0), + unwrapper<T>::template apply<V>(v1)); // 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_; +}; + +// hashing visitor +struct hasher +{ + template <typename T> + std::size_t operator()(const T& hashable) const + { + return std::hash<T>{}(hashable); + } +}; + +} // 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?"); + static_assert(!detail::disjunction<std::is_array<Types>...>::value, "Variant can not hold array types."); + static_assert(sizeof...(Types) < std::numeric_limits<type_index_t>::max(), "Internal index type must be able to accommodate all alternatives."); +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; +public: + struct adapted_variant_tag; + using types = std::tuple<Types...>; +private: + using first_type = typename std::tuple_element<0, types>::type; + using unwrap_first_type = typename detail::unwrapper<first_type>::value_type; + using data_type = typename std::aligned_storage<data_size, data_align>::type; + using helper_type = detail::variant_helper<Types...>; + + template <typename V, typename T = unwrap_first_type> + using alternative_ref = typename detail::copy_cvref<V, T>::type; + + type_index_t type_index; +#ifdef __clang_analyzer__ + data_type data {}; +#else + data_type data; +#endif + +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 && !std::is_same<variant<Types...>, typename Traits::value_type>::value>::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(detail::conjunction<std::is_nothrow_move_constructible<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) + // note we check for nothrow-constructible, not nothrow-assignable, since + // move_assign uses move-construction via placement new. + noexcept(detail::conjunction<std::is_nothrow_move_constructible<Types>...>::value) + { + if (this == &other) { // playing safe in release mode, hit assertion in debug. + assert(false); + return *this; + } + move_assign(std::move(other)); + return *this; + } + + VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other) + { + if (this != &other) + copy_assign(other); + return *this; + } + + // conversions + // move-assign + template <typename T, typename Traits = detail::value_traits<T, Types...>, + typename Enable = typename std::enable_if<Traits::is_valid && !std::is_same<variant<Types...>, typename Traits::value_type>::value>::type > + VARIANT_INLINE variant<Types...>& operator=(T&& rhs) + // not that we check is_nothrow_constructible<T>, not is_nothrow_move_assignable<T>, + // since we construct a temporary + noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value + && std::is_nothrow_move_assignable<variant<Types...>>::value) + { + 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 type_index_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 T0 = alternative_ref<V>, + typename R = detail::result_of_unary_visit<F, T0>> + VARIANT_INLINE static R visit(V&& v, F&& f) + { + return detail::dispatcher<R, Types...>::apply(std::forward<V>(v), std::forward<F>(f)); + } + + // binary + template <typename F, typename V, typename T0 = alternative_ref<V>, + typename R = detail::result_of_binary_visit<F, T0>> + VARIANT_INLINE static R binary_visit(V&& v0, V&& v1, F&& f) + { + return detail::binary_dispatcher<R, Types...>::apply(std::forward<V>(v0), + std::forward<V>(v1), + std::forward<F>(f)); + } + + // match + // unary + template <typename... Fs> + auto VARIANT_INLINE match(Fs&&... fs) const& + -> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...))) + { + return variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)); + } + // non-const + template <typename... Fs> + auto VARIANT_INLINE match(Fs&&... fs) & + -> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...))) + { + return variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)); + } + template <typename... Fs> + auto VARIANT_INLINE match(Fs&&... fs) && + -> decltype(variant::visit(std::move(*this), ::mapbox::util::make_visitor(std::forward<Fs>(fs)...))) + { + return variant::visit(std::move(*this), ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)); + } + + ~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 +template <typename F, typename V> +auto VARIANT_INLINE apply_visitor(F&& f, V&& v) + -> decltype(v.visit(std::forward<V>(v), std::forward<F>(f))) +{ + return v.visit(std::forward<V>(v), std::forward<F>(f)); +} + +// binary visitor interface +template <typename F, typename V> +auto VARIANT_INLINE apply_visitor(F&& f, V&& v0, V&& v1) + -> decltype(v0.binary_visit(std::forward<V>(v0), std::forward<V>(v1), std::forward<F>(f))) +{ + return v0.binary_visit(std::forward<V>(v0), std::forward<V>(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>(); +} +// variant_size +template <typename T> +struct variant_size; + +//variable templates is c++14 +//template <typename T> +//constexpr std::size_t variant_size_v = variant_size<T>::value; + +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... Types> +struct variant_size<variant<Types...>> + : std::integral_constant<std::size_t, sizeof...(Types)> {}; + +// variant_alternative +template <std::size_t Index, typename T> +struct variant_alternative; + +#if defined(__clang__) +#if __has_builtin(__type_pack_element) +#define has_type_pack_element +#endif +#endif + +#if defined(has_type_pack_element) +template <std::size_t Index, typename ...Types> +struct variant_alternative<Index, variant<Types...>> +{ + static_assert(sizeof...(Types) > Index , "Index out of range"); + using type = __type_pack_element<Index, Types...>; +}; +#else +template <std::size_t Index, typename First, typename...Types> +struct variant_alternative<Index, variant<First, Types...>> + : variant_alternative<Index - 1, variant<Types...>> +{ + static_assert(sizeof...(Types) > Index -1 , "Index out of range"); +}; + +template <typename First, typename...Types> +struct variant_alternative<0, variant<First, Types...>> +{ + using type = First; +}; + +#endif + +template <size_t Index, typename T> +using variant_alternative_t = typename variant_alternative<Index, T>::type; + +template <size_t Index, typename T> +struct variant_alternative<Index, const T> + : std::add_const<variant_alternative<Index, T>> {}; + +template <size_t Index, typename T> +struct variant_alternative<Index, volatile T> + : std::add_volatile<variant_alternative<Index, T>> {}; + +template <size_t Index, typename T> +struct variant_alternative<Index, const volatile T> + : std::add_cv<variant_alternative<Index, T>> {}; + +} // namespace util +} // namespace mapbox + +// hashable iff underlying types are hashable +namespace std { +template <typename... Types> +struct hash< ::mapbox::util::variant<Types...>> { + std::size_t operator()(const ::mapbox::util::variant<Types...>& v) const noexcept + { + return ::mapbox::util::apply_visitor(::mapbox::util::detail::hasher{}, v); + } +}; + +} + +#endif // MAPBOX_UTIL_VARIANT_HPP diff --git a/src/mapbox/variant_cast.hpp b/src/mapbox/variant_cast.hpp new file mode 100644 index 0000000..fe1ab35 --- /dev/null +++ b/src/mapbox/variant_cast.hpp @@ -0,0 +1,85 @@ +#ifndef VARIANT_CAST_HPP +#define VARIANT_CAST_HPP + +#include <type_traits> + +namespace mapbox { +namespace util { + +namespace detail { + +template <class T> +class static_caster +{ +public: + template <class V> + T& operator()(V& v) const + { + return static_cast<T&>(v); + } +}; + +template <class T> +class dynamic_caster +{ +public: + using result_type = T&; + template <class V> + T& operator()(V& v, typename std::enable_if<!std::is_polymorphic<V>::value>::type* = nullptr) const + { + throw std::bad_cast(); + } + template <class V> + T& operator()(V& v, typename std::enable_if<std::is_polymorphic<V>::value>::type* = nullptr) const + { + return dynamic_cast<T&>(v); + } +}; + +template <class T> +class dynamic_caster<T*> +{ +public: + using result_type = T*; + template <class V> + T* operator()(V& v, typename std::enable_if<!std::is_polymorphic<V>::value>::type* = nullptr) const + { + return nullptr; + } + template <class V> + T* operator()(V& v, typename std::enable_if<std::is_polymorphic<V>::value>::type* = nullptr) const + { + return dynamic_cast<T*>(&v); + } +}; +} + +template <class T, class V> +typename detail::dynamic_caster<T>::result_type +dynamic_variant_cast(V& v) +{ + return mapbox::util::apply_visitor(detail::dynamic_caster<T>(), v); +} + +template <class T, class V> +typename detail::dynamic_caster<const T>::result_type +dynamic_variant_cast(const V& v) +{ + return mapbox::util::apply_visitor(detail::dynamic_caster<const T>(), v); +} + +template <class T, class V> +T& static_variant_cast(V& v) +{ + return mapbox::util::apply_visitor(detail::static_caster<T>(), v); +} + +template <class T, class V> +const T& static_variant_cast(const V& v) +{ + return mapbox::util::apply_visitor(detail::static_caster<const T>(), v); +} +} +} + +#endif // VARIANT_CAST_HPP diff --git a/src/mapbox/variant_io.hpp b/src/mapbox/variant_io.hpp new file mode 100644 index 0000000..1456cc5 --- /dev/null +++ b/src/mapbox/variant_io.hpp @@ -0,0 +1,45 @@ +#ifndef MAPBOX_UTIL_VARIANT_IO_HPP +#define MAPBOX_UTIL_VARIANT_IO_HPP + +#include <iosfwd> + +#include <mapbox/variant.hpp> + +namespace mapbox { +namespace util { + +namespace detail { +// operator<< helper +template <typename Out> +class printer +{ +public: + explicit printer(Out& out) + : out_(out) {} + printer& operator=(printer const&) = delete; + + // visitor + template <typename T> + void operator()(T const& operand) const + { + out_ << operand; + } + +private: + Out& out_; +}; +} + +// operator<< +template <typename CharT, typename Traits, typename... Types> +VARIANT_INLINE std::basic_ostream<CharT, Traits>& +operator<<(std::basic_ostream<CharT, Traits>& out, variant<Types...> const& rhs) +{ + detail::printer<std::basic_ostream<CharT, Traits>> visitor(out); + apply_visitor(visitor, rhs); + return out; +} +} // namespace util +} // namespace mapbox + +#endif // MAPBOX_UTIL_VARIANT_IO_HPP diff --git a/src/mapbox/variant_visitor.hpp b/src/mapbox/variant_visitor.hpp new file mode 100644 index 0000000..54ddba0 --- /dev/null +++ b/src/mapbox/variant_visitor.hpp @@ -0,0 +1,43 @@ +#ifndef MAPBOX_UTIL_VARIANT_VISITOR_HPP +#define MAPBOX_UTIL_VARIANT_VISITOR_HPP + +#include <utility> + +namespace mapbox { +namespace util { + +template <typename... Fns> +struct visitor; + +template <typename Fn> +struct visitor<Fn> : Fn +{ + using Fn::operator(); + + template<typename T> + visitor(T&& fn) : Fn(std::forward<T>(fn)) {} +}; + +template <typename Fn, typename... Fns> +struct visitor<Fn, Fns...> : Fn, visitor<Fns...> +{ + using Fn::operator(); + using visitor<Fns...>::operator(); + + template<typename T, typename... Ts> + visitor(T&& fn, Ts&&... fns) + : Fn(std::forward<T>(fn)) + , visitor<Fns...>(std::forward<Ts>(fns)...) {} +}; + +template <typename... Fns> +visitor<typename std::decay<Fns>::type...> make_visitor(Fns&&... fns) +{ + return visitor<typename std::decay<Fns>::type...> + (std::forward<Fns>(fns)...); +} + +} // namespace util +} // namespace mapbox + +#endif // MAPBOX_UTIL_VARIANT_VISITOR_HPP |