1. Config
1.1 ConfigVarBase
配置变量基类:每个配置的变量都有变量名name
和变量描述description
两个基础成员变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class ConfigVarBase { public: typedef std::shared_ptr<ConfigVarBase> ptr; ConfigVarBase(const std::string& name, const std::string& description = "") :m_name(name) , m_description(description) { std::transform(m_name.begin(), m_name.end(), m_name.begin(), ::tolower); }
virtual ~ConfigVarBase() {}
const std::string& getName() const { return m_name; } const std::string& getDescription() const { return m_description; } virtual std::string toString() = 0; virtual bool fromString(const std::string& val) = 0; virtual std::string getTypeName() const = 0; protected: std::string m_name; std::string m_description; };
|
1.2 ConfigVar
- 成员变量
T m_val
:保存变量本身
- 成员变量
std::map<uint64_t, on_change_cb> m_cbs
:回调函数,变量变化调用
- 父类成员变量
name
:变量名
- 父类成员变量
description
:描述变量作用
- 成员方法
toString()
:将m_val
转换为YAML String
- 成员方法
fronString()
:将YAML String
转换为m_val
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| template<class T, class FromStr = LexicalCast<std::string, T> , class ToStr = LexicalCast<T, std::string> > class ConfigVar : public ConfigVarBase { public: typedef std::shared_ptr<ConfigVar> ptr; typedef std::function<void(const T& old_value, const T& new_value)> on_change_cb;
ConfigVar(const std::string& name , const T& default_value , const std::string& description = "") :ConfigVarBase(name, description) , m_val(default_value) { }
std::string toString() override { try { return boost::lexical_cast<std::string>(m_val); RWMutexType::ReadLock lock(m_mutex); return ToStr()(m_val); } catch (std::exception& e) { SYLAR_LOG_ERROR(SYLAR_LOG_ROOT()) << "ConfigVar::toString exception " << e.what() << " convert: " << TypeToName<T>() << " to string" << " name=" << m_name; } return ""; }
bool fromString(const std::string& val) override { try { setValue(FromStr()(val)); } catch (std::exception& e) { SYLAR_LOG_ERROR(SYLAR_LOG_ROOT()) << "ConfigVar::fromString exception " << e.what() << " convert: string to " << TypeToName<T>() << " name=" << m_name << " - " << val; } return false; }
const T getValue() { RWMutexType::ReadLock lock(m_mutex); return m_val; }
void setValue(const T& v) { { RWMutexType::ReadLock lock(m_mutex); if (v == m_val) { return; } for (auto& i : m_cbs) { i.second(m_val, v); } } RWMutexType::WriteLock lock(m_mutex); m_val = v; }
std::string getTypeName() const override { return TypeToName<T>(); }
uint64_t addListener(on_change_cb cb) { static uint64_t s_fun_id = 0; RWMutexType::WriteLock lock(m_mutex); ++s_fun_id; m_cbs[s_fun_id] = cb; return s_fun_id; } void delListener(uint64_t key) { RWMutexType::WriteLock lock(m_mutex); m_cbs.erase(key); }
on_change_cb getListener(uint64_t key) { RWMutexType::ReadLock lock(m_mutex); auto it = m_cbs.find(key); return it == m_cbs.end() ? nullptr : it->second; } void clearListener() { RWMutexType::WriteLock lock(m_mutex); m_cbs.clear(); } private: RWMutexType m_mutex; T m_val; std::map<uint64_t, on_change_cb> m_cbs; };
|
1.3 Config
- 静态成员变量
ConfigVarMap
:定义为unordered_map<std::string, ConfigVarBase::ptr>
,保存了全部配置文件的属性名以及对应的属性值
- 静态成员函数
Lookup()
:根据参数名,返回一个ConfigVar<T>
配置参数
- 如果已存在参数名
- 如果参数名和类型都相同,返回该参数
- 如果类型名不相同,返回空指针
- 如果不存在参数名,创建
ConfigVar<T>
并返回
- 成员函数
LoadFromYaml()
:从YAML
格式文档加载到一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| class Config { public: typedef std::unordered_map<std::string, ConfigVarBase::ptr> ConfigVarMap; typedef RWMutex RWMutexType; template<class T> static typename ConfigVar<T>::ptr Lookup(const std::string& name, const T& default_value, const std::string& description = "") { RWMutexType::WriteLock lock(GetMutex()); auto it = GetDatas().find(name); if (it != GetDatas().end()) { auto tmp = std::dynamic_pointer_cast<ConfigVar<T>>(it->second); if (tmp) { SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << "Lookup name=" << name << " exists"; return tmp; } else { SYLAR_LOG_ERROR(SYLAR_LOG_ROOT()) << "Lookup name=" << name << " exists but type not " << TypeToName<T>() << " real_type=" << it->second->getTypeName() << " " << it->second->toString(); return nullptr; } }
if (name.find_first_not_of("abcdefghikjlmnopqrstuvwxyz._012345678") != std::string::npos) { SYLAR_LOG_ERROR(SYLAR_LOG_ROOT()) << "Lookup name invalid " << name; throw std::invalid_argument(name); }
typename ConfigVar<T>::ptr v(new ConfigVar<T>(name, default_value, description)); GetDatas()[name] = v; return v; }
template<class T> static typename ConfigVar<T>::ptr Lookup(const std::string& name) { RWMutexType::ReadLock lock(GetMutex()); auto it = GetDatas().find(name); if (it == GetDatas().end()) { return nullptr; } return std::dynamic_pointer_cast<ConfigVar<T>>(it->second); }
static void LoadFromYaml(const YAML::Node& root); static void LoadFromConfDir(const std::string& path, bool force = false); static ConfigVarBase::ptr LookupBase(const std::string& name); static void Visit(std::function<void(ConfigVarBase::ptr)> cb);
private: static ConfigVarMap& GetDatas() { static ConfigVarMap s_datas; return s_datas; }
static RWMutexType& GetMutex() { static RWMutexType s_mutex; return s_mutex; } };
|
2. LexicalCast
2.1 泛型类型转换
1 2 3 4 5 6 7
| template<class F, class T> class LexicalCast { public: T operator()(const F& v) { return boost::lexical_cast<T>(v); } };
|
2.2 偏特化类型转换
下面是几个例子方便理解,其他的大同小异不再列举
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| template<class T> class LexicalCast<std::string, std::vector<T> > { public: std::vector<T> operator()(const std::string& v) { YAML::Node node = YAML::Load(v); typename std::vector<T> vec; std::stringstream ss; for (size_t i = 0; i < node.size(); ++i) { ss.str(""); ss << node[i]; vec.push_back(LexicalCast<std::string, T>()(ss.str())); } return vec; } };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| template<class T> class LexicalCast<std::string, std::set<T> > { public: std::set<T> operator()(const std::string& v) { YAML::Node node = YAML::Load(v); typename std::set<T> vec; std::stringstream ss; for (size_t i = 0; i < node.size(); ++i) { ss.str(""); ss << node[i]; vec.insert(LexicalCast<std::string, T>()(ss.str())); } return vec; } };
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| template<class T> class LexicalCast<std::set<T>, std::string> { public: std::string operator()(const std::set<T>& v) { YAML::Node node(YAML::NodeType::Sequence); for (auto& i : v) { node.push_back(YAML::Load(LexicalCast<T, std::string>()(i))); } std::stringstream ss; ss << node; return ss.str(); } };
|
3. Config使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13
| void test_config() { sylar::ConfigVar<int>::ptr g_int_value_config = sylar::Config::Lookup("system.port", (int)8080, "system port"); sylar::ConfigVar<std::map<std::string, std::string>>::ptr g_int_map_config = sylar::Config::Lookup("system.userid", std::map<std::string, std::string>{{"xuan", "0001"}}, "system str int map");
SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << "system.port: " << sylar::Config::Lookup<int>("system.port")->toString(); SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << "system.userid: " << sylar::Config::Lookup<std::map<std::string, std::string>>("system.userid")->toString(); }
|
Author:
mxwu
Permalink:
https://mingxuanwu.com/2024/07/01/202407011705/
License:
Copyright (c) 2023 CC-BY-NC-4.0 LICENSE