Corrected move constructor / initialisation of empty variant
authorJohannes Schanda <schanda@itestra.de>
Wed, 29 May 2013 21:13:34 +0000 (23:13 +0200)
committerJohannes Schanda <schanda@itestra.de>
Wed, 29 May 2013 21:13:34 +0000 (23:13 +0200)
src/CommonAPI/SerializableVariant.h
src/CommonAPI/SerializableVariant.hpp
src/test/VariantTest.cpp

index 51f8224..37f7320 100644 (file)
@@ -198,13 +198,18 @@ public:
                     typename std::enable_if<!std::is_reference<_Type>::value>::type* = 0,
                     typename std::enable_if<!std::is_same<_Type, Variant>::value>::type* = 0);
 
+    /**
+     * \brief Get value of variant, template to content type. Throws exception if type is not contained.
+     *
+     * Get value of variant, template to content type. Throws exception if type is not contained.
+     */
     template <typename _Type>
     const _Type& get() const;
 
     /**
-     * \brief Get index in template list of type actually contained
+     * \brief Get index in template list of type actually contained, starting at 1 at the end of the template list
      *
-     * Get index in template list of type actually contained
+     * Get index in template list of type actually contained, starting at 1 at the end of the template list
      *
      * @return Index of contained type
      */
@@ -214,7 +219,7 @@ public:
 
 private:
     inline bool hasValue() const {
-        return valueType_ < TypesTupleSize::value;
+        return valueType_ <= TypesTupleSize::value;
     }
 
     template<typename _U>
@@ -223,7 +228,7 @@ private:
     template<typename _U>
     void set( _U&& value, const bool clear);
 
-    template<typename _FriendType>
+    template<typename >
     friend struct TypeWriter;
     template<typename ... _FriendTypes>
     friend struct AssignmentVisitor;
@@ -233,6 +238,8 @@ private:
     friend struct PartialEqualsVisitor;
     template<typename ... _FriendTypes>
     friend struct InputStreamReadVisitor;
+    template<class Variant, typename ... _FTypes>
+    friend struct ApplyVoidIndexVisitor;
 
     uint8_t valueType_;
     typename std::aligned_storage<maxSize>::type valueStorage_;
index 3760118..2919638 100644 (file)
 
 namespace CommonAPI {
 
+template<class Variant, typename ... _Types>
+struct ApplyVoidIndexVisitor;
+
+template<class Variant>
+struct ApplyVoidIndexVisitor<Variant> {
+    static const uint8_t index = 0;
+
+    static
+    void visit(Variant&, uint8_t&) {
+        //won't be called
+        assert(false);
+    }
+};
+
+template<class Variant, typename _Type, typename ... _Types>
+struct ApplyVoidIndexVisitor<Variant, _Type, _Types...> {
+    static const uint8_t index = ApplyVoidIndexVisitor<Variant,
+                    _Types...>::index + 1;
+
+    static void visit(Variant& var, uint8_t& ind) {
+        if (ind == index) {
+            new (&var.valueStorage_) _Type();
+            var.valueType_ = index;
+        } else {
+            ApplyVoidIndexVisitor<Variant, _Types...>::visit(var, ind);
+        }
+    }
+};
+
 template<class Visitor, class Variant, typename ... _Types>
 struct ApplyVoidVisitor;
 
@@ -87,7 +116,7 @@ struct ApplyBoolVisitor<Visitor, Variant, _Type, _Types...> {
     }
 };
 
