Add Array type to JSON
authorSangwan Kwon <sangwan.kwon@samsung.com>
Tue, 12 May 2020 08:26:43 +0000 (17:26 +0900)
committer권상완/Security 2Lab(SR)/Engineer/삼성전자 <sangwan.kwon@samsung.com>
Mon, 18 May 2020 00:52:02 +0000 (09:52 +0900)
Signed-off-by: Sangwan Kwon <sangwan.kwon@samsung.com>
src/vist/json/array.hpp [new file with mode: 0644]
src/vist/json/json.hpp
src/vist/json/object.hpp
src/vist/json/tests/json.cpp

diff --git a/src/vist/json/array.hpp b/src/vist/json/array.hpp
new file mode 100644 (file)
index 0000000..7f7083a
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *  Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the language governing permissions and
+ *  limitations under the License
+ */
+
+#pragma once
+
+#include <vist/json/value.hpp>
+
+#include <string>
+#include <vector>
+
+namespace vist {
+namespace json {
+
+struct Array : public Value {
+       std::size_t size() const noexcept
+       {
+               return this->buffer.size();
+       }
+
+       std::string serialize() const override
+       {
+               std::stringstream ss;
+               ss << "[ ";
+
+               std::size_t i = 0;
+               for (const auto& value : buffer) {
+                       ss << value->serialize();
+
+                       if (i++ < buffer.size() - 1)
+                               ss << ",";
+
+                       ss << " ";
+               }
+               ss << "]";
+
+               return ss.str();
+       }
+
+       template <typename Type>
+       void push(const Type& data)
+       {
+               auto value = std::make_shared<Value>();
+               *value = data;
+               this->buffer.emplace_back(std::move(value));
+       }
+
+       Value& at(std::size_t index)
+       {
+               if (index > this->size())
+                       throw std::invalid_argument("Wrong index.");
+
+               return *(this->buffer[index]);
+       }
+
+       Value& operator[](std::size_t index)
+       {
+               if (index > this->size())
+                       throw std::invalid_argument("Wrong index.");
+
+               return *(this->buffer[index]);
+       }
+
+       std::vector<std::shared_ptr<Value>> buffer;
+};
+
+} // namespace json
+} // namespace vist
index 74e3552..7e1990d 100644 (file)
@@ -18,7 +18,7 @@
  *   - Applied design pattern: Composite pattern
  *     - Component structure: Value 
  *     - Leaf structure: Int, String (To be added: Bool, Null)
