/* Copyright (C) 2013 BMW Group * Author: Manfred Bathelt (manfred.bathelt@bmw.de) * Author: Juergen Gehring (juergen.gehring@bmw.de) * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef COMMONAPI_SERIALIZABLE_VARIANT_IMPL_ #define COMMONAPI_SERIALIZABLE_VARIANT_IMPL_ #include "OutputStream.h" #include "InputStream.h" #include namespace CommonAPI { template struct ApplyVoidIndexVisitor; template struct ApplyVoidIndexVisitor { static const uint8_t index = 0; static void visit(Variant&, uint8_t&) { //won't be called assert(false); } }; template struct ApplyVoidIndexVisitor { static const uint8_t index = ApplyVoidIndexVisitor::index + 1; static void visit(Variant& var, uint8_t& ind) { if (ind == index) { new (&var.valueStorage_) _Type(); var.valueType_ = index; } else { ApplyVoidIndexVisitor::visit(var, ind); } } }; template struct ApplyVoidVisitor; template struct ApplyVoidVisitor { static const uint8_t index = 0; static void visit(Visitor&, Variant&) { //won't be called assert(false); } static void visit(Visitor&, const Variant&) { //won't be called assert(false); } }; template struct ApplyVoidVisitor { static const uint8_t index = ApplyVoidVisitor::index + 1; static void visit(Visitor& visitor, Variant& var) { if (var.getValueType() == index) { visitor(var.template get<_Type>()); } else { ApplyVoidVisitor::visit(visitor, var); } } static void visit(Visitor& visitor, const Variant& var) { if (var.getValueType() == index) { visitor(var.template get<_Type>()); } else { ApplyVoidVisitor::visit(visitor, var); } } }; template struct ApplyBoolVisitor ; template struct ApplyBoolVisitor { static const uint8_t index = 0; static bool visit(Visitor&, Variant&) { //won't be called assert(false); return false; } }; template struct ApplyBoolVisitor { static const uint8_t index = ApplyBoolVisitor::index + 1; static bool visit(Visitor& visitor, Variant& var) { if (var.getValueType() == index) { return visitor(var.template get<_Type>()); } else { return ApplyBoolVisitor::visit(visitor, var); } } }; template struct DeleteVisitor { public: DeleteVisitor(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_; }; struct TypeOutputStreamWriteVisitor { public: TypeOutputStreamWriteVisitor(TypeOutputStream& typeStream) : typeStream_(typeStream) { } template void operator()(const _Type&) const { TypeWriter<_Type>::writeType(typeStream_); } private: TypeOutputStream& typeStream_; }; struct OutputStreamWriteVisitor { public: OutputStreamWriteVisitor(OutputStream& outputStream) : outputStream_(outputStream) { } template void operator()(const _Type& value) const { outputStream_ << value; } private: OutputStream& outputStream_; }; template struct InputStreamReadVisitor { public: InputStreamReadVisitor(Variant<_Types...>& lhs, InputStream& inputStream) : lhs_(lhs), inputStream_(inputStream) { } template void operator()(const _Type&) { _Type value; inputStream_ >> value; lhs_.Variant<_Types...>::template set<_Type>(std::move(value), false); } private: Variant<_Types...>& lhs_; InputStream& inputStream_; }; template struct TypeEqualsVisitor { public: TypeEqualsVisitor(const _Type& rhs): rhs_(rhs) { } bool operator()(const _Type& lhs) const { return lhs == rhs_; } template bool operator()(const _U&) const { return false; } private: const _Type& rhs_; }; template struct PartialEqualsVisitor { public: PartialEqualsVisitor(const Variant<_Types...>& lhs) : lhs_(lhs) { } template bool operator()(const _Type& rhs) const { TypeEqualsVisitor<_Type> visitor(rhs); return ApplyBoolVisitor, const Variant<_Types...>, _Types...>::visit(visitor, lhs_); } private: const Variant<_Types...>& lhs_; }; template struct AssignmentVisitor { public: AssignmentVisitor(Variant<_Types...>& lhs, const bool clear = true) : lhs_(lhs), clear_(clear) { } template void operator()(const _Type& value) const { lhs_.Variant<_Types...>::template set<_Type>(value, clear_); } template void operator()(_Type& value) const { lhs_.Variant<_Types...>::template set<_Type>(value, clear_); } private: Variant<_Types...>& lhs_; const bool clear_; }; template struct TypeSelector; template struct TypeSelector<_U> { }; //_U == _Type template struct TypeSelector<_Type, _Type, _Types...> { typedef _Type type; }; //_U& == _Type template struct TypeSelector<_Type, _Type&, _Types...> { typedef _Type& type; }; //_U == _Type& template struct TypeSelector<_Type&, _Type, _Types...> { typedef _Type type; }; //const _U& == _Type template struct TypeSelector<_Type, const _Type&, _Types...> { typedef const _Type& type; }; //_U == const _Type& template struct TypeSelector { typedef _Type type; }; //_U == X* //_Type == const X* template struct TypeSelector<_Type*, const _Type*, _Types...> { typedef const _Type* type; }; //_U == X& //_Type == const X& template struct TypeSelector<_Type&, const _Type&, _Types...> { typedef const _Type& type; }; //_U != _Type, let's try to find _U among _Types template struct TypeSelector<_U, _Type, _Types...> { typedef typename TypeSelector<_U, _Types...>::type type; }; template struct TypeIndex; template<> struct TypeIndex<> { static const uint8_t index = 0; template static uint8_t get() { return 0; } }; template struct TypeIndex<_Type, _Types...> { static const uint8_t index = TypeIndex<_Types...>::index + 1; template static uint8_t get( typename std::enable_if::value>::type* = 0) { return index; } template static uint8_t get(typename std::enable_if::value>::type* = 0) { return TypeIndex<_Types...>::template get<_U>(); } }; template Variant<_Types...>::Variant() : valueType_(TypesTupleSize::value) { ApplyVoidIndexVisitor, _Types...>::visit(*this, valueType_); } template Variant<_Types...>::Variant(const Variant& fromVariant) { AssignmentVisitor<_Types...> visitor(*this, false); ApplyVoidVisitor , Variant<_Types...>, _Types...>::visit(visitor, fromVariant); } template Variant<_Types...>::Variant(Variant&& fromVariant) { AssignmentVisitor<_Types...> visitor(*this, false); ApplyVoidVisitor , Variant<_Types...>, _Types...>::visit(visitor, fromVariant); } /*template Variant<_Types...>::Variant(Variant&& fromVariant) : valueType_(std::move(fromVariant.valueType_)), valueStorage_(std::move(fromVariant.valueStorage_)) { }*/ template Variant<_Types...>::~Variant() { if (hasValue()) { DeleteVisitor visitor(valueStorage_); ApplyVoidVisitor, Variant<_Types...>, _Types...>::visit(visitor, *this); } } template void Variant<_Types...>::readFromInputStream(const uint8_t typeIndex, InputStream& inputStream) { if(hasValue()) { DeleteVisitor visitor(valueStorage_); ApplyVoidVisitor, Variant<_Types...>, _Types...>::visit(visitor, *this); } valueType_ = typeIndex; InputStreamReadVisitor<_Types...> visitor(*this, inputStream); ApplyVoidVisitor, Variant<_Types...>, _Types...>::visit(visitor, *this); } template void Variant<_Types...>::writeToOutputStream(OutputStream& outputStream) const { OutputStreamWriteVisitor visitor(outputStream); ApplyVoidVisitor, _Types...>::visit( visitor, *this); } template void Variant<_Types...>::writeToTypeOutputStream(TypeOutputStream& typeOutputStream) const { TypeOutputStreamWriteVisitor visitor(typeOutputStream); ApplyVoidVisitor, _Types...>::visit( visitor, *this); } template Variant<_Types...>& Variant<_Types...>::operator=(const Variant<_Types...>& rhs) { AssignmentVisitor<_Types...> visitor(*this, hasValue()); ApplyVoidVisitor, Variant<_Types...>, _Types...>::visit( visitor, rhs); return *this; } template Variant<_Types...>& Variant<_Types...>::operator=(Variant<_Types...>&& rhs) { AssignmentVisitor<_Types...> visitor(*this, hasValue()); ApplyVoidVisitor, Variant<_Types...>, _Types...>::visit(visitor, rhs); return *this; } template template typename std::enable_if>::value, Variant<_Types...>&>::type Variant<_Types...>::operator=(const _Type& value) { set::type>(value, hasValue()); return *this; } template template const bool Variant<_Types...>::isType() const { typedef typename TypeSelector<_Type, _Types...>::type selected_type_t; uint8_t cType = TypeIndex<_Types...>::template get(); if (cType == valueType_) { return true; } else { return false; } } template template Variant<_Types...>::Variant(const _Type& value, typename std::enable_if::value>::type*, typename std::enable_if::value>::type*, typename std::enable_if>::value>::type*) { set::type>(value, false); } template template Variant<_Types...>::Variant(_Type && value, typename std::enable_if::value>::type*, typename std::enable_if::value>::type*, typename std::enable_if>::value>::type*) { set::type>(std::move(value), false); } template template const _Type & Variant<_Types...>::get() const { typedef typename TypeSelector<_Type, _Types...>::type selected_type_t; uint8_t cType = TypeIndex<_Types...>::template get(); if (cType == valueType_) { return *(reinterpret_cast(&valueStorage_)); } else { #ifdef __EXCEPTIONS std::bad_cast toThrow; throw toThrow; #else printf("SerializableVariant.hpp:%i %s: Incorrect access to variant; attempting to get type not currently contained", __LINE__, __FUNCTION__); abort(); #endif } } template template void Variant<_Types...>::set(const _U& value, const bool clear) { typedef typename TypeSelector<_U, _Types...>::type selected_type_t; if (clear) { DeleteVisitor visitor(valueStorage_); ApplyVoidVisitor, Variant<_Types...>, _Types...>::visit(visitor, *this); } new (&valueStorage_) selected_type_t(std::move(value)); valueType_ = TypeIndex<_Types...>::template get(); } template template void Variant<_Types...>::set(_U&& value, const bool clear) { typedef typename TypeSelector<_U, _Types...>::type selected_type_t; selected_type_t&& any_container_value = std::move(value); if(clear) { DeleteVisitor visitor(valueStorage_); ApplyVoidVisitor, Variant<_Types...>, _Types...>::visit(visitor, *this); } else { new (&valueStorage_) selected_type_t(std::move(any_container_value)); } valueType_ = TypeIndex<_Types...>::template get(); } template bool Variant<_Types...>::operator==(const Variant<_Types...>& rhs) const { PartialEqualsVisitor<_Types...> visitor(*this); return ApplyBoolVisitor, const Variant<_Types...>, _Types...>::visit( visitor, rhs); } template bool Variant<_Types...>::operator!=(const Variant<_Types...>& rhs) const { return !(*this == rhs); } } #endif //COMMONAPI_SERIALIZABLE_VARIANT_IMPL_