26#include <boost/array.hpp>
39template<
typename Value_set>
382template<
typename... S_d_value_set>
411 "Must have even number of template args to Config_manager; use a trailing Null_value_set if needed.");
551 template<
typename... Value_set>
575 template<
typename... Value_set>
577 const fs::path& static_cfg_path,
666 const fs::path& cfg_path,
731 template<
typename... Value_set>
758 template<
typename... Value_set>
760 const fs::path& dynamic_cfg_path,
798 template<
typename... Value_set>
822 template<
typename... Value_set>
837 template<
typename Value_set>
854 template<
typename Value_set>
888 template<
typename... Value_set>
905 template<
typename Value_set>
934 template<
typename Value_set>
1007 S_STATIC_AND_DYNAMIC,
1024 template<
typename Value_set>
1037 template<
typename Value_set>
1048 template<
typename Value_set>
1067 template<
typename Value_set>
1069 bool canonicalize_else_reject,
bool* changed_or_null);
1086 template<
typename... Value_set>
1088 const fs::path& static_cfg_path,
1107 template<
typename... Value_set>
1109 const fs::path& dynamic_cfg_path,
1127 const fs::path& cfg_path,
1151 template<
typename... Value_set>
1154 const fs::path& cfg_path,
const boost::unordered_set<std::string>& all_opt_names_or_empty,
1202 template<
typename Value_set>
1204 const boost::unordered_set<std::string>& all_opt_names_or_empty,
1206 bool* skip_parsing);
1231 template<
typename Value_set>
1253 template<
typename Value_set>
1264 template<
typename Value_set>
1428template<
typename... S_d_value_set>
1444 std::list<On_dynamic_change_func>::const_iterator
m_pos;
1469template<
typename... S_d_value_set>
1474 m_nickname(nickname),
1475 m_dynamic_values_set(false),
1476 m_multi_src_update_in_progress(
Update_type::S_NONE)
1485 &&
"Must have at least 2 template args to Config_manager; otherwise what are you configuring?");
1497 bool dyn_else_st =
false;
1498 size_t value_set_idx = 0;
1499 size_t d_value_set_idx = 0;
1510 std::move(declare_opts_func_moved))),
1517 && (opt_set<S_d_value_set>(value_set_idx)->null()
1522 =
Void_ptr(
new typename S_d_value_set::Const_ptr),
1527 dyn_else_st = !dyn_else_st
1532 "managing [" <<
S_N_S_VALUE_SETS <<
"] dynamic+static option set pairs (some may be null/unused).");
1535template<
typename... S_d_value_set>
1536template<
typename Value_set>
1542 assert(value_set_idx < S_N_VALUE_SETS);
1544 (m_s_d_opt_sets[value_set_idx].get());
1547template<
typename... S_d_value_set>
1548template<
typename Value_set>
1554 assert(d_value_set_idx < S_N_D_VALUE_SETS);
1555 return static_cast<Value_set*
>
1556 (m_d_baseline_value_sets[d_value_set_idx].get());
1559template<
typename... S_d_value_set>
1560template<
typename Value_set>
1564 return const_cast<Config_manager<S_d_value_set...
>*>(
this)->opt_set<Value_set>(value_set_idx);
1567template<
typename... S_d_value_set>
1568template<
typename Value_set>
1572 if (opt_set->
null())
1576 && (*changed_or_null =
false);
1585template<
typename... S_d_value_set>
1586template<
typename Value_set>
1587typename Config_manager<S_d_value_set...>::On_dynamic_change_func_handle
1591 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Adding dynamic-change listener for dynamic value set "
1592 "[" << d_value_set_idx <<
"].");
1594 assert((d_value_set_idx < S_N_D_VALUE_SETS) &&
"Invalid dynamic option set index.");
1595 assert((!opt_set<Value_set>((d_value_set_idx * 2) + 1)->null())
1596 &&
"Do not register dynamic change listener for Null_value_set or otherwise null value set.");
1599 m_on_dynamic_change_funcs[d_value_set_idx].emplace_back(std::move(on_dynamic_change_func_moved));
1600 const auto& callback_pos = std::prev(m_on_dynamic_change_funcs[d_value_set_idx].end());
1602 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Added dynamic-change listener [@" << &(*callback_pos) <<
1603 "] for dynamic value set [" << d_value_set_idx <<
"].");
1608template<
typename... S_d_value_set>
1613 auto& on_dynamic_change_funcs = m_on_dynamic_change_funcs[handle.
m_d_value_set_idx];
1614 on_dynamic_change_funcs.erase(handle.
m_pos);
1616 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Removed dynamic-change listener [@" << &(*handle.
m_pos) <<
1620template<
typename... S_d_value_set>
1621template<
typename... Value_set>
1623 (
const fs::path& static_cfg_path,
1627 return apply_static_impl<Value_set...>(
false, static_cfg_path, final_validator_func..., commit);
1630template<
typename... S_d_value_set>
1631template<
typename... Value_set>
1634 const fs::path& static_cfg_path,
1638 return apply_static_impl<Value_set...>(
true, static_cfg_path, final_validator_func..., commit);
1641template<
typename... S_d_value_set>
1642template<
typename... Value_set>
1644 (
bool allow_invalid_defaults,
1645 const fs::path& static_cfg_path,
1649 using boost::unordered_set;
1652 using std::is_same_v;
1654 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Request to apply static config file [" << static_cfg_path <<
"]. "
1655 "Invalid defaults allowed if explicitly set in file? = [" << allow_invalid_defaults <<
"]. "
1656 "This application (if successful) shall end with canonicalizing values? = [" << commit <<
"]; "
1657 "multi-source update already in progress (0=none) = [" <<
int(m_multi_src_update_in_progress) <<
"].");
1659 reject_candidates_if_update_type_changed(Update_type::S_STATIC);
1664 static_assert(
sizeof...(Value_set) == S_N_S_VALUE_SETS,
1665 "You must supply N/2 `final_validator_func`s, where N is # of S_d_value_set params. "
1666 "Use null_final_validator_func() for any Null_value_set.");
1674 size_t value_set_idx;
1675 bool success =
true;
1679 if ((!allow_invalid_defaults) && (m_multi_src_update_in_progress == Update_type::S_NONE))
1682 [[maybe_unused]]
const auto dummy =
1687 opt_set<Value_set>(value_set_idx)
1688 ->validate_values(&success),
1697 "Request to apply static config file [" << static_cfg_path <<
"]: "
1698 "Will not parse file, because stringent check "
1699 "of defaults detected at least 1 individually-invalid default value. Either correct "
1700 "the default or use apply_static(allow_invalid_defaults_tag_t) overload.");
1705 unordered_set<string> all_opt_names;
1706 unordered_set<string>
const * this_opt_names;
1708 static_assert(is_same_v<
decltype(declval<Option_set<Null_value_set>>().option_names()),
1709 decltype(*this_opt_names)>,
1710 "Option_set<>::option_names() must return ref-to-const. Bug?");
1717 this_opt_names = &(opt_set<Value_set>
1718 (value_set_idx)->option_names()),
1719 all_opt_names.insert(this_opt_names->begin(), this_opt_names->end()),
1725 success = apply_static_or_dynamic_impl<Value_set...>
1727 static_cfg_path, all_opt_names, final_validator_func...);
1730 if ((!commit) && success)
1732 m_multi_src_update_in_progress = Update_type::S_STATIC;
1733 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Multi-source update has successfully begun or continued. "
1734 "Expecting more sources before we can canonicalize candidate(s).");
1750 option_set_canonicalize_or_reject(opt_set<Value_set>(value_set_idx),
1756 if (m_multi_src_update_in_progress != Update_type::S_NONE)
1758 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Multi-source update is now finished.");
1759 m_multi_src_update_in_progress = Update_type::S_NONE;
1763 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: State that was just made canonical follows.");
1769template<
typename... S_d_value_set>
1770template<
typename... Value_set>
1772 (
bool dyn_else_st,
const fs::path& cfg_path,
const boost::unordered_set<std::string>& all_opt_names_or_empty,
1775 size_t s_d_value_set_idx = 0;
1776 size_t value_set_idx = dyn_else_st ? 1 : 0;
1780 bool skip_parsing =
false;
1800 success = apply_impl(opt_set<Value_set>
1803 ((m_multi_src_update_in_progress == Update_type::S_NONE)
1804 && dyn_else_st && (!opt_set<Value_set>(value_set_idx)->null()))
1805 ? d_baseline_value_set<Value_set>
1807 :
static_cast<const Value_set*
>(0),
1809 cfg_path, all_opt_names_or_empty,
1810 final_validator_func,
1812 ++s_d_value_set_idx,
1819template<
typename... S_d_value_set>
1820template<
typename Value_set>
1823 const Value_set* baseline_value_set_or_null,
1824 const fs::path& cfg_path,
1825 const boost::unordered_set<std::string>& all_opt_names_or_empty,
1830 auto& opts = *opt_set;
1843 if (baseline_value_set_or_null)
1868 const auto pre_parse_candidate = candidate_or_null ? *candidate_or_null : opt_set->
values();
1872 if (skip_parsing && (*skip_parsing))
1875 "Parsing, individual-option validation, and final-validation are being skipped "
1876 "for this value set, as requested by the caller. This file's values will not be applied. "
1877 "This has happened because this value set is successive to a value set whose "
1878 "final-validation determined that it shall not be applied. This is not an error.");
1879 opts.parse_direct_values(pre_parse_candidate);
1893 opts.parse_config_file(cfg_path,
true, &ok, all_opt_names_or_empty);
1901 opts.validate_values_candidate(&ok);
1905 "Request to apply config file [" << cfg_path <<
"] for a particular value set: "
1906 "Individual values present in file were OK, but at least 1 default value (see above) "
1907 "was invalid. Either correct the default or ensure it is properly overridden in file.");
1914 const auto final_validator_outcome = final_validator_func(*opts.values_candidate());
1915 switch (final_validator_outcome)
1924 "Request to apply config file [" << cfg_path <<
"] for a particular value set: "
1925 "Individual values present in file were OK, but the final-validator logic specified "
1926 "that this file's values not be applied (to skip the file after all). "
1927 "Rewinding the candidate value-set to pre-parse state. This is not an error.");
1928 opts.parse_direct_values(pre_parse_candidate);
1931 assert((!*skip_parsing) &&
"We should have `return`ed already.");
1932 *skip_parsing =
true;
1940template<
typename... S_d_value_set>
1942 (
const fs::path& cfg_path,
1946 return apply_static_and_dynamic_impl(
false, cfg_path, final_validator_func..., commit);
1949template<
typename... S_d_value_set>
1952 const fs::path& cfg_path,
1956 return apply_static_and_dynamic_impl(
true, cfg_path, final_validator_func..., commit);
1959template<
typename... S_d_value_set>
1961 (
bool allow_invalid_defaults,
1962 const fs::path& cfg_path,
1967 using boost::unordered_set;
1970 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Request to apply config file [" << cfg_path <<
"] as both "
1971 "static config and *baseline* dynamic config. Parsing in that order for each pair. "
1972 "Invalid defaults allowed if explicitly set in file? = [" << allow_invalid_defaults <<
"]. "
1973 "This application (if successful) shall end with canonicalizing values? = [" << commit <<
"]; "
1974 "multi-source update already in progress (0=none) = [" <<
int(m_multi_src_update_in_progress) <<
"].");
1976 reject_candidates_if_update_type_changed(Update_type::S_STATIC_AND_DYNAMIC);
1984 size_t value_set_idx;
1985 bool success =
true;
1989 if ((!allow_invalid_defaults) && (m_multi_src_update_in_progress == Update_type::S_NONE))
1996 opt_set<S_d_value_set>(value_set_idx)
1997 ->validate_values(&success),
2005 FLOW_LOG_WARNING(
"Config_manager [" << *
this <<
"]: Request to apply config file [" << cfg_path <<
"] as both "
2006 "static config and *baseline* dynamic config: Will not parse file, because stringent check "
2007 "of defaults detected at least 1 individually-invalid default value. Either correct "
2008 "the default or use apply_static_and_dynamic(allow_invalid_defaults_tag_t) overload.");
2013 unordered_set<string> all_opt_names;
2014 unordered_set<string> this_opt_names;
2020 bool skip_parsing =
false;
2025 this_opt_names = opt_set<S_d_value_set>(value_set_idx)->option_names(),
2026 all_opt_names.insert(this_opt_names.begin(), this_opt_names.end()),
2037 success = apply_impl(opt_set<S_d_value_set>(value_set_idx),
2039 static_cast<const S_d_value_set*
>(0),
2040 cfg_path, all_opt_names,
2041 final_validator_func,
2049 if ((!commit) && success)
2051 m_multi_src_update_in_progress = Update_type::S_STATIC_AND_DYNAMIC;
2052 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Multi-source update has successfully begun or continued. "
2053 "Expecting more sources before we can canonicalize candidate(s).");
2068 option_set_canonicalize_or_reject
2069 (opt_set<S_d_value_set>(value_set_idx),
2075 if (m_multi_src_update_in_progress != Update_type::S_NONE)
2077 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Multi-source update is now finished.");
2078 m_multi_src_update_in_progress = Update_type::S_NONE;
2087 assert(commit &&
"Maintenance bug? We should have returned above if `!commit` but success==true.");
2089 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: State that was just made canonical follows.");
2095 bool dyn_else_st =
false;
2097 size_t d_value_set_idx = 0;
2108 && (opt_set<S_d_value_set>(value_set_idx)->null()
2109 || (*(d_baseline_value_set<S_d_value_set>(d_value_set_idx))
2110 = opt_set<S_d_value_set>(value_set_idx)->values(),
2116 dyn_else_st = !dyn_else_st
2122 Lock_guard<
decltype(m_d_value_sets_mutex)> lock(m_d_value_sets_mutex);
2124 dyn_else_st =
false;
2130 && (save_dynamic_value_set_locked<S_d_value_set>
2131 (opt_set<S_d_value_set>(value_set_idx), value_set_idx / 2),
2134 dyn_else_st = !dyn_else_st
2140 assert((!m_dynamic_values_set)
2141 &&
"User apparently attempted apply_static_and_dynamic(), but dynamic config was already initialized OK.");
2142 m_dynamic_values_set =
true;
2145 for (d_value_set_idx = 0; d_value_set_idx != S_N_D_VALUE_SETS; ++d_value_set_idx)
2147 invoke_dynamic_change_listeners(d_value_set_idx,
true);
2153template<
typename... S_d_value_set>
2154template<
typename... Value_set>
2156 (
const fs::path& dynamic_cfg_path,
2160 return apply_dynamic_impl<Value_set...>(
false, dynamic_cfg_path, final_validator_func..., commit);
2163template<
typename... S_d_value_set>
2164template<
typename... Value_set>
2167 const fs::path& dynamic_cfg_path,
2171 return apply_dynamic_impl<Value_set...>(
true, dynamic_cfg_path, final_validator_func..., commit);
2174template<
typename... S_d_value_set>
2175template<
typename... Value_set>
2177 (
bool allow_invalid_defaults,
2178 const fs::path& dynamic_cfg_path,
2187 if (m_dynamic_values_set)
2190 "Request to apply dynamic config file [" << dynamic_cfg_path <<
"]. "
2191 "Initializing dynamic config? = [false]. "
2192 "This application (if successful) shall end with canonicalizing values? = [" << commit <<
"]; "
2193 "multi-source update already in progress "
2194 "(0=none) = [" <<
int(m_multi_src_update_in_progress) <<
"].");
2199 "Request to apply dynamic config file [" << dynamic_cfg_path <<
"]. "
2200 "Initializing dynamic config? = [true]. "
2201 "Invalid defaults allowed if explicitly set in file? = [" << allow_invalid_defaults <<
"]. "
2202 "This application (if successful) shall end with canonicalizing values? = [" << commit <<
"]; "
2203 "multi-source update already in progress "
2204 "(0=none) = [" <<
int(m_multi_src_update_in_progress) <<
"].");
2207 reject_candidates_if_update_type_changed(Update_type::S_DYNAMIC);
2215 size_t value_set_idx;
2216 bool success =
true;
2220 if ((!m_dynamic_values_set) && (!allow_invalid_defaults) && (m_multi_src_update_in_progress == Update_type::S_NONE))
2223 [[maybe_unused]]
const auto dummy =
2228 opt_set<Value_set>(value_set_idx)
2229 ->validate_values(&success),
2238 "Request to initially-apply dynamic config file [" << dynamic_cfg_path <<
"]: "
2239 "Will not parse file, because stringent check "
2240 "of defaults detected at least 1 individually-invalid default value. Either correct "
2241 "the default or use apply_dynamic(allow_invalid_defaults_tag_t) overload.");
2251 && apply_static_or_dynamic_impl<Value_set...>(
true,
2252 dynamic_cfg_path, {}, final_validator_func...);
2254 if ((!commit) && success)
2256 m_multi_src_update_in_progress = Update_type::S_DYNAMIC;
2257 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Multi-source update has successfully begun or continued. "
2258 "Expecting more sources before we can canonicalize candidate(s).");
2267 size_t d_value_set_idx = 0;
2271 array<bool, S_N_D_VALUE_SETS> changed{};
2272 bool some_changed =
false;
2276 value_set_idx = (d_value_set_idx * 2) + 1,
2279 option_set_canonicalize_or_reject(opt_set<Value_set>(value_set_idx),
2282 m_dynamic_values_set ? &changed[d_value_set_idx] : 0),
2284 changed[d_value_set_idx] = (!m_dynamic_values_set) || changed[d_value_set_idx],
2286 some_changed = some_changed || changed[d_value_set_idx],
2291 if (m_multi_src_update_in_progress != Update_type::S_NONE)
2293 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Multi-source update is now finished.");
2294 m_multi_src_update_in_progress = Update_type::S_NONE;
2312 os.os() <<
"Config_manager [" << *
this <<
"]: (Dynamic) state that was just made canonical follows.\n";
2318 state_to_ostream_impl<Value_set>(value_set_idx, os.os()),
2332 Lock_guard<
decltype(m_d_value_sets_mutex)> lock(m_d_value_sets_mutex);
2333 d_value_set_idx = 0;
2337 value_set_idx = (d_value_set_idx * 2) + 1,
2339 changed[d_value_set_idx]
2340 && (save_dynamic_value_set_locked<Value_set>
2341 (opt_set<Value_set>(value_set_idx),
2349 const bool was_dynamic_values_set = m_dynamic_values_set;
2350 m_dynamic_values_set =
true;
2354 for (d_value_set_idx = 0; d_value_set_idx != S_N_D_VALUE_SETS; ++d_value_set_idx)
2356 if (changed[d_value_set_idx])
2358 invoke_dynamic_change_listeners(d_value_set_idx, !was_dynamic_values_set);
2365template<
typename... S_d_value_set>
2368 if (m_multi_src_update_in_progress == Update_type::S_NONE)
2370 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Request to abandon multi-source update in-progress; but none "
2371 "is in progress. Doing nothing.");
2376 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Request to abandon multi-source update in-progress. Doing so.");
2379 size_t value_set_idx = 0;
2385 option_set_canonicalize_or_reject
2386 (opt_set<S_d_value_set>(value_set_idx),
2392 m_multi_src_update_in_progress = Update_type::S_NONE;
2395template<
typename... S_d_value_set>
2398 assert(this_update_type != Update_type::S_NONE);
2399 if ((m_multi_src_update_in_progress == Update_type::S_NONE)
2400 || (m_multi_src_update_in_progress == this_update_type))
2406 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: An update of type [" <<
int(this_update_type) <<
"] "
2407 "is interrupting (canceling) an in-progress multi-source update of type "
2408 "[" <<
int(m_multi_src_update_in_progress) <<
"]. Reverting any uncommitted values "
2409 "from the latter. Suggest invoking reject_candidates() explicitly if intentional; this "
2410 "message will then go away, while the code will be more deliberate.");
2412 reject_candidates();
2413 assert(m_multi_src_update_in_progress == Update_type::S_NONE);
2416template<
typename... S_d_value_set>
2417template<
typename Value_set>
2421 assert(opt_set_ptr);
2422 auto& opt_set = *opt_set_ptr;
2427 *(
static_cast<typename Value_set::Const_ptr*
>(m_d_value_sets[d_value_set_idx].get()))
2429 = Value_set::const_ptr_cast(opt_set.mutable_values_copy());
2432template<
typename... S_d_value_set>
2436 "Dynamic update for dynamic option set [" << d_value_set_idx <<
"] (0-based) of "
2437 "[" << S_N_D_VALUE_SETS <<
"] (1-based); trigger was "
2438 "[" << (init ?
"initial-update" :
"change-detected") <<
"].");
2440 const auto& on_dynamic_change_funcs = m_on_dynamic_change_funcs[d_value_set_idx];
2443 for (
const auto& on_dynamic_change_func : on_dynamic_change_funcs)
2445 FLOW_LOG_INFO(
"Invoking listener [" << idx <<
"] (0-based) of [" << on_dynamic_change_funcs.size() <<
"] "
2447 on_dynamic_change_func();
2450 FLOW_LOG_INFO(
"Done invoking change listeners for dynamic option set.");
2453template<
typename... S_d_value_set>
2454template<
typename... Value_set>
2457 static_assert(
sizeof...(Value_set) == S_N_S_VALUE_SETS,
2458 "You must supply N/2 `value_set_or_null`s, where N is # of S_d_value_set params. "
2459 "Use nullptr for any Null_value_set and/or Value_set of no interest.");
2461 size_t s_value_set_idx = 0;
2462 size_t value_set_idx;
2466 value_set_idx = s_value_set_idx * 2,
2468 (value_set_or_null && (!opt_set<Value_set>
2469 (value_set_idx)->null()))
2470 && (*value_set_or_null = &(opt_set<Value_set>(value_set_idx)->values()),
2477template<
typename... S_d_value_set>
2478template<
typename... Value_set>
2481 static_assert(
sizeof...(Value_set) == S_N_S_VALUE_SETS,
2482 "You must supply N/2 `value_set_or_null`s, where N is # of S_d_value_set params. "
2483 "Use nullptr for any Null_value_set and/or Value_set of no interest.");
2485 size_t s_value_set_idx = 0;
2486 size_t value_set_idx;
2490 value_set_idx = s_value_set_idx * 2,
2491 (value_set_or_null && (!opt_set<Value_set>
2492 (value_set_idx)->null()))
2498 && (*value_set_or_null = opt_set<Value_set>(value_set_idx)->values_candidate()
2500 ?: &(opt_set<Value_set>(value_set_idx)->values()),
2507template<
typename... S_d_value_set>
2508template<
typename Value_set>
2511 assert((s_value_set_idx < S_N_S_VALUE_SETS) &&
"Invalid static option set index.");
2513 return opt_set<Value_set>(s_value_set_idx * 2)->values();
2516template<
typename... S_d_value_set>
2517template<
typename Value_set>
2520 assert((s_value_set_idx < S_N_S_VALUE_SETS) &&
"Invalid static option set index.");
2522 const auto opt = opt_set<Value_set>(s_value_set_idx * 2);
2528 const Value_set* values = opt->values_candidate();
2531 values = &(opt->values());
2537template<
typename... S_d_value_set>
2538template<
typename... Value_set>
2540 (
typename Value_set::Const_ptr*... value_set_or_null)
const
2544 static_assert(
sizeof...(Value_set) == S_N_D_VALUE_SETS,
2545 "You must supply N/2 `value_set_or_null`s, where N is # of S_d_value_set params. "
2546 "Use nullptr for any Null_value_set and/or Value_set of no interest.");
2549 Lock_guard<
decltype(m_d_value_sets_mutex)> lock(m_d_value_sets_mutex);
2551 size_t d_value_set_idx = 0;
2552 size_t value_set_idx;
2556 value_set_idx = (d_value_set_idx * 2) + 1,
2558 (value_set_or_null && (!opt_set<Value_set>
2559 (value_set_idx)->null()))
2560 && (*value_set_or_null
2561 = *(
static_cast<typename Value_set::Const_ptr*
>(m_d_value_sets[d_value_set_idx].get())),
2569template<
typename... S_d_value_set>
2570template<
typename Value_set>
2571typename Value_set::Const_ptr
2576 assert((d_value_set_idx < S_N_D_VALUE_SETS) &&
"Invalid dynamic option set index.");
2579 Lock_guard<
decltype(m_d_value_sets_mutex)> lock(m_d_value_sets_mutex);
2580 return *(
static_cast<typename Value_set::Const_ptr*
>(m_d_value_sets[d_value_set_idx].get()));
2584template<
typename... S_d_value_set>
2587 os <<
"Config_manager [" << *
this <<
"]: Current state + config documentation:\n";
2589 size_t value_set_idx = 0;
2592 state_to_ostream_impl<S_d_value_set>(value_set_idx++, os)
2596template<
typename... S_d_value_set>
2597template<
typename Value_set>
2600 const auto& opts = *(opt_set<Value_set>(value_set_idx));
2607 const size_t s_d_value_set_idx = value_set_idx / 2;
2608 const bool dyn_else_st = (value_set_idx % 2) == 1;
2610 os <<
"-- [" << (dyn_else_st ?
"DYNAMIC" :
"STATIC") <<
"] [" << s_d_value_set_idx <<
"] --\n";
2614 const auto output_uncanonicalized = [&]()
2616 if (m_multi_src_update_in_progress != Update_type::S_NONE)
2620 const auto candidate_or_none = opts.values_candidate();
2621 if (candidate_or_none)
2623 os <<
" <incomplete multi-source update type [" << int(m_multi_src_update_in_progress) <<
"] in-progress / "
2624 "current candidate values follow>\n";
2625 opts.values_to_ostream(os, candidate_or_none);
2632 opts.values_to_ostream(os);
2633 output_uncanonicalized();
2638 if (m_dynamic_values_set)
2640 opts.values_to_ostream(os);
2641 output_uncanonicalized();
2651 os <<
"<no dynamic config init payload / option docs follow instead>\n";
2652 opts.help_to_ostream(os);
2654 output_uncanonicalized();
2657template<
typename... S_d_value_set>
2664 state_to_ostream(os.os());
2669template<
typename... S_d_value_set>
2672 os <<
"Config_manager [" << *
this <<
"]: Config help:\n";
2674 size_t value_set_idx = 0;
2677 help_to_ostream_impl<S_d_value_set>(value_set_idx++, os)
2681template<
typename... S_d_value_set>
2682template<
typename Value_set>
2685 const auto opts = opt_set<Value_set>(value_set_idx);
2692 const size_t s_d_value_set_idx = value_set_idx / 2;
2693 const bool dyn_else_st = (value_set_idx % 2) == 1;
2695 os <<
"-- [" << (dyn_else_st ?
"DYNAMIC" :
"STATIC") <<
"] [" << s_d_value_set_idx <<
"] --\n";
2696 opts->help_to_ostream(os);
2699template<
typename... S_d_value_set>
2706 help_to_ostream(os.os());
2711template<
typename Value_set>
2717template<
typename... S_d_value_set>
2720 return os <<
'[' << val.
m_nickname <<
"]@" << &val;
Manages a config setup, intended for a single daemon process, by maintaining 1 or more set(s) of stat...
void log_help(log::Sev sev=log::Sev::S_INFO) const
Logs what help_to_ostream() would print.
boost::array< std::list< On_dynamic_change_func >, S_N_D_VALUE_SETS > m_on_dynamic_change_funcs
List of callbacks to execute after m_d_value_sets members (the pointers) are next assigned: one per e...
void state_to_ostream(std::ostream &os) const
Prints a human-targeted long-form summary of our contents, doubling as a usage message and a dump of ...
void log_state(log::Sev sev=log::Sev::S_INFO) const
Logs what state_to_ostream() would print.
bool apply_static(const fs::path &static_cfg_path, const typename Final_validator_func< Value_set >::Type &... final_validator_func, bool commit=true)
Invoke this after construction to load the permanent set of static config from config sources includi...
bool apply_dynamic(allow_invalid_defaults_tag_t, const fs::path &dynamic_cfg_path, const typename Final_validator_func< Value_set >::Type &... final_validator_func, bool commit=true)
Identical to apply_dynamic() overload without allow_invalid_defaults_tag_t tag; except that – applica...
bool apply_dynamic(const fs::path &dynamic_cfg_path, const typename Final_validator_func< Value_set >::Type &... final_validator_func, bool commit=true)
Load the first or subsequent set of dynamic config from config source including a dynamic config file...
void option_set_canonicalize_or_reject(Option_set< Value_set > *opt_set, bool canonicalize_else_reject, bool *changed_or_null)
Helper that executes opt_set->canonicalize_candidate() or opt_set->reject_candidate().
Option_set< Value_set > * opt_set(size_t value_set_idx)
Helper that obtains the Option_set in the slot m_s_d_opt_sets[value_set_idx], which stores an Option_...
boost::array< Void_ptr, S_N_D_VALUE_SETS > m_d_value_sets
The dynamic config ref-counted handles returned by all_dynamic_values().
boost::array< Void_ptr, S_N_D_VALUE_SETS > m_d_baseline_value_sets
The baseline dynamic value sets, in the same order as S_N_D_VALUE_SETS dynamic S_d_value_set template...
void unregister_dynamic_change_listener(const On_dynamic_change_func_handle &handle)
Remove a previously registered dynamic change callback.
boost::array< Void_ptr, S_N_VALUE_SETS > m_s_d_opt_sets
The static and dynamic value sets, in the same order as the S_N_VALUE_SETS S_d_value_set template arg...
void invoke_dynamic_change_listeners(size_t d_value_set_idx, bool init) const
Invokes the registered listeners for the given dynamic config slot (synchronously).
bool apply_static_and_dynamic(allow_invalid_defaults_tag_t, const fs::path &cfg_path, const typename Final_validator_func< S_d_value_set >::Type &... final_validator_func, bool commit=true)
Identical to apply_static_and_dynamic() overload without allow_invalid_defaults_tag_t tag; but skips ...
void all_static_values_candidates(const Value_set **... value_set_or_null) const
Similar to all_static_values(), but if called from within a validator function passed to apply_static...
bool apply_static_and_dynamic_impl(bool allow_invalid_defaults, const fs::path &cfg_path, const typename Final_validator_func< S_d_value_set >::Type &... final_validator_func, bool commit)
Implements all apply_static_and_dynamic() overloads.
allow_invalid_defaults_tag_t
Tag type: indicates an apply_*() method must allow invalid defaults and only complain if the config s...
@ S_ALLOW_INVALID_DEFAULTS
Sole value for tag type allow_invalid_defaults_tag_t.
const std::string m_nickname
See nickname ctor arg.
void all_dynamic_values(typename Value_set::Const_ptr *... value_set_or_null) const
Obtain ref-counted pointers to each currently-canonical set of dynamic config; each pointed-at struct...
boost::shared_ptr< void > Void_ptr
Short-hand for shared_ptr-to-void type used to store variable-type values in internal containers.
void all_static_values(const Value_set **... value_set_or_null) const
Emit a pointer to each permanently set static config value set; the same pointers are emitted through...
const Value_set & static_values(size_t s_value_set_idx) const
Similar to all_static_values(), but obtains the static config in one specified slot as opposed to all...
void save_dynamic_value_set_locked(Option_set< Value_set > *opt_set, size_t d_value_set_idx)
Little helper that, having assumed m_d_value_sets_mutex is locked, makes a newly allocated copy of th...
bool apply_dynamic_impl(bool allow_invalid_defaults, const fs::path &dynamic_cfg_path, const typename Final_validator_func< Value_set >::Type &... final_validator_func, bool commit)
Implements all apply_dynamic() overloads.
void help_to_ostream_impl(size_t value_set_idx, std::ostream &os) const
Helper of help_to_ostream() for m_s_d_opt_sets slot value_set_idx.
On_dynamic_change_func_handle register_dynamic_change_listener(size_t d_value_set_idx, On_dynamic_change_func &&on_dynamic_change_func_moved)
Saves the given callback; next time apply_dynamic(commit = true) or apply_static_and_dynamic(commit =...
static constexpr size_t S_N_S_VALUE_SETS
The number of static value sets (including any Null_value_sets).
bool apply_static_and_dynamic(const fs::path &cfg_path, const typename Final_validator_func< S_d_value_set >::Type &... final_validator_func, bool commit=true)
If you use dynamic config, and you allow for initial values for dynamic options to be read from the s...
Update_type
Useful at least in the context of multi-source (commit == false) apply_*() methods,...
bool m_dynamic_values_set
Starts false; set to true permanently on successful apply_static_and_dynamic() or apply_dynamic().
bool apply_static_or_dynamic_impl(bool dyn_else_st, const fs::path &cfg_path, const boost::unordered_set< std::string > &all_opt_names_or_empty, const typename Final_validator_func< Value_set >::Type &... final_validator_func)
Work-horse helper that parses either all static value sets or all dynamic value sets from the specifi...
util::Mutex_non_recursive m_d_value_sets_mutex
Mutex protecting m_d_value_sets.
Value_set * d_baseline_value_set(size_t d_value_set_idx)
Helper that obtains the baseline dynamic Value_set in the slot m_d_baseline_value_sets[value_set_idx]...
void reject_candidates_if_update_type_changed(Update_type this_update_type)
Helper for the top of apply_*() that guards against a call to apply_Y() following apply_X(commit == f...
void reject_candidates()
Cancel a not-yet-canonicalized (incomplete) multi-source update, if one is in progress.
Value_set::Const_ptr dynamic_values(size_t d_value_set_idx) const
Similar to all_dynamic_values() but obtains the dynamic config in one specified slot as opposed to al...
static constexpr size_t S_N_D_VALUE_SETS
The number of dynamic value sets (including any Null_value_sets).
bool apply_impl(Option_set< Value_set > *opt_set, const Value_set *baseline_value_set_or_null, const fs::path &cfg_path, const boost::unordered_set< std::string > &all_opt_names_or_empty, const typename Final_validator_func< Value_set >::Type &final_validator_func, bool *skip_parsing)
Work-horse helper that parses into one given Option_set in m_s_d_opt_sets (from opt_set()) from the s...
Update_type m_multi_src_update_in_progress
In short, truthy if and only if a commit == false update is currently in progress,...
bool apply_static_impl(bool allow_invalid_defaults, const fs::path &static_cfg_path, const typename Final_validator_func< Value_set >::Type &... final_validator_func, bool commit)
Implements all apply_static() overloads.
static constexpr size_t S_N_VALUE_SETS
The number of template params in this Config_manager instantiation. It must be even and positive.
Config_manager(log::Logger *logger_ptr, util::String_view nickname, typename Option_set< S_d_value_set >::Declare_options_func &&... declare_opts_func_moved)
Constructs a Config_manager ready to read initial config via apply_*() and other setup methods; and f...
void help_to_ostream(std::ostream &os) const
Prints a human-targeted long-form usage message that includes all options with their descriptions and...
const Value_set & static_values_candidate(size_t s_value_set_idx) const
Similar to static_values(), but if called from within a validator function passed to apply_static() o...
bool apply_static(allow_invalid_defaults_tag_t, const fs::path &static_cfg_path, const typename Final_validator_func< Value_set >::Type &... final_validator_func, bool commit=true)
Identical to apply_static() overload without allow_invalid_defaults_tag_t tag; but skips the stringen...
const Option_set< Value_set > * opt_set(size_t value_set_idx) const
const overload of the other opt_set() helper.
void state_to_ostream_impl(size_t value_set_idx, std::ostream &os) const
Helper of state_to_ostream() for m_s_d_opt_sets slot value_set_idx.
The core config-parsing facility, which builds parsing/comparison/output capabilities on top of a giv...
const Values & values() const
Externally immutable internally stored canonical (current) config values as last constructed or parse...
void canonicalize_candidate(bool *change_detected=0)
In PARSING state enters CANONICAL state, finalizing values() from values_candidate().
void reject_candidate()
In PARSING state, returns to CANONICAL state, as if no parse attempts have occurred.
bool null() const
Return true if and only if the option-declaring function passed to the constructor declared no option...
const Values * values_candidate() const
Returns null in CANONICAL state; or in PARSING state a pointer to the not-yet-canonical values after ...
void parse_direct_values(const Values &src_values)
Enters into (from CANONICAL state) or continues in PARSING state by simply setting *values_candidate(...
Convenience class that simply stores a Logger and/or Component passed into a constructor; and returns...
Logger * get_logger() const
Returns the stored Logger pointer, particularly as many FLOW_LOG_*() macros expect.
Interface that the user should implement, passing the implementing Logger into logging classes (Flow'...
Convenience class template that endows the given subclass T with nested aliases Ptr and Const_ptr ali...
Similar to ostringstream but allows fast read-only access directly into the std::string being written...
#define FLOW_LOG_INFO(ARG_stream_fragment)
Logs an INFO message into flow::log::Logger *get_logger() with flow::log::Component get_log_component...
#define FLOW_LOG_WARNING(ARG_stream_fragment)
Logs a WARNING message into flow::log::Logger *get_logger() with flow::log::Component get_log_compone...
#define FLOW_LOG_WITH_CHECKING(ARG_sev, ARG_stream_fragment)
Logs a message of the specified severity into flow::log::Logger *get_logger() with flow::log::Compone...
#define FLOW_LOG_TRACE(ARG_stream_fragment)
Logs a TRACE message into flow::log::Logger *get_logger() with flow::log::Component get_log_component...
Flow module that facilitates configuring modules, such as applications and APIs, via statically and/o...
Final_validator_outcome
Result enumeration for a Final_validator_func::Type function which is used by a Config_manager user w...
@ S_ACCEPT
The holistically-checked cumulative Value_set has no problems and shall be accepted into the candidat...
@ S_SKIP
The holistically-checked cumulative Value_set has contents such that the validator function decided t...
@ S_FAIL
The holistically-checked cumulative Value_set has invalid contents; the candidate shall be rejected,...
Option_set< Null_value_set >::Declare_options_func null_declare_opts_func()
Returns a value usable as declare_opts_func_moved Config_manager ctor arg for a Null_value_set value ...
Final_validator_func< Null_value_set >::Type null_final_validator_func()
Returns a value usable as final_validator_func arg to Config_manager::apply_static() and others – for...
std::ostream & operator<<(std::ostream &os, const Option_set< Value_set > &val)
Serializes (briefly) an Option_set to a standard output stream.
Sev
Enumeration containing one of several message severity levels, ordered from highest to lowest.
@ S_INFO
Message indicates a not-"bad" condition that is not frequent enough to be of severity Sev::S_TRACE.
boost::unique_lock< Mutex > Lock_guard
Short-hand for advanced-capability RAII lock guard for any mutex, ensuring exclusive ownership of tha...
std::string ostream_op_string(T const &... ostream_args)
Equivalent to ostream_op_to_string() but returns a new string by value instead of writing to the call...
boost::mutex Mutex_non_recursive
Short-hand for non-reentrant, exclusive mutex. ("Reentrant" = one can lock an already-locked-in-that-...
Basic_string_view< char > String_view
Commonly used char-based Basic_string_view. See its doc header.
Flow_log_component
The flow::log::Component payload enumeration comprising various log components used by Flow's own int...
Opaque handle for managing a dynamic config change callback.
size_t m_d_value_set_idx
Opaque handle detail.
std::list< On_dynamic_change_func >::const_iterator m_pos
Opaque handle detail.
Utility/traits type to concisely work with final-validation functions when calling methods like Confi...
static Type null()
Returns a final-validator function that simply always returns Final_validator_outcome::S_ACCEPT.
Empty struct suitable as a *_value_set template arg for Config_manager, when a slot requires a Value_...