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 =
nullptr);
810 bool* success_or_null =
nullptr,
811 const boost::unordered_set<std::string>& allowed_unregistered_opts_or_empty = {});
927 template<
typename Value>
929 Function<
bool (
const Value& val)>&& validator_func_moved,
951 template<
typename Value>
970 template<
typename Value>
994 template<
typename Value>
1023 const boost::unordered_set<std::string>&
option_names()
const;
1158#define FLOW_CFG_OPTION_SET_DECLARE_OPTION(ARG_m_value, ARG_description, ARG_bool_validate_expr) \
1159 FLOW_CFG_OPTION_SET_DECLARE_OPTION_WITH_KNOBS(ARG_m_value, ARG_description, ARG_bool_validate_expr, false)
1179#define FLOW_CFG_OPTION_SET_DECLARE_OPTION_NO_ACC(ARG_m_value, ARG_description, ARG_bool_validate_expr) \
1180 FLOW_CFG_OPTION_SET_DECLARE_OPTION_WITH_KNOBS(ARG_m_value, ARG_description, ARG_bool_validate_expr, true)
1278#define FLOW_CFG_OPTION_SET_DECLARE_OPTION_KEYED(ARG_m_value, ARG_description, ARG_bool_validate_expr, ARG_key) \
1279 FLOW_UTIL_SEMICOLON_SAFE \
1281 const ::std::string FLOW_CFG_SET_DECL_OPT_KEYED_name \
1282 = ::flow::cfg::value_set_member_id_to_opt_name_keyed(#ARG_m_value, ARG_key); \
1283 FLOW_CFG_OPTION_SET_DECLARE_OPTION_MANUALLY_NAMED \
1284 (ARG_m_value, FLOW_CFG_SET_DECL_OPT_KEYED_name.c_str(), ARG_description, ARG_bool_validate_expr, false); \
1302#define FLOW_CFG_OPTION_SET_DECLARE_OPTION_KEYED_NO_ACC(ARG_m_value, ARG_description, ARG_bool_validate_expr, ARG_key) \
1303 FLOW_UTIL_SEMICOLON_SAFE \
1305 const ::std::string FLOW_CFG_SET_DECL_OPT_KEYED_name \
1306 = ::flow::cfg::value_set_member_id_to_opt_name_keyed(#ARG_m_value, ARG_key); \
1307 FLOW_CFG_OPTION_SET_DECLARE_OPTION_MANUALLY_NAMED \
1308 (ARG_m_value, FLOW_CFG_SET_DECL_OPT_KEYED_name.c_str(), ARG_description, ARG_bool_validate_expr, true); \
1331#define FLOW_CFG_OPTION_SET_DECLARE_OPTION_WITH_KNOBS(ARG_m_value, ARG_description, ARG_bool_validate_expr, \
1332 ARG_no_accumulation) \
1333 FLOW_UTIL_SEMICOLON_SAFE \
1335 const ::std::string FLOW_CFG_SET_DECL_OPT_name = ::flow::cfg::value_set_member_id_to_opt_name(#ARG_m_value); \
1336 FLOW_CFG_OPTION_SET_DECLARE_OPTION_MANUALLY_NAMED \
1337 (ARG_m_value, FLOW_CFG_SET_DECL_OPT_name.c_str(), ARG_description, ARG_bool_validate_expr, \
1338 ARG_no_accumulation); \
1370#define FLOW_CFG_OPTION_SET_DECLARE_OPTION_MANUALLY_NAMED(ARG_m_value, ARG_opt_name_c_str, \
1371 ARG_description, ARG_bool_validate_expr, \
1372 ARG_no_accumulation) \
1373 FLOW_UTIL_SEMICOLON_SAFE \
1375 char const * const FLOW_CFG_SET_DECL_OPT_MANUAL_name_c_str = ARG_opt_name_c_str; \
1377 const ::flow::util::String_view FLOW_CFG_SET_DECL_OPT_MANUAL_name_view{FLOW_CFG_SET_DECL_OPT_MANUAL_name_c_str}; \
1378 const bool FLOW_CFG_SET_DECL_OPT_MANUAL_no_acc = ARG_no_accumulation; \
1379 switch (args.m_call_type) \
1381 case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_FILL_PARSING_ROLE_OPT_TABLE: \
1383 using Value = decltype(args.m_args.m_fill_parsing_role_opt_table_args.m_values_candidate->ARG_m_value); \
1386 flow::Function<bool (const Value&)> FLOW_CFG_SET_DECL_OPT_MANUAL_validator_func \
1387 = [FLOW_CFG_SET_DECL_OPT_MANUAL_name_std_str = std::string(FLOW_CFG_SET_DECL_OPT_MANUAL_name_c_str)] \
1388 ([[maybe_unused]] const Value& val) -> bool { return ARG_bool_validate_expr; }; \
1389 args.m_args.m_fill_parsing_role_opt_table_args.m_option_set \
1390 ->declare_option_for_parsing \
1391 (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \
1392 &args.m_args.m_fill_parsing_role_opt_table_args.m_values_candidate->ARG_m_value, \
1398 FLOW_CFG_SET_DECL_OPT_MANUAL_no_acc \
1399 ? &args.m_args.m_fill_parsing_role_opt_table_args.m_values_default_no_acc->ARG_m_value \
1401 ::std::move(FLOW_CFG_SET_DECL_OPT_MANUAL_validator_func), \
1402 ::flow::util::String_view{#ARG_bool_validate_expr}); \
1405 case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_FILL_OUTPUT_HELP_ROLE_OPT_TABLE: \
1406 args.m_args.m_fill_output_help_role_opt_table_args.m_option_set \
1407 ->declare_option_for_help \
1408 (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \
1409 args.m_args.m_fill_output_help_role_opt_table_args.m_values_default->ARG_m_value, \
1412 case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_FILL_OUTPUT_CURRENT_ROLE_OPT_TABLE: \
1413 ::flow::cfg::Option_set_base::declare_option_for_output \
1414 (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \
1415 args.m_args.m_fill_output_current_role_opt_table_args.m_target_opts, \
1416 args.m_args.m_fill_output_current_role_opt_table_args.m_values_default->ARG_m_value, \
1417 args.m_args.m_fill_output_current_role_opt_table_args.m_values_current->ARG_m_value, \
1420 case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_COMPARE_PARSED_VALS: \
1421 args.m_args.m_compare_parsed_vals_args.m_option_set \
1422 ->scan_parsed_option \
1423 (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \
1424 args.m_args.m_compare_parsed_vals_args.m_option_set->values().ARG_m_value); \
1426 case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_LOAD_VALS_AS_IF_PARSED: \
1427 args.m_args.m_load_val_as_if_parsed_args.m_option_set \
1428 ->load_option_value_as_if_parsed \
1429 (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \
1430 &args.m_args.m_load_val_as_if_parsed_args.m_values_candidate->ARG_m_value, \
1431 args.m_args.m_load_val_as_if_parsed_args.m_values_to_load->ARG_m_value); \
1433 case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_VALIDATE_STORED_VALS: \
1436 using Value = decltype(args.m_args.m_validate_stored_vals_args.m_values_to_validate->ARG_m_value); \
1437 flow::Function<bool (const Value&)> FLOW_CFG_SET_DECL_OPT_MANUAL_validator_func \
1438 = [FLOW_CFG_SET_DECL_OPT_MANUAL_name_std_str = std::string(FLOW_CFG_SET_DECL_OPT_MANUAL_name_c_str)] \
1439 ([[maybe_unused]] const Value& val) -> bool { return ARG_bool_validate_expr; }; \
1441 ::flow::cfg::Option_set_base::validate_parsed_option \
1442 (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \
1443 args.m_args.m_validate_stored_vals_args.m_values_to_validate->ARG_m_value, \
1444 ::std::move(FLOW_CFG_SET_DECL_OPT_MANUAL_validator_func), \
1445 ::flow::util::String_view{#ARG_bool_validate_expr}); \
1454template<
typename Value_set>
1458 m_nickname(nickname),
1460 m_declare_opts_func(std::move(declare_opts_func_moved)),
1464 FLOW_LOG_TRACE(
"Option_set[" << *
this <<
"]: Created with default values payload. Options table setup begins.");
1481 FLOW_LOG_TRACE(
"Option_set[" << *
this <<
"]: Options table setup finished. Null set? = [" <<
null() <<
"].");
1484template<
typename Value_set>
1490template<
typename Value_set>
1496template<
typename Value_set>
1502template<
typename Value_set>
1505 return m_parsing ? &m_values_candidate :
nullptr;
1508template<
typename Value_set>
1513 constexpr unsigned int LINE_LENGTH = 1000;
1514 constexpr unsigned int DESC_LENGTH = LINE_LENGTH - 1;
1516 Opt_table opts_for_output(LINE_LENGTH, DESC_LENGTH);
1519 args.
m_call_type = Declare_options_func_args::Call_type::S_FILL_OUTPUT_CURRENT_ROLE_OPT_TABLE;
1521 = { &opts_for_output, &m_values_default,
1522 values_or_null ? values_or_null : &m_values };
1523 m_declare_opts_func(args);
1525 os << opts_for_output;
1528template<
typename Value_set>
1535 values_to_ostream(os.os(), values_or_null);
1537 FLOW_LOG_WITH_CHECKING(sev,
"Option_set[" << *
this <<
"]: Values payload [" << summary <<
"]:\n" << os.str());
1540template<
typename Value_set>
1543 os << m_opts_for_help;
1546template<
typename Value_set>
1553 help_to_ostream(os.os());
1558template<
typename Value_set>
1564template<
typename Value_set>
1565template<
typename Value>
1567 Value* target_value,
const Value* value_default_if_no_acc,
1568 Function<
bool (
const Value& val)>&& validator_func_moved,
1576 assert(target_value);
1577 string name(name_view);
1579 m_opt_names.insert(name);
1582 FLOW_LOG_TRACE(
"Option_set[" << *
this <<
"]: Options table of parsing-role: "
1583 "Declaring parsing-capable option [" << name <<
"]; raw shallow size [" <<
sizeof(Value) <<
"].");
1588 const auto val_spec = value<Value>(target_value)
1589 ->notifier(throw_on_invalid_func(name_view, std::move(validator_func_moved),
1590 validator_cond_str_view));
1595 if (value_default_if_no_acc)
1598 String_ostream default_str_os;
1600 default_str_os.os() << flush;
1602 val_spec->default_value(*value_default_if_no_acc, default_str_os.str());
1605 m_opts_for_parsing.add_options()(name.c_str(), val_spec);
1610template<
typename Value>
1613 Function<
bool (
const Value& val)>&& validator_func_moved,
1621 return [validator_func = std::move(validator_func_moved),
1622 validator_cond_str = string(validator_cond_str_view),
1623 name = string(name_view)]
1626 if (!(validator_func(val)))
1628 String_ostream msg_os;
1629 msg_os.
os() <<
"Option [" << name <<
"]: "
1630 "Validation failed; the following condition must hold: [" << validator_cond_str <<
"]. "
1631 "Option value `val` = [";
1633 msg_os.os() <<
"]." << flush;
1634 throw Runtime_error{msg_os.str()};
1639template<
typename Value_set>
1640template<
typename Value>
1649 assert(!description.empty());
1655 String_ostream default_str_os;
1657 default_str_os.os() << flush;
1659 m_opts_for_help.add_options()
1660 (string(name).c_str(),
1663 ->default_value(value_default, default_str_os.str()),
1664 string(description).c_str());
1669template<
typename Value>
1671 const Value& value_default,
const Value& current_value,
1679 assert(!description.empty());
1688 String_ostream description_os;
1692 description_os.os() <<
" (";
1696 description_os.os() <<
") <==current | default==^\n"
1697 " " << description << flush;
1700 String_ostream default_str_os;
1702 default_str_os.os() << flush;
1704 target_opts->add_options()
1705 (string(name).c_str(),
1708 ->default_value(value_default, default_str_os.str()),
1709 description_os.str().c_str());
1714template<
typename Value_set>
1715template<
typename Value>
1718 using boost::any_cast;
1720 string name{name_view};
1728 const auto it = m_iterable_values_candidate.find(name);
1729 if (it == m_iterable_values_candidate.end())
1735 const auto& new_val = any_cast<const Value&>(it->second);
1736 const auto& old_val = canonical_value;
1738 if (old_val == new_val)
1740 m_iterable_values_candidate.erase(name);
1745template<
typename Value_set>
1746template<
typename Value>
1748 Value* target_value,
1749 const Value& source_value)
1752 string name{name_view};
1754 assert(target_value);
1762 *target_value = source_value;
1765 m_iterable_values_candidate[name] = source_value;
1773template<
typename Value>
1775 Function<
bool (
const Value& val)>&& validator_func_moved,
1778 const auto validate_or_throw_func =
throw_on_invalid_func(name_view, std::move(validator_func_moved),
1779 validator_cond_str_view);
1780 validate_or_throw_func(value);
1783template<
typename Value_set>
1785 (
const fs::path& cfg_path,
bool allow_unregistered,
bool* success_or_null,
1786 const boost::unordered_set<std::string>& allowed_unregistered_opts_or_empty)
1793 using opts::variables_map;
1794 using boost::system::system_category;
1796 using std::exception;
1800 if (success_or_null)
1804 parse_config_file(cfg_path, allow_unregistered,
nullptr, allowed_unregistered_opts_or_empty);
1806 catch (
const exception& exc)
1809 *success_or_null =
false;
1812 *success_or_null =
true;
1820 FLOW_LOG_INFO(
"Option_set[" << *
this <<
"]: State CANONICAL: Request to parse file [" << cfg_path <<
"]; "
1821 "entering state PARSING. Initial candidate values payload initialized from current canonical "
1822 "values payload. Details follow (TRACE log level).");
1824 assert(m_iterable_values_candidate.empty());
1828 FLOW_LOG_INFO(
"Option_set[" << *
this <<
"]: State PARSING: Request to parse file [" << cfg_path <<
"]; "
1829 "continuing by parsing this next config source. "
1830 "The values payload going into it is as it was after the previous config source. "
1831 "Details follow (TRACE log level).");
1834 log_values(
"pre-parsing candidate config", &m_values_candidate,
log::Sev::S_TRACE);
1836 ifstream ifs{cfg_path};
1839 const Error_code sys_err_code{errno, system_category()};
1842 throw Runtime_error{sys_err_code,
ostream_op_string(
"Could not open file [", cfg_path,
"].")};
1852 const auto values_candidate_backup = m_values_candidate;
1853 opts::parsed_options parsed_options{&m_opts_for_parsing};
1856 parsed_options = opts::parse_config_file(ifs, m_opts_for_parsing, allow_unregistered);
1858 catch (
const exception& exc)
1860 m_values_candidate = values_candidate_backup;
1864 "Parsing file [" << cfg_path <<
"]: Exception occurred; parse failed. Values payload untouched. "
1865 "Message = [" << exc.what() <<
"].");
1873 if (allow_unregistered)
1875 for (
const auto& option : parsed_options.options)
1877 if (option.unregistered)
1879 assert(!option.original_tokens.empty());
1880 const string opt_name = option.original_tokens.front();
1882 if (allowed_unregistered_opts_or_empty.empty())
1885 FLOW_LOG_TRACE(
"Option_set[" << *
this <<
"]: State PARSING: Ignoring unregistered option named "
1886 "[" << opt_name <<
"]. We were not given an approved-list. Perhaps this file contains "
1887 "other option sets, or it has to do with forward/backward-compatibility.");
1891 if (!
key_exists(allowed_unregistered_opts_or_empty, opt_name))
1894 m_values_candidate = values_candidate_backup;
1896 FLOW_LOG_WARNING(
"Option_set[" << *
this <<
"]: State PARSING: Unregistered option named "
1897 "[" << opt_name <<
"] is not approved; parse failed. Values payload untouched.");
1899 "] is not approved; parse failed.")};
1904 FLOW_LOG_TRACE(
"Option_set[" << *
this <<
"]: State PARSING: Ignoring unregistered option named "
1905 "[" << opt_name <<
"]; it is in the approved-list. Perhaps this file contains "
1906 "other option sets.");
1916 FLOW_LOG_TRACE(
"Option_set[" << *
this <<
"]: State PARSING: Parsed general format successfully. "
1917 "Will now parse each option's value.");
1927 variables_map fresh_iterable_values;
1930 store(parsed_options, fresh_iterable_values);
1932 catch (
const exception& exc)
1935 m_values_candidate = values_candidate_backup;
1938 "Parsed file [" << cfg_path <<
"]: Exception occurred; individual option parsing failed. "
1939 "Values payload untouched. Message = [" << exc.what() <<
"].");
1943 FLOW_LOG_TRACE(
"Option_set[" << *
this <<
"]: State PARSING: Parsed each individual option successfully. "
1944 "Will now further validate each option value logically and store on success.");
1950 notify(fresh_iterable_values);
1952 catch (
const exception& exc)
1955 m_values_candidate = values_candidate_backup;
1958 "Parsed file [" << cfg_path <<
"]: Exception occurred; individual logical validation failed. "
1959 "Values payload untouched. Message = [" << exc.what() <<
"].");
1964 for (
const auto& pair : fresh_iterable_values)
1966 const auto& name = pair.first;
1967 const auto& var_value = pair.second.value();
1969 assert((!
key_exists(m_iterable_values_candidate, name) ||
1970 (m_iterable_values_candidate[name].type() == var_value.type())));
1972 m_iterable_values_candidate[name] = var_value;
1977 args.
m_call_type = Declare_options_func_args::Call_type::S_COMPARE_PARSED_VALS;
1979 m_declare_opts_func(args);
1987 FLOW_LOG_TRACE(
"Option_set[" << *
this <<
"]: State PARSING: Validate/store succeded. "
1988 "Further validation deferred until attempt to enter state CANONICAL. "
1989 "Updated values payload details follow.");
1990 log_values(
"post-parsing candidate config", &m_values_candidate,
log::Sev::S_TRACE);
1993template<
typename Value_set>
1999 FLOW_LOG_INFO(
"Option_set[" << *
this <<
"]: State CANONICAL: Request to load values from source struct "
2000 "[" << &src_values <<
"]; entering state PARSING. "
2001 "Any preceding canonical state will be ignored. Details follow (TRACE log level).");
2003 assert(m_iterable_values_candidate.empty());
2007 FLOW_LOG_INFO(
"Option_set[" << *
this <<
"]: State PARSING: Request to load values from source struct "
2008 "[" << &src_values <<
"]; continuing by parsing this next config source. "
2009 "Any current candidate values payload will be overwritten entirely. "
2010 "Details follow (TRACE log level).");
2025 args.
m_call_type = Declare_options_func_args::Call_type::S_LOAD_VALS_AS_IF_PARSED;
2027 m_declare_opts_func(args);
2035 args.
m_call_type = Declare_options_func_args::Call_type::S_COMPARE_PARSED_VALS;
2037 m_declare_opts_func(args);
2039 log_values(
"post-loading (perhaps baseline or rewound) candidate config", &m_values_candidate,
log::Sev::S_TRACE);
2042template<
typename Value_set>
2049 FLOW_LOG_INFO(
"Option_set[" << *
this <<
"]: State PARSING: Entering state CANONICAL. "
2050 "Values payload finalized. Details follow (TRACE log level).");
2051 log_values(
"entering-CANONICAL-state finalized config", &m_values_candidate,
log::Sev::S_TRACE);
2057 for (
const auto& pair : m_iterable_values_candidate)
2059 const auto& name = pair.first;
2060 FLOW_LOG_INFO(
"Option_set[" << *
this <<
"]: Detected change in option named [" << name <<
"].");
2063 if (change_detected)
2065 *change_detected = (!m_iterable_values_candidate.empty());
2071 m_values = m_values_candidate;
2072 m_iterable_values_candidate.clear();
2075template<
typename Value_set>
2080 FLOW_LOG_INFO(
"Option_set[" << *
this <<
"]: State PARSING: Rejecting candidate payload built; "
2081 "reverting to state CANONICAL.");
2083 m_iterable_values_candidate.clear();
2088template<
typename Value_set>
2091 validate_values(values(), success_or_null);
2094template<
typename Value_set>
2097 const auto candidate = values_candidate();
2098 assert(candidate &&
"Do not invoke validate_values_candidate() in CANONICAL state; only while PARSING.");
2099 validate_values(*candidate, success_or_null);
2102template<
typename Value_set>
2105 bool* success_or_null)
2107 using std::exception;
2110 if (success_or_null)
2114 validate_values(logger_ptr, values_to_validate, declare_opts_func);
2116 catch (
const exception& exc)
2119 *success_or_null =
false;
2122 *success_or_null =
true;
2130 args.
m_call_type = Declare_options_func_args::Call_type::S_VALIDATE_STORED_VALS;
2139 declare_opts_func(args);
2141 catch (
const exception& exc)
2143 FLOW_LOG_WARNING(
"Stand-alone validation check failed: Details: [" << exc.what() <<
"].");
2148template<
typename Value_set>
2151 validate_values(get_logger(), values_to_validate, m_declare_opts_func, success_or_null);
2154template<
typename Value_set>
2157 return os <<
'[' << val.
m_nickname <<
"]@" << &val;
2160template<
typename Value>
2166template<
typename Rep,
typename Period>
2171 using boost::chrono::ceil;
2172 using boost::chrono::nanoseconds;
2173 using boost::chrono::microseconds;
2174 using boost::chrono::milliseconds;
2175 using boost::chrono::seconds;
2176 using boost::chrono::minutes;
2177 using boost::chrono::hours;
2180 using raw_ticks_t = uint64_t;
2183 nanoseconds val_ns{val};
2186 raw_ticks_t raw_abs_ticks = (val_ns.count() < 0) ? (-val_ns.count()) : val_ns.count();
2191 if (raw_abs_ticks == 0)
2193 os << seconds::zero();
2199 const auto try_next_unit = [&](
auto pre_division_dur, raw_ticks_t divide_by) ->
bool
2201 if ((raw_abs_ticks % divide_by) == 0)
2204 raw_abs_ticks /= divide_by;
2212 if (!(try_next_unit(val_ns, 1000)
2213 || try_next_unit(ceil<microseconds>(val), 1000)
2214 || try_next_unit(ceil<milliseconds>(val), 1000)
2215 || try_next_unit(ceil<seconds>(val), 60)
2216 || try_next_unit(ceil<minutes>(val), 60)))
2218 os << ceil<hours>(val);
2222template<
typename Element>
2225 for (
size_t idx = 0; idx != val.size(); ++idx)
2228 value_to_ostream<Element>(os, val[idx]);
2230 if (idx != (val.size() - 1))
2237template<
typename Key>
2243 using boost::regex_match;
2244 using boost::smatch;
2253 smatch matched_groups;
2257 const string member_id_str{member_id};
2259 const bool matched_ok =
2262 assert(matched_ok &&
"Member identifier must look like: <longest possible stuff>[<key to replace>]<the rest>");
2264 constexpr char INDEX_SEP_BEFORE(
'.');
2273 size_t(matched_groups[1].length())}),
2277 size_t(matched_groups[2].length())}));
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).
void validate_values(bool *success_or_null=nullptr) const
Validates the current contents of values() using the validators *this Option_set<Value_set> is config...
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_...
void validate_values_candidate(bool *success_or_null=nullptr) const
Equivalent to validate_values(success_or_null) but validates *values_candidate() instead of 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 values_to_ostream(std::ostream &os, const Values *values_or_null=nullptr) const
Writes a multi-line user-suitable representation of the current values in a Values object,...
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 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...
void parse_config_file(const fs::path &cfg_path, bool allow_unregistered, bool *success_or_null=nullptr, 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 ...
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.
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 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 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.
Values m_values_default
Copy of values() when it is first constructed; i.e., the defaults.
void log_values(util::String_view summary, const Values *values_or_null=nullptr, log::Sev sev=log::Sev::S_INFO) const
Logs the given values payload using values_to_ostream().
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 &&... 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.