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_...