From 99a0fcd8e3bd39a82df84e779719d058276148e3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Tomic=CC=8Cevic=CC=81?=
 <dominik.tomicevic@gmail.com>
Date: Sat, 20 Feb 2016 17:53:09 +0100
Subject: [PATCH] finished refactoring properties

---
 examples/proptest.cpp                         | 49 ++++++++++++++++
 proptest.cpp                                  | 28 ---------
 storage/model/properties/all.hpp              | 27 +++++++++
 storage/model/properties/bool.hpp             | 10 ++++
 storage/model/properties/double.hpp           | 13 +++++
 storage/model/properties/float.hpp            |  7 +++
 storage/model/properties/int32.hpp            | 34 ++---------
 storage/model/properties/int64.hpp            | 14 +++++
 storage/model/properties/integral.hpp         | 11 +++-
 storage/model/properties/null.hpp             | 10 ++++
 storage/model/properties/number.hpp           |  9 ++-
 storage/model/properties/properties.hpp       | 13 +----
 storage/model/properties/property.hpp         | 57 +++----------------
 storage/model/properties/string.hpp           | 10 ++++
 .../{ => traversers}/jsonwriter.hpp           |  9 ++-
 storage/model/properties/utils/modulo.hpp     | 10 ++++
 .../model/properties/utils/unary_negation.hpp |  2 +-
 utils/crtp.hpp                                |  5 ++
 18 files changed, 194 insertions(+), 124 deletions(-)
 create mode 100644 examples/proptest.cpp
 delete mode 100644 proptest.cpp
 create mode 100644 storage/model/properties/all.hpp
 create mode 100644 storage/model/properties/double.hpp
 create mode 100644 storage/model/properties/int64.hpp
 rename storage/model/properties/{ => traversers}/jsonwriter.hpp (88%)
 create mode 100644 storage/model/properties/utils/modulo.hpp

diff --git a/examples/proptest.cpp b/examples/proptest.cpp
new file mode 100644
index 000000000..a4b531677
--- /dev/null
+++ b/examples/proptest.cpp
@@ -0,0 +1,49 @@
+#include <iostream>
+
+#include "storage/model/properties/properties.hpp"
+#include "storage/model/properties/property.hpp"
+#include "storage/model/properties/traversers/jsonwriter.hpp"
+
+using std::endl;
+using std::cout;
+
+int main(void)
+{
+    Properties props;
+    props.set<Bool>("awesome", true);
+    props.set<Bool>("lame", false);
+    props.set<Int32>("age", 32);
+
+    // integral
+    Int32 a = 12;
+    Int32 b = 24;
+    Int32 c = b;
+
+    Property& d = b;
+
+    cout << "a = " << a << "; b = " << b << endl;
+    cout << (a > b) << (a < b) << (a == b) << (a != b) << endl;
+
+    cout << "b == d" << " -> " << (b == d) << endl;
+
+    Float x = 3.14;
+    Float y = 6.28;
+
+    Float z = x * 3.28 / y + a * b + 3;
+
+    cout << x << endl;
+    cout << z << endl;
+
+    props.set<Float>("pi", z);
+
+    StringBuffer buffer;
+    JsonWriter<StringBuffer> writer(buffer);
+
+    props.accept(writer);
+    cout << buffer.str() << endl;
+
+    return 0;
+}
+
+
+
diff --git a/proptest.cpp b/proptest.cpp
deleted file mode 100644
index 9b1db673a..000000000
--- a/proptest.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <iostream>
-
-#include "storage/model/properties/properties.hpp"
-#include "storage/model/properties/property.hpp"
-
-int main(void)
-{
-    StringBuffer buffer;
-    auto handler = JsonWriter<StringBuffer>(buffer);
-
-    Properties props;
-    props.emplace<Null>("sadness");
-    props.emplace<Bool>("awesome", true);
-    props.emplace<Bool>("lame", false);
-    props.emplace<Int32>("age", 32);
-    props.emplace<Int64>("money", 12345678910111213);
-    props.emplace<String>("name", "caca");
-    props.emplace<Float>("pi", 3.14159265358979323846264338327950288419716939937510582097);
-    props.emplace<Double>("pi2", 3.141592653589793238462643383279502884197169399375105820);
-
-    props.accept(handler);
-    handler.finish();
-
-    std::cout.precision(25);
-    std::cout << buffer.str() << std::endl;
-
-    return 0;
-}
diff --git a/storage/model/properties/all.hpp b/storage/model/properties/all.hpp
new file mode 100644
index 000000000..9a9eaebdd
--- /dev/null
+++ b/storage/model/properties/all.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "property.hpp"
+
+#include "null.hpp"
+#include "bool.hpp"
+#include "string.hpp"
+#include "int32.hpp"
+#include "int64.hpp"
+#include "float.hpp"
+#include "double.hpp"
+
+template <class Handler>
+void Property::accept(Handler& h)
+{
+    switch(flags)
+    {
+        case Flags::True:   return h.handle(static_cast<Bool&>(*this));
+        case Flags::False:  return h.handle(static_cast<Bool&>(*this));
+        case Flags::String: return h.handle(static_cast<String&>(*this));
+        case Flags::Int32:  return h.handle(static_cast<Int32&>(*this));
+        case Flags::Int64:  return h.handle(static_cast<Int64&>(*this));
+        case Flags::Float:  return h.handle(static_cast<Float&>(*this));
+        case Flags::Double: return h.handle(static_cast<Double&>(*this));
+        default: return;
+    }
+}
diff --git a/storage/model/properties/bool.hpp b/storage/model/properties/bool.hpp
index f27e19ab4..69d68287b 100644
--- a/storage/model/properties/bool.hpp
+++ b/storage/model/properties/bool.hpp
@@ -43,5 +43,15 @@ public:
     {
         return value() == v;
     }
