From b4a6ca3487ae18e2fd75f9c2b3bedb1c7aea0d40 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Tomic=CC=8Cevic=CC=81?=
 <dominik.tomicevic@gmail.com>
Date: Sun, 21 Jun 2015 21:15:46 +0200
Subject: [PATCH] added a JSON class

---
 data_model/json/all.hpp       |  14 +++++
 data_model/json/array.hpp     |  84 +++++++++++++++++++++++++++
 data_model/json/bool.hpp      |  33 +++++++++++
 data_model/json/integral.hpp  |  33 +++++++++++
 data_model/json/json.hpp      |  47 +++++++++++++++
 data_model/json/null.hpp      |  30 ++++++++++
 data_model/json/object.hpp    | 106 ++++++++++++++++++++++++++++++++++
 data_model/json/primitive.hpp |  29 ++++++++++
 data_model/json/real.hpp      |  33 +++++++++++
 data_model/json/string.hpp    |  34 +++++++++++
 10 files changed, 443 insertions(+)
 create mode 100644 data_model/json/all.hpp
 create mode 100644 data_model/json/array.hpp
 create mode 100644 data_model/json/bool.hpp
 create mode 100644 data_model/json/integral.hpp
 create mode 100644 data_model/json/json.hpp
 create mode 100644 data_model/json/null.hpp
 create mode 100644 data_model/json/object.hpp
 create mode 100644 data_model/json/primitive.hpp
 create mode 100644 data_model/json/real.hpp
 create mode 100644 data_model/json/string.hpp

