21#include <unordered_map>
36 std::vector<std::string>,
37 std::unordered_map<std::string, std::any>
90 if (!std::filesystem::exists(config_file)) {
95 std::ifstream file(config_file);
96 if (!file.is_open()) {
103 while (std::getline(file, line)) {
120 std::ofstream file(config_file);
121 if (!file.is_open()) {
125 std::lock_guard<std::mutex> lock(
mutex_);
126 for (
const auto& [key, value] :
config_) {
145 auto result = it->second(path, value);
152 bool had_value =
false;
155 std::lock_guard<std::mutex> lock(
mutex_);
157 old_value = it->second;
182 T
get(
const std::string& path,
const T& default_value = T{})
const {
183 std::lock_guard<std::mutex> lock(
mutex_);
187 return std::get<T>(it->second);
188 }
catch (
const std::bad_variant_access&) {
192 return default_value;
203 std::lock_guard<std::mutex> lock(
mutex_);
207 return std::get<T>(it->second);
208 }
catch (
const std::bad_variant_access&) {
220 bool has(
const std::string& path)
const {
221 std::lock_guard<std::mutex> lock(
mutex_);
231 std::lock_guard<std::mutex> lock(
mutex_);
232 return config_.erase(path) > 0;
256 it->second.erase(
id);
257 if (it->second.empty()) {
269 std::lock_guard<std::mutex> lock(
mutex_);
279 std::lock_guard<std::mutex> lock(
mutex_);
281 for (
const auto& [path, value] :
config_) {
283 auto path_result = it->second(path, value);
284 if (!path_result.is_valid) {
286 for (
const auto&
error : path_result.errors) {
290 for (
const auto&
warning : path_result.warnings) {
305 const std::unordered_map<std::string, config_value>& config) {
306 for (
const auto& [key, value] : config) {
307 set(system_name +
"." + key, value);
317 const std::string& system_name)
const {
318 std::unordered_map<std::string, config_value>
result;
319 std::string prefix = system_name +
".";
321 std::lock_guard<std::mutex> lock(
mutex_);
322 for (
const auto& [key, value] :
config_) {
323 if (key.starts_with(prefix)) {
324 result[key.substr(prefix.length())] = value;
335 std::lock_guard<std::mutex> lock(
mutex_);
353 if (line.empty() || line[0] ==
'#' || line[0] ==
';') {
357 auto pos = line.find(
'=');
358 if (pos != std::string::npos) {
359 std::string key = line.substr(0, pos);
360 std::string value_str = line.substr(pos + 1);
363 key.erase(0, key.find_first_not_of(
" \t"));
364 key.erase(key.find_last_not_of(
" \t") + 1);
365 value_str.erase(0, value_str.find_first_not_of(
" \t"));
366 value_str.erase(value_str.find_last_not_of(
" \t") + 1);
370 if (value_str ==
"true" || value_str ==
"false") {
371 value = (value_str ==
"true");
372 }
else if (std::all_of(value_str.begin(), value_str.end(), ::isdigit)) {
373 value = std::stoi(value_str);
376 value = std::stod(value_str);
390 return std::visit([](
const auto& v) -> std::string {
391 using T = std::decay_t<
decltype(v)>;
392 if constexpr (std::is_same_v<T, bool>) {
393 return v ?
"true" :
"false";
394 }
else if constexpr (std::is_same_v<T, std::string>) {
396 }
else if constexpr (std::is_arithmetic_v<T>) {
397 return std::to_string(v);
411 if (a.index() != b.index()) {
414 return std::visit([&b](
const auto& val_a) ->
bool {
415 using T = std::decay_t<
decltype(val_a)>;
416 const auto& val_b = std::get<T>(b);
417 if constexpr (std::is_same_v<T, std::unordered_map<std::string, std::any>>) {
420 return val_a == val_b;
433 for (
const auto& [
id,
callback] : it->second) {
440 for (
const auto& [
id,
callback] : it->second) {
448 std::unordered_map<std::string, config_value>
config_;
450 std::unordered_map<std::string, std::unordered_map<std::size_t, change_callback>>
callbacks_;
Configuration manager for unified system configuration.
std::string value_to_string(const config_value &value) const
Convert value to string.
void notify_change(const std::string &path, const config_value &value)
Notify change callbacks.
std::unordered_map< std::string, std::unordered_map< std::size_t, change_callback > > callbacks_
void remove_callback(const std::string &path, std::size_t id)
Unregister a change callback.
std::size_t next_callback_id_
configuration_manager(std::shared_ptr< event_bus > bus=nullptr)
Constructor.
bool save_to_file(const std::filesystem::path &config_file) const
Save configuration to file.
void clear()
Clear all configuration.
std::function< validation_result(const std::string &, const config_value &)> validator_func
Configuration validator.
void parse_config_line(const std::string &line)
Parse a configuration line.
std::unordered_map< std::string, config_value > get_system_config(const std::string &system_name) const
Get configuration for a specific system.
bool remove(const std::string &path)
Remove a configuration value.
std::optional< T > get_optional(const std::string &path) const
Get a configuration value as optional.
validation_result validate_all() const
Validate all configuration.
std::shared_ptr< event_bus > event_bus_
void add_validator(const std::string &path, validator_func validator)
Register a configuration validator.
void apply_system_config(const std::string &system_name, const std::unordered_map< std::string, config_value > &config)
Apply configuration for a specific system.
bool values_equal(const config_value &a, const config_value &b) const
Check if two values are equal.
std::function< void(const std::string &, const config_value &)> change_callback
Configuration change callback.
bool load_from_file(const std::filesystem::path &config_file)
Load configuration from file.
std::mutex callbacks_mutex_
bool set(const std::string &path, const config_value &value)
Set a configuration value.
std::size_t on_change(const std::string &path, change_callback callback)
Register a change callback.
bool has(const std::string &path) const
Check if configuration exists.
std::unordered_map< std::string, config_value > config_
std::unordered_map< std::string, validator_func > validators_
T get(const std::string &path, const T &default_value=T{}) const
Get a configuration value.
static configuration_manager & instance()
Get singleton instance.
Represents an error in the thread system.
A template class representing either a value or an error.
Type-safe publish-subscribe event bus for thread system events.
@ callback
Call user callback for custom decision.
Core threading foundation of the thread system library.
std::variant< bool, int, double, std::string, std::vector< std::string >, std::unordered_map< std::string, std::any > > config_value
Configuration value type.
Configuration changed event.
Configuration validation result.
void add_warning(const std::string &warning)
void add_error(const std::string &error)
std::vector< std::string > errors
std::vector< std::string > warnings