+
+    std::ostream& print(std::ostream& stream) const override
+    {
+        return operator<<(stream, *this);
+    }
+
+    friend std::ostream& operator<<(std::ostream& stream, const Bool& prop)
+    {
+        return stream << prop.value();
+    }
 };
 
diff --git a/storage/model/properties/double.hpp b/storage/model/properties/double.hpp
new file mode 100644
index 000000000..780c2cba0
--- /dev/null
+++ b/storage/model/properties/double.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "floating.hpp"
+
+struct Double : public Floating<Double>
+{
+    static constexpr Flags type = Flags::Double;
+
+    Double(double value) : Floating(Flags::Double), value(value) {}
+
+    double value;
+};
+
diff --git a/storage/model/properties/float.hpp b/storage/model/properties/float.hpp
index 177f92187..64496ba0d 100644
--- a/storage/model/properties/float.hpp
+++ b/storage/model/properties/float.hpp
@@ -1,12 +1,19 @@
 #pragma once
 
 #include "floating.hpp"
+#include "double.hpp"
 
 class Float : public Floating<Float>
 {
+public:
     static constexpr Flags type = Flags::Float;
 
     Float(float value) : Floating(Flags::Float), value(value) {}
 
+    operator Double() const
+    {
+        return Double(value);
+    }
+
     float value;
 };
diff --git a/storage/model/properties/int32.hpp b/storage/model/properties/int32.hpp
index 2415e9ccb..ed588b4fd 100644
--- a/storage/model/properties/int32.hpp
+++ b/storage/model/properties/int32.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "integral.hpp"
+#include "int64.hpp"
 
 class Int32 : public Integral<Int32>
 {
@@ -9,35 +10,10 @@ public:
 
     Int32(int32_t value) : Integral(Flags::Int32), value(value) {}
 
-    /* friend constexpr bool operator==(const Int32& lhs, const Int32& rhs) */
-    /* { */
-    /*     return lhs.value == rhs.value; */
-    /* } */
-
-    /* friend constexpr bool operator<(const Int32& lhs, const Int32& rhs) */
-    /* { */
-    /*     return lhs.value < rhs.value; */
-    /* } */
-
-    /* friend constexpr bool operator==(const Int32& lhs, int32_t rhs) */
-    /* { */
-    /*     return lhs.value == rhs; */
-    /* } */
-
-    /* friend constexpr bool operator<(const Int32& lhs, int32_t rhs) */
-    /* { */
-    /*     return lhs.value < rhs; */
-    /* } */
-
-    /* friend constexpr bool operator==(int32_t lhs, const Int32& rhs) */
-    /* { */
-    /*     return lhs == rhs.value; */
-    /* } */
-
-    /* friend constexpr bool operator<(int32_t lhs, const Int32& rhs) */
-    /* { */
-    /*     return lhs < rhs.value; */
-    /* } */
+    operator Int64() const
+    {
+        return Int64(value);
+    }
 
     int32_t value;
 };
diff --git a/storage/model/properties/int64.hpp b/storage/model/properties/int64.hpp
new file mode 100644
index 000000000..eb699ce06
--- /dev/null
+++ b/storage/model/properties/int64.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "integral.hpp"
+
+class Int64 : public Integral<Int64>
+{
+public:
+    static constexpr Flags type = Flags::Int64;
+
+    Int64(int64_t value) : Integral(Flags::Int64), value(value) {}
+
+    int64_t value;
+};
+
diff --git a/storage/model/properties/integral.hpp b/storage/model/properties/integral.hpp
index dcffa541b..e94bed313 100644
--- a/storage/model/properties/integral.hpp
+++ b/storage/model/properties/integral.hpp
@@ -1,9 +1,18 @@
 #pragma once
 
 #include "number.hpp"