diff --git a/data_model/json/all.hpp b/data_model/json/all.hpp
new file mode 100644
index 000000000..eb179eadd
--- /dev/null
+++ b/data_model/json/all.hpp
@@ -0,0 +1,14 @@
+#ifndef JSON_ALL_HPP
+#define JSON_ALL_HPP
+
+#include "array.hpp"
+#include "bool.hpp"
+#include "integral.hpp"
+#include "json.hpp"
+#include "null.hpp"
+#include "object.hpp"
+#include "primitive.hpp"
+#include "real.hpp"
+#include "string.hpp"
+
+#endif
diff --git a/data_model/json/array.hpp b/data_model/json/array.hpp
new file mode 100644
index 000000000..bd0ef1a76
--- /dev/null
+++ b/data_model/json/array.hpp
@@ -0,0 +1,84 @@
+#ifndef JSON_ARRAY_HPP
+#define JSON_ARRAY_HPP
+
+#include <cassert>
+#include <memory>
+#include <vector>
+
+#include "../utilities/utils.hpp"
+
+#include "json.hpp"
+
+namespace json
+{
+
+class Array final : public Json
+{
+public:
+    Array() {}
+
+    template <typename It>
+    Array(It first, It last)
+        : elements(first, last) {}
+
+    Array(std::initializer_list<spJson> elements)
+        : elements(elements) {}
+
+    virtual bool is_array() const;
+
+    size_t size() const;
+
+    Array& push(const std::shared_ptr<Json>& element);
+
+    const spJson& operator[](size_t i) const;
+          spJson  operator[](size_t i);
+
+    virtual operator std::string() const;
+
+private:
+    std::vector<spJson> elements;
+};
+
+bool Array::is_array() const
+{
+    return true;
+}
+
+size_t Array::size() const
+{
+    return elements.size();
+}
+
+Array& Array::push(const spJson& element)
+{
+    assert(element);
+
+    elements.push_back(element);
+    return *this;
+}
+
+const spJson& Array::operator[](size_t i) const
+{
+    return elements[i];
+}
+
+spJson Array::operator[](size_t i)
+{
+    return elements[i];
+}
+
+Array::operator std::string() const
+{
+    std::vector<std::string> xs;
+
+    std::transform(elements.begin(), elements.end(), std::back_inserter(xs),
+        [](const spJson& element) {
+            return static_cast<std::string>(*element);
+        });
+
+    return "[" + utils::intercalate(xs.begin(), xs.end(), ",") + "]";
+}
+
+}
+
+#endif  
diff --git a/data_model/json/bool.hpp b/data_model/json/bool.hpp
new file mode 100644
index 000000000..f91d1f20f
--- /dev/null
+++ b/data_model/json/bool.hpp
@@ -0,0 +1,33 @@
+#ifndef JSON_BOOL_HPP
+#define JSON_BOOL_HPP
+
+#include "primitive.hpp"
+
+namespace json {
+
+class Bool final : public Primitive<bool> 
+{
+public:
+    Bool() {}
+
+    Bool(bool value) 
+        : Primitive<bool>(value) {}
+    
+    virtual bool is_boolean() const;
+
+    virtual operator std::string() const;
+};
+
+bool Bool::is_boolean() const
+{
+    return true;
+}
+
+Bool::operator std::string() const
+{
+    return value == true ? "true" : "false";
+}
+
+}
+
+#endif
diff --git a/data_model/json/integral.hpp b/data_model/json/integral.hpp
new file mode 100644
index 000000000..fd961ebbd
--- /dev/null
+++ b/data_model/json/integral.hpp
@@ -0,0 +1,33 @@
+#ifndef JSON_INTEGRAL_HPP
+#define JSON_INTEGRAL_HPP
+
+#include "primitive.hpp"
+
+namespace json {
+
+class Integral final : public Primitive<int64_t>
+{
+public:
+    Integral() {}
+
+    Integral(int64_t value)
+        : Primitive<int64_t>(value) {}
+
+    virtual bool is_integral() const;
+
+    virtual operator std::string() const;  
+};
+
+bool Integral::is_integral() const
+{
+    return true;
+}
+
+Integral::operator std::string() const
+{
+    return std::to_string(value);
+}
+
+}
+
+#endif
diff --git a/data_model/json/json.hpp b/data_model/json/json.hpp
new file mode 100644
index 000000000..f966b841a
--- /dev/null
+++ b/data_model/json/json.hpp
@@ -0,0 +1,47 @@
+#ifndef JSON_JSON_HPP
+#define JSON_JSON_HPP
+
+#include <initializer_list>
+#include <string>
+#include <memory>
+
+namespace json {
+
+class Json;
+
+typedef std::shared_ptr<Json> spJson;
+
+class Json
+{
+public:
+    Json() {}
+    virtual ~Json() {}
+
+    virtual bool is_object()   const { return false; }
+    virtual bool is_array()    const { return false; }
+    virtual bool is_real()     const { return false; }
+    virtual bool is_integral() const { return false; }
+    virtual bool is_boolean()  const { return false; }
+    virtual bool is_null()     const { return false; }
+
+    template <typename T> T& as();
+    template <typename T> const T& as() const;
+
+    virtual operator std::string() const = 0;
+};
+
+template <typename T>
+T& Json::as()
+{
+    return *dynamic_cast<T*>(this);
+}
+
+template <typename T>
+const T& Json::as() const
+{
+    return *dynamic_cast<T*>(this);
+}
+
+}
+
+#endif
diff --git a/data_model/json/null.hpp b/data_model/json/null.hpp
new file mode 100644
index 000000000..982363e4e
--- /dev/null
+++ b/data_model/json/null.hpp
@@ -0,0 +1,30 @@
+#ifndef JSON_NULL_HPP
+#define JSON_NULL_HPP
+
+#include "json.hpp"
+
+namespace json {
+
+class Null final : public Json 
+{
+public:
+    Null() {}
+    
+    virtual bool is_null() const;
+
+    virtual operator std::string() const;
+};
+
+bool Null::is_null() const
+{
+    return true;
+}
+
+Null::operator std::string() const
+{
+    return "null";
+}
+    
+}
+
+#endif
diff --git a/data_model/json/object.hpp b/data_model/json/object.hpp
new file mode 100644
index 000000000..5ecbbc378
--- /dev/null
+++ b/data_model/json/object.hpp
@@ -0,0 +1,106 @@
+#ifndef JSON_OBJECT_HPP
+#define JSON_OBJECT_HPP
+
+#include <iostream>
+
+#include <functional>
+#include <sstream>
+#include <cassert>
+#include <vector>
+#include <map>
+
+#include "../utilities/utils.hpp"
+
+#include "json.hpp"
+
+namespace json {
+
+typedef std::pair<const std::string, spJson> const_kv_pair_t;
+typedef std::pair<std::string, spJson> kv_pair_t;
+
+class Object;
+
+typedef std::shared_ptr<Object> spObject;
+
+class Object : public Json
+{
+public:
+    Object() {}
+
+    Object(std::initializer_list<const_kv_pair_t> elements)
+        : props(elements) {}
+
+    virtual bool is_object() const;
+
+    const spJson& at(const std::string& key) const;
+          spJson  at(const std::string& key);
+
+    const spJson& operator[](const std::string& key) const;
+          spJson  operator[](const std::string& key);
+
+    Object& put(const std::string& key, spJson value);
+
+    Object& operator<<(const kv_pair_t& kv_pair);
+
+    virtual operator std::string() const;
+
+protected:
+    std::map<std::string, spJson> props;
+};
+
+bool Object::is_object() const
+{
+    return true;
+}
+
+const spJson& Object::at(const std::string& key) const
+{
+    return props.at(key);
+}
+
+spJson Object::at(const std::string& key)
+{
+    return props.at(key);
+}
+
+const spJson& Object::operator[](const std::string& key) const
+{
+    return this->at(key);
+}
+
+spJson Object::operator[](const std::string& key)
+{
+    return this->at(key);
+}
+
+Object& Object::put(const std::string& key, spJson value)
+{
+    assert(value);
+
+    props[key] = value;
+    return *this;
+}
+
+Object& Object::operator<<(const kv_pair_t& kv_pair)
+{
+    return this->put(std::get<0>(kv_pair), std::get<1>(kv_pair));
+}
+
+Object::operator std::string() const
+{
+    if(props.empty())
+        return "{}";
+
+    std::vector<std::string> xs;
+
+    std::transform(props.begin(), props.end(), std::back_inserter(xs),
+        [](const kv_pair_t& kvp) {
+            return "\"" + kvp.first + "\":" + static_cast<std::string>(*kvp.second);
+        });
+
+    return "{" + utils::intercalate(xs.begin(), xs.end(), ",") + "}";
+}
+
+}
+
+#endif
diff --git a/data_model/json/primitive.hpp b/data_model/json/primitive.hpp
new file mode 100644
index 000000000..a0da326a8
--- /dev/null
+++ b/data_model/json/primitive.hpp
@@ -0,0 +1,29 @@
+#ifndef JSON_PRIMITIVE
+#define JSON_PRIMITIVE
+
+#include "json.hpp"
+
+namespace json {
+
+template <class T>
+class Primitive : public Json
+{
+public:
+    Primitive() {}
+
+    Primitive(const T& value)
+        : value(value) {}
+
+    T get() const { return value; }
+    void set(T value) { this->value = value; }
+
+    operator T() const { return this->get(); }
+    
+protected:
+    T value;
+};
+
+
+}
+
+#endif
diff --git a/data_model/json/real.hpp b/data_model/json/real.hpp
new file mode 100644
index 000000000..e3e5d3eff
--- /dev/null
+++ b/data_model/json/real.hpp
@@ -0,0 +1,33 @@
+#ifndef JSON_REAL_HPP
+#define JSON_REAL_HPP
+
+#include "primitive.hpp"
+
+namespace json {
+
+class Real final : public Primitive<float> 
+{
+public:
+    Real() {}
+
+    Real(float value)
+        : Primitive<float>(value) {}
+    
+    virtual bool is_real() const;
+
+    virtual operator std::string() const;
+};
+
+bool Real::is_real() const
+{
+    return true;
+}
+
+Real::operator std::string() const
+{
+    return std::to_string(value);
+}
+
+}
+
+#endif
diff --git a/data_model/json/string.hpp b/data_model/json/string.hpp
new file mode 100644
index 000000000..5fdd5b27d
--- /dev/null
+++ b/data_model/json/string.hpp
@@ -0,0 +1,34 @@
+#ifndef JSON_STRING_HPP
+#define JSON_STRING_HPP
+
+#include "primitive.hpp"
+
+namespace json
+{
+
+class String final : public Primitive<std::string>
+{
+public:
+    String() {}
+
+    String(const std::string& value) 
+        : Primitive<std::string>(value) {}
+
+    virtual bool is_string() const;
+
+    virtual operator std::string() const;
+};
+
+bool String::is_string() const
+{
+    return true;
+}
+
+String::operator std::string() const
+{
+    return "\"" + value + "\"";
+}
+
+}
+
+#endif