23#include "flow/error/error.hpp" 
   25#include <boost/algorithm/string.hpp> 
   26#include <boost/unordered_set.hpp> 
   54    S_FILL_PARSING_ROLE_OPT_TABLE,
 
   62    S_FILL_OUTPUT_HELP_ROLE_OPT_TABLE,
 
   71    S_FILL_OUTPUT_CURRENT_ROLE_OPT_TABLE,
 
   80    S_COMPARE_PARSED_VALS,
 
   90    S_LOAD_VALS_AS_IF_PARSED,
 
  100    S_VALIDATE_STORED_VALS
 
  129  template<
typename Value>
 
  131                                        const Value& value_default, 
const Value& current_value,
 
  155  template<
typename Value>
 
  157                                     Function<
bool (
const Value& val)>&& validator_func_moved,
 
  235  template<
typename Value>
 
  238                                              Function<
bool (
const Value& val)>&& validator_func_moved,
 
  417template<
typename Value_set>
 
  421  private boost::noncopyable
 
  699                              bool* success_or_null = 0);
 
  809                         bool* success_or_null = 0,
 
  810                         const boost::unordered_set<std::string>& allowed_unregistered_opts_or_empty = {});
 
  926  template<
typename Value>
 
  928                                  Function<
bool (
const Value& val)>&& validator_func_moved,
 
  950  template<
typename Value>
 
  969  template<
typename Value>
 
  993  template<
typename Value>
 
 1022  const boost::unordered_set<std::string>& 