- *     - Composite structure: Object (To be added: Array)
+ *     - Composite structure: Array, Object
  */
 /*
  * Usage:
@@ -37,8 +37,9 @@
 
 #pragma once
 
-#include <vist/json/value.hpp>
+#include <vist/json/array.hpp>
 #include <vist/json/object.hpp>
+#include <vist/json/value.hpp>
 
 #include <sstream>
 #include <stdexcept>
@@ -72,26 +73,42 @@ struct Json {
                return this->root.serialize();
        }
 
-       void push(const std::string& key, Json& child)
+       template <typename CompositeType>
+       void push(const std::string& key, CompositeType& child)
+       {
+               auto composite = std::make_shared<CompositeType>();
+               if constexpr (std::is_same_v<CompositeType, Array>)
+                       composite->buffer = std::move(child.buffer);
+               else if constexpr (std::is_same_v<CompositeType, Object>)
+                       composite->pairs = std::move(child.pairs);
+               else
+                       static_assert(dependent_false<CompositeType>::value, "Only Composite type supported.");
+
+               this->root.pairs[key] = composite; 
+       }
+
+       void push(const std::string& key, Array& child)
        {
-               auto object = std::make_shared<Object>();
-               object->pairs = std::move(child.root.pairs);
-               this->root.pairs[key] = object
+               auto array = std::make_shared<Array>();
+               array->buffer = std::move(child.buffer);
+               this->root.pairs[key] = array
        }
 
-       Json pop(const std::string& key)
+       template <typename CompositeType>
+       CompositeType& get(const std::string& key)
        {
                if (!this->root.exist(key))
                        throw std::runtime_error("Not exist key.");
 
-               if (auto downcast = std::dynamic_pointer_cast<Object>(this->root.pairs[key]);
-                       downcast == nullptr)
-                       throw std::runtime_error("Mismatched type.");
-               else {
-                       Json json;
-                       json.root.pairs = std::move(downcast->pairs);
-                       this->root.pairs.erase(key);
-                       return json;
+               if constexpr (std::is_same_v<CompositeType, Array> ||
+                                         std::is_same_v<CompositeType, Object>) {
+                       if (auto downcast = std::dynamic_pointer_cast<CompositeType>(this->root.pairs[key]);
+                               downcast == nullptr)
+                               throw std::runtime_error("Mismatched type.");
+                       else
+                               return *downcast;
+               } else {
+                       static_assert(dependent_false<CompositeType>::value, "Only Composite type supported.");
                }
        }
 
index f6c01c9..8542147 100644 (file)
@@ -55,6 +55,14 @@ struct Object : public Value {
                return ss.str();
        }
 
+       template <typename Type>
+       void push(const std::string& key, const Type& data)
+       {
+               auto value = std::make_shared<Value>();
+               *value = data;
+               this->pairs[key] = std::move(value);
+       }
+
        Value& operator[](const char* key)
        {
                if (!this->exist(key))
index e6821dc..6b120e0 100644 (file)
@@ -79,19 +79,47 @@ TEST(JsonTests, string_type_mismatch)
        }
 }
 
-TEST(JsonTests, object)
+TEST(JsonTests, array)
 {
-       Json root, child;
-       child["int"] = 1;
-       child["string"] = "initial value";
+       Array array;
+       array.push(100);
+       array.push("string");
+
+       EXPECT_EQ(array.size(), 2);
+       EXPECT_EQ(array.serialize(), "[ 100, \"string\" ]");
 
-       root.push("child", child);
-       EXPECT_EQ(root.size(), 1);
+       EXPECT_EQ(static_cast<int>(array.at(0)), 100);
+       EXPECT_EQ(static_cast<std::string>(array.at(1)), "string");
+
+       Json json;
+       json.push("array", array);
+       EXPECT_EQ(json.size(), 1);
 
-       auto result = root.pop("child");
-       EXPECT_EQ(root.size(), 0);
+       auto& result = json.get<Array>("array");
+       EXPECT_EQ(json.size(), 1);
        EXPECT_EQ(result.size(), 2);
 
+       EXPECT_EQ(static_cast<int>(result.at(0)), 100);
+       EXPECT_EQ(static_cast<std::string>(result.at(1)), "string");
+}
+
+TEST(JsonTests, object)
+{
+       Object object;
+       object["int"] = 1;
+       object["string"] = "initial value";
+
+       EXPECT_EQ(object.size(), 2);
+       EXPECT_EQ(object.serialize(), "{ \"string\": \"initial value\", \"int\": 1 }");
+
+       EXPECT_EQ(static_cast<int>(object["int"]), 1);
+       EXPECT_EQ(static_cast<std::string>(object["string"]), "initial value");
+
+       Json json;
+       json.push("object", object);
+       EXPECT_EQ(json.size(), 1);
+
+       auto result = json.get<Object>("object");
        EXPECT_EQ(static_cast<int>(result["int"]), 1);
        EXPECT_EQ(static_cast<std::string>(result["string"]), "initial value");
 }
@@ -104,7 +132,7 @@ TEST(JsonTests, serialize)
        // expected: { "string": "root value", "int": 1 }
        EXPECT_EQ(json.serialize(), "{ \"string\": \"root value\", \"int\": 1 }");
 
-       Json child;
+       Object child;
        child["int"] = 2;
        child["string"] = "child value";
        json.push("child", child);