-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #75 from fktn-k/feature/5_implement_serialize_yaml…
…_nodes #5 implemented yaml node serializer
- Loading branch information
Showing
3 changed files
with
262 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
/** | ||
* @file Deserializer.hpp | ||
* @brief Implementation of the serializer for YAML nodes. | ||
* | ||
* Copyright (c) 2023 fktn | ||
* Distributed under the MIT License (https://opensource.org/licenses/MIT) | ||
*/ | ||
|
||
#ifndef FK_YAML_SERIALIZER_HPP_ | ||
#define FK_YAML_SERIALIZER_HPP_ | ||
|
||
#include <cmath> | ||
#include <sstream> | ||
#include <string> | ||
|
||
#include "fkYAML/VersioningMacros.hpp" | ||
#include "fkYAML/Exception.hpp" | ||
#include "fkYAML/Node.hpp" | ||
#include "fkYAML/NodeType.hpp" | ||
#include "fkYAML/NodeTypeTraits.hpp" | ||
|
||
FK_YAML_NAMESPACE_BEGIN | ||
|
||
template <typename BasicNodeType = Node> | ||
class BasicSerializer | ||
{ | ||
static_assert(IsBasicNode<BasicNodeType>::value, "BasicSerializer only accepts (const) BasicNode<...>"); | ||
|
||
public: | ||
/** | ||
* @brief Construct a new BasicSerializer object. | ||
*/ | ||
BasicSerializer() = default; | ||
|
||
std::string Serialize(BasicNodeType& node) | ||
{ | ||
std::string str {}; | ||
SerializeNode(node, 0, str); | ||
return str; | ||
} | ||
|
||
private: | ||
void SerializeNode(BasicNodeType& node, const uint32_t cur_indent, std::string& str, bool is_seq_item = false) | ||
{ | ||
switch (node.Type()) | ||
{ | ||
case NodeType::SEQUENCE: | ||
for (auto& seq_item : node) | ||
{ | ||
InsertIndentation(cur_indent, str); | ||
str += "-"; | ||
if (seq_item.IsScalar()) | ||
{ | ||
str += " "; | ||
SerializeNode(seq_item, cur_indent, str, true); | ||
str += "\n"; | ||
} | ||
else | ||
{ | ||
str += "\n"; | ||
SerializeNode(seq_item, cur_indent + 2, str, true); | ||
} | ||
} | ||
break; | ||
case NodeType::MAPPING: | ||
for (auto itr = node.Begin(); itr != node.End(); ++itr) | ||
{ | ||
InsertIndentation(cur_indent, str); | ||
SerializeKey(itr.Key(), cur_indent, str); | ||
if (itr->IsScalar()) | ||
{ | ||
str += " "; | ||
SerializeNode(*itr, cur_indent, str); | ||
str += "\n"; | ||
} | ||
else | ||
{ | ||
str += "\n"; | ||
SerializeNode(*itr, cur_indent + 2, str); | ||
} | ||
} | ||
break; | ||
case NodeType::NULL_OBJECT: | ||
str += "null"; | ||
break; | ||
case NodeType::BOOLEAN: | ||
if (node.ToBoolean()) | ||
{ | ||
str += "true"; | ||
} | ||
else | ||
{ | ||
str += "false"; | ||
} | ||
break; | ||
case NodeType::SIGNED_INTEGER: | ||
str += std::to_string(node.ToSignedInteger()); | ||
break; | ||
case NodeType::UNSIGNED_INTEGER: | ||
str += std::to_string(node.ToUnsignedInteger()); | ||
break; | ||
case NodeType::FLOAT_NUMBER: { | ||
typename BasicNodeType::float_number_type float_val = node.ToFloatNumber(); | ||
if (std::isnan(float_val)) | ||
{ | ||
str += ".nan"; | ||
} | ||
else if (std::isinf(float_val)) | ||
{ | ||
if (float_val == std::numeric_limits<typename BasicNodeType::float_number_type>::infinity()) | ||
{ | ||
str += ".inf"; | ||
} | ||
else | ||
{ | ||
str += "-.inf"; | ||
} | ||
} | ||
else | ||
{ | ||
std::stringstream ss; | ||
ss << node.ToFloatNumber(); | ||
str += ss.str(); | ||
} | ||
break; | ||
} | ||
case NodeType::STRING: | ||
str += node.ToString(); | ||
break; | ||
default: | ||
throw Exception("Unsupported node type found."); | ||
} | ||
} | ||
|
||
void SerializeKey(const std::string& key, const uint32_t cur_indent, std::string& str) | ||
{ | ||
str += key + ":"; | ||
} | ||
|
||
void InsertIndentation(const uint32_t cur_indent, std::string& str) | ||
{ | ||
for (uint32_t i = 0; i < cur_indent; ++i) | ||
{ | ||
str += " "; | ||
} | ||
} | ||
}; | ||
|
||
using Serializer = BasicSerializer<>; | ||
|
||
FK_YAML_NAMESPACE_END | ||
|
||
#endif /* FK_YAML_SERIALIZER_HPP_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
/** | ||
* SerializerClassTest.cpp - implementation of test functions for the Serializer class | ||
* | ||
* Copyright (c) 2023 fktn | ||
* Distributed under the MIT License (https://opensource.org/licenses/MIT) | ||
*/ | ||
|
||
#include "catch2/catch.hpp" | ||
|
||
#include <limits> | ||
|
||
#include "fkYAML/Node.hpp" | ||
#include "fkYAML/Serializer.hpp" | ||
|
||
TEST_CASE("SerializerClassTest_SerializeSequenceNode", "[SerializerClassTest]") | ||
{ | ||
using NodeStrPair = std::pair<fkyaml::Node, std::string>; | ||
auto node_str_pair = GENERATE( | ||
NodeStrPair( | ||
fkyaml::Node::Sequence({fkyaml::Node::BooleanScalar(true), fkyaml::Node::BooleanScalar(false)}), | ||
"- true\n- false\n"), | ||
NodeStrPair( | ||
fkyaml::Node::Sequence( | ||
{fkyaml::Node::Mapping({{"foo", fkyaml::Node::SignedIntegerScalar(-1234)}, {"bar", fkyaml::Node()}})}), | ||
"-\n bar: null\n foo: -1234\n")); // FIXME: keep insertion order. | ||
fkyaml::Serializer serializer; | ||
REQUIRE(serializer.Serialize(node_str_pair.first) == node_str_pair.second); | ||
} | ||
|
||
TEST_CASE("SerializerClassTest_SerializeMappingNode", "[SerializerClassTest]") | ||
{ | ||
using NodeStrPair = std::pair<fkyaml::Node, std::string>; | ||
auto node_str_pair = GENERATE( | ||
NodeStrPair( | ||
fkyaml::Node::Mapping({{"foo", fkyaml::Node::SignedIntegerScalar(-1234)}, {"bar", fkyaml::Node()}}), | ||
"bar: null\nfoo: -1234\n"), // FIXME: keep insertion order. | ||
NodeStrPair( | ||
fkyaml::Node::Mapping( | ||
{{"foo", | ||
fkyaml::Node::Sequence({fkyaml::Node::BooleanScalar(true), fkyaml::Node::BooleanScalar(false)})}}), | ||
"foo:\n - true\n - false\n")); | ||
fkyaml::Serializer serializer; | ||
REQUIRE(serializer.Serialize(node_str_pair.first) == node_str_pair.second); | ||
} | ||
|
||
TEST_CASE("SerializerClassTest_SerializeNullNode", "[SerializerClassTest]") | ||
{ | ||
fkyaml::Serializer serializer; | ||
fkyaml::Node node; | ||
REQUIRE(serializer.Serialize(node) == "null"); | ||
} | ||
|
||
TEST_CASE("SerializerClassTest_SerializeBooleanNode", "[SerializerClassTest]") | ||
{ | ||
using NodeStrPair = std::pair<fkyaml::Node, std::string>; | ||
auto node_str_pair = GENERATE( | ||
NodeStrPair(fkyaml::Node::BooleanScalar(false), "false"), | ||
NodeStrPair(fkyaml::Node::BooleanScalar(true), "true")); | ||
fkyaml::Serializer serializer; | ||
REQUIRE(serializer.Serialize(node_str_pair.first) == node_str_pair.second); | ||
} | ||
|
||
TEST_CASE("SerializerClassTest_SerializeSignedIntegerNode", "[SerializerClassTest]") | ||
{ | ||
using NodeStrPair = std::pair<fkyaml::Node, std::string>; | ||
auto node_str_pair = GENERATE( | ||
NodeStrPair(fkyaml::Node::SignedIntegerScalar(-1234), "-1234"), | ||
NodeStrPair(fkyaml::Node::SignedIntegerScalar(5678), "5678")); | ||
fkyaml::Serializer serializer; | ||
REQUIRE(serializer.Serialize(node_str_pair.first) == node_str_pair.second); | ||
} | ||
|
||
TEST_CASE("SerializeClassTest_SerializeUnsignedIntegerNode", "[SerializeClassTest]") | ||
{ | ||
using NodeStrPair = std::pair<fkyaml::Node, std::string>; | ||
auto node_str_pair = GENERATE( | ||
NodeStrPair(fkyaml::Node::UnsignedIntegerScalar(1234), "1234"), | ||
NodeStrPair(fkyaml::Node::UnsignedIntegerScalar(5678), "5678")); | ||
fkyaml::Serializer serializer; | ||
REQUIRE(serializer.Serialize(node_str_pair.first) == node_str_pair.second); | ||
} | ||
|
||
TEST_CASE("SerializeClassTest_SerializeFloatNumberNode", "[SerializeClassTest]") | ||
{ | ||
using NodeStrPair = std::pair<fkyaml::Node, std::string>; | ||
auto node_str_pair = GENERATE( | ||
NodeStrPair(fkyaml::Node::FloatNumberScalar(3.14), "3.14"), | ||
NodeStrPair(fkyaml::Node::FloatNumberScalar(-53.97), "-53.97"), | ||
NodeStrPair( | ||
fkyaml::Node::FloatNumberScalar(std::numeric_limits<fkyaml::NodeFloatNumberType>::infinity()), ".inf"), | ||
NodeStrPair( | ||
fkyaml::Node::FloatNumberScalar(-1 * std::numeric_limits<fkyaml::NodeFloatNumberType>::infinity()), | ||
"-.inf"), | ||
NodeStrPair(fkyaml::Node::FloatNumberScalar(std::nan("")), ".nan")); | ||
fkyaml::Serializer serializer; | ||
REQUIRE(serializer.Serialize(node_str_pair.first) == node_str_pair.second); | ||
} | ||
|
||
TEST_CASE("SerializerClassTest_SerializeStringNode", "[SerializerClassTest]") | ||
{ | ||
using NodeStrPair = std::pair<fkyaml::Node, std::string>; | ||
auto node_str_pair = GENERATE( | ||
NodeStrPair(fkyaml::Node::StringScalar("test"), "test"), | ||
NodeStrPair(fkyaml::Node::StringScalar("foo bar"), "foo bar")); | ||
|
||
fkyaml::Serializer serializer; | ||
REQUIRE(serializer.Serialize(node_str_pair.first) == node_str_pair.second); | ||
} |