-/*template<uint8_t size>
+template<uint8_t size>
 struct DeleteVisitor {
 public:
     DeleteVisitor(typename std::aligned_storage<size>::type& storage) :
@@ -96,31 +125,11 @@ public:
 
     template<typename _Type>
     void operator()(const _Type&) const {
-        _Type thing = (reinterpret_cast<const _Type&>(storage_));
-        thing.~_Type();
+        (reinterpret_cast<const _Type *>(&storage_))->~_Type();
     }
 
 private:
     typename std::aligned_storage<size>::type& storage_;
-};*/
-
-template<uint8_t size, typename ... _Types>
-struct DeleteVisitor {
-public:
-    DeleteVisitor(Variant<_Types ...>& storage) :
-        storage_(storage)
-    {
-
-    }
-
-    template<typename _Type>
-    void operator()(const _Type& value) const {
-        value.~_Type();
-        //storage_.get<_Type>().~_Type();
-    }
-
-private:
-    Variant<_Types...>& storage_;
 };
 
 struct TypeOutputStreamWriteVisitor {
@@ -326,6 +335,7 @@ struct TypeIndex<_Type, _Types...> {
 template<typename ... _Types>
 Variant<_Types...>::Variant() :
                 valueType_(TypesTupleSize::value) {
+    ApplyVoidIndexVisitor<Variant<_Types...>, _Types...>::visit(*this, valueType_);
 }
 
 template<typename ... _Types>
@@ -335,24 +345,32 @@ Variant<_Types...>::Variant(const Variant& fromVariant) {
 }
 
 template<typename ... _Types>
-Variant<_Types...>::Variant(Variant&& fromVariant) {
+Variant<_Types...>::Variant(Variant&& fromVariant)
+{
     AssignmentVisitor<_Types...> visitor(*this, false);
     ApplyVoidVisitor<AssignmentVisitor<_Types...> , Variant<_Types...>, _Types...>::visit(visitor, fromVariant);
 }
 
+/*template<typename ... _Types>
+Variant<_Types...>::Variant(Variant&& fromVariant) :
+    valueType_(std::move(fromVariant.valueType_)),
+    valueStorage_(std::move(fromVariant.valueStorage_))
+{
+}*/
+
 template<typename ... _Types>
 Variant<_Types...>::~Variant() {
     if (hasValue()) {
-        DeleteVisitor<maxSize, _Types...> visitor(*this);
-        ApplyVoidVisitor<DeleteVisitor<maxSize, _Types...>, Variant<_Types...>, _Types...>::visit(visitor, *this);
+        DeleteVisitor<maxSize> visitor(valueStorage_);
+        ApplyVoidVisitor<DeleteVisitor<maxSize>, Variant<_Types...>, _Types...>::visit(visitor, *this);
     }
 }
 
 template<typename ... _Types>
 void Variant<_Types...>::readFromInputStream(const uint8_t typeIndex, InputStream& inputStream) {
     if(hasValue()) {
-        DeleteVisitor<maxSize, _Types...> visitor(*this);
-        ApplyVoidVisitor<DeleteVisitor<maxSize, _Types...>, Variant<_Types...>, _Types...>::visit(visitor, *this);
+               DeleteVisitor<maxSize> visitor(valueStorage_);
+        ApplyVoidVisitor<DeleteVisitor<maxSize>, Variant<_Types...>, _Types...>::visit(visitor, *this);
     }
     valueType_ = typeIndex;
     InputStreamReadVisitor<_Types...> visitor(*this, inputStream);
@@ -447,8 +465,8 @@ void Variant<_Types...>::set(const _U& value, const bool clear) {
     typedef typename TypeSelector<_U, _Types...>::type selected_type_t;
 
     if (clear) {
-        DeleteVisitor<maxSize, _Types...> visitor(*this);
-        ApplyVoidVisitor<DeleteVisitor<maxSize, _Types...>, Variant<_Types...>, _Types...>::visit(visitor, *this);
+               DeleteVisitor<maxSize> visitor(valueStorage_);
+        ApplyVoidVisitor<DeleteVisitor<maxSize>, Variant<_Types...>, _Types...>::visit(visitor, *this);
     }
     new (&valueStorage_) selected_type_t(std::move(value));
     valueType_ = TypeIndex<_Types...>::template get<selected_type_t>();
@@ -462,8 +480,8 @@ void Variant<_Types...>::set(_U&& value, const bool clear) {
     selected_type_t&& any_container_value = std::move(value);
     if(clear)
     {
-        DeleteVisitor<maxSize, _Types...> visitor(*this);
-        ApplyVoidVisitor<DeleteVisitor<maxSize, _Types...>, Variant<_Types...>, _Types...>::visit(visitor, *this);
+               DeleteVisitor<maxSize> visitor(valueStorage_);
+        ApplyVoidVisitor<DeleteVisitor<maxSize>, Variant<_Types...>, _Types...>::visit(visitor, *this);
     } else {
         new (&valueStorage_) selected_type_t(std::move(any_container_value));
     }
index 441a288..4d7e5e1 100755 (executable)
@@ -15,6 +15,52 @@ class VariantTest: public ::testing::Test {
   }
 };
 
+
+struct test1: CommonAPI::SerializableStruct {
+    int a;
+    std::string b;
+
+    test1() = default;
+    test1(const int& a, const std::string& b) :
+    a(a), b(b) {
+    }
+
+    void readFromInputStream(CommonAPI::InputStream& inputStream) {
+
+    }
+
+    void writeToOutputStream(CommonAPI::OutputStream& outputStream) const {
+
+    }
+
+    static inline void writeToTypeOutputStream(CommonAPI::TypeOutputStream& typeOutputStream) {
+    }
+
+};
+
+struct test2: CommonAPI::SerializableStruct {
+    int a;
+    std::string b;
+
+    test2() = default;
+    test2(const int& a, const std::string& b) :
+    a(a), b(b) {
+    }
+
+    void readFromInputStream(CommonAPI::InputStream& inputStream) {
+
+    }
+
+    void writeToOutputStream(CommonAPI::OutputStream& outputStream) const {
+
+    }
+
+    static inline void writeToTypeOutputStream(CommonAPI::TypeOutputStream& typeOutputStream) {
+    }
+
+};
+
+
 TEST_F(VariantTest, VariantTestPack) {
 
     int fromInt = 5;
@@ -70,6 +116,11 @@ TEST_F(VariantTest, VariantTestPack) {
     std::cout << "myInt is std::string = " << "\n";
     EXPECT_FALSE(myVariant.isType<std::string>());
 
+    Variant<int, double, std::string> movedVariant = std::move(myVariant);
+    std::cout << "myMovedInt is int = " << " (" << std::boolalpha << movedVariant.isType<int>() << ")\n";
+    EXPECT_TRUE(movedVariant.isType<int>());
+    EXPECT_EQ(fromInt, movedVariant.get<int>());
+
     const double& myDouble = myVariantf.get<double>();
     std::cout << "myDouble = " << myDouble << "\n";
 
@@ -85,6 +136,14 @@ TEST_F(VariantTest, VariantTestPack) {
     std::cout << "myStringCopy = " << myStringCopy << "\n";
 
     delete myVariants;
+
+    test1 sourceStruct = {1, "a"};
+
+    Variant<test1, test2> complexSource = sourceStruct;
+
+    Variant<test1, test2> complexTarget = complexSource;
+    EXPECT_EQ(1, complexTarget.get<test1>().a);
+
 }
 
 int main(int argc, char** argv) {