rm hard copy of variant.
This commit is contained in:
		
							parent
							
								
									f5caf96d2e
								
							
						
					
					
						commit
						201afbbeec
					
				| @ -1,69 +0,0 @@ | ||||
| #ifndef MAPBOX_UTIL_OPTIONAL_HPP | ||||
| #define MAPBOX_UTIL_OPTIONAL_HPP | ||||
| 
 | ||||
| #include <type_traits> | ||||
| 
 | ||||
| #include "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{}; } | ||||
| }; | ||||
| } | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| @ -1,127 +0,0 @@ | ||||
| #ifndef MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP | ||||
| #define MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP | ||||
| 
 | ||||
| #include <utility> | ||||
| 
 | ||||
| namespace mapbox { namespace util { | ||||
| 
 | ||||
| template <typename T> | ||||
| class recursive_wrapper | ||||
| { | ||||
| public: | ||||
|     using type = T; | ||||
| private: | ||||
| 
 | ||||
|     T* p_; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     ~recursive_wrapper(); | ||||
|     recursive_wrapper(); | ||||
| 
 | ||||
|     recursive_wrapper(recursive_wrapper const& operand); | ||||
|     recursive_wrapper(T const& operand); | ||||
|     recursive_wrapper(recursive_wrapper&& operand); | ||||
|     recursive_wrapper(T&& operand); | ||||
| 
 | ||||
| private: | ||||
| 
 | ||||
|     void assign(const T& rhs); | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     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; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     T& get() { return *get_pointer(); } | ||||
|     const T& get() const { 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(); } | ||||
| }; | ||||
| 
 | ||||
| template <typename T> | ||||
| recursive_wrapper<T>::~recursive_wrapper() | ||||
| { | ||||
|     delete p_; | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| recursive_wrapper<T>::recursive_wrapper() | ||||
|     : p_(new T) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| recursive_wrapper<T>::recursive_wrapper(recursive_wrapper const& operand) | ||||
|     : p_(new T( operand.get() )) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| recursive_wrapper<T>::recursive_wrapper(T const& operand) | ||||
|     : p_(new T(operand)) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| recursive_wrapper<T>::recursive_wrapper(recursive_wrapper&& operand) | ||||
|     : p_(operand.p_) | ||||
| { | ||||
|     operand.p_ = nullptr; | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| recursive_wrapper<T>::recursive_wrapper(T&& operand) | ||||
|     : p_(new T( std::move(operand) )) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| void recursive_wrapper<T>::assign(const T& rhs) | ||||
| { | ||||
|     this->get() = rhs; | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept | ||||
| { | ||||
|     lhs.swap(rhs); | ||||
| } | ||||
| 
 | ||||
| }} | ||||
| 
 | ||||
| #endif // MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
 | ||||
| @ -1,740 +0,0 @@ | ||||
| #ifndef MAPBOX_UTIL_VARIANT_HPP | ||||
| #define MAPBOX_UTIL_VARIANT_HPP | ||||
| 
 | ||||
| #include <utility> | ||||
| #include <typeinfo> | ||||
| #include <type_traits> | ||||
| #include <stdexcept> // runtime_error
 | ||||
| #include <new> // operator new
 | ||||
| #include <cstddef> // size_t
 | ||||
| #include <iosfwd> | ||||
| #include <string> | ||||
| 
 | ||||
| #include "recursive_wrapper.hpp" | ||||
| 
 | ||||
| #ifdef _MSC_VER | ||||
|  // http://msdn.microsoft.com/en-us/library/z8y1yy88.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 | ||||
| 
 | ||||
| #define VARIANT_MAJOR_VERSION 0 | ||||
| #define VARIANT_MINOR_VERSION 1 | ||||
| #define VARIANT_PATCH_VERSION 0 | ||||
| 
 | ||||
| // translates to 100
 | ||||
| #define VARIANT_VERSION (VARIANT_MAJOR_VERSION*100000) + (VARIANT_MINOR_VERSION*100) + (VARIANT_PATCH_VERSION) | ||||
| 
 | ||||
| namespace mapbox { namespace util { 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; | ||||
| }; | ||||
| 
 | ||||
| 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 | ||||
|         ? 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 | ||||
| { | ||||
|     static constexpr std::size_t direct_index = direct_type<T, Types...>::index; | ||||
|     static constexpr std::size_t index = | ||||
|         (direct_index == invalid_value) ? convertible_type<T, Types...>::index : direct_index; | ||||
| }; | ||||
| 
 | ||||
| template <typename T, typename...Types> | ||||
| struct is_valid_type; | ||||
| 
 | ||||
| template <typename T, typename First, typename... Types> | ||||
| struct is_valid_type<T, First, Types...> | ||||
| { | ||||
|     static constexpr bool value = std::is_convertible<T, First>::value | ||||
|         || is_valid_type<T, Types...>::value; | ||||
| }; | ||||
| 
 | ||||
| template <typename T> | ||||
| struct is_valid_type<T> : std::false_type {}; | ||||
| 
 | ||||
| template <std::size_t N, typename ... Types> | ||||
| struct select_type | ||||
| { | ||||
|     static_assert(N < sizeof...(Types), "index out of bounds"); | ||||
| }; | ||||
| 
 | ||||
| template <std::size_t N, typename T, typename ... Types> | ||||
| struct select_type<N, T, Types...> | ||||
| { | ||||
|     using type = typename select_type<N - 1, Types...>::type; | ||||
| }; | ||||
| 
 | ||||
| template <typename T, typename ... Types> | ||||
| struct select_type<0, T, Types...> | ||||
| { | ||||
|     using type = T; | ||||
| }; | ||||
| 
 | ||||
| } // namespace detail
 | ||||
| 
 | ||||
| // static visitor
 | ||||
| template <typename R = void> | ||||
| struct static_visitor | ||||
| { | ||||
|     using result_type = R; | ||||
| protected: | ||||
|     static_visitor() {} | ||||
|     ~static_visitor() {} | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 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 id, void * data) | ||||
|     { | ||||
|         if (id == sizeof...(Types)) | ||||
|         { | ||||
|             reinterpret_cast<T*>(data)->~T(); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             variant_helper<Types...>::destroy(id, data); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     VARIANT_INLINE static void move(const std::size_t old_id, void * old_value, void * new_value) | ||||
|     { | ||||
|         if (old_id == sizeof...(Types)) | ||||
|         { | ||||
|             new (new_value) T(std::move(*reinterpret_cast<T*>(old_value))); | ||||
|             //std::memcpy(new_value, old_value, sizeof(T));
 | ||||
|             // ^^  DANGER: this should only be considered for relocatable types e.g built-in types
 | ||||
|             // Also, I don't see any measurable performance benefit just yet
 | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             variant_helper<Types...>::move(old_id, old_value, new_value); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     VARIANT_INLINE static void copy(const std::size_t old_id, const void * old_value, void * new_value) | ||||
|     { | ||||
|         if (old_id == sizeof...(Types)) | ||||
|         { | ||||
|             new (new_value) T(*reinterpret_cast<const T*>(old_value)); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             variant_helper<Types...>::copy(old_id, 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 *) {} | ||||
| }; | ||||
| 
 | ||||
| namespace detail { | ||||
| 
 | ||||
| template <typename T> | ||||
| struct unwrapper | ||||
| { | ||||
|     T const& operator() (T const& obj) const | ||||
|     { | ||||
|         return obj; | ||||
|     } | ||||
| 
 | ||||
|     T& operator() (T & obj) const | ||||
|     { | ||||
|         return obj; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| template <typename T> | ||||
| struct unwrapper<recursive_wrapper<T>> | ||||
| { | ||||
|     auto operator() (recursive_wrapper<T> const& obj) const | ||||
|         -> typename recursive_wrapper<T>::type const& | ||||
|     { | ||||
|         return obj.get(); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| template <typename F, typename V, typename...Types> | ||||
| struct dispatcher; | ||||
| 
 | ||||
| template <typename F, typename V, typename T, typename...Types> | ||||
| struct dispatcher<F, V, T, Types...> | ||||
| { | ||||
|     using result_type = typename F::result_type; | ||||
|     VARIANT_INLINE static result_type apply_const(V const& v, F f) | ||||
|     { | ||||
|         if (v.get_type_index() == sizeof...(Types)) | ||||
|         { | ||||
|             return f(unwrapper<T>()(v. template get<T>())); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return dispatcher<F, V, Types...>::apply_const(v, f); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     VARIANT_INLINE static result_type apply(V & v, F f) | ||||
|     { | ||||
|         if (v.get_type_index() == sizeof...(Types)) | ||||
|         { | ||||
|             return f(unwrapper<T>()(v. template get<T>())); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return dispatcher<F, V, Types...>::apply(v, f); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| template<typename F, typename V> | ||||
| struct dispatcher<F, V> | ||||
| { | ||||
|     using result_type = typename F::result_type; | ||||
|     VARIANT_INLINE static result_type apply_const(V const&, F) | ||||
|     { | ||||
|         throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name()); | ||||
|     } | ||||
| 
 | ||||
|     VARIANT_INLINE static result_type apply(V &, F) | ||||
|     { | ||||
|         throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name()); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| template <typename F, typename V, typename T, typename...Types> | ||||
| struct binary_dispatcher_rhs; | ||||
| 
 | ||||
| template <typename F, typename V, typename T0, typename T1, typename...Types> | ||||
| struct binary_dispatcher_rhs<F, V, T0, T1, Types...> | ||||
| { | ||||
|     using result_type = typename F::result_type; | ||||
|     VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f) | ||||
|     { | ||||
|         if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
 | ||||
|         { | ||||
|             return f(unwrapper<T0>()(lhs. template get<T0>()), | ||||
|                      unwrapper<T1>()(rhs. template get<T1>())); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return binary_dispatcher_rhs<F, V, T0, Types...>::apply_const(lhs, rhs, f); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f) | ||||
|     { | ||||
|         if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
 | ||||
|         { | ||||
|             return f(unwrapper<T0>()(lhs. template get<T0>()), | ||||
|                      unwrapper<T1>()(rhs. template get<T1>())); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return binary_dispatcher_rhs<F, V, T0, Types...>::apply(lhs, rhs, f); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| template<typename F, typename V, typename T> | ||||
| struct binary_dispatcher_rhs<F, V, T> | ||||
| { | ||||
|     using result_type = typename F::result_type; | ||||
|     VARIANT_INLINE static result_type apply_const(V const&, V const&, F) | ||||
|     { | ||||
|         throw std::runtime_error("binary dispatch: FAIL"); | ||||
|     } | ||||
|     VARIANT_INLINE static result_type apply(V &, V &, F) | ||||
|     { | ||||
|         throw std::runtime_error("binary dispatch: FAIL"); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| template <typename F, typename V, typename T, typename...Types> | ||||
| struct binary_dispatcher_lhs; | ||||
| 
 | ||||
| template <typename F, typename V, typename T0, typename T1, typename...Types> | ||||
| struct binary_dispatcher_lhs<F, V, T0, T1, Types...> | ||||
| { | ||||
|     using result_type = typename F::result_type; | ||||
|     VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f) | ||||
|     { | ||||
|         if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
 | ||||
|         { | ||||
|             return f(lhs. template get<T1>(), rhs. template get<T0>()); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return binary_dispatcher_lhs<F, V, T0, Types...>::apply_const(lhs, rhs, f); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f) | ||||
|     { | ||||
|         if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
 | ||||
|         { | ||||
|             return f(lhs. template get<T1>(), rhs. template get<T0>()); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return binary_dispatcher_lhs<F, V, T0, Types...>::apply(lhs, rhs, f); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| template<typename F, typename V, typename T> | ||||
| struct binary_dispatcher_lhs<F, V, T> | ||||
| { | ||||
|     using result_type = typename F::result_type; | ||||
|     VARIANT_INLINE static result_type apply_const(V const&, V const&, F) | ||||
|     { | ||||
|         throw std::runtime_error("binary dispatch: FAIL"); | ||||
|     } | ||||
| 
 | ||||
|     VARIANT_INLINE static result_type apply(V &, V &, F) | ||||
|     { | ||||
|         throw std::runtime_error("binary dispatch: FAIL"); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| template <typename F, typename V, typename...Types> | ||||
| struct binary_dispatcher; | ||||
| 
 | ||||
| template <typename F, typename V, typename T, typename...Types> | ||||
| struct binary_dispatcher<F, V, T, Types...> | ||||
| { | ||||
|     using result_type = typename F::result_type; | ||||
|     VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f) | ||||
|     { | ||||
|         if (v0.get_type_index() == sizeof...(Types)) | ||||
|         { | ||||
|             if (v0.get_type_index() == v1.get_type_index()) | ||||
|             { | ||||
|                 return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
 | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return binary_dispatcher_rhs<F, V, T, Types...>::apply_const(v0, v1, f); | ||||
|             } | ||||
|         } | ||||
|         else if (v1.get_type_index() == sizeof...(Types)) | ||||
|         { | ||||
|             return binary_dispatcher_lhs<F, V, T, Types...>::apply_const(v0, v1, f); | ||||
|         } | ||||
|         return binary_dispatcher<F, V, Types...>::apply_const(v0, v1, f); | ||||
|     } | ||||
| 
 | ||||
|     VARIANT_INLINE static result_type apply(V & v0, V & v1, F f) | ||||
|     { | ||||
|         if (v0.get_type_index() == sizeof...(Types)) | ||||
|         { | ||||
|             if (v0.get_type_index() == v1.get_type_index()) | ||||
|             { | ||||
|                 return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
 | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return binary_dispatcher_rhs<F, V, T, Types...>::apply(v0, v1, f); | ||||
|             } | ||||
|         } | ||||
|         else if (v1.get_type_index() == sizeof...(Types)) | ||||
|         { | ||||
|             return binary_dispatcher_lhs<F, V, T, Types...>::apply(v0, v1, f); | ||||
|         } | ||||
|         return binary_dispatcher<F, V, Types...>::apply(v0, v1, f); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| template<typename F, typename V> | ||||
| struct binary_dispatcher<F, V> | ||||
| { | ||||
|     using result_type = typename F::result_type; | ||||
|     VARIANT_INLINE static result_type apply_const(V const&, V const&, F) | ||||
|     { | ||||
|         throw std::runtime_error("binary dispatch: FAIL"); | ||||
|     } | ||||
| 
 | ||||
|     VARIANT_INLINE static result_type apply(V &, V &, F) | ||||
|     { | ||||
|         throw std::runtime_error("binary dispatch: FAIL"); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| // 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 static_visitor<bool> | ||||
| { | ||||
| 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<T>(); | ||||
|         return Comp()(lhs_content, rhs_content); | ||||
|     } | ||||
| private: | ||||
|     Variant const& lhs_; | ||||
| }; | ||||
| 
 | ||||
| // operator<< helper
 | ||||
| template <typename Out> | ||||
| class printer : public static_visitor<> | ||||
| { | ||||
| 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_; | ||||
| }; | ||||
| 
 | ||||
| } // namespace detail
 | ||||
| 
 | ||||
| struct no_init {}; | ||||
| 
 | ||||
| template<typename... Types> | ||||
| class variant | ||||
| { | ||||
| private: | ||||
| 
 | ||||
|     static const std::size_t data_size = static_max<sizeof(Types)...>::value; | ||||
|     static const std::size_t data_align = static_max<alignof(Types)...>::value; | ||||
| 
 | ||||
|     using data_type = typename std::aligned_storage<data_size, data_align>::type; | ||||
|     using helper_type = variant_helper<Types...>; | ||||
| 
 | ||||
|     std::size_t type_index; | ||||
|     data_type data; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
| 
 | ||||
|     VARIANT_INLINE variant() | ||||
|         : type_index(sizeof...(Types) - 1) | ||||
|     { | ||||
|         new (&data) typename detail::select_type<0, Types...>::type(); | ||||
|     } | ||||
| 
 | ||||
|     VARIANT_INLINE variant(no_init) | ||||
|         : type_index(detail::invalid_value) {} | ||||
| 
 | ||||
|     // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
 | ||||
|     template <typename T, class = typename std::enable_if< | ||||
|                           detail::is_valid_type<typename std::remove_reference<T>::type, Types...>::value>::type> | ||||
|     VARIANT_INLINE variant(T && val) noexcept | ||||
|         : type_index(detail::value_traits<typename std::remove_reference<T>::type, Types...>::index) | ||||
|     { | ||||
|         constexpr std::size_t index = sizeof...(Types) - detail::value_traits<typename std::remove_reference<T>::type, Types...>::index - 1; | ||||
|         using target_type = typename detail::select_type<index, Types...>::type; | ||||
|         new (&data) target_type(std::forward<T>(val)); // nothrow
 | ||||
|     } | ||||
| 
 | ||||
|     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 | ||||
|         : type_index(old.type_index) | ||||
|     { | ||||
|         helper_type::move(old.type_index, &old.data, &data); | ||||
|     } | ||||
| 
 | ||||
|     friend void swap(variant<Types...> & first, variant<Types...> & second) | ||||
|     { | ||||
|         using std::swap; //enable ADL
 | ||||
|         swap(first.type_index, second.type_index); | ||||
|         swap(first.data, second.data); | ||||
|     } | ||||
| 
 | ||||
|     VARIANT_INLINE variant<Types...>& operator=(variant<Types...> other) | ||||
|     { | ||||
|         swap(*this, other); | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     // conversions
 | ||||
|     // move-assign
 | ||||
|     template <typename T> | ||||
|     VARIANT_INLINE variant<Types...>& operator=(T && rhs) noexcept | ||||
|     { | ||||
|         variant<Types...> temp(std::forward<T>(rhs)); | ||||
|         swap(*this, temp); | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     // copy-assign
 | ||||
|     template <typename T> | ||||
|     VARIANT_INLINE variant<Types...>& operator=(T const& rhs) | ||||
|     { | ||||
|         variant<Types...> temp(rhs); | ||||
|         swap(*this, temp); | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     template<typename T> | ||||
|     VARIANT_INLINE bool is() const | ||||
|     { | ||||
|         return (type_index == detail::direct_type<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); | ||||
|         new (&data) T(std::forward<Args>(args)...); | ||||
|         type_index = detail::direct_type<T, Types...>::index; | ||||
|     } | ||||
| 
 | ||||
|     template<typename T> | ||||
|     VARIANT_INLINE T& get() | ||||
|     { | ||||
|         if (type_index == detail::direct_type<T, Types...>::index) | ||||
|         { | ||||
|             return *reinterpret_cast<T*>(&data); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             throw std::runtime_error("in get()"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     template<typename T> | ||||
|     VARIANT_INLINE T const& get() const | ||||
|     { | ||||
|         if (type_index == detail::direct_type<T, Types...>::index) | ||||
|         { | ||||
|             return *reinterpret_cast<T const*>(&data); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             throw std::runtime_error("in get()"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     VARIANT_INLINE std::size_t get_type_index() const | ||||
|     { | ||||
|         return type_index; | ||||
|     } | ||||
| 
 | ||||
|     // visitor
 | ||||
|     // unary
 | ||||
|     template <typename F, typename V> | ||||
|     auto VARIANT_INLINE | ||||
|     static visit(V const& v, F f) | ||||
|         -> decltype(detail::dispatcher<F, V, Types...>::apply_const(v, f)) | ||||
|     { | ||||
|         return detail::dispatcher<F, V, Types...>::apply_const(v, f); | ||||
|     } | ||||
|     // non-const
 | ||||
|     template <typename F, typename V> | ||||
|     auto VARIANT_INLINE | ||||
|     static visit(V & v, F f) | ||||
|         -> decltype(detail::dispatcher<F, V, Types...>::apply(v, f)) | ||||
|     { | ||||
|         return detail::dispatcher<F, V, Types...>::apply(v, f); | ||||
|     } | ||||
| 
 | ||||
|     // binary
 | ||||
|     // const
 | ||||
|     template <typename F, typename V> | ||||
|     auto VARIANT_INLINE | ||||
|     static binary_visit(V const& v0, V const& v1, F f) | ||||
|         -> decltype(detail::binary_dispatcher<F, V, Types...>::apply_const(v0, v1, f)) | ||||
|     { | ||||
|         return detail::binary_dispatcher<F, V, Types...>::apply_const(v0, v1, f); | ||||
|     } | ||||
|     // non-const
 | ||||
|     template <typename F, typename V> | ||||
|     auto VARIANT_INLINE | ||||
|     static binary_visit(V& v0, V& v1, F f) | ||||
|         -> decltype(detail::binary_dispatcher<F, V, Types...>::apply(v0, v1, f)) | ||||
|     { | ||||
|         return detail::binary_dispatcher<F, V, Types...>::apply(v0, v1, f); | ||||
|     } | ||||
| 
 | ||||
|     ~variant() noexcept | ||||
|     { | ||||
|         helper_type::destroy(type_index, &data); | ||||
|     } | ||||
| 
 | ||||
|     // comparison operators
 | ||||
|     // equality
 | ||||
|     VARIANT_INLINE bool operator==(variant const& rhs) const | ||||
|     { | ||||
|         if (this->get_type_index() != rhs.get_type_index()) | ||||
|             return false; | ||||
|         detail::comparer<variant, detail::equal_comp> visitor(*this); | ||||
|         return visit(rhs, visitor); | ||||
|     } | ||||
|     // less than
 | ||||
|     VARIANT_INLINE bool operator<(variant const& rhs) const | ||||
|     { | ||||
|         if (this->get_type_index() != rhs.get_type_index()) | ||||
|         { | ||||
|             return this->get_type_index() < rhs.get_type_index(); | ||||
|             // ^^ borrowed from boost::variant
 | ||||
|         } | ||||
|         detail::comparer<variant, detail::less_comp> visitor(*this); | ||||
|         return visit(rhs, visitor); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| // unary visitor interface
 | ||||
| 
 | ||||
| // const
 | ||||
| template <typename V, typename F> | ||||
| auto VARIANT_INLINE static apply_visitor(F f, V const& v) -> decltype(V::visit(v, f)) | ||||
| { | ||||
|     return V::visit(v, f); | ||||
| } | ||||
| // non-const
 | ||||
| template <typename V, typename F> | ||||
| auto VARIANT_INLINE static apply_visitor(F f, V & v) -> decltype(V::visit(v, f)) | ||||
| { | ||||
|     return V::visit(v, f); | ||||
| } | ||||
| 
 | ||||
| // binary visitor interface
 | ||||
| // const
 | ||||
| template <typename V, typename F> | ||||
| auto VARIANT_INLINE static apply_visitor(F f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, f)) | ||||
| { | ||||
|     return V::binary_visit(v0, v1, f); | ||||
| } | ||||
| // non-const
 | ||||
| template <typename V, typename F> | ||||
| auto VARIANT_INLINE static apply_visitor(F f, V & v0, V & v1) -> decltype(V::binary_visit(v0, v1, f)) | ||||
| { | ||||
|     return V::binary_visit(v0, v1, f); | ||||
| } | ||||
| 
 | ||||
| // getter interface
 | ||||
| template<typename ResultType, typename T> | ||||
| ResultType &  get(T & var) | ||||
| { | ||||
|     return var.template get<ResultType>(); | ||||
| } | ||||
| 
 | ||||
| template<typename ResultType, typename T> | ||||
| ResultType const&  get(T const& var) | ||||
| { | ||||
|     return var.template get<ResultType>(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // 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; | ||||
| } | ||||
| 
 | ||||
| }} | ||||
| 
 | ||||
| #endif  // MAPBOX_UTIL_VARIANT_HPP
 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user