feat/update_config #10
@ -219,6 +219,7 @@ set(TILE_SRCS
|
|||||||
"tile/base/config/ini_file_configuration.cc"
|
"tile/base/config/ini_file_configuration.cc"
|
||||||
"tile/base/config/json_configuration.cc"
|
"tile/base/config/json_configuration.cc"
|
||||||
"tile/base/config/layered_configuration.cc"
|
"tile/base/config/layered_configuration.cc"
|
||||||
|
"tile/base/config/toml_configuration.cc"
|
||||||
)
|
)
|
||||||
|
|
||||||
if((NOT TILE_HAVE_GETIFADDRS) OR (NOT TILE_HAVE_FREEIFADDRS))
|
if((NOT TILE_HAVE_GETIFADDRS) OR (NOT TILE_HAVE_FREEIFADDRS))
|
||||||
@ -243,6 +244,7 @@ target_include_directories(
|
|||||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
${THIRD_PARTY_INCLUDE_DIRS}
|
${THIRD_PARTY_INCLUDE_DIRS}
|
||||||
RPIVATE
|
RPIVATE
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/third_party/header_only/"
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include")
|
"${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include")
|
||||||
|
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
|
3
third_party/README.md
vendored
Normal file
3
third_party/README.md
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Library
|
||||||
|
|
||||||
|
- [toml11](https://github.com/ToruNiina/toml11/archive/refs/tags/v4.2.0.tar.gz)
|
17241
third_party/header_only/toml.hpp
vendored
Normal file
17241
third_party/header_only/toml.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,6 @@
|
|||||||
#include "tile/base/config/json_configuration.h"
|
#include "tile/base/config/json_configuration.h"
|
||||||
|
|
||||||
|
#include "gmock/gmock-matchers.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
namespace tile {
|
namespace tile {
|
||||||
@ -85,16 +86,11 @@ TEST(json_configuration, Enumerate)
|
|||||||
ASSERT_TRUE(config.load(istr));
|
ASSERT_TRUE(config.load(istr));
|
||||||
auto keys = config.keys("");
|
auto keys = config.keys("");
|
||||||
ASSERT_EQ(5, keys.size());
|
ASSERT_EQ(5, keys.size());
|
||||||
ASSERT_EQ("key1", keys[0]);
|
ASSERT_THAT(keys, ::testing::UnorderedElementsAre("key1", "key2", "key3", "key4", "key5"));
|
||||||
ASSERT_EQ("key2", keys[1]);
|
|
||||||
ASSERT_EQ("key3", keys[2]);
|
|
||||||
ASSERT_EQ("key4", keys[3]);
|
|
||||||
ASSERT_EQ("key5", keys[4]);
|
|
||||||
|
|
||||||
keys = config.keys("key5");
|
keys = config.keys("key5");
|
||||||
ASSERT_EQ(2, keys.size());
|
ASSERT_EQ(2, keys.size());
|
||||||
ASSERT_EQ("key5.key51", keys[0]);
|
ASSERT_THAT(keys, ::testing::UnorderedElementsAre("key5.key51", "key5.key52"));
|
||||||
ASSERT_EQ("key5.key52", keys[1]);
|
|
||||||
|
|
||||||
config.Remove("key5.key51");
|
config.Remove("key5.key51");
|
||||||
keys = config.keys("key5");
|
keys = config.keys("key5");
|
||||||
|
219
tile/base/config/toml_configuration.cc
Normal file
219
tile/base/config/toml_configuration.cc
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
#include "tile/base/config/toml_configuration.h"
|
||||||
|
|
||||||
|
#include "tile/base/logging.h"
|
||||||
|
#include "tile/base/string.h"
|
||||||
|
#include "toml.hpp"
|
||||||
|
|
||||||
|
namespace tile {
|
||||||
|
class TomlConfiguration::Impl {
|
||||||
|
public:
|
||||||
|
Impl() {}
|
||||||
|
|
||||||
|
~Impl() = default;
|
||||||
|
|
||||||
|
bool load(std::istream &istr)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
value_ = toml::parse(istr);
|
||||||
|
return true;
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load(const std::string &path)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
value_ = toml::parse(path);
|
||||||
|
return true;
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toml::value *operator->() { return &value_; }
|
||||||
|
|
||||||
|
toml::value &operator*() { return value_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
toml::value value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TomlConfiguration::TomlConfiguration() : impl_(new Impl) {}
|
||||||
|
|
||||||
|
TomlConfiguration::~TomlConfiguration() {}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TomlConfiguration::load(std::istream &istr)
|
||||||
|
{
|
||||||
|
return impl_->load(istr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TomlConfiguration::load(const std::string &path)
|
||||||
|
{
|
||||||
|
return impl_->load(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TomlConfiguration::SetInt(const Slice &key, int value)
|
||||||
|
{
|
||||||
|
Configuration::SetInt(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TomlConfiguration::SetBool(const Slice &key, bool value)
|
||||||
|
{
|
||||||
|
Configuration::SetBool(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TomlConfiguration::SetDouble(const Slice &key, double value)
|
||||||
|
{
|
||||||
|
Configuration::SetDouble(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TomlConfiguration::SetString(const Slice &key, const std::string &value)
|
||||||
|
{
|
||||||
|
Configuration::SetString(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
TomlConfiguration::Dump() const
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return toml::format(**impl_);
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
TILE_LOG_WARNING_EVERY_SECOND("{}", e.what());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TomlConfiguration::GetRaw(const Slice &key, std::string *value) const
|
||||||
|
{
|
||||||
|
if (key.empty()) { return false; }
|
||||||
|
auto keys = Split(key, '.');
|
||||||
|
|
||||||
|
try {
|
||||||
|
auto cur = **impl_;
|
||||||
|
for (const auto &k : keys) {
|
||||||
|
auto next = toml::find(cur, k);
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
std::stringstream ss;
|
||||||
|
if (cur.is_string()) {
|
||||||
|
ss << cur.as_string();
|
||||||
|
} else if (cur.is_integer()) {
|
||||||
|
ss << cur.as_integer();
|
||||||
|
} else if (cur.is_boolean()) {
|
||||||
|
ss << cur.as_boolean();
|
||||||
|
} else if (cur.is_floating()) {
|
||||||
|
ss << cur.as_floating();
|
||||||
|
} else if (cur.is_empty()) {
|
||||||
|
ss << "";
|
||||||
|
} else {
|
||||||
|
ss << toml::format(cur);
|
||||||
|
}
|
||||||
|
*value = ss.str();
|
||||||
|
return true;
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
TILE_LOG_WARNING_EVERY_SECOND("{}", e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TomlConfiguration::SetRaw(const Slice &key, const Slice &value)
|
||||||
|
{
|
||||||
|
if (key.empty()) { return false; }
|
||||||
|
auto keys = Split(key, '.');
|
||||||
|
try {
|
||||||
|
auto &root = **impl_;
|
||||||
|
for (size_t i = 0; i < keys.size() - 1; ++i) {
|
||||||
|
auto &next = toml::find(root, keys[i]);
|
||||||
|
root = next;
|
||||||
|
}
|
||||||
|
root[keys.back()] = value.ToString();
|
||||||
|
return true;
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
TILE_LOG_WARNING_EVERY_SECOND("{}", e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TomlConfiguration::RemoveRaw(const Slice &key)
|
||||||
|
{
|
||||||
|
if (key.empty()) { return; }
|
||||||
|
auto keys = Split(key, '.');
|
||||||
|
while (!keys.empty() && keys.back() == "") { keys.pop_back(); }
|
||||||
|
try {
|
||||||
|
if (keys.empty()) {
|
||||||
|
auto &root = **impl_;
|
||||||
|
root = toml::table();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto root = **impl_;
|
||||||
|
for (size_t i = 0; i + 1 < keys.size(); ++i) {
|
||||||
|
if (!root.contains(keys[i])) { return; }
|
||||||
|
root = root.at(keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!root.contains(keys.back())) { return; }
|
||||||
|
auto last_root = root.at(key.back());
|
||||||
|
|
||||||
|
// remove the last key
|
||||||
|
toml::value new_node = toml::table();
|
||||||
|
for (const auto &p : last_root.as_table()) {
|
||||||
|
if (p.first != keys.back()) { new_node[p.first] = p.second; }
|
||||||
|
}
|
||||||
|
last_root = new_node;
|
||||||
|
} catch (...) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Configuration::Keys
|
||||||
|
TomlConfiguration::Enumerate(const Slice &range) const
|
||||||
|
{
|
||||||
|
Configuration::Keys keys;
|
||||||
|
auto split_keys = Split(range, '.');
|
||||||
|
auto last_key = split_keys.empty() ? "" : split_keys.back();
|
||||||
|
std::string prefix = range;
|
||||||
|
if (!prefix.empty() && prefix.back() != '.') { prefix += "."; }
|
||||||
|
|
||||||
|
auto root = **impl_;
|
||||||
|
try {
|
||||||
|
// if (!root.is_empty()) {
|
||||||
|
for (int i = 0; i < split_keys.size(); ++i) {
|
||||||
|
auto next = toml::find(root, split_keys[i]);
|
||||||
|
root = next;
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (root.is_empty()) { return keys; }
|
||||||
|
|
||||||
|
// for (const auto &k : keys_) {
|
||||||
|
// auto next = toml::find(root, k);
|
||||||
|
// root = next;
|
||||||
|
// }
|
||||||
|
|
||||||
|
auto visitor = [&](const toml::value &node) {
|
||||||
|
if (node.is_table()) {
|
||||||
|
for (const auto &p : node.as_table()) {
|
||||||
|
/*if (EndsWith(p.first, prefix)) */ {
|
||||||
|
keys.push_back(prefix + p.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
toml::visit(visitor, root);
|
||||||
|
// TILE_LOG_INFO("{}", toml::format(root));
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
TILE_LOG_WARNING_EVERY_SECOND("{}\n{}\n", e.what(), Dump());
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
}// namespace tile
|
40
tile/base/config/toml_configuration.h
Normal file
40
tile/base/config/toml_configuration.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef TILE_BASE_CONFIG_TOML_CONFIGURATION_H
|
||||||
|
#define TILE_BASE_CONFIG_TOML_CONFIGURATION_H
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "tile/base/config/configuration.h"
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace tile {
|
||||||
|
class TomlConfiguration : public Configuration {
|
||||||
|
public:
|
||||||
|
using Ptr = RefPtr<TomlConfiguration>;
|
||||||
|
|
||||||
|
TomlConfiguration();
|
||||||
|
~TomlConfiguration() override;
|
||||||
|
|
||||||
|
bool load(std::istream &istr);
|
||||||
|
bool load(const std::string &path);
|
||||||
|
|
||||||
|
void SetInt(const Slice &key, int value) override;
|
||||||
|
void SetBool(const Slice &key, bool value) override;
|
||||||
|
void SetDouble(const Slice &key, double value) override;
|
||||||
|
void SetString(const Slice &key, const std::string &value) override;
|
||||||
|
|
||||||
|
void RemoveRaw(const Slice &key) override;
|
||||||
|
std::string Dump() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool GetRaw(const Slice &key, std::string *value) const override;
|
||||||
|
bool SetRaw(const Slice &key, const Slice &value) override;
|
||||||
|
Keys Enumerate(const Slice &range) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Impl;
|
||||||
|
|
||||||
|
std::unique_ptr<Impl> impl_;
|
||||||
|
};
|
||||||
|
}// namespace tile
|
||||||
|
|
||||||
|
#endif// TILE_BASE_CONFIG_TOML_CONFIGURATION_H
|
71
tile/base/config/toml_configuration_test.cc
Normal file
71
tile/base/config/toml_configuration_test.cc
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include "tile/base/config/toml_configuration.h"
|
||||||
|
|
||||||
|
#include "gmock/gmock-matchers.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace tile {
|
||||||
|
namespace {
|
||||||
|
const char *kTomlConfig = R"(
|
||||||
|
key1=1
|
||||||
|
key2=2
|
||||||
|
key3=1.9
|
||||||
|
key4=true
|
||||||
|
|
||||||
|
[key5]
|
||||||
|
key51="value51"
|
||||||
|
key52=52
|
||||||
|
)";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TomlConfiguration, Load)
|
||||||
|
{
|
||||||
|
TomlConfiguration config;
|
||||||
|
std::istringstream istr(kTomlConfig);
|
||||||
|
ASSERT_TRUE(config.load(istr));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TomlConfiguration, Has)
|
||||||
|
{
|
||||||
|
TomlConfiguration config;
|
||||||
|
std::istringstream istr(kTomlConfig);
|
||||||
|
ASSERT_TRUE(config.load(istr));
|
||||||
|
ASSERT_TRUE(config.Has("key1"));
|
||||||
|
ASSERT_TRUE(config.Has("key2"));
|
||||||
|
ASSERT_TRUE(config.Has("key3"));
|
||||||
|
ASSERT_TRUE(config.Has("key4"));
|
||||||
|
ASSERT_TRUE(config.Has("key5"));
|
||||||
|
ASSERT_TRUE(config.Has("key5.key51"));
|
||||||
|
ASSERT_TRUE(config.Has("key5.key52"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TomlConfiguration, SampleSet)
|
||||||
|
{
|
||||||
|
TomlConfiguration config;
|
||||||
|
std::istringstream istr(kTomlConfig);
|
||||||
|
ASSERT_TRUE(config.load(istr));
|
||||||
|
ASSERT_TRUE(config.GetInt32("key2"));
|
||||||
|
ASSERT_EQ(*config.GetInt32("key2"), 2);
|
||||||
|
|
||||||
|
config.SetInt("key2", 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TomlConfiguration, Enumerate)
|
||||||
|
{
|
||||||
|
TomlConfiguration config;
|
||||||
|
std::istringstream istr(kTomlConfig);
|
||||||
|
ASSERT_TRUE(config.load(istr));
|
||||||
|
auto keys = config.keys("");
|
||||||
|
ASSERT_EQ(5, keys.size());
|
||||||
|
ASSERT_THAT(keys, ::testing::UnorderedElementsAre("key1", "key2", "key3", "key4", "key5"));
|
||||||
|
|
||||||
|
keys = config.keys("key5");
|
||||||
|
// for (const auto &key : keys) { TILE_LOG_INFO("key5: {}", key); }
|
||||||
|
ASSERT_EQ(2, keys.size());
|
||||||
|
ASSERT_THAT(keys, ::testing::UnorderedElementsAre("key5.key51", "key5.key52"));
|
||||||
|
|
||||||
|
config.Remove("key5.key51");
|
||||||
|
keys = config.keys("key5");
|
||||||
|
ASSERT_EQ("key5.key52", keys[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}// namespace tile
|
@ -175,8 +175,8 @@ public:
|
|||||||
inline operator string_t() const { return ToString(); }
|
inline operator string_t() const { return ToString(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char *data_;
|
const char *data_{nullptr};
|
||||||
size_t len_;
|
size_t len_{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
|
Loading…
Reference in New Issue
Block a user