+#include "floating.hpp"
+#include "utils/modulo.hpp"
 
 template <class Derived>
-struct Integral : public Number<Derived>
+struct Integral : public Number<Derived>, public Modulo<Derived>
 {
     using Number<Derived>::Number;
+
+    template <class T, typename = std::enable_if_t<
+                std::is_base_of<Floating<T>, T>::value>>
+    operator T() const
+    {
+        return T(this->derived().value);
+    }
 };
diff --git a/storage/model/properties/null.hpp b/storage/model/properties/null.hpp
index 7a867a089..c09171ba6 100644
--- a/storage/model/properties/null.hpp
+++ b/storage/model/properties/null.hpp
@@ -29,6 +29,16 @@ public:
         return false;
     }
 
+    friend std::ostream& operator<<(std::ostream& stream, const Null&)
+    {
+        return stream << "NULL";
+    }
+
+    std::ostream& print(std::ostream& stream) const override
+    {
+        return operator<<(stream, *this);
+    }
+
 private:
     // the constructor for null is private, it can be constructed only as a
     // value inside the Property class, Property::Null
diff --git a/storage/model/properties/number.hpp b/storage/model/properties/number.hpp
index d4c278b42..41a710487 100644
--- a/storage/model/properties/number.hpp
+++ b/storage/model/properties/number.hpp
@@ -1,14 +1,12 @@
 #pragma once
 
 #include "property.hpp"
-#include "utils/crtp.hpp"
 #include "utils/total_ordering.hpp"
 #include "utils/unary_negation.hpp"
 #include "utils/math_operations.hpp"
 
 template <class Derived>
 class Number : public Property,
-               public Crtp<Derived>,
                public TotalOrdering<Derived>,
                public MathOperations<Derived>,
                public UnaryNegation<Derived>
@@ -18,7 +16,7 @@ public:
 
     bool operator==(const Property& other) const override
     {
-        return other.is<Derived>() && *this == other.as<Derived>();
+        return other.is<Derived>() && this->derived() == other.as<Derived>();
     }
 
     friend bool operator==(const Derived& lhs, const Derived& rhs)
@@ -35,4 +33,9 @@ public:
     {
         return s << number.value;
     }
+
+    std::ostream& print(std::ostream& stream) const override
+    {
+        return operator<<(stream, this->derived());
+    }
 };
diff --git a/storage/model/properties/properties.hpp b/storage/model/properties/properties.hpp
index 26d16a282..4452804c9 100644
--- a/storage/model/properties/properties.hpp
+++ b/storage/model/properties/properties.hpp
@@ -3,10 +3,7 @@
 #include <map>
 
 #include "property.hpp"
-#include "null.hpp"
-#include "bool.hpp"
-#include "string.hpp"
-#include "int32.hpp"
+#include "all.hpp"
 
 class Properties
 {
@@ -52,15 +49,9 @@ public:
     template <class Handler>
     void accept(Handler& handler) const
     {
-        bool first = true;
-
         for(auto& kv : props)
-        {
-            handler.handle(kv.first, *kv.second, first);
+            handler.handle(kv.first, *kv.second);
 
-            if(first)
-                first = false;
-        }
         handler.finish();
     }
 
diff --git a/storage/model/properties/property.hpp b/storage/model/properties/property.hpp
index a03e04565..50b5fb6e6 100644
--- a/storage/model/properties/property.hpp
+++ b/storage/model/properties/property.hpp
@@ -3,6 +3,7 @@
 #include <memory>
 #include <string>
 #include <cassert>
+#include <ostream>
 
 #include "utils/underlying_cast.hpp"
 
@@ -61,10 +62,6 @@ public:
 
     Property(Flags flags) : flags(flags) {}
 
-    // this is giving problems with default constructors in derived classes
-    // Property(const Property&) = delete;
-    // Property(Property&&) = delete;
-
     virtual bool operator==(const Property& other) const = 0;
 
     bool operator!=(const Property& other) const
@@ -92,54 +89,16 @@ public:
         return *static_cast<const T*>(this);
     }
 
+    virtual std::ostream& print(std::ostream& stream) const = 0;
+
+    friend std::ostream& operator<<(std::ostream& stream, const Property& prop)
+    {
+        return prop.print(stream);
+    }
+
     template <class Handler>
     void accept(Handler& handler);
 
     const Flags flags;
 };
 