option_names() 
const;
 
 1157#define FLOW_CFG_OPTION_SET_DECLARE_OPTION(ARG_m_value, ARG_description, ARG_bool_validate_expr) \ 
 1158  FLOW_CFG_OPTION_SET_DECLARE_OPTION_WITH_KNOBS(ARG_m_value, ARG_description, ARG_bool_validate_expr, false) 
 1178#define FLOW_CFG_OPTION_SET_DECLARE_OPTION_NO_ACC(ARG_m_value, ARG_description, ARG_bool_validate_expr) \ 
 1179  FLOW_CFG_OPTION_SET_DECLARE_OPTION_WITH_KNOBS(ARG_m_value, ARG_description, ARG_bool_validate_expr, true) 
 1277#define FLOW_CFG_OPTION_SET_DECLARE_OPTION_KEYED(ARG_m_value, ARG_description, ARG_bool_validate_expr, ARG_key) \ 
 1278  FLOW_UTIL_SEMICOLON_SAFE \ 
 1280      const ::std::string FLOW_CFG_SET_DECL_OPT_KEYED_name \ 
 1281        = ::flow::cfg::value_set_member_id_to_opt_name_keyed(#ARG_m_value, ARG_key); \ 
 1282      FLOW_CFG_OPTION_SET_DECLARE_OPTION_MANUALLY_NAMED \ 
 1283        (ARG_m_value, FLOW_CFG_SET_DECL_OPT_KEYED_name.c_str(), ARG_description, ARG_bool_validate_expr, false); \ 
 1301#define FLOW_CFG_OPTION_SET_DECLARE_OPTION_KEYED_NO_ACC(ARG_m_value, ARG_description, ARG_bool_validate_expr, ARG_key) \ 
 1302  FLOW_UTIL_SEMICOLON_SAFE \ 
 1304      const ::std::string FLOW_CFG_SET_DECL_OPT_KEYED_name \ 
 1305        = ::flow::cfg::value_set_member_id_to_opt_name_keyed(#ARG_m_value, ARG_key); \ 
 1306      FLOW_CFG_OPTION_SET_DECLARE_OPTION_MANUALLY_NAMED \ 
 1307        (ARG_m_value, FLOW_CFG_SET_DECL_OPT_KEYED_name.c_str(), ARG_description, ARG_bool_validate_expr, true); \ 
 1330#define FLOW_CFG_OPTION_SET_DECLARE_OPTION_WITH_KNOBS(ARG_m_value, ARG_description, ARG_bool_validate_expr, \ 
 1331                                                      ARG_no_accumulation) \ 
 1332  FLOW_UTIL_SEMICOLON_SAFE \ 
 1334      const ::std::string FLOW_CFG_SET_DECL_OPT_name = ::flow::cfg::value_set_member_id_to_opt_name(#ARG_m_value); \ 
 1335      FLOW_CFG_OPTION_SET_DECLARE_OPTION_MANUALLY_NAMED \ 
 1336        (ARG_m_value, FLOW_CFG_SET_DECL_OPT_name.c_str(), ARG_description, ARG_bool_validate_expr, \ 
 1337         ARG_no_accumulation); \ 
 1369#define FLOW_CFG_OPTION_SET_DECLARE_OPTION_MANUALLY_NAMED(ARG_m_value, ARG_opt_name_c_str, \ 
 1370                                                          ARG_description, ARG_bool_validate_expr, \ 
 1371                                                          ARG_no_accumulation) \ 
 1372  FLOW_UTIL_SEMICOLON_SAFE \ 
 1374      char const * const FLOW_CFG_SET_DECL_OPT_MANUAL_name_c_str = ARG_opt_name_c_str; \ 
 1376      const ::flow::util::String_view FLOW_CFG_SET_DECL_OPT_MANUAL_name_view(FLOW_CFG_SET_DECL_OPT_MANUAL_name_c_str); \ 
 1377      const bool FLOW_CFG_SET_DECL_OPT_MANUAL_no_acc = ARG_no_accumulation; \ 
 1378      switch (args.m_call_type) \ 
 1380      case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_FILL_PARSING_ROLE_OPT_TABLE: \ 
 1382        using Value = decltype(args.m_args.m_fill_parsing_role_opt_table_args.m_values_candidate->ARG_m_value); \ 
 1385        flow::Function<bool (const Value&)> FLOW_CFG_SET_DECL_OPT_MANUAL_validator_func \ 
 1386          = [FLOW_CFG_SET_DECL_OPT_MANUAL_name_std_str = std::string(FLOW_CFG_SET_DECL_OPT_MANUAL_name_c_str)] \ 
 1387              ([[maybe_unused]] const Value& val) -> bool { return ARG_bool_validate_expr; }; \ 
 1388        args.m_args.m_fill_parsing_role_opt_table_args.m_option_set \ 
 1389          ->declare_option_for_parsing \ 
 1390              (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \ 
 1391               &args.m_args.m_fill_parsing_role_opt_table_args.m_values_candidate->ARG_m_value, \ 
 1397               FLOW_CFG_SET_DECL_OPT_MANUAL_no_acc \ 
 1398                 ? &args.m_args.m_fill_parsing_role_opt_table_args.m_values_default_no_acc->ARG_m_value \ 
 1400               ::std::move(FLOW_CFG_SET_DECL_OPT_MANUAL_validator_func), \ 
 1401               ::flow::util::String_view(#ARG_bool_validate_expr)); \ 
 1404      case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_FILL_OUTPUT_HELP_ROLE_OPT_TABLE: \ 
 1405        args.m_args.m_fill_output_help_role_opt_table_args.m_option_set \ 
 1406          ->declare_option_for_help \ 
 1407              (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \ 
 1408               args.m_args.m_fill_output_help_role_opt_table_args.m_values_default->ARG_m_value, \ 
 1411      case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_FILL_OUTPUT_CURRENT_ROLE_OPT_TABLE: \ 
 1412        ::flow::cfg::Option_set_base::declare_option_for_output \ 
 1413          (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \ 
 1414           args.m_args.m_fill_output_current_role_opt_table_args.m_target_opts, \ 
 1415           args.m_args.m_fill_output_current_role_opt_table_args.m_values_default->ARG_m_value, \ 
 1416           args.m_args.m_fill_output_current_role_opt_table_args.m_values_current->ARG_m_value, \ 
 1419      case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_COMPARE_PARSED_VALS: \ 
 1420        args.m_args.m_compare_parsed_vals_args.m_option_set \ 
 1421          ->scan_parsed_option \ 
 1422              (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \ 
 1423               args.m_args.m_compare_parsed_vals_args.m_option_set->values().ARG_m_value); \ 
 1425      case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_LOAD_VALS_AS_IF_PARSED: \ 
 1426        args.m_args.m_load_val_as_if_parsed_args.m_option_set \ 
 1427          ->load_option_value_as_if_parsed \ 
 1428              (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \ 
 1429               &args.m_args.m_load_val_as_if_parsed_args.m_values_candidate->ARG_m_value, \ 
 1430               args.m_args.m_load_val_as_if_parsed_args.m_values_to_load->ARG_m_value); \ 
 1432      case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_VALIDATE_STORED_VALS: \ 
 1435        using Value = decltype(args.m_args.m_validate_stored_vals_args.m_values_to_validate->ARG_m_value); \ 
 1436        flow::Function<bool (const Value&)> FLOW_CFG_SET_DECL_OPT_MANUAL_validator_func \ 
 1437          = [FLOW_CFG_SET_DECL_OPT_MANUAL_name_std_str = std::string(FLOW_CFG_SET_DECL_OPT_MANUAL_name_c_str)] \ 
 1438              ([[maybe_unused]] const Value& val) -> bool { return ARG_bool_validate_expr; }; \ 
 1440        ::flow::cfg::Option_set_base::validate_parsed_option \ 
 1441          (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \ 
 1442           args.m_args.m_validate_stored_vals_args.m_values_to_validate->ARG_m_value, \ 
 1443           ::std::move(FLOW_CFG_SET_DECL_OPT_MANUAL_validator_func), \ 
 1444           ::flow::util::String_view(#ARG_bool_validate_expr)); \ 
 1453template<
typename Value_set>
 
 1457  m_nickname(nickname),
 
 1459  m_declare_opts_func(std::move(declare_opts_func_moved)),
 
 1463  FLOW_LOG_TRACE(
"Option_set[" << *
this << 
"]: Created with default values payload.  Options table setup begins.");
 
 1480  FLOW_LOG_TRACE(
"Option_set[" << *
this << 
"]: Options table setup finished.  Null set? = [" << 
null() << 
"].");
 
 1483template<
typename Value_set>
 
 1489template<
typename Value_set>
 
 1495template<
typename Value_set>
 
 1501template<
typename Value_set>
 
 1504  return m_parsing ? &m_values_candidate : 0;
 
 1507template<
typename Value_set>
 
 1512  constexpr unsigned int LINE_LENGTH = 1000;
 
 1513  constexpr unsigned int DESC_LENGTH = LINE_LENGTH - 1;
 
 1515  Opt_table opts_for_output(LINE_LENGTH, DESC_LENGTH);
 
 1518  args.
m_call_type = Declare_options_func_args::Call_type::S_FILL_OUTPUT_CURRENT_ROLE_OPT_TABLE;
 
 1520    = { &opts_for_output, &m_values_default,
 
 1521        values_or_null ? values_or_null : &m_values };
 
 1522  m_declare_opts_func(args);
 
 1524  os << opts_for_output; 
 
 1527template<
typename Value_set>
 
 1534  values_to_ostream(os.os(), values_or_null);
 
 1536  FLOW_LOG_WITH_CHECKING(sev, 
"Option_set[" << *
this << 
"]: Values payload [" << summary << 
"]:\n" << os.str());
 
 1539template<
typename Value_set>
 
 1542  os << m_opts_for_help; 
 
 1545template<
typename Value_set>
 
 1552  help_to_ostream(os.os());
 
 1557template<
typename Value_set>
 
 1563template<
typename Value_set>
 
 1564template<
typename Value>
 
 1566                                                       Value* target_value, 
const Value* value_default_if_no_acc,
 
 1567                                                       Function<
bool (
const Value& val)>&& validator_func_moved,
 
 1575  assert(target_value);
 
 1576  string name(name_view);
 
 1578  m_opt_names.insert(name);
 
 1581  FLOW_LOG_TRACE(
"Option_set[" << *
this << 
"]: Options table of parsing-role: " 
 1582                 "Declaring parsing-capable option [" << name << 
"]; raw shallow size [" << 
sizeof(Value) << 
"].");
 
 1587  const auto val_spec = value<Value>(target_value)
 
 1588                          ->notifier(throw_on_invalid_func(name_view, std::move(validator_func_moved),
 
 1589                                                           validator_cond_str_view));
 
 1594  if (value_default_if_no_acc)
 
 1597    String_ostream default_str_os;
 
 1599    default_str_os.os() << flush;
 
 1601    val_spec->default_value(*value_default_if_no_acc, default_str_os.str());
 
 1604  m_opts_for_parsing.add_options()(name.c_str(), val_spec);
 
 1609template<
typename Value>
 
 1612                                     Function<
bool (
const Value& val)>&& validator_func_moved,
 
 1620  return [validator_func = std::move(validator_func_moved),
 
 1621          validator_cond_str = string(validator_cond_str_view),
 
 1622          name = string(name_view)]
 
 1625    if (!(validator_func(val)))
 
 1627      String_ostream msg_os;
 
 1628      msg_os.
os() << 
"Option [" << name << 
"]: " 
 1629                     "Validation failed; the following condition must hold: [" << validator_cond_str << 
"].  " 
 1630                     "Option value `val` = [";
 
 1632      msg_os.os() << 
"]." << flush;
 
 1633      throw Runtime_error(msg_os.str());
 
 1638template<
typename Value_set>
 
 1639template<
typename Value>
 
 1648  assert(!description.empty());
 
 1654  String_ostream default_str_os;
 
 1656  default_str_os.os() << flush;
 
 1658  m_opts_for_help.add_options()
 
 1659    (string(name).c_str(),
 
 1662       ->default_value(value_default, default_str_os.str()),
 
 1663     string(description).c_str());
 
 1668template<
typename Value>
 
 1670                                                const Value& value_default, 
const Value& current_value,
 
 1678  assert(!description.empty());
 
 1687  String_ostream description_os;
 
 1691  description_os.os() << 
"    (";
 
 1695  description_os.os() << 
") <==current | default==^\n" 
 1696                         "      " << description << flush;
 
 1699  String_ostream default_str_os;
 
 1701  default_str_os.os() << flush;
 
 1703  target_opts->add_options()
 
 1704    (string(name).c_str(),
 
 1707       ->default_value(value_default, default_str_os.str()),
 
 1708     description_os.str().c_str());
 
 1713template<
typename Value_set>
 
 1714template<
typename Value>
 
 1717  using boost::any_cast;
 
 1719  string name(name_view);
 
 1727  const auto it = m_iterable_values_candidate.find(name);
 
 1728  if (it == m_iterable_values_candidate.end())
 
 1734  const auto& new_val = any_cast<const Value&>(it->second);
 
 1735  const auto& old_val = canonical_value;
 
 1737  if (old_val == new_val)
 
 1739    m_iterable_values_candidate.erase(name);
 
 1744template<
typename Value_set>
 
 1745template<
typename Value>
 
 1747                                                           Value* target_value,
 
 1748                                                           const Value& source_value)
 
 1751  string name(name_view);
 
 1753  assert(target_value);
 
 1761  *target_value = source_value;
 
 1764  m_iterable_values_candidate[name] = source_value;
 
 1772template<
typename Value>
 
 1774                                             Function<
bool (
const Value& val)>&& validator_func_moved,
 
 1777  const auto validate_or_throw_func = 
throw_on_invalid_func(name_view, std::move(validator_func_moved),
 
 1778                                                            validator_cond_str_view);
 
 1779  validate_or_throw_func(value);
 
 1782template<
typename Value_set>
 
 1784       (
const fs::path& cfg_path, 
bool allow_unregistered, 
bool* success_or_null,
 
 1785        const boost::unordered_set<std::string>& allowed_unregistered_opts_or_empty)
 
 1792  using opts::variables_map;
 
 1793  using boost::system::system_category;
 
 1795  using std::exception;
 
 1799  if (success_or_null)
 
 1803      parse_config_file(cfg_path, allow_unregistered, 0, allowed_unregistered_opts_or_empty);
 
 1805    catch (
const exception& exc)
 
 1808      *success_or_null = 
false;
 
 1811    *success_or_null = 
true;
 
 1819    FLOW_LOG_INFO(
"Option_set[" << *
this << 
"]: State CANONICAL: Request to parse file [" << cfg_path << 
"]; " 
 1820                  "entering state PARSING.  Initial candidate values payload initialized from current canonical " 
 1821                  "values payload.  Details follow (TRACE log level).");
 
 1823    assert(m_iterable_values_candidate.empty());
 
 1827    FLOW_LOG_INFO(
"Option_set[" << *
this << 
"]: State PARSING: Request to parse file [" << cfg_path << 
"]; " 
 1828                  "continuing by parsing this next config source.  " 
 1829                  "The values payload going into it is as it was after the previous config source.  " 
 1830                  "Details follow (TRACE log level).");
 
 1833  log_values(
"pre-parsing candidate config", &m_values_candidate, 
log::Sev::S_TRACE);
 
 1835  ifstream ifs(cfg_path);
 
 1838    const Error_code sys_err_code(errno, system_category());
 
 1841    throw Runtime_error(sys_err_code, 
ostream_op_string(
"Could not open file [", cfg_path, 
"]."));
 
 1851  const auto values_candidate_backup = m_values_candidate;
 
 1852  opts::parsed_options parsed_options(&m_opts_for_parsing);
 
 1855    parsed_options = opts::parse_config_file(ifs, m_opts_for_parsing, allow_unregistered);
 
 1857  catch (
const exception& exc)
 
 1859    m_values_candidate = values_candidate_backup;
 
 1863                     "Parsing file [" << cfg_path << 
"]: Exception occurred; parse failed.  Values payload untouched.  " 
 1864                     "Message = [" << exc.what() << 
"].");
 
 1872  if (allow_unregistered)
 
 1874    for (
const auto& option : parsed_options.options)
 
 1876      if (option.unregistered)
 
 1878        assert(!option.original_tokens.empty());
 
 1879        const string opt_name = option.original_tokens.front();
 
 1881        if (allowed_unregistered_opts_or_empty.empty())
 
 1884          FLOW_LOG_TRACE(
"Option_set[" << *
this << 
"]: State PARSING: Ignoring unregistered option named " 
 1885                         "[" << opt_name << 
"].  We were not given an approved-list.  Perhaps this file contains " 
 1886                         "other option sets, or it has to do with forward/backward-compatibility.");
 
 1890          if (!
key_exists(allowed_unregistered_opts_or_empty, opt_name))
 
 1893            m_values_candidate = values_candidate_backup;
 
 1895            FLOW_LOG_WARNING(
"Option_set[" << *
this << 
"]: State PARSING: Unregistered option named " 
 1896                             "[" << opt_name << 
"] is not approved; parse failed.  Values payload untouched.");
 
 1898                                                  "] is not approved; parse failed."));
 
 1903          FLOW_LOG_TRACE(
"Option_set[" << *
this << 
"]: State PARSING: Ignoring unregistered option named " 
 1904                         "[" << opt_name << 
"]; it is in the approved-list.  Perhaps this file contains " 
 1905                         "other option sets.");
 
 1915  FLOW_LOG_TRACE(
"Option_set[" << *
this << 
"]: State PARSING: Parsed general format successfully.  " 
 1916                 "Will now parse each option's value.");
 
 1926  variables_map fresh_iterable_values;
 
 1929    store(parsed_options, fresh_iterable_values);
 
 1931  catch (
const exception& exc)
 
 1934    m_values_candidate = values_candidate_backup;
 
 1937                     "Parsed file [" << cfg_path << 
"]: Exception occurred; individual option parsing failed.  " 
 1938                     "Values payload untouched.  Message = [" << exc.what() << 
"].");
 
 1942  FLOW_LOG_TRACE(
"Option_set[" << *
this << 
"]: State PARSING: Parsed each individual option successfully.  " 
 1943                 "Will now further validate each option value logically and store on success.");
 
 1949    notify(fresh_iterable_values);
 
 1951  catch (
const exception& exc)
 
 1954    m_values_candidate = values_candidate_backup;
 
 1957                     "Parsed file [" << cfg_path << 
"]: Exception occurred; individual logical validation failed.  " 
 1958                     "Values payload untouched.  Message = [" << exc.what() << 
"].");
 
 1963  for (
const auto& pair : fresh_iterable_values)
 
 1965    const auto& name = pair.first;
 
 1966    const auto& var_value = pair.second.value(); 
 
 1968    assert((!
key_exists(m_iterable_values_candidate, name) ||
 
 1969           (m_iterable_values_candidate[name].type() == var_value.type())));
 
 1971    m_iterable_values_candidate[name] = var_value; 
 
 1976  args.
m_call_type = Declare_options_func_args::Call_type::S_COMPARE_PARSED_VALS;
 
 1978  m_declare_opts_func(args);
 
 1986  FLOW_LOG_TRACE(
"Option_set[" << *
this << 
"]: State PARSING: Validate/store succeded.  " 
 1987                 "Further validation deferred until attempt to enter state CANONICAL.  " 
 1988                 "Updated values payload details follow.");
 
 1989  log_values(
"post-parsing candidate config", &m_values_candidate, 
log::Sev::S_TRACE);
 
 1992template<
typename Value_set>
 
 1998    FLOW_LOG_INFO(
"Option_set[" << *
this << 
"]: State CANONICAL: Request to load values from source struct " 
 1999                  "[" << &src_values << 
"]; entering state PARSING.  " 
 2000                  "Any preceding canonical state will be ignored.  Details follow (TRACE log level).");
 
 2002    assert(m_iterable_values_candidate.empty());
 
 2006    FLOW_LOG_INFO(
"Option_set[" << *
this << 
"]: State PARSING: Request to load values from source struct " 
 2007                  "[" << &src_values << 
"]; continuing by parsing this next config source.  " 
 2008                  "Any current candidate values payload will be overwritten entirely.  " 
 2009                  "Details follow (TRACE log level).");
 
 2024  args.
m_call_type = Declare_options_func_args::Call_type::S_LOAD_VALS_AS_IF_PARSED;
 
 2026  m_declare_opts_func(args);
 
 2034  args.
m_call_type = Declare_options_func_args::Call_type::S_COMPARE_PARSED_VALS;
 
 2036  m_declare_opts_func(args);
 
 2038  log_values(
"post-loading (perhaps baseline or rewound) candidate config", &m_values_candidate, 
log::Sev::S_TRACE);
 
 2041template<
typename Value_set>
 
 2048  FLOW_LOG_INFO(
"Option_set[" << *
this << 
"]: State PARSING: Entering state CANONICAL.  " 
 2049                "Values payload finalized.  Details follow (TRACE log level).");
 
 2050  log_values(
"entering-CANONICAL-state finalized config", &m_values_candidate, 
log::Sev::S_TRACE);
 
 2056  for (
const auto& pair : m_iterable_values_candidate)
 
 2058    const auto& name = pair.first;
 
 2059    FLOW_LOG_INFO(
"Option_set[" << *
this << 
"]: Detected change in option named [" << name << 
"].");
 
 2062  if (change_detected)
 
 2064    *change_detected = (!m_iterable_values_candidate.empty());
 
 2070  m_values = m_values_candidate;
 
 2071  m_iterable_values_candidate.clear();
 
 2074template<
typename Value_set>
 
 2079    FLOW_LOG_INFO(
"Option_set[" << *
this << 
"]: State PARSING: Rejecting candidate payload built; " 
 2080                  "reverting to state CANONICAL.");
 
 2082    m_iterable_values_candidate.clear();
 
 2087template<
typename Value_set>
 
 2090  validate_values(values(), success_or_null);
 
 2093template<
typename Value_set>
 
 2096  const auto candidate = values_candidate();
 
 2097  assert(candidate && 
"Do not invoke validate_values_candidate() in CANONICAL state; only while PARSING.");
 
 2098  validate_values(*candidate, success_or_null);
 
 2101template<
typename Value_set>
 
 2104                                            bool* success_or_null) 
 
 2106  using std::exception;
 
 2109  if (success_or_null)
 
 2113      validate_values(logger_ptr, values_to_validate, declare_opts_func);
 
 2115    catch (
const exception& exc)
 
 2118      *success_or_null = 
