26#include <boost/array.hpp>
27#include <boost/unordered/unordered_set.hpp>
40template<
typename Value_set>
383template<
typename... S_d_value_set>
412 "Must have even number of template args to Config_manager; use a trailing Null_value_set if needed.");
552 template<
typename... Value_set>
576 template<
typename... Value_set>
578 const fs::path& static_cfg_path,
667 const fs::path& cfg_path,
732 template<
typename... Value_set>
759 template<
typename... Value_set>
761 const fs::path& dynamic_cfg_path,
799 template<
typename... Value_set>
823 template<
typename... Value_set>
838 template<
typename Value_set>
855 template<
typename Value_set>
889 template<
typename... Value_set>
906 template<
typename Value_set>
935 template<
typename Value_set>
1008 S_STATIC_AND_DYNAMIC,
1025 template<
typename Value_set>
1038 template<
typename Value_set>
1049 template<
typename Value_set>
1068 template<
typename Value_set>
1070 bool canonicalize_else_reject,
bool* changed_or_null);
1087 template<
typename... Value_set>
1089 const fs::path& static_cfg_path,
1108 template<
typename... Value_set>
1110 const fs::path& dynamic_cfg_path,
1128 const fs::path& cfg_path,
1152 template<
typename... Value_set>
1155 const fs::path& cfg_path,
const boost::unordered_set<std::string>& all_opt_names_or_empty,
1203 template<
typename Value_set>
1205 const boost::unordered_set<std::string>& all_opt_names_or_empty,
1207 bool* skip_parsing);
1232 template<
typename Value_set>
1254 template<
typename Value_set>
1265 template<
typename Value_set>
1429template<
typename... S_d_value_set>
1445 std::list<On_dynamic_change_func>::const_iterator
m_pos;
1470template<
typename... S_d_value_set>
1475 m_nickname(nickname),
1476 m_dynamic_values_set(false),
1477 m_multi_src_update_in_progress(
Update_type::S_NONE)
1486 &&
"Must have at least 2 template args to Config_manager; otherwise what are you configuring?");
1498 bool dyn_else_st =
false;
1499 size_t value_set_idx = 0;
1500 size_t d_value_set_idx = 0;
1511 std::move(declare_opts_func_moved)}},
1518 && (opt_set<S_d_value_set>(value_set_idx)->null()
1523 =
Void_ptr{
new typename S_d_value_set::Const_ptr},
1528 dyn_else_st = !dyn_else_st
1533 "managing [" <<
S_N_S_VALUE_SETS <<
"] dynamic+static option set pairs (some may be null/unused).");
1536template<
typename... S_d_value_set>
1537template<
typename Value_set>
1543 assert(value_set_idx < S_N_VALUE_SETS);
1545 (m_s_d_opt_sets[value_set_idx].get());
1548template<
typename... S_d_value_set>
1549template<
typename Value_set>
1555 assert(d_value_set_idx < S_N_D_VALUE_SETS);
1556 return static_cast<Value_set*
>
1557 (m_d_baseline_value_sets[d_value_set_idx].get());
1560template<
typename... S_d_value_set>
1561template<
typename Value_set>
1565 return const_cast<Config_manager<S_d_value_set...
>*>(
this)->opt_set<Value_set>(value_set_idx);
1568template<
typename... S_d_value_set>
1569template<
typename Value_set>
1573 if (opt_set->
null())
1577 && (*changed_or_null =
false);
1586template<
typename... S_d_value_set>
1587template<
typename Value_set>
1588typename Config_manager<S_d_value_set...>::On_dynamic_change_func_handle
1592 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Adding dynamic-change listener for dynamic value set "
1593 "[" << d_value_set_idx <<
"].");
1595 assert((d_value_set_idx < S_N_D_VALUE_SETS) &&
"Invalid dynamic option set index.");
1596 assert((!opt_set<Value_set>((d_value_set_idx * 2) + 1)->null())
1597 &&
"Do not register dynamic change listener for Null_value_set or otherwise null value set.");
1600 m_on_dynamic_change_funcs[d_value_set_idx].emplace_back(std::move(on_dynamic_change_func_moved));
1601 const auto& callback_pos = std::prev(m_on_dynamic_change_funcs[d_value_set_idx].end());
1603 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Added dynamic-change listener [@" << &(*callback_pos) <<
1604 "] for dynamic value set [" << d_value_set_idx <<
"].");
1609template<
typename... S_d_value_set>
1614 auto& on_dynamic_change_funcs = m_on_dynamic_change_funcs[handle.
m_d_value_set_idx];
1615 on_dynamic_change_funcs.erase(handle.
m_pos);
1617 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Removed dynamic-change listener [@" << &(*handle.
m_pos) <<
1621template<
typename... S_d_value_set>
1622template<
typename... Value_set>
1624 (
const fs::path& static_cfg_path,
1628 return apply_static_impl<Value_set...>(
false, static_cfg_path, final_validator_func..., commit);
1631template<
typename... S_d_value_set>
1632template<
typename... Value_set>
1635 const fs::path& static_cfg_path,
1639 return apply_static_impl<Value_set...>(
true, static_cfg_path, final_validator_func..., commit);
1642template<
typename... S_d_value_set>
1643template<
typename... Value_set>
1645 (
bool allow_invalid_defaults,
1646 const fs::path& static_cfg_path,
1650 using boost::unordered_set;
1653 using std::is_same_v;
1655 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Request to apply static config file [" << static_cfg_path <<
"]. "
1656 "Invalid defaults allowed if explicitly set in file? = [" << allow_invalid_defaults <<
"]. "
1657 "This application (if successful) shall end with canonicalizing values? = [" << commit <<
"]; "
1658 "multi-source update already in progress (0=none) = [" <<
int(m_multi_src_update_in_progress) <<
"].");
1660 reject_candidates_if_update_type_changed(Update_type::S_STATIC);
1665 static_assert(
sizeof...(Value_set) == S_N_S_VALUE_SETS,
1666 "You must supply N/2 `final_validator_func`s, where N is # of S_d_value_set params. "
1667 "Use null_final_validator_func() for any Null_value_set.");
1675 size_t value_set_idx;
1676 bool success =
true;
1680 if ((!allow_invalid_defaults) && (m_multi_src_update_in_progress == Update_type::S_NONE))
1683 [[maybe_unused]]
const auto dummy =
1688 opt_set<Value_set>(value_set_idx)
1689 ->validate_values(&success),
1698 "Request to apply static config file [" << static_cfg_path <<
"]: "
1699 "Will not parse file, because stringent check "
1700 "of defaults detected at least 1 individually-invalid default value. Either correct "
1701 "the default or use apply_static(allow_invalid_defaults_tag_t) overload.");
1706 unordered_set<string> all_opt_names;
1707 unordered_set<string>
const * this_opt_names;
1709 static_assert(is_same_v<
decltype(declval<Option_set<Null_value_set>>().option_names()),
1710 decltype(*this_opt_names)>,
1711 "Option_set<>::option_names() must return ref-to-const. Bug?");
1718 this_opt_names = &(opt_set<Value_set>
1719 (value_set_idx)->option_names()),
1720 all_opt_names.insert(this_opt_names->begin(), this_opt_names->end()),
1726 success = apply_static_or_dynamic_impl<Value_set...>
1728 static_cfg_path, all_opt_names, final_validator_func...);
1731 if ((!commit) && success)
1733 m_multi_src_update_in_progress = Update_type::S_STATIC;
1734 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Multi-source update has successfully begun or continued. "
1735 "Expecting more sources before we can canonicalize candidate(s).");
1751 option_set_canonicalize_or_reject(opt_set<Value_set>(value_set_idx),
1757 if (m_multi_src_update_in_progress != Update_type::S_NONE)
1759 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Multi-source update is now finished.");
1760 m_multi_src_update_in_progress = Update_type::S_NONE;
1764 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: State that was just made canonical follows.");
1770template<
typename... S_d_value_set>
1771template<
typename... Value_set>
1773 (
bool dyn_else_st,
const fs::path& cfg_path,
const boost::unordered_set<std::string>& all_opt_names_or_empty,
1776 size_t s_d_value_set_idx = 0;
1777 size_t value_set_idx = dyn_else_st ? 1 : 0;
1781 bool skip_parsing =
false;
1801 success = apply_impl(opt_set<Value_set>
1804 ((m_multi_src_update_in_progress == Update_type::S_NONE)
1805 && dyn_else_st && (!opt_set<Value_set>(value_set_idx)->null()))
1806 ? d_baseline_value_set<Value_set>
1808 :
static_cast<const Value_set*
>(
nullptr),
1810 cfg_path, all_opt_names_or_empty,
1811 final_validator_func,
1813 ++s_d_value_set_idx,
1820template<
typename... S_d_value_set>
1821template<
typename Value_set>
1824 const Value_set* baseline_value_set_or_null,
1825 const fs::path& cfg_path,
1826 const boost::unordered_set<std::string>& all_opt_names_or_empty,
1831 auto& opts = *opt_set;
1844 if (baseline_value_set_or_null)
1869 const auto pre_parse_candidate = candidate_or_null ? *candidate_or_null : opt_set->
values();
1873 if (skip_parsing && (*skip_parsing))
1876 "Parsing, individual-option validation, and final-validation are being skipped "
1877 "for this value set, as requested by the caller. This file's values will not be applied. "
1878 "This has happened because this value set is successive to a value set whose "
1879 "final-validation determined that it shall not be applied. This is not an error.");
1880 opts.parse_direct_values(pre_parse_candidate);
1894 opts.parse_config_file(cfg_path,
true, &ok, all_opt_names_or_empty);
1902 opts.validate_values_candidate(&ok);
1906 "Request to apply config file [" << cfg_path <<
"] for a particular value set: "
1907 "Individual values present in file were OK, but at least 1 default value (see above) "
1908 "was invalid. Either correct the default or ensure it is properly overridden in file.");
1915 const auto final_validator_outcome = final_validator_func(*opts.values_candidate());
1916 switch (final_validator_outcome)
1925 "Request to apply config file [" << cfg_path <<
"] for a particular value set: "
1926 "Individual values present in file were OK, but the final-validator logic specified "
1927 "that this file's values not be applied (to skip the file after all). "
1928 "Rewinding the candidate value-set to pre-parse state. This is not an error.");
1929 opts.parse_direct_values(pre_parse_candidate);
1932 assert((!*skip_parsing) &&
"We should have `return`ed already.");
1933 *skip_parsing =
true;
1941template<
typename... S_d_value_set>
1943 (
const fs::path& cfg_path,
1947 return apply_static_and_dynamic_impl(
false, cfg_path, final_validator_func..., commit);
1950template<
typename... S_d_value_set>
1953 const fs::path& cfg_path,
1957 return apply_static_and_dynamic_impl(
true, cfg_path, final_validator_func..., commit);
1960template<
typename... S_d_value_set>
1962 (
bool allow_invalid_defaults,
1963 const fs::path& cfg_path,
1968 using boost::unordered_set;
1971 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Request to apply config file [" << cfg_path <<
"] as both "
1972 "static config and *baseline* dynamic config. Parsing in that order for each pair. "
1973 "Invalid defaults allowed if explicitly set in file? = [" << allow_invalid_defaults <<
"]. "
1974 "This application (if successful) shall end with canonicalizing values? = [" << commit <<
"]; "
1975 "multi-source update already in progress (0=none) = [" <<
int(m_multi_src_update_in_progress) <<
"].");
1977 reject_candidates_if_update_type_changed(Update_type::S_STATIC_AND_DYNAMIC);
1985 size_t value_set_idx;
1986 bool success =
true;
1990 if ((!allow_invalid_defaults) && (m_multi_src_update_in_progress == Update_type::S_NONE))
1997 opt_set<S_d_value_set>(value_set_idx)
1998 ->validate_values(&success),
2006 FLOW_LOG_WARNING(
"Config_manager [" << *
this <<
"]: Request to apply config file [" << cfg_path <<
"] as both "
2007 "static config and *baseline* dynamic config: Will not parse file, because stringent check "
2008 "of defaults detected at least 1 individually-invalid default value. Either correct "
2009 "the default or use apply_static_and_dynamic(allow_invalid_defaults_tag_t) overload.");
2014 unordered_set<string> all_opt_names;
2015 unordered_set<string> this_opt_names;
2021 bool skip_parsing =
false;
2026 this_opt_names = opt_set<S_d_value_set>(value_set_idx)->option_names(),
2027 all_opt_names.insert(this_opt_names.begin(), this_opt_names.end()),
2038 success = apply_impl(opt_set<S_d_value_set>(value_set_idx),
2040 static_cast<const S_d_value_set*
>(
nullptr),
2041 cfg_path, all_opt_names,
2042 final_validator_func,
2050 if ((!commit) && success)
2052 m_multi_src_update_in_progress = Update_type::S_STATIC_AND_DYNAMIC;
2053 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Multi-source update has successfully begun or continued. "
2054 "Expecting more sources before we can canonicalize candidate(s).");
2069 option_set_canonicalize_or_reject
2070 (opt_set<S_d_value_set>(value_set_idx),
2076 if (m_multi_src_update_in_progress != Update_type::S_NONE)
2078 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Multi-source update is now finished.");
2079 m_multi_src_update_in_progress = Update_type::S_NONE;
2088 assert(commit &&
"Maintenance bug? We should have returned above if `!commit` but success==true.");
2090 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: State that was just made canonical follows.");
2096 bool dyn_else_st =
false;
2098 size_t d_value_set_idx = 0;
2109 && (opt_set<S_d_value_set>(value_set_idx)->null()
2110 || (*(d_baseline_value_set<S_d_value_set>(d_value_set_idx))
2111 = opt_set<S_d_value_set>(value_set_idx)->values(),
2117 dyn_else_st = !dyn_else_st
2123 Lock_guard<
decltype(m_d_value_sets_mutex)> lock{m_d_value_sets_mutex};
2125 dyn_else_st =
false;
2131 && (save_dynamic_value_set_locked<S_d_value_set>
2132 (opt_set<S_d_value_set>(value_set_idx), value_set_idx / 2),
2135 dyn_else_st = !dyn_else_st
2141 assert((!m_dynamic_values_set)
2142 &&
"User apparently attempted apply_static_and_dynamic(), but dynamic config was already initialized OK.");
2143 m_dynamic_values_set =
true;
2146 for (d_value_set_idx = 0; d_value_set_idx != S_N_D_VALUE_SETS; ++d_value_set_idx)
2148 invoke_dynamic_change_listeners(d_value_set_idx,
true);
2154template<
typename... S_d_value_set>
2155template<
typename... Value_set>
2157 (
const fs::path& dynamic_cfg_path,
2161 return apply_dynamic_impl<Value_set...>(
false, dynamic_cfg_path, final_validator_func..., commit);
2164template<
typename... S_d_value_set>
2165template<
typename... Value_set>
2168 const fs::path& dynamic_cfg_path,
2172 return apply_dynamic_impl<Value_set...>(
true, dynamic_cfg_path, final_validator_func..., commit);
2175template<
typename... S_d_value_set>
2176template<
typename... Value_set>
2178 (
bool allow_invalid_defaults,
2179 const fs::path& dynamic_cfg_path,
2188 if (m_dynamic_values_set)
2191 "Request to apply dynamic config file [" << dynamic_cfg_path <<
"]. "
2192 "Initializing dynamic config? = [false]. "
2193 "This application (if successful) shall end with canonicalizing values? = [" << commit <<
"]; "
2194 "multi-source update already in progress "
2195 "(0=none) = [" <<
int(m_multi_src_update_in_progress) <<
"].");
2200 "Request to apply dynamic config file [" << dynamic_cfg_path <<
"]. "
2201 "Initializing dynamic config? = [true]. "
2202 "Invalid defaults allowed if explicitly set in file? = [" << allow_invalid_defaults <<
"]. "
2203 "This application (if successful) shall end with canonicalizing values? = [" << commit <<
"]; "
2204 "multi-source update already in progress "
2205 "(0=none) = [" <<
int(m_multi_src_update_in_progress) <<
"].");
2208 reject_candidates_if_update_type_changed(Update_type::S_DYNAMIC);
2216 size_t value_set_idx;
2217 bool success =
true;
2221 if ((!m_dynamic_values_set) && (!allow_invalid_defaults) && (m_multi_src_update_in_progress == Update_type::S_NONE))
2224 [[maybe_unused]]
const auto dummy =
2229 opt_set<Value_set>(value_set_idx)
2230 ->validate_values(&success),
2239 "Request to initially-apply dynamic config file [" << dynamic_cfg_path <<
"]: "
2240 "Will not parse file, because stringent check "
2241 "of defaults detected at least 1 individually-invalid default value. Either correct "
2242 "the default or use apply_dynamic(allow_invalid_defaults_tag_t) overload.");
2252 && apply_static_or_dynamic_impl<Value_set...>(
true,
2253 dynamic_cfg_path, {}, final_validator_func...);
2255 if ((!commit) && success)
2257 m_multi_src_update_in_progress = Update_type::S_DYNAMIC;
2258 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Multi-source update has successfully begun or continued. "
2259 "Expecting more sources before we can canonicalize candidate(s).");
2268 size_t d_value_set_idx = 0;
2272 array<bool, S_N_D_VALUE_SETS> changed{};
2273 bool some_changed =
false;
2277 value_set_idx = (d_value_set_idx * 2) + 1,
2280 option_set_canonicalize_or_reject(opt_set<Value_set>(value_set_idx),
2283 m_dynamic_values_set ? &changed[d_value_set_idx] :
nullptr),
2285 changed[d_value_set_idx] = (!m_dynamic_values_set) || changed[d_value_set_idx],
2287 some_changed = some_changed || changed[d_value_set_idx],
2292 if (m_multi_src_update_in_progress != Update_type::S_NONE)
2294 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Multi-source update is now finished.");
2295 m_multi_src_update_in_progress = Update_type::S_NONE;
2313 os.os() <<
"Config_manager [" << *
this <<
"]: (Dynamic) state that was just made canonical follows.\n";
2319 state_to_ostream_impl<Value_set>(value_set_idx, os.os()),
2333 Lock_guard<
decltype(m_d_value_sets_mutex)> lock{m_d_value_sets_mutex};
2334 d_value_set_idx = 0;
2338 value_set_idx = (d_value_set_idx * 2) + 1,
2340 changed[d_value_set_idx]
2341 && (save_dynamic_value_set_locked<Value_set>
2342 (opt_set<Value_set>(value_set_idx),
2350 const bool was_dynamic_values_set = m_dynamic_values_set;
2351 m_dynamic_values_set =
true;
2355 for (d_value_set_idx = 0; d_value_set_idx != S_N_D_VALUE_SETS; ++d_value_set_idx)
2357 if (changed[d_value_set_idx])
2359 invoke_dynamic_change_listeners(d_value_set_idx, !was_dynamic_values_set);
2366template<
typename... S_d_value_set>
2369 if (m_multi_src_update_in_progress == Update_type::S_NONE)
2371 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Request to abandon multi-source update in-progress; but none "
2372 "is in progress. Doing nothing.");
2377 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: Request to abandon multi-source update in-progress. Doing so.");
2380 size_t value_set_idx = 0;
2386 option_set_canonicalize_or_reject
2387 (opt_set<S_d_value_set>(value_set_idx),
2393 m_multi_src_update_in_progress = Update_type::S_NONE;
2396template<
typename... S_d_value_set>
2399 assert(this_update_type != Update_type::S_NONE);
2400 if ((m_multi_src_update_in_progress == Update_type::S_NONE)
2401 || (m_multi_src_update_in_progress == this_update_type))
2407 FLOW_LOG_INFO(
"Config_manager [" << *
this <<
"]: An update of type [" <<
int(this_update_type) <<
"] "
2408 "is interrupting (canceling) an in-progress multi-source update of type "
2409 "[" <<
int(m_multi_src_update_in_progress) <<
"]. Reverting any uncommitted values "
2410 "from the latter. Suggest invoking reject_candidates() explicitly if intentional; this "
2411 "message will then go away, while the code will be more deliberate.");
2413 reject_candidates();
2414 assert(m_multi_src_update_in_progress == Update_type::S_NONE);
2417template<
typename... S_d_value_set>
2418template<
typename Value_set>
2422 assert(opt_set_ptr);
2423 auto& opt_set = *opt_set_ptr;
2428 *(
static_cast<typename Value_set::Const_ptr*
>(m_d_value_sets[d_value_set_idx].get()))
2430 = Value_set::const_ptr_cast(opt_set.mutable_values_copy());
2433template<
typename... S_d_value_set>
2437 "Dynamic update for dynamic option set [" << d_value_set_idx <<
"] (0-based) of "
2438 "[" << S_N_D_VALUE_SETS <<
"] (1-based); trigger was "
2439 "[" << (init ?
"initial-update" :
"change-detected") <<
"].");
2441 const auto& on_dynamic_change_funcs = m_on_dynamic_change_funcs[d_value_set_idx];
2444 for (
const auto& on_dynamic_change_func : on_dynamic_change_funcs)
2446 FLOW_LOG_INFO(
"Invoking listener [" << idx <<
"] (0-based) of [" << on_dynamic_change_funcs.size() <<
"] "
2448 on_dynamic_change_func();
2451 FLOW_LOG_INFO(
"Done invoking change listeners for dynamic option set.");
2454template<
typename... S_d_value_set>
2455template<
typename... Value_set>
2458 static_assert(
sizeof...(Value_set) == S_N_S_VALUE_SETS,
2459 "You must supply N/2 `value_set_or_null`s, where N is # of S_d_value_set params. "
2460 "Use nullptr for any Null_value_set and/or Value_set of no interest.");
2462 size_t s_value_set_idx = 0;
2463 size_t value_set_idx;
2467 value_set_idx = s_value_set_idx * 2,
2469 (value_set_or_null && (!opt_set<Value_set>
2470 (value_set_idx)->null()))
2471 && (*value_set_or_null = &(opt_set<Value_set>(value_set_idx)->values()),
2478template<
typename... S_d_value_set>
2479template<
typename... Value_set>
2482 static_assert(
sizeof...(Value_set) == S_N_S_VALUE_SETS,
2483 "You must supply N/2 `value_set_or_null`s, where N is # of S_d_value_set params. "
2484 "Use nullptr for any Null_value_set and/or Value_set of no interest.");
2486 size_t s_value_set_idx = 0;
2487 size_t value_set_idx;
2491 value_set_idx = s_value_set_idx * 2,
2492 (value_set_or_null && (!opt_set<Value_set>
2493 (value_set_idx)->null()))
2499 && (*value_set_or_null = opt_set<Value_set>(value_set_idx)->values_candidate()
2501 ?: &(opt_set<Value_set>(value_set_idx)->values()),
2508template<
typename... S_d_value_set>
2509template<
typename Value_set>
2512 assert((s_value_set_idx < S_N_S_VALUE_SETS) &&
"Invalid static option set index.");
2514 return opt_set<Value_set>(s_value_set_idx * 2)->values();
2517template<
typename... S_d_value_set>
2518template<
typename Value_set>
2521 assert((s_value_set_idx < S_N_S_VALUE_SETS) &&
"Invalid static option set index.");
2523 const auto opt = opt_set<Value_set>(s_value_set_idx * 2);
2529 const Value_set* values = opt->values_candidate();
2532 values = &(opt->values());
2538template<
typename... S_d_value_set>
2539template<
typename... Value_set>
2541 (
typename Value_set::Const_ptr*... value_set_or_null)
const
2545 static_assert(
sizeof...(Value_set) == S_N_D_VALUE_SETS,
2546 "You must supply N/2 `value_set_or_null`s, where N is # of S_d_value_set params. "
2547 "Use nullptr for any Null_value_set and/or Value_set of no interest.");
2550 Lock_guard<
decltype(m_d_value_sets_mutex)> lock{m_d_value_sets_mutex};
2552 size_t d_value_set_idx = 0;
2553 size_t value_set_idx;
2557 value_set_idx = (d_value_set_idx * 2) + 1,
2559 (value_set_or_null && (!opt_set<Value_set>
2560 (value_set_idx)->null()))
2561 && (*value_set_or_null
2562 = *(
static_cast<typename Value_set::Const_ptr*
>(m_d_value_sets[d_value_set_idx].get())),
2570template<
typename... S_d_value_set>
2571template<
typename Value_set>
2572typename Value_set::Const_ptr
2577 assert((d_value_set_idx < S_N_D_VALUE_SETS) &&
"Invalid dynamic option set index.");
2580 Lock_guard<
decltype(m_d_value_sets_mutex)> lock{m_d_value_sets_mutex};
2581 return *(
static_cast<typename Value_set::Const_ptr*
>(m_d_value_sets[d_value_set_idx].get()));
2585template<
typename... S_d_value_set>
2588 os <<
"Config_manager [" << *
this <<
"]: Current state + config documentation:\n";
2590 size_t value_set_idx = 0;
2593 state_to_ostream_impl<S_d_value_set>(value_set_idx++, os)
2597template<
typename... S_d_value_set>
2598template<
typename Value_set>
2601 const auto& opts = *(opt_set<Value_set>(value_set_idx));
2608 const size_t s_d_value_set_idx = value_set_idx / 2;
2609 const bool dyn_else_st = (value_set_idx % 2) == 1;
2611 os <<
"-- [" << (dyn_else_st ?
"DYNAMIC" :
"STATIC") <<
"] [" << s_d_value_set_idx <<
"] --\n";
2615 const auto output_uncanonicalized = [&]()
2617 if (m_multi_src_update_in_progress != Update_type::S_NONE)
2621 const auto candidate_or_none = opts.values_candidate();
2622 if (candidate_or_none)
2624 os <<
" <incomplete multi-source update type [" << int(m_multi_src_update_in_progress) <<
"] in-progress / "
2625 "current candidate values follow>\n";
2626 opts.values_to_ostream(os, candidate_or_none);
2633 opts.values_to_ostream(os);
2634 output_uncanonicalized();
2639 if (m_dynamic_values_set)
2641 opts.values_to_ostream(os);
2642 output_uncanonicalized();
2652 os <<
"<no dynamic config init payload / option docs follow instead>\n";
2653 opts.help_to_ostream(os);
2655 output_uncanonicalized();
2658template<
typename... S_d_value_set>
2665 state_to_ostream(os.os());
2670template<
typename... S_d_value_set>
2673 os <<
"Config_manager [" << *
this <<
"]: Config help:\n";
2675 size_t value_set_idx = 0;
2678 help_to_ostream_impl<S_d_value_set>(value_set_idx++, os)
2682template<
typename... S_d_value_set>
2683template<
typename Value_set>
2686 const auto opts = opt_set<Value_set>(value_set_idx);
2693 const size_t s_d_value_set_idx = value_set_idx / 2;
2694 const bool dyn_else_st = (value_set_idx % 2) == 1;
2696 os <<
"-- [" << (dyn_else_st ?
"DYNAMIC" :
"STATIC") <<
"] [" << s_d_value_set_idx <<
"] --\n";
2697 opts->help_to_ostream(os);
2700template<
typename... S_d_value_set>
2707 help_to_ostream(os.os());
2712template<
typename Value_set>
2718template<
typename... S_d_value_set>
2721 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 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...
void canonicalize_candidate(bool *change_detected=nullptr)
In PARSING state enters CANONICAL state, finalizing values() from values_candidate().
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 &&... 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_...