Skip to content

Commit

Permalink
Merge be21e5a into e886233
Browse files Browse the repository at this point in the history
  • Loading branch information
fktn-k committed Sep 17, 2023
2 parents e886233 + be21e5a commit 486f180
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 9 deletions.
4 changes: 4 additions & 0 deletions clang_tidy/ClangTidyHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
#include "fkYAML/Node.hpp"
#include "fkYAML/NodeType.hpp"
#include "fkYAML/NodeTypeTraits.hpp"
#include "fkYAML/OrderedMap.hpp"
#include "fkYAML/Serializer.hpp"
#include "fkYAML/VersioningMacros.hpp"
#include "fkYAML/YAMLVersionType.hpp"

// This is just a dummy main function for compilation.
int main()
Expand Down
4 changes: 2 additions & 2 deletions include/fkYAML/Node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

#include <cstdint>
#include <cstring>
#include <map>
#include <memory>
#include <string>
#include <type_traits>
Expand All @@ -22,6 +21,7 @@
#include "fkYAML/Exception.hpp"
#include "fkYAML/Iterator.hpp"
#include "fkYAML/NodeType.hpp"
#include "fkYAML/OrderedMap.hpp"
#include "fkYAML/YAMLVersionType.hpp"

/**
Expand All @@ -44,7 +44,7 @@ FK_YAML_NAMESPACE_BEGIN
*/
template <
template <typename, typename...> class SequenceType = std::vector,
template <typename, typename, typename...> class MappingType = std::map, typename BooleanType = bool,
template <typename, typename, typename...> class MappingType = OrderedMap, typename BooleanType = bool,
typename SignedIntegerType = std::int64_t, typename UnsignedIntegerType = std::uint64_t,
typename FloatNumberType = double, typename StringType = std::string>
class BasicNode
Expand Down
150 changes: 150 additions & 0 deletions include/fkYAML/OrderedMap.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/**
* @file Deserializer.hpp
* @brief Implementation of a minimal map-like container which preserves insertion order.
*
* Copyright (c) 2023 fktn
* Distributed under the MIT License (https://opensource.org/licenses/MIT)
*/

#ifndef FK_YAML_ORDERED_MAP_HPP_
#define FK_YAML_ORDERED_MAP_HPP_

#include <functional>
#include <initializer_list>
#include <memory>
#include <utility>
#include <vector>

#include "fkYAML/VersioningMacros.hpp"
#include "fkYAML/Exception.hpp"

/**
* @namespace fkyaml
* @brief namespace for fkYAML library.
*/
FK_YAML_NAMESPACE_BEGIN

/**
* @brief A minimal map-like container which preserves insertion order.
*
* @tparam Key
* @tparam Value
* @tparam IgnoredCompare
* @tparam Allocator
*/
template <
typename Key, typename Value, typename IgnoredCompare = std::less<Key>,
typename Allocator = std::allocator<std::pair<const Key, Value>>>
class OrderedMap : public std::vector<std::pair<const Key, Value>, Allocator>
{
public:
using key_type = Key;
using mapped_type = Value;
using Container = std::vector<std::pair<const Key, Value>, Allocator>;
using value_type = typename Container::value_type;
using iterator = typename Container::iterator;
using const_iterator = typename Container::const_iterator;
using size_type = typename Container::size_type;
using key_compare = std::equal_to<Key>;

public:
/**
* @brief Construct a new OrderedMap object.
*/
OrderedMap() noexcept(noexcept(Container()))
: Container(),
m_compare()
{
}

/**
* @brief Construct a new OrderedMap object with an initializer list.
*
* @param init An initializer list to construct the inner container object.
*/
OrderedMap(std::initializer_list<value_type> init)
: Container {init},
m_compare()
{
}

public:
mapped_type& operator[](const key_type& key) noexcept
{
return emplace(key, mapped_type()).first->second;
}

public:
// NOLINTNEXTLINE(readability-identifier-naming)
std::pair<iterator, bool> emplace(const key_type& key, const mapped_type& value) noexcept
{
for (auto itr = this->begin(); itr != this->end(); ++itr)
{
if (m_compare(itr->first, key))
{
return {itr, false};
}
}
this->emplace_back(key, value);
return {std::prev(this->end()), true};
}

// NOLINTNEXTLINE(readability-identifier-naming)
mapped_type& at(const key_type& key)
{
for (auto itr = this->begin(); itr != this->end(); ++itr)
{
if (m_compare(itr->first, key))
{
return itr->second;
}
}
throw Exception("key not found.");
}

// NOLINTNEXTLINE(readability-identifier-naming)
const mapped_type& at(const key_type& key) const
{
for (auto itr = this->begin(); itr != this->end(); ++itr)
{
if (m_compare(itr->first, key))
{
return itr->second;
}
}
throw Exception("key not found.");
}

// NOLINTNEXTLINE(readability-identifier-naming)
iterator find(const key_type& key) noexcept
{
for (auto itr = this->begin(); itr != this->end(); ++itr)
{
if (m_compare(itr->first, key))
{
return itr;
}
}
return this->end();
}

// NOLINTNEXTLINE(readability-identifier-naming)
const_iterator find(const key_type& key) const noexcept
{
for (auto itr = this->begin(); itr != this->end(); ++itr)
{
if (m_compare(itr->first, key))
{
return itr;
}
}
return this->end();
}

private:
key_compare m_compare;
};