false;
 
 2121    *success_or_null = 
true;
 
 2129  args.
m_call_type = Declare_options_func_args::Call_type::S_VALIDATE_STORED_VALS;
 
 2138    declare_opts_func(args);
 
 2140  catch (
const exception& exc)
 
 2142    FLOW_LOG_WARNING(
"Stand-alone validation check failed: Details: [" << exc.what() << 
"].");
 
 2147template<
typename Value_set>
 
 2150  validate_values(get_logger(), values_to_validate, m_declare_opts_func, success_or_null);
 
 2153template<
typename Value_set>
 
 2156  return os << 
'[' << val.
m_nickname << 
"]@" << &val;
 
 2159template<
typename Value>
 
 2165template<
typename Rep, 
typename Period>
 
 2170  using boost::chrono::ceil;
 
 2171  using boost::chrono::nanoseconds;
 
 2172  using boost::chrono::microseconds;
 
 2173  using boost::chrono::milliseconds;
 
 2174  using boost::chrono::seconds;
 
 2175  using boost::chrono::minutes;
 
 2176  using boost::chrono::hours;
 
 2179  using raw_ticks_t = uint64_t; 
 
 2182  nanoseconds val_ns(val);
 
 2185  raw_ticks_t raw_abs_ticks = (val_ns.count() < 0) ? (-val_ns.count()) : val_ns.count();
 
 2190  if (raw_abs_ticks == 0)
 
 2192    os << seconds::zero(); 
 
 2198  const auto try_next_unit = [&](
auto pre_division_dur, raw_ticks_t divide_by) -> 
bool 
 2200    if ((raw_abs_ticks % divide_by) == 0)
 
 2203      raw_abs_ticks /= divide_by;
 
 2211  if (!(try_next_unit(val_ns, 1000)
 
 2212        || try_next_unit(ceil<microseconds>(val), 1000)
 
 2213        || try_next_unit(ceil<milliseconds>(val), 1000)
 
 2214        || try_next_unit(ceil<seconds>(val), 60)
 
 2215        || try_next_unit(ceil<minutes>(val), 60)))
 
 2217    os << ceil<hours>(val);
 
 2221template<