-/* struct Int64 : public Property */
-/* { */
-/*     static constexpr Flags type = Flags::Int64; */
-
-/*     Int64(int64_t value) */
-/*         : Property(Flags::Int64), value(value) {} */
-
-/*     int64_t value; */
-/* }; */
-
-/* struct Float : public Property */
-/* { */
-/*     static constexpr Flags type = Flags::Float; */
-
-/*     Float(float value) */
-/*         : Property(Flags::Float), value(value) {} */
-
-/*     float value; */
-/* }; */
-
-/* struct Double : public Property */
-/* { */
-/*     static constexpr Flags type = Flags::Double; */
-
-/*     Double(double value) */
-/*         : Property(Flags::Double), value(value) {} */
-
-/*     double value; */
-/* }; */
-
-template <class Handler>
-void Property::accept(Handler& h)
-{
-    /* switch(flags) */
-    /* { */
-    /*     case Flags::True:   return h.handle(static_cast<Bool&>(*this)); */
-    /*     case Flags::False:  return h.handle(static_cast<Bool&>(*this)); */
-    /*     case Flags::String: return h.handle(static_cast<String&>(*this)); */
-    /*     case Flags::Int32:  return h.handle(static_cast<Int32&>(*this)); */
-    /*     case Flags::Int64:  return h.handle(static_cast<Int64&>(*this)); */
-    /*     case Flags::Float:  return h.handle(static_cast<Float&>(*this)); */
-    /*     case Flags::Double: return h.handle(static_cast<Double&>(*this)); */
-    /*     default: return; */
-    /* } */
-}
diff --git a/storage/model/properties/string.hpp b/storage/model/properties/string.hpp
index 028d10d5e..38e2699b7 100644
--- a/storage/model/properties/string.hpp
+++ b/storage/model/properties/string.hpp
@@ -34,5 +34,15 @@ public:
         return value == other;
     }
 
+    friend std::ostream& operator<<(std::ostream& stream, const String& prop)
+    {
+        return stream << prop.value;
+    }
+
+    std::ostream& print(std::ostream& stream) const override
+    {
+        return operator<<(stream, *this);
+    }
+
     std::string value;
 };
diff --git a/storage/model/properties/jsonwriter.hpp b/storage/model/properties/traversers/jsonwriter.hpp
similarity index 88%
rename from storage/model/properties/jsonwriter.hpp
rename to storage/model/properties/traversers/jsonwriter.hpp
index 179b64bf1..b4d03ec23 100644
--- a/storage/model/properties/jsonwriter.hpp
+++ b/storage/model/properties/traversers/jsonwriter.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
-#include "properties.hpp"
+#include "../properties.hpp"
+#include "../all.hpp"
 
 template <class Buffer>
 struct JsonWriter
@@ -11,11 +12,14 @@ public:
         buffer << '{';
     };
 
-    void handle(const std::string& key, Property& value, bool first)
+    void handle(const std::string& key, Property& value)
     {
         if(!first)
             buffer << ',';
 
+        if(first)
+            first = false;
+
         buffer << '"' << key << "\":";
         value.accept(*this);
     }
@@ -56,6 +60,7 @@ public:
     }
 
 private:
+    bool first {true};
     Buffer& buffer;
 };
 
diff --git a/storage/model/properties/utils/modulo.hpp b/storage/model/properties/utils/modulo.hpp
new file mode 100644
index 000000000..6d43d50b1
--- /dev/null
+++ b/storage/model/properties/utils/modulo.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+template <class Derived>
+struct Modulo
+{
+    friend Derived operator%(const Derived& lhs, const Derived& rhs)
+    {
+        return Derived(lhs.value % rhs.value);
+    }
+};
diff --git a/storage/model/properties/utils/unary_negation.hpp b/storage/model/properties/utils/unary_negation.hpp
index c324a9cd4..511c1d55a 100644
--- a/storage/model/properties/utils/unary_negation.hpp
+++ b/storage/model/properties/utils/unary_negation.hpp
@@ -3,7 +3,7 @@
 #include "utils/crtp.hpp"
 
 template <class Derived>
-struct UnaryNegation : Crtp<Derived>
+struct UnaryNegation : public Crtp<Derived>
 {
     Derived operator-() const
     {
diff --git a/utils/crtp.hpp b/utils/crtp.hpp
index 08dda592f..e07ed7426 100644
--- a/utils/crtp.hpp
+++ b/utils/crtp.hpp
@@ -10,4 +10,9 @@ struct Crtp
     {
         return *static_cast<Derived*>(this);
     }
+
+    const Derived& derived() const
+    {
+        return *static_cast<const Derived*>(this);
+    }
 };