diff options
-rw-r--r-- | include/cru/common/Base.hpp | 2 | ||||
-rw-r--r-- | include/cru/common/PropertyTree.hpp | 63 | ||||
-rw-r--r-- | include/cru/common/String.hpp | 5 | ||||
-rw-r--r-- | src/common/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/common/PropertyTree.cpp | 71 | ||||
-rw-r--r-- | test/common/CMakeLists.txt | 1 | ||||
-rw-r--r-- | test/common/PropertyTreeTest.cpp | 26 |
7 files changed, 168 insertions, 1 deletions
diff --git a/include/cru/common/Base.hpp b/include/cru/common/Base.hpp index ef5727c5..cb06cc09 100644 --- a/include/cru/common/Base.hpp +++ b/include/cru/common/Base.hpp @@ -36,7 +36,7 @@ classname(classname&&) = delete; \ classname& operator=(classname&&) = delete; -#define CRU_DEFAULT_DESTRUCTOR(classname) ~classname() override = default; +#define CRU_DEFAULT_DESTRUCTOR(classname) ~classname() = default; #define CRU_DEFAULT_CONSTRUCTOR_DESTRUCTOR(classname) \ classname() = default; \ diff --git a/include/cru/common/PropertyTree.hpp b/include/cru/common/PropertyTree.hpp new file mode 100644 index 00000000..01b50dac --- /dev/null +++ b/include/cru/common/PropertyTree.hpp @@ -0,0 +1,63 @@ +#pragma once + +#include "Base.hpp" +#include "String.hpp" + +#include <unordered_map> + +namespace cru { +class PropertyTree; + +class PropertySubTreeRef { + public: + static String CombineKey(StringView left, StringView right); + + explicit PropertySubTreeRef(PropertyTree* tree, String path = {}); + + CRU_DEFAULT_COPY(PropertySubTreeRef); + CRU_DEFAULT_MOVE(PropertySubTreeRef); + + CRU_DEFAULT_DESTRUCTOR(PropertySubTreeRef); + + public: + PropertyTree* GetTree() const { return tree_; } + + String GetPath() const { return path_; } + void SetPath(String path) { path_ = std::move(path); } + + PropertySubTreeRef GetParent() const; + PropertySubTreeRef GetChild(const String& key) const; + + String GetValue(const String& key) const; + void SetValue(const String& key, String value); + void DeleteValue(const String& key); + + private: + PropertyTree* tree_; + String path_; +}; + +class PropertyTree { + public: + static String CombineKey(StringView left, StringView right); + + PropertyTree() = default; + explicit PropertyTree(std::unordered_map<String, String> values); + + CRU_DELETE_COPY(PropertyTree); + CRU_DELETE_MOVE(PropertyTree); + + CRU_DEFAULT_DESTRUCTOR(PropertyTree); + + public: + String GetValue(const String& key) const; + void SetValue(const String& key, String value); + void DeleteValue(const String& key); + + PropertySubTreeRef GetSubTreeRef(const String& path); + + private: + std::unordered_map<String, String> values_; +}; + +} // namespace cru diff --git a/include/cru/common/String.hpp b/include/cru/common/String.hpp index 0ae223cf..8acb6a87 100644 --- a/include/cru/common/String.hpp +++ b/include/cru/common/String.hpp @@ -82,6 +82,8 @@ class CRU_BASE_API String { String(std::initializer_list<value_type> l); + explicit String(StringView str); + #ifdef CRU_PLATFORM_WINDOWS String(const wchar_t* str); String(const wchar_t* str, Index size); @@ -259,6 +261,7 @@ class CRU_BASE_API StringView { ~StringView() = default; + bool empty() const { return size_ == 0; } Index size() const { return size_; } const value_type* data() const { return ptr_; } @@ -405,6 +408,8 @@ inline void String::append(StringView str) { inline String String::From(StringView str) { return str.ToString(); } +inline String::String(StringView str) : String(str.data(), str.size()) {} + inline String ToString(StringView value) { return value.ToString(); } inline CodePoint Utf16PreviousCodePoint(StringView str, Index current, diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index e07017bb..5cc60690 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -1,6 +1,7 @@ set(CRU_BASE_INCLUDE_DIR ${CRU_INCLUDE_DIR}/cru/common) add_library(cru_base SHARED Logger.cpp + PropertyTree.cpp String.cpp StringUtil.cpp ) diff --git a/src/common/PropertyTree.cpp b/src/common/PropertyTree.cpp new file mode 100644 index 00000000..cc3e9cb5 --- /dev/null +++ b/src/common/PropertyTree.cpp @@ -0,0 +1,71 @@ +#include "cru/common/PropertyTree.hpp" +#include <unordered_map> +#include "cru/common/Exception.hpp" + +namespace cru { +String PropertySubTreeRef::CombineKey(StringView left, StringView right) { + return PropertyTree::CombineKey(left, right); +} + +PropertySubTreeRef::PropertySubTreeRef(PropertyTree* tree, String path) + : tree_(tree), path_(std::move(path)) { + Expects(tree); +} + +PropertySubTreeRef PropertySubTreeRef::GetParent() const { + for (Index i = path_.size() - 1; i >= 0; i--) { + if (path_[i] == '.') { + return PropertySubTreeRef(tree_, path_.substr(0, i)); + } + } + + return PropertySubTreeRef(tree_, {}); +} + +PropertySubTreeRef PropertySubTreeRef::GetChild(const String& key) const { + return PropertySubTreeRef(tree_, CombineKey(path_, key)); +} + +String PropertySubTreeRef::GetValue(const String& key) const { + return tree_->GetValue(CombineKey(path_, key)); +} + +void PropertySubTreeRef::SetValue(const String& key, String value) { + tree_->SetValue(CombineKey(path_, key), std::move(value)); +} + +void PropertySubTreeRef::DeleteValue(const String& key) { + tree_->DeleteValue(CombineKey(path_, key)); +} + +String PropertyTree::CombineKey(StringView left, StringView right) { + return String(left) + String(left.empty() ? u"" : u".") + String(right); +} + +PropertyTree::PropertyTree(std::unordered_map<String, String> values) + : values_(std::move(values)) {} + +String PropertyTree::GetValue(const String& key) const { + auto it = values_.find(key); + if (it == values_.end()) { + throw Exception(u"Property tree has no value."); + } + return it->second; +} + +void PropertyTree::SetValue(const String& key, String value) { + values_[key] = std::move(value); +} + +void PropertyTree::DeleteValue(const String& key) { + auto it = values_.find(key); + if (it != values_.end()) { + values_.erase(it); + } +} + +PropertySubTreeRef PropertyTree::GetSubTreeRef(const String& path) { + return PropertySubTreeRef(this, path); +} + +} // namespace cru diff --git a/test/common/CMakeLists.txt b/test/common/CMakeLists.txt index 730607d2..810c68d5 100644 --- a/test/common/CMakeLists.txt +++ b/test/common/CMakeLists.txt @@ -1,5 +1,6 @@ add_executable(cru_base_test HandlerRegistryTest.cpp + PropertyTreeTest.cpp StringTest.cpp StringUtilTest.cpp ) diff --git a/test/common/PropertyTreeTest.cpp b/test/common/PropertyTreeTest.cpp new file mode 100644 index 00000000..03b8971a --- /dev/null +++ b/test/common/PropertyTreeTest.cpp @@ -0,0 +1,26 @@ +#include "cru/common/PropertyTree.hpp" + +#include <gtest/gtest.h> + +TEST(PropertyTree, Test) { + using cru::PropertySubTreeRef; + using cru::PropertyTree; + + PropertyTree tree({ + {u"k1", u"v1"}, + {u"k2", u"v2"}, + {u"k3.sub", u"v3"}, + }); + + ASSERT_EQ(tree.GetValue(u"k1"), u"v1"); + ASSERT_EQ(tree.GetValue(u"k2"), u"v2"); + ASSERT_EQ(tree.GetValue(u"k3.sub"), u"v3"); + + PropertySubTreeRef sub_tree = tree.GetSubTreeRef(u"k3"); + ASSERT_EQ(sub_tree.GetValue(u"sub"), u"v3"); + + PropertySubTreeRef root_tree = sub_tree.GetParent(); + ASSERT_EQ(root_tree.GetValue(u"k1"), u"v1"); + ASSERT_EQ(root_tree.GetValue(u"k2"), u"v2"); + ASSERT_EQ(root_tree.GetValue(u"k3.sub"), u"v3"); +} |