typename Element>
 
 2224  for (
size_t idx = 0; idx != val.size(); ++idx)
 
 2227    value_to_ostream<Element>(os, val[idx]);
 
 2229    if (idx != (val.size() - 1))
 
 2236template<
typename Key>
 
 2242  using boost::regex_match;
 
 2243  using boost::smatch;
 
 2252  smatch matched_groups;
 
 2256  const string member_id_str(member_id);
 
 2258  const bool matched_ok =
 
 2261  assert(matched_ok && 
"Member identifier must look like: <longest possible stuff>[<key to replace>]<the rest>");
 
 2263  constexpr char INDEX_SEP_BEFORE(
'.');
 
Un-templated base for Option_set.
static void declare_option_for_output(util::String_view name, opts::options_description *target_opts, const Value &value_default, const Value ¤t_value, util::String_view description)
Internal-through-macro helper function; the user shall not call this directly but only through FLOW_C...
static Function< void(const Value &val)> throw_on_invalid_func(util::String_view name, Function< bool(const Value &val)> &&validator_func_moved, util::String_view validator_cond_str)
Returns a function that wraps a Value->Boolean validator function, as passed to declare_option_for_pa...
Declare_options_func_call_type
Internal-use type to use with Option_set::Declare_options_func callback.
@ S_FILL_OUTPUT_HELP_ROLE_OPT_TABLE
Internal use only through macro.
@ S_FILL_PARSING_ROLE_OPT_TABLE
Internal use only through macro.
static void validate_parsed_option(util::String_view name, const Value &value, Function< bool(const Value &val)> &&validator_func_moved, util::String_view validator_cond_str)
Internal-through-macro helper function; the user shall not call this directly but only through FLOW_C...
opts::options_description Opt_table
Short-hand for boost.program_options config options description, each of which is used for parsing an...
The core config-parsing facility, which builds parsing/comparison/output capabilities on top of a giv...
typename Values::Ptr Mutable_values_ptr
Short-hand for ref-counted pointer to a mutable Values (config payload storable in an Option_set).
const boost::unordered_set< std::string > & option_names() const
Returns set of all option names declared by the option-declaring function passed to the constructor.
std::map< std::string, boost::any > Iterable_values
Similar to a boost.program_options parsing results variables_map, which conceptually mirrors the resu...
Opt_table m_opts_for_parsing
The parsing-role Opt_table (see extensive explanation in Opt_table doc header).
Iterable_values m_iterable_values_candidate
Structure mirroring m_values_candidate, where the values are the parsing-enabled members of m_values_...
Mutable_values_ptr mutable_values_copy() const
Convenience method that heap-allocates a copy of the internally stored values() and wraps in a ref-co...
void validate_values(bool *success_or_null=0) const
Validates the current contents of values() using the validators *this Option_set<Value_set> is config...
void parse_config_file(const fs::path &cfg_path, bool allow_unregistered, bool *success_or_null=0, const boost::unordered_set< std::string > &allowed_unregistered_opts_or_empty={})
Enters into (from CANONICAL state) or continues in PARSING state by parsing the config source in the ...
const std::string m_nickname
See nickname ctor arg.
boost::unordered_set< std::string > m_opt_names
See option_names().
void log_help(util::String_view summary, log::Sev sev=log::Sev::S_INFO) const
Logs a multi-line help message using help_to_ostream().
Values m_values
See values().
void load_option_value_as_if_parsed(util::String_view name, Value *target_value, const Value &source_value)
Internal-through-macro helper function; the user shall not call this directly but only through FLOW_C...
const Values & values() const
Externally immutable internally stored canonical (current) config values as last constructed or parse...
Declare_options_func m_declare_opts_func
The Opt_table-filling, or m_iterable_values_candidate-scanning, callback passed to the constructor an...
typename Values::Const_ptr Values_ptr
Short-hand for ref-counted pointer to an immutable Value_set (config payload storable in an Option_se...
void canonicalize_candidate(bool *change_detected=0)
In PARSING state enters CANONICAL state, finalizing values() from values_candidate().
void declare_option_for_parsing(util::String_view name, Value *target_value, const Value *value_default_if_no_acc, Function< bool(const Value &val)> &&validator_func_moved, util::String_view validator_cond_str)
Internal-through-macro helper function; the user shall not call this directly but only through FLOW_C...
Opt_table m_opts_for_help
The output-role Opt_table, help-text sub-role (see extensive explanation in Opt_table doc header).
Value_set Values
Short-hand for the template parameter type Value_set.
Option_set(log::Logger *logger_ptr, util::String_view nickname, Declare_options_func &&declare_opts_func_moved)
Constructs an option set in CANONICAL state with a default-valued values() payload and options declar...
bool m_parsing
See values_candidate() – true if and only if that returns non-null (PARSING state; else CANONICAL sta...
void reject_candidate()
In PARSING state, returns to CANONICAL state, as if no parse attempts have occurred.
void log_values(util::String_view summary, const Values *values_or_null=0, log::Sev sev=log::Sev::S_INFO) const
Logs the given values payload using values_to_ostream().
bool null() const
Return true if and only if the option-declaring function passed to the constructor declared no option...
void declare_option_for_help(util::String_view name, const Value &value_default, util::String_view description)
Internal-through-macro helper function; the user shall not call this directly but only through FLOW_C...
void values_to_ostream(std::ostream &os, const Values *values_or_null=0) const
Writes a multi-line user-suitable representation of the current values in a Values object,...
const Values * values_candidate() const
Returns null in CANONICAL state; or in PARSING state a pointer to the not-yet-canonical values after ...
void help_to_ostream(std::ostream &os) const
Prints a multi-line help message about the set of options that *this can parse.
Values m_values_candidate
See values_candidate(). When that returns null (m_parsing == false) this value is meaningless.
void validate_values_candidate(bool *success_or_null=0) const
Equivalent to validate_values(success_or_null) but validates *values_candidate() instead of values().
Values m_values_default
Copy of values() when it is first constructed; i.e., the defaults.
void parse_direct_values(const Values &src_values)
Enters into (from CANONICAL state) or continues in PARSING state by simply setting *values_candidate(...
void scan_parsed_option(util::String_view name, const Value &canonical_value)
Internal-through-macro helper function; the user shall not call this directly but only through FLOW_C...
An std::runtime_error (which is an std::exception) that stores an Error_code.
Convenience class that simply stores a Logger and/or Component passed into a constructor; and returns...
Interface that the user should implement, passing the implementing Logger into logging classes (Flow'...
Similar to ostringstream but allows fast read-only access directly into the std::string being written...
std::ostream & os()
Access to stream that will write to owned string.
#define FLOW_ERROR_SYS_ERROR_LOG_WARNING()
Logs a warning about the (often errno-based or from a library) error code in sys_err_code.
#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_SET_CONTEXT(ARG_logger_ptr, ARG_component_payload)
For the rest of the block within which this macro is instantiated, causes all FLOW_LOG_....
#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...
void value_to_ostream(std::ostream &os, const Value &val)
Serializes a value of type Value to the given ostream suitably for output in Option_set-related outpu...
std::string value_set_member_id_to_opt_name(util::String_view member_id)
Utility, used by FLOW_CFG_OPTION_SET_DECLARE_OPTION() internally but made available as a public API i...
std::string value_set_member_id_to_opt_name_keyed(util::String_view member_id, const Key &key)
Similar to value_set_member_id_to_opt_name() but used by FLOW_CFG_OPTION_SET_DECLARE_OPTION_KEYED() i...
const boost::regex VALUE_SET_MEMBER_ID_TO_OPT_NAME_KEYED_REGEX
An internal constant for value_set_member_id_to_opt_name_keyed().
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_TRACE
Message indicates any condition that may occur with great frequency (thus verbose if logged).
@ S_INFO
Message indicates a not-"bad" condition that is not frequent enough to be of severity Sev::S_TRACE.
bool key_exists(const Container &container, const typename Container::key_type &key)
Returns true if and only if the given key is present at least once in the given associative container...
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...
Basic_string_view< char > String_view
Commonly used char-based Basic_string_view. See its doc header.
boost::system::error_code Error_code
Short-hand for a boost.system error code (which basically encapsulates an integer/enum error code and...
Flow_log_component
The flow::log::Component payload enumeration comprising various log components used by Flow's own int...
Internal-use structure to use with Declare_options_func callback.
Option_set * m_option_set
m_option_set->m_opts_for_parsing shall be filled out.
const Values * m_values_current
The current values loaded into *m_target_opts (e.g., via description text) will originate here.
struct flow::cfg::Option_set::Declare_options_func_args::@0::@1 m_fill_parsing_role_opt_table_args
Corresponds to Call_type::S_FILL_PARSING_ROLE_OPT_TABLE.
struct flow::cfg::Option_set::Declare_options_func_args::@0::@2 m_fill_output_help_role_opt_table_args
Corresponds to Call_type::S_FILL_OUTPUT_HELP_ROLE_OPT_TABLE.
struct flow::cfg::Option_set::Declare_options_func_args::@0::@3 m_fill_output_current_role_opt_table_args
Corresponds to Call_type::S_FILL_OUTPUT_CURRENT_ROLE_OPT_TABLE.
struct flow::cfg::Option_set::Declare_options_func_args::@0::@5 m_load_val_as_if_parsed_args
Corresponds to Call_type::S_LOAD_VALS_AS_IF_PARSED.
struct flow::cfg::Option_set::Declare_options_func_args::@0::@4 m_compare_parsed_vals_args
Corresponds to Call_type::S_COMPARE_PARSED_VALS.
const Values * m_values_to_validate
Each validator-enabled (via a Declare_options_func) member in this structure shall be validated.
const Values * m_values_default
m_option_set->m_values_default: defaults loaded into Option_set::m_opts_for_help will originate here.
const Values * m_values_to_load
Values shall be copied from this external Value_set.
opts::options_description * m_target_opts
m_target_opts shall be filled out based on the defaults earlier saved into m_values_default and curre...
Call_type m_call_type
Why Declare_options_func is being called.
Values * m_values_candidate
m_option_set->m_values_candidate, the parsing-in-progress Value_set filled out whenever parsing using...
const Values * m_values_default_no_acc
m_option_set->m_values_default: the defaults loaded into m_values_candidate at the top of each parse,...
union flow::cfg::Option_set::Declare_options_func_args::@0 m_args
The args to pass in depending on m_call_type.
struct flow::cfg::Option_set::Declare_options_func_args::@0::@6 m_validate_stored_vals_args
Corresponds to Call_type::S_VALIDATE_STORED_VALS.