FK_YAML_NAMESPACE_END

#endif /* FK_YAML_ORDERED_MAP_HPP_ */
10 changes: 5 additions & 5 deletions include/fkYAML/Serializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class BasicSerializer
}

private:
void SerializeNode(BasicNodeType& node, const uint32_t cur_indent, std::string& str, bool is_seq_item = false)
void SerializeNode(BasicNodeType& node, const uint32_t cur_indent, std::string& str)
{
switch (node.Type())
{
Expand All @@ -52,21 +52,21 @@ class BasicSerializer
if (seq_item.IsScalar())
{
str += " ";
SerializeNode(seq_item, cur_indent, str, true);
SerializeNode(seq_item, cur_indent, str);
str += "\n";
}
else
{
str += "\n";
SerializeNode(seq_item, cur_indent + 2, str, true);
SerializeNode(seq_item, cur_indent + 2, str);
}
}
break;
case NodeType::MAPPING:
for (auto itr = node.Begin(); itr != node.End(); ++itr)
{
InsertIndentation(cur_indent, str);
SerializeKey(itr.Key(), cur_indent, str);
SerializeKey(itr.Key(), str);
if (itr->IsScalar())
{
str += " ";
Expand Down Expand Up @@ -132,7 +132,7 @@ class BasicSerializer
}
}

void SerializeKey(const std::string& key, const uint32_t cur_indent, std::string& str)
void SerializeKey(const std::string& key, std::string& str)
{
str += key + ":";
}
Expand Down
1 change: 1 addition & 0 deletions test/unit_test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ set(TEST_TARGET "fkYAMLUnitTest")

add_executable(${TEST_TARGET}
ExceptionClassTest.cpp
OrderedMapClassTest.cpp
NodeClassTest.cpp
IteratorClassTest.cpp
LexicalAnalyzerClassTest.cpp
Expand Down
102 changes: 102 additions & 0 deletions test/unit_test/OrderedMapClassTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* OrderedMapClassTest.cpp - implementation of test functions for the OrderedMap class
*
* Copyright (c) 2023 fktn
* Distributed under the MIT License (https://opensource.org/licenses/MIT)
*/

#include "catch2/catch.hpp"

#include <string>

#include "fkYAML/OrderedMap.hpp"

TEST_CASE("OrderedMapClassTest_DefaultCtorTest", "[OrderedMapClassTest]")
{
fkyaml::OrderedMap<std::string, bool> map;
REQUIRE(map.empty());
}

TEST_CASE("OrderedMapClassTest_InitListCtorTest", "[OrderedMapClassTest]")
{
fkyaml::OrderedMap<std::string, bool> map {{"foo", true}, {"bar", false}};
REQUIRE_FALSE(map.empty());
REQUIRE(map.size() == 2);
REQUIRE(map["foo"] == true);
REQUIRE(map["bar"] == false);
REQUIRE_NOTHROW(map.at("foo"));
REQUIRE_NOTHROW(map.at("bar"));
REQUIRE_THROWS_AS(map.at("buz"), fkyaml::Exception);
auto itr = map.begin();
REQUIRE(itr->first == "foo");
REQUIRE(itr->second == true);
++itr;
REQUIRE(itr->first == "bar");
REQUIRE(itr->second == false);
}

TEST_CASE("OrderedMapClassTest_SubscriptOperatorTest", "[OrderedMapClassTest]")
{
fkyaml::OrderedMap<std::string, bool> map {{"foo", true}, {"buz", false}};
REQUIRE(map["foo"] == true);
REQUIRE(map["bar"] == false);
REQUIRE(map["buz"] == false);
map["buz"] = true;
REQUIRE(map["buz"] == true);
}

TEST_CASE("OrderedMapClassTest_EmplaceTest", "[OrderedMapClassTest]")
{
fkyaml::OrderedMap<std::string, bool> map;
REQUIRE(map.emplace("foo", true).second == true);
REQUIRE(map.emplace("foo", false).second == false);
REQUIRE(map["foo"] == true);
REQUIRE(map.emplace("bar", false).second == true);
REQUIRE(map["bar"] == false);
}

TEST_CASE("OrderedMapClassTest_NonConstAtTest", "[OrderedMapClassTest]")
{
fkyaml::OrderedMap<std::string, bool> map;
REQUIRE_THROWS_AS(map.at("foo"), fkyaml::Exception);
map.emplace("foo", true);
REQUIRE_NOTHROW(map.at("foo"));
REQUIRE(map.at("foo") == true);
REQUIRE_THROWS_AS(map.at("bar"), fkyaml::Exception);
}

TEST_CASE("OrderedMapClassTest_ConstAtTest", "[OrderedMapClassTest]")
{
const fkyaml::OrderedMap<std::string, bool> map;
REQUIRE_THROWS_AS(map.at("foo"), fkyaml::Exception);
fkyaml::OrderedMap<std::string, bool> map_ = map;
map_.emplace("foo", true);
const fkyaml::OrderedMap<std::string, bool> map__ = map_;
REQUIRE_NOTHROW(map__.at("foo"));
REQUIRE(map__.at("foo") == true);
REQUIRE_THROWS_AS(map.at("bar"), fkyaml::Exception);
}

TEST_CASE("OrderedMapClassTest_NonConstFindTest", "[OrderedMapClassTest]")
{
fkyaml::OrderedMap<std::string, bool> map;
REQUIRE(map.find("foo") == map.end());
map.emplace("foo", true);
REQUIRE(map.find("foo") != map.end());
REQUIRE(map.find("foo")->first == "foo");
REQUIRE(map.find("foo")->second == true);
REQUIRE(map.find("bar") == map.end());
}

TEST_CASE("OrderedMapClassTest_ConstFindTest", "[OrderedMapClassTest]")
{
const fkyaml::OrderedMap<std::string, bool> map;
REQUIRE(map.find("foo") == map.end());
fkyaml::OrderedMap<std::string, bool> map_ = map;
map_.emplace("foo", true);
const fkyaml::OrderedMap<std::string, bool> map__ = map_;
REQUIRE(map__.find("foo") != map__.end());
REQUIRE(map__.find("foo")->first == "foo");
REQUIRE(map__.find("foo")->second == true);
REQUIRE(map__.find("bar") == map__.end());
}
4 changes: 2 additions & 2 deletions test/unit_test/SerializerClassTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ TEST_CASE("SerializerClassTest_SerializeSequenceNode", "[SerializerClassTest]")
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.
"-\n foo: -1234\n bar: null\n"));
fkyaml::Serializer serializer;
REQUIRE(serializer.Serialize(node_str_pair.first) == node_str_pair.second);
}
Expand All @@ -33,7 +33,7 @@ TEST_CASE("SerializerClassTest_SerializeMappingNode", "[SerializerClassTest]")
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.
"foo: -1234\nbar: null\n"),
NodeStrPair(
fkyaml::Node::Mapping(
{{"foo",
Expand Down

0 comments on commit 486f180

Please sign in to comment.