Commit 09beed9d authored by tqcq's avatar tqcq
Browse files

feat add config

parent 56068d35
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ target_include_directories(sled PUBLIC src/ 3party/eigen 3party/inja
target_sources(
  sled
  PRIVATE src/sled/async/async.cc
          src/sled/config.cc
          src/sled/debugging/demangle.cc
          src/sled/debugging/symbolize.cc
          src/sled/event_bus/event_bus.cc
@@ -194,6 +195,7 @@ if(SLED_BUILD_TESTS)
  sled_add_test(NAME sled_string_view_test SRCS
                src/sled/nonstd/string_view_test.cc)
  sled_add_test(NAME sled_expected_test SRCS src/sled/nonstd/expected_test.cc)
  sled_add_test(NAME sled_config_test SRCS src/sled//config_test.cc)
endif(SLED_BUILD_TESTS)

if(SLED_BUILD_FUZZ)

src/sled/config.cc

0 → 100644
+228 −0
Original line number Diff line number Diff line
#include "sled/config.h"
#include "sled/log/log.h"
#include "sled/strings/utils.h"
#include <fstream>

namespace sled {
Config::Config() = default;

Config::Config(sled::string_view name) : Config(name, "") {}

Config::Config(sled::string_view name, sled::string_view path) : config_name_(name)
{
    config_paths_.emplace_back(path.to_string());
}

void
Config::SetConfigName(sled::string_view name)
{
    config_name_ = name.to_string();
}

void
Config::AddConfigPath(sled::string_view path)
{
    config_paths_.emplace_back(path.to_string());
}

bool
Config::ReadInConfig()
{
    const static std::vector<std::string> extensions = {".toml"};
    for (const auto &path : config_paths_) {
        auto name = path + config_name_;
        for (const auto &ext : extensions) {
            const std::ifstream file(name + ext);
            if (file.good()) {
                try {
                    std::stringstream ss;
                    ss << file.rdbuf();

                    std::istringstream stream_data(ss.str(), std::ios_base::binary | std::ios_base::in);
                    toml_ = toml::parse(stream_data, "string");
                    return true;
                    // goto config_read_success;
                } catch (...) {
                    LOGD("Failed to parse config file: {}", name + ext);
                }
            }
        }
    }

    // config_read_success:
    //     // pair<key, value>
    //     for (auto &pair : default_values_) {
    //         toml::value value;
    //         if (!GetNode(pair.first, value)) { AddDefaultNode(pair.first, pair.second); }
    //     }

    return false;
}

bool
Config::IsSet(sled::string_view key) const
{
    toml::value value;
    return GetNode(key, value);
}

bool
Config::GetBoolOr(sled::string_view key, const bool &def) const
{
    toml::value value;
    try {
        if (GetNode(key, value) && value.is_boolean()) { return value.as_boolean(); }
    } catch (...) {}
    return def;
}

int
Config::GetIntOr(sled::string_view key, const int &def) const
{
    toml::value value;
    try {
        if (GetNode(key, value)) {
            if (value.is_integer()) {
                return value.as_integer();
            } else if (value.is_boolean()) {
                return value.as_boolean() ? 1 : 0;
            } else if (value.is_floating()) {
                return static_cast<int>(value.as_floating());
            }
        }
    } catch (...) {}
    return def;
}

double
Config::GetDoubleOr(sled::string_view key, const double &def) const
{
    toml::value value;
    try {
        if (GetNode(key, value)) {
            if (value.is_floating()) {
                return value.as_floating();
            } else if (value.is_integer()) {
                return static_cast<double>(value.as_integer());
            }
        }
    } catch (...) {}
    return def;
}

std::string
Config::GetStringOr(sled::string_view key, sled::string_view def) const
{
    toml::value value;
    try {
        if (GetNode(key, value) && value.is_string()) { return value.as_string(); }
    } catch (...) {}
    return def.to_string();
}

void
Config::SetDefault(sled::string_view key, const bool &value)
{
    default_values_.insert({key.to_string(), value});
}

void
Config::SetDefault(sled::string_view key, const char *value)
{
    SetDefault(key, std::string(value));
}

void
Config::SetDefault(sled::string_view key, const std::string &value)
{
    default_values_.insert({key.to_string(), value});
}

void
Config::SetDefault(sled::string_view key, sled::string_view value)
{
    SetDefault(key, std::string(value));
}

void
Config::SetDefault(sled::string_view key, const int &value)
{
    default_values_.insert({key.to_string(), value});
}

void
Config::SetDefault(sled::string_view key, const double &value)
{
    default_values_.insert({key.to_string(), value});
}

bool
Config::GetNode(sled::string_view key, toml::value &value) const
{
    auto keys = StrSplit(key.to_string(), ".");
    auto cur  = toml_;
    for (const auto &k : keys) {
        try {
            auto next = toml::find(cur, k);
            cur       = next;
        } catch (...) {
            if (GetDefaultNode(key, value)) { return true; }
            return false;
        }
    }
    value = cur;
    return true;
}

bool
Config::AddDefaultNode(sled::string_view key, ValueType value)
{
    auto keys = StrSplit(key.to_string(), ".");
    if (keys.size() == 1) {
        auto first_key = keys[0];
        switch (value.index()) {
        case 0:
            toml_[first_key] = sled::get<bool>(value);
            break;
        case 1:
            toml_[first_key] = sled::get<std::string>(value);
            break;
        case 2:
            toml_[first_key] = sled::get<int>(value);
            break;
        case 3:
            toml_[first_key] = sled::get<double>(value);
            break;
        default:
            return false;
        }
        return true;
    }
    return false;
}

bool
Config::GetDefaultNode(sled::string_view key, toml::value &value) const
{
    auto iter = default_values_.find(key.to_string());
    if (iter == default_values_.end()) { return false; }
    auto &default_value = iter->second;
    switch (default_value.index()) {
    case 0:
        value = sled::get<bool>(default_value);
        break;
    case 1:
        value = sled::get<std::string>(default_value);
        break;
    case 2:
        value = sled::get<int>(default_value);
        break;
    case 3:
        value = sled::get<double>(default_value);
        break;
    default:
        return false;
    }
    return true;
}
}// namespace sled

src/sled/config.h

0 → 100644
+49 −0
Original line number Diff line number Diff line
#ifndef SLED_CONFIG_H
#define SLED_CONFIG_H

#include "sled/nonstd/string_view.h"
#include "sled/variant.h"
#include "toml.hpp"

namespace sled {
class Config {
public:
    using ValueType = sled::variant<bool, std::string, int, double>;
    Config();
    Config(sled::string_view name);
    Config(sled::string_view name, sled::string_view path);
    Config(const Config &lhs)                = delete;
    Config(Config &&rhs) noexcept            = delete;
    Config &operator=(const Config &lhs)     = delete;
    Config &operator=(Config &&rhs) noexcept = delete;

    void SetConfigName(sled::string_view name);
    void AddConfigPath(sled::string_view path);

    bool ReadInConfig();

    bool IsSet(sled::string_view key) const;
    bool GetBoolOr(sled::string_view key, const bool &def = false) const;
    int GetIntOr(sled::string_view key, const int &def = 0) const;
    double GetDoubleOr(sled::string_view key, const double &def = 0.0) const;
    std::string GetStringOr(sled::string_view key, const sled::string_view def = "") const;

    void SetDefault(sled::string_view key, const bool &value);
    void SetDefault(sled::string_view key, const char *value);
    void SetDefault(sled::string_view key, const std::string &value);
    void SetDefault(sled::string_view key, sled::string_view value);
    void SetDefault(sled::string_view key, const int &value);
    void SetDefault(sled::string_view key, const double &value);

private:
    bool GetNode(sled::string_view key, toml::value &value) const;
    bool AddDefaultNode(sled::string_view, ValueType value);
    bool GetDefaultNode(sled::string_view key, toml::value &value) const;

    std::unordered_map<std::string, ValueType> default_values_;
    std::vector<std::string> config_paths_;
    std::string config_name_;
    toml::value toml_;
};
}// namespace sled
#endif// SLED_CONFIG_H
+33 −0
Original line number Diff line number Diff line
#include <sled/config.h>
#include <sled/strings/utils.h>

static std::string test_config_name = "config_test";
static std::string test_config_path = sled::StripSuffix(__FILE__, "config_test.cc").to_string();

TEST_SUITE("Config")
{
    TEST_CASE("config")
    {
        sled::Config config;
        config.SetConfigName(test_config_name);
        config.AddConfigPath(test_config_path);
        config.SetDefault("top-string", "no effect");
        config.SetDefault("top-kk", "kk");
        CHECK(config.ReadInConfig());

        CHECK(config.IsSet("top-string"));
        CHECK_EQ(config.GetStringOr("top-string"), "bob");

        CHECK(config.IsSet("top-kk"));
        CHECK_EQ(config.GetStringOr("top-kk"), "kk");

        CHECK(config.IsSet("top-int"));
        CHECK(config.IsSet("top-bool"));
        CHECK_EQ(config.GetIntOr("top-int"), 10);
        CHECK_EQ(config.GetBoolOr("top-bool"), true);
        CHECK_EQ(config.GetIntOr("top-bool"), 1);

        CHECK(config.IsSet("top-table.key1"));
        CHECK_EQ(config.GetStringOr("top-table.key1"), "value1");
    }
}
+24 −0
Original line number Diff line number Diff line
top-string = "bob"
top-int = 10
top-bool = true
top-array = [ "item1", "item2", "item3" ]
nested-array = [
    [ "nested-item1-subitem1", "nested-item1-subitem2"],
    [ "nested-item2-subitem1", "nested-item2-subitem2"]
]

[top-table]
key1 = "value1"
key2 = "value2"
key3 = "value3"

# Nested table
[nested-table.key1]

key1-subkey1 = "value1-1"
key1-subkey2 = "value1-2"

[nested-table.key2]

key2-subkey1 = "value2-1"
key2-subkey2 = "value2-2"
Loading