From 214765454130024a7dabfc08df1bcfd0287c61fa Mon Sep 17 00:00:00 2001 From: Johannes Schanda Date: Mon, 14 Jan 2013 12:13:02 +0100 Subject: [PATCH] Variant class --- src/CommonAPI/SerializableVariant.h | 424 ++++++++++++++++++++++++++++++++++++ 1 file changed, 424 insertions(+) diff --git a/src/CommonAPI/SerializableVariant.h b/src/CommonAPI/SerializableVariant.h index f850280..ccab034 100644 --- a/src/CommonAPI/SerializableVariant.h +++ b/src/CommonAPI/SerializableVariant.h @@ -11,6 +11,11 @@ #include #include +#include +#include +#include +#include +#include #ifndef __COMMON_API_EXPERIMENTAL #error "Use -D__COMMON_API_EXPERIMENTAL to include experimental variant support" @@ -36,6 +41,425 @@ uint32_t SerializableVariant::getType() const { return type_; } +template +struct assign_visitor; + +template +struct complete_equals_visitor; + +template +struct partial_equals_visitor; + +template +struct apply_void_visitor; + +template +struct apply_void_visitor { + static const unsigned int index = 0; + + static + void visit(Visitor&, Variant&) { + //won't be called + assert(false); + throw ""; + } +}; + +template +struct apply_void_visitor { + static const unsigned int index = apply_void_visitor::index + 1; + + static + void visit(Visitor& visitor, Variant& var) { + if (var.getValueType() == index) { + bool b; + visitor(var.template get(b)); + } else { + apply_void_visitor::visit(visitor, var); + } + } +}; + +template +struct apply_return_visitor +; + +template +struct apply_return_visitor { + static const unsigned int index = 0; + + static bool visit(Visitor&, Variant&) { + //won't be called + assert(false); + } +}; + +template +struct apply_return_visitor { + static const unsigned int index = apply_return_visitor::index + 1; + + static bool visit(Visitor& visitor, Variant& var) { + if (var.getValueType() == index) { + bool b; + return visitor(var.template get(b)); + } else { + return apply_return_visitor::visit(visitor, + var); + } + } +}; + +template +struct clear_visitor { +public: + clear_visitor(typename std::aligned_storage::type& storage) : + storage_(storage) { + } + + template + void operator()(const _Type&) const { + (reinterpret_cast(&storage_))->~_Type(); + } + + private: + typename std::aligned_storage::type& storage_; +}; + +template +struct select_type; + +template +struct select_type { +}; + +//U == T +template +struct select_type { + typedef T type; +}; + +//U& == T +template +struct select_type { + typedef T& type; +}; + +//U == T& +template +struct select_type { + typedef T type; +}; + +//const U& == T +template +struct select_type { + typedef const T& type; +}; + +//U == const T& +template +struct select_type { + typedef T type; +}; + +//U == X* +//T == const X* +template +struct select_type { + typedef const T* type; +}; + +//U == X& +//T == const X& +template +struct select_type { + typedef const T& type; +}; + +//U != T, let's try to find U among Ts +template +struct select_type { + typedef typename select_type::type type; +}; + +template +struct type_index_getter; + +template<> +struct type_index_getter<> { + static const unsigned int index = 0; + + template + static + unsigned int get() { + return 0; + } +}; + +template +struct type_index_getter { + static const unsigned int index = type_index_getter::index + 1; + + template + static + unsigned int get( + typename std::enable_if::value >::type* = 0) { + return index; + } + + template + static + unsigned int get(typename std::enable_if::value >::type* = 0) { + return type_index_getter::template get(); + } +}; + +template +struct max_size; + +template<> +struct max_size<> { + static const unsigned int value = 0; +}; + +template +struct max_size { + static const unsigned int current_type_size = sizeof(T); + static const unsigned int next_type_size = max_size::value; + static const unsigned int value = + current_type_size > next_type_size ? + current_type_size : next_type_size; +}; + +template +struct VariantTypeSelector: VariantTypeSelector<_SearchType, _RestTypes...> { +}; + +template +struct VariantTypeSelector<_SearchType, _SearchType, _RestTypes...> { + typedef _SearchType type; +}; + +template +class Variant { + private: + typedef std::tuple_size> TypesTupleSize; + + public: + + static const unsigned int maxSize = max_size<_Types...>::value; + + + Variant(): valueType_(TypesTupleSize::value) { + } + + Variant(const Variant& fromVariant): + valueType_(fromVariant.valueType_), + valueStorage_(fromVariant.valueStorage_) { + } + + Variant(Variant&& fromVariant): + valueType_(std::move(fromVariant.valueType_)), + valueStorage_(std::move(fromVariant.valueStorage_)) { + fromVariant.valueType_ = TypesTupleSize::value; + } + + ~Variant() { + if (hasValue()) { + clear_visitor visitor(valueStorage_); + apply_void_visitor, Variant<_Types...>, _Types...>::visit(visitor, *this); + } + } + + Variant& operator=(const Variant& rhs) + { + assign_visitor<_Types...> visitor(*this); + apply_void_visitor, Variant<_Types...>, _Types...>::visit(visitor, rhs); + return *this; + } + + Variant& operator=(Variant&& rhs) { + assign_visitor<_Types...> visitor(*this); + apply_void_visitor, Variant<_Types...>, _Types...>::visit(visitor, rhs); + return *this; + } + + template + typename std::enable_if>::value, Variant<_Types...>&>::type + operator=(const _Type& value) + { + set::type>(value); + return *this; + } + + template + const bool isType() const { + typedef typename select_type<_Type, _Types...>::type selected_type_t; + unsigned int cType = type_index_getter<_Types...>::template get(); + if(cType == valueType_) { + return true; + } else { + return false; + } + } + + template + Variant(const _Type& value, + typename std::enable_if::value>::type* = 0, + typename std::enable_if::value>::type* = 0, + typename std::enable_if::value>::type* = 0) { + set::type>(value, false); + } + + template + Variant(_Type && value, + typename std::enable_if::value>::type* = 0, + typename std::enable_if::value>::type* = 0, + typename std::enable_if::value>::type* = 0) { + set2::type>(std::move(value), false); + } + + //TODO: Return type??? + template + const typename VariantTypeSelector<_Type, _Types...>::type & get(bool& success) const { + typedef typename select_type<_Type, _Types...>::type selected_type_t; + unsigned int cType = type_index_getter<_Types...>::template get(); + if(cType == valueType_) { + success = true; + return *(reinterpret_cast(&valueStorage_)); + } else { + success = false; + return *(reinterpret_cast(&valueStorage_)); + } + } + + inline size_t getValueType() const { + return valueType_; + } + + template + void set( const U& value, const bool clear) { + typedef typename select_type::type selected_type_t; + + const selected_type_t& type_value = value; + if(clear) { + clear_visitor visitor(valueStorage_); + apply_void_visitor, Variant<_Types...>, _Types...>::visit(visitor, *this); + } + new (&valueStorage_) selected_type_t(std::move(value)); + valueType_ = type_index_getter<_Types...>::template get(); + } + + template + void set2( U&& value, const bool clear) { + typedef typename select_type::type selected_type_t; + + selected_type_t&& any_container_value = std::move(value); + if(clear) + { + clear_visitor visitor(valueStorage_); + apply_void_visitor, Variant<_Types...>, _Types...>::visit(visitor, *this); + } else { + new (&valueStorage_) selected_type_t(std::move(any_container_value)); + } + + valueType_ = type_index_getter<_Types...>::template get(); + } + + private: + inline bool hasValue() const { + return valueType_ < TypesTupleSize::value; + } + + size_t valueType_; + typename std::aligned_storage::type valueStorage_; + +}; + +template +bool operator==(const Variant<_Types...>& lhs, const Variant<_Types...>& rhs) +{ + partial_equals_visitor<_Types...> visitor(lhs); + return apply_return_visitor, const Variant<_Types...>, _Types...>::visit(visitor, rhs); +} + +template +bool operator!=(const Variant<_Types...>& lhs, const Variant<_Types...>& rhs) +{ + return !(lhs == rhs); +} + +template +struct complete_equals_visitor +{ + public: + complete_equals_visitor(const T& rhs): + rhs_(rhs) + { + } + + bool + operator()(const T& lhs) const + { + return lhs == rhs_; + } + + template + bool + operator()(const U&) const + { + return false; + } + + private: + const T& rhs_; +}; + +template +struct partial_equals_visitor +{ + public: + partial_equals_visitor(const Variant& lhs): + lhs_(lhs) + { + } + + template + bool + operator()(const T& rhs) const + { + complete_equals_visitor visitor(rhs); + return apply_return_visitor, const Variant, Ts...>::visit(visitor, lhs_); + } + + private: + const Variant& lhs_; +}; + +template +struct assign_visitor { +public: + assign_visitor(Variant& lhs, const bool clear = true) : + lhs_(lhs), clear_(clear) { + } + + template + void operator()(const T& value) const { + lhs_.template set(value, clear_); + } + + template + void operator()(T& value) const { + lhs_.template set(value, clear_); + } + +private: + Variant& lhs_; + const bool clear_; +}; + } // namespace CommonAPI #endif // COMMONAPI_SERIALIZABLE_VARIANT_H_ -- 2.7.4