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
712 bool* success_or_null =
nullptr);
823 bool* success_or_null =
nullptr,
824 const boost::unordered_set<std::string>& allowed_unregistered_opts_or_empty = {});
940 template<
typename Value>
942 Function<
bool (
const Value& val)>&& validator_func_moved,
964 template<
typename Value>
983 template<
typename Value>
1007 template<
typename Value>
1036 const boost::unordered_set<std::string>&
option_names()
const;
1171#define FLOW_CFG_OPTION_SET_DECLARE_OPTION(ARG_m_value, ARG_description, ARG_bool_validate_expr) \
1172 FLOW_CFG_OPTION_SET_DECLARE_OPTION_WITH_KNOBS(ARG_m_value, ARG_description, ARG_bool_validate_expr, false)
1192#define FLOW_CFG_OPTION_SET_DECLARE_OPTION_NO_ACC(ARG_m_value, ARG_description, ARG_bool_validate_expr) \
1193 FLOW_CFG_OPTION_SET_DECLARE_OPTION_WITH_KNOBS(ARG_m_value, ARG_description, ARG_bool_validate_expr, true)
1291#define FLOW_CFG_OPTION_SET_DECLARE_OPTION_KEYED(ARG_m_value, ARG_description, ARG_bool_validate_expr, ARG_key) \
1292 FLOW_UTIL_SEMICOLON_SAFE \
1294 const ::std::string FLOW_CFG_SET_DECL_OPT_KEYED_name \
1295 = ::flow::cfg::value_set_member_id_to_opt_name_keyed(#ARG_m_value, ARG_key); \
1296 FLOW_CFG_OPTION_SET_DECLARE_OPTION_MANUALLY_NAMED \
1297 (ARG_m_value, FLOW_CFG_SET_DECL_OPT_KEYED_name.c_str(), ARG_description, ARG_bool_validate_expr, false); \
1315#define FLOW_CFG_OPTION_SET_DECLARE_OPTION_KEYED_NO_ACC(ARG_m_value, ARG_description, ARG_bool_validate_expr, ARG_key) \
1316 FLOW_UTIL_SEMICOLON_SAFE \
1318 const ::std::string FLOW_CFG_SET_DECL_OPT_KEYED_name \
1319 = ::flow::cfg::value_set_member_id_to_opt_name_keyed(#ARG_m_value, ARG_key); \
1320 FLOW_CFG_OPTION_SET_DECLARE_OPTION_MANUALLY_NAMED \
1321 (ARG_m_value, FLOW_CFG_SET_DECL_OPT_KEYED_name.c_str(), ARG_description, ARG_bool_validate_expr, true); \
1344#define FLOW_CFG_OPTION_SET_DECLARE_OPTION_WITH_KNOBS(ARG_m_value, ARG_description, ARG_bool_validate_expr, \
1345 ARG_no_accumulation) \
1346 FLOW_UTIL_SEMICOLON_SAFE \
1348 const ::std::string FLOW_CFG_SET_DECL_OPT_name = ::flow::cfg::value_set_member_id_to_opt_name(#ARG_m_value); \
1349 FLOW_CFG_OPTION_SET_DECLARE_OPTION_MANUALLY_NAMED \
1350 (ARG_m_value, FLOW_CFG_SET_DECL_OPT_name.c_str(), ARG_description, ARG_bool_validate_expr, \
1351 ARG_no_accumulation); \
1383#define FLOW_CFG_OPTION_SET_DECLARE_OPTION_MANUALLY_NAMED(ARG_m_value, ARG_opt_name_c_str, \
1384 ARG_description, ARG_bool_validate_expr, \
1385 ARG_no_accumulation) \
1386 FLOW_UTIL_SEMICOLON_SAFE \
1388 char const * const FLOW_CFG_SET_DECL_OPT_MANUAL_name_c_str = ARG_opt_name_c_str; \
1390 const ::flow::util::String_view FLOW_CFG_SET_DECL_OPT_MANUAL_name_view{FLOW_CFG_SET_DECL_OPT_MANUAL_name_c_str}; \
1391 const bool FLOW_CFG_SET_DECL_OPT_MANUAL_no_acc = ARG_no_accumulation; \
1392 switch (args.m_call_type) \
1394 case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_FILL_PARSING_ROLE_OPT_TABLE: \
1396 using Value = decltype(args.m_args.m_fill_parsing_role_opt_table_args.m_values_candidate->ARG_m_value); \
1399 flow::Function<bool (const Value&)> FLOW_CFG_SET_DECL_OPT_MANUAL_validator_func \
1400 = [FLOW_CFG_SET_DECL_OPT_MANUAL_name_std_str = std::string{FLOW_CFG_SET_DECL_OPT_MANUAL_name_c_str}] \
1401 (const Value&) -> bool { return ARG_bool_validate_expr; }; \
1402 args.m_args.m_fill_parsing_role_opt_table_args.m_option_set \
1403 ->declare_option_for_parsing \
1404 (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \
1405 &args.m_args.m_fill_parsing_role_opt_table_args.m_values_candidate->ARG_m_value, \
1411 FLOW_CFG_SET_DECL_OPT_MANUAL_no_acc \
1412 ? &args.m_args.m_fill_parsing_role_opt_table_args.m_values_default_no_acc->ARG_m_value \
1414 ::std::move(FLOW_CFG_SET_DECL_OPT_MANUAL_validator_func), \
1415 ::flow::util::String_view{#ARG_bool_validate_expr}); \
1418 case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_FILL_OUTPUT_HELP_ROLE_OPT_TABLE: \
1419 args.m_args.m_fill_output_help_role_opt_table_args.m_option_set \
1420 ->declare_option_for_help \
1421 (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \
1422 args.m_args.m_fill_output_help_role_opt_table_args.m_values_default->ARG_m_value, \
1425 case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_FILL_OUTPUT_CURRENT_ROLE_OPT_TABLE: \
1426 ::flow::cfg::Option_set_base::declare_option_for_output \
1427 (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \
1428 args.m_args.m_fill_output_current_role_opt_table_args.m_target_opts, \
1429 args.m_args.m_fill_output_current_role_opt_table_args.m_values_default->ARG_m_value, \
1430 args.m_args.m_fill_output_current_role_opt_table_args.m_values_current->ARG_m_value, \
1433 case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_COMPARE_PARSED_VALS: \
1434 args.m_args.m_compare_parsed_vals_args.m_option_set \
1435 ->scan_parsed_option \
1436 (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \
1437 args.m_args.m_compare_parsed_vals_args.m_option_set->values().ARG_m_value); \
1439 case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_LOAD_VALS_AS_IF_PARSED: \
1440 args.m_args.m_load_val_as_if_parsed_args.m_option_set \
1441 ->load_option_value_as_if_parsed \
1442 (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \
1443 &args.m_args.m_load_val_as_if_parsed_args.m_values_candidate->ARG_m_value, \
1444 args.m_args.m_load_val_as_if_parsed_args.m_values_to_load->ARG_m_value); \
1446 case ::flow::cfg::Option_set_base::Declare_options_func_call_type::S_VALIDATE_STORED_VALS: \
1449 using Value = decltype(args.m_args.m_validate_stored_vals_args.m_values_to_validate->ARG_m_value); \
1450 flow::Function<bool (const Value&)> FLOW_CFG_SET_DECL_OPT_MANUAL_validator_func \
1451 = [FLOW_CFG_SET_DECL_OPT_MANUAL_name_std_str = std::string{FLOW_CFG_SET_DECL_OPT_MANUAL_name_c_str}] \
1452 (const Value&) -> bool { return ARG_bool_validate_expr; }; \
1454 ::flow::cfg::Option_set_base::validate_parsed_option \
1455 (FLOW_CFG_SET_DECL_OPT_MANUAL_name_view, \
1456 args.m_args.m_validate_stored_vals_args.m_values_to_validate->ARG_m_value, \
1457 ::std::move(FLOW_CFG_SET_DECL_OPT_MANUAL_validator_func), \
1458 ::flow::util::String_view{#ARG_bool_validate_expr}); \
1467template<
typename Value_set>
1471 m_nickname(nickname),
1473 m_declare_opts_func(std::move(declare_opts_func_moved)),
1477 FLOW_LOG_TRACE(
"Option_set[" << *
this <<
"]: Created with default values payload. Options table setup begins.");
1494 FLOW_LOG_TRACE(
"Option_set[" << *
this <<
"]: Options table setup finished. Null set? = [" <<
null() <<
"].");
1497template<
typename Value_set>
1503template<
typename Value_set>
1509template<
typename Value_set>
1515template<
typename Value_set>
1518 return m_parsing ? &m_values_candidate :
nullptr;
1521template<
typename Value_set>
1526 constexpr unsigned int LINE_LENGTH = 1000;
1527 constexpr unsigned int DESC_LENGTH = LINE_LENGTH - 1;
1529 Opt_table opts_for_output{LINE_LENGTH, DESC_LENGTH};
1532 args.
m_call_type = Declare_options_func_args::Call_type::S_FILL_OUTPUT_CURRENT_ROLE_OPT_TABLE;
1534 = { &opts_for_output, &m_values_default,
1535 values_or_null ? values_or_null : &m_values };
1536 m_declare_opts_func(args);
1538 os << opts_for_output;
1541template<
typename Value_set>
1548 values_to_ostream(os.os(), values_or_null);
1550 FLOW_LOG_WITH_CHECKING(sev,
"Option_set[" << *
this <<
"]: Values payload [" << summary <<
"]:\n" << os.str());
1553template<
typename Value_set>
1556 os << m_opts_for_help;
1559template<
typename Value_set>
1566 help_to_ostream(os.os());
1571template<
typename Value_set>
1577template<
typename Value_set>
1578template<
typename Value>
1580 Value* target_value,
const Value* value_default_if_no_acc,
1581 Function<
bool (
const Value& val)>&& validator_func_moved,
1589 assert(target_value);
1590 string name(name_view);
1592 m_opt_names.insert(name);
1595 FLOW_LOG_TRACE(
"Option_set[" << *
this <<
"]: Options table of parsing-role: "
1596 "Declaring parsing-capable option [" << name <<
"]; raw shallow size [" <<
sizeof(Value) <<
"].");
1601 const auto val_spec = value<Value>(target_value)
1602 ->notifier(throw_on_invalid_func(name_view, std::move(validator_func_moved),
1603 validator_cond_str_view));
1608 if (value_default_if_no_acc)
1611 String_ostream default_str_os;
1613 default_str_os.os() << flush;
1615 val_spec->default_value(*value_default_if_no_acc, default_str_os.str());
1618 m_opts_for_parsing.add_options()(name.c_str(), val_spec);
1623template<
typename Value>
1626 Function<
bool (
const Value& val)>&& validator_func_moved,
1634 return [validator_func = std::move(validator_func_moved),
1635 validator_cond_str =
string{validator_cond_str_view},
1636 name =
string{name_view}]
1639 if (!(validator_func(val)))
1641 String_ostream msg_os;
1642 msg_os.
os() <<
"Option [" << name <<
"]: "
1643 "Validation failed; the following condition must hold: [" << validator_cond_str <<
"]. "
1644 "Option value `val` = [";
1646 msg_os.os() <<
"]." << flush;
1647 throw Runtime_error{msg_os.str()};
1652template<
typename Value_set>
1653template<
typename Value>
1662 assert(!description.empty());
1668 String_ostream default_str_os;
1670 default_str_os.os() << flush;
1672 m_opts_for_help.add_options()
1673 (
string{name}.c_str(),
1676 ->default_value(value_default, default_str_os.str()),
1677 string{description}.c_str());
1682template<
typename Value>
1684 const Value& value_default,
const Value& current_value,
1692 assert(!description.empty());
1701 String_ostream description_os;
1705 description_os.os() <<
" (";
1709 description_os.os() <<
") <==current | default==^\n"
1710 " " << description << flush;
1713 String_ostream default_str_os;
1715 default_str_os.os() << flush;
1717 target_opts->add_options()
1718 (
string{name}.c_str(),
1721 ->default_value(value_default, default_str_os.str()),
1722 description_os.str().c_str());
1727template<
typename Value_set>
1728template<
typename Value>
1731 using boost::any_cast;
1733 string name{name_view};
1741 const auto it = m_iterable_values_candidate.find(name);
1742 if (it == m_iterable_values_candidate.end())
1748 const auto& new_val = any_cast<const Value&>(it->second);
1749 const auto& old_val = canonical_value;
1751 if (old_val == new_val)
1753 m_iterable_values_candidate.erase(name);
1758template<
typename Value_set>
1759template<
typename Value>
1761 Value* target_value,
1762 const Value& source_value)
1765 string name{name_view};
1767 assert(target_value);
1775 *target_value = source_value;
1778 m_iterable_values_candidate[name] = source_value;
1786template<
typename Value>
1788 Function<
bool (
const Value& val)>&& validator_func_moved,
1791 const auto validate_or_throw_func =
throw_on_invalid_func(name_view, std::move(validator_func_moved),
1792 validator_cond_str_view);
1793 validate_or_throw_func(value);
1796template<
typename Value_set>
1798 (
const fs::path& cfg_path,
bool allow_unregistered,
bool* success_or_null,
1799 const boost::unordered_set<std::string>& allowed_unregistered_opts_or_empty)
1806 using opts::variables_map;
1807 using boost::system::system_category;
1809 using std::exception;
1813 if (success_or_null)
1817 parse_config_file(cfg_path, allow_unregistered,
nullptr, allowed_unregistered_opts_or_empty);
1819 catch (
const exception& exc)
1822 *success_or_null =
false;
1825 *success_or_null =
true;
1833 FLOW_LOG_INFO(
"Option_set[" << *
this <<
"]: State CANONICAL: Request to parse file [" << cfg_path <<
"]; "
1834 "entering state PARSING. Initial candidate values payload initialized from current canonical "
1835 "values payload. Details follow (TRACE log level).");
1837 assert(m_iterable_values_candidate.empty());
1841 FLOW_LOG_INFO(
"Option_set[" << *
this <<
"]: State PARSING: Request to parse file [" << cfg_path <<
"]; "
1842 "continuing by parsing this next config source. "
1843 "The values payload going into it is as it was after the previous config source. "
1844 "Details follow (TRACE log level).");
1847 log_values(
"pre-parsing candidate config", &m_values_candidate,
log::Sev::S_TRACE);
1849 ifstream ifs{cfg_path};
1852 const Error_code sys_err_code{errno, system_category()};
1855 throw Runtime_error{sys_err_code,
ostream_op_string(
"Could not open file [", cfg_path,
"].")};
1865 const auto values_candidate_backup = m_values_candidate;
1866 opts::parsed_options parsed_options{&m_opts_for_parsing};
1869 parsed_options = opts::parse_config_file(ifs, m_opts_for_parsing, allow_unregistered);
1871 catch (
const exception& exc)
1873 m_values_candidate = values_candidate_backup;
1877 "Parsing file [" << cfg_path <<
"]: Exception occurred; parse failed. Values payload untouched. "
1878 "Message = [" << exc.what() <<
"].");
1886 if (allow_unregistered)
1888 for (
const auto& option : parsed_options.options)
1890 if (option.unregistered)
1892 assert(!option.original_tokens.empty());
1893 const string opt_name = option.original_tokens.front();
1895 if (allowed_unregistered_opts_or_empty.empty())
1898 FLOW_LOG_TRACE(
"Option_set[" << *
this <<
"]: State PARSING: Ignoring unregistered option named "
1899 "[" << opt_name <<
"]. We were not given an approved-list. Perhaps this file contains "
1900 "other option sets, or it has to do with forward/backward-compatibility.");
1904 if (!
key_exists(allowed_unregistered_opts_or_empty, opt_name))
1907 m_values_candidate = values_candidate_backup;
1909 FLOW_LOG_WARNING(
"Option_set[" << *
this <<
"]: State PARSING: Unregistered option named "
1910 "[" << opt_name <<
"] is not approved; parse failed. Values payload untouched.");
1912 "] is not approved; parse failed.")};
1917 FLOW_LOG_TRACE(
"Option_set[" << *
this <<
"]: State PARSING: Ignoring unregistered option named "
1918 "[" << opt_name <<
"]; it is in the approved-list. Perhaps this file contains "
1919 "other option sets.");
1929 FLOW_LOG_TRACE(
"Option_set[" << *
this <<
"]: State PARSING: Parsed general format successfully. "
1930 "Will now parse each option's value.");
1940 variables_map fresh_iterable_values;
1943 store(parsed_options, fresh_iterable_values);
1945 catch (
const exception& exc)
1948 m_values_candidate = values_candidate_backup;
1951 "Parsed file [" << cfg_path <<
"]: Exception occurred; individual option parsing failed. "
1952 "Values payload untouched. Message = [" << exc.what() <<
"].");
1956 FLOW_LOG_TRACE(
"Option_set[" << *
this <<
"]: State PARSING: Parsed each individual option successfully. "
1957 "Will now further validate each option value logically and store on success.");
1963 notify(fresh_iterable_values);
1965 catch (
const exception& exc)
1968 m_values_candidate = values_candidate_backup;
1971 "Parsed file [" << cfg_path <<
"]: Exception occurred; individual logical validation failed. "
1972 "Values payload untouched. Message = [" << exc.what() <<
"].");
1977 for (
const auto& pair : fresh_iterable_values)
1979 const auto& name = pair.first;
1980 const auto& var_value = pair.second.value();
1982 assert((!
key_exists(m_iterable_values_candidate, name) ||
1983 (m_iterable_values_candidate[name].type() == var_value.type())));
1985 m_iterable_values_candidate[name] = var_value;
1990 args.
m_call_type = Declare_options_func_args::Call_type::S_COMPARE_PARSED_VALS;
1992 m_declare_opts_func(args);
2000 FLOW_LOG_TRACE(
"Option_set[" << *
this <<
"]: State PARSING: Validate/store succeded. "
2001 "Further validation deferred until attempt to enter state CANONICAL. "
2002 "Updated values payload details follow.");
2003 log_values(
"post-parsing candidate config", &m_values_candidate,
log::Sev::S_TRACE);
2006template<
typename Value_set>
2012 FLOW_LOG_INFO(
"Option_set[" << *
this <<
"]: State CANONICAL: Request to load values from source struct "
2013 "[" << &src_values <<
"]; entering state PARSING. "
2014 "Any preceding canonical state will be ignored. Details follow (TRACE log level).");
2016 assert(m_iterable_values_candidate.empty());
2020 FLOW_LOG_INFO(
"Option_set[" << *
this <<
"]: State PARSING: Request to load values from source struct "
2021 "[" << &src_values <<
"]; continuing by parsing this next config source. "
2022 "Any current candidate values payload will be overwritten entirely. "
2023 "Details follow (TRACE log level).");
2038 args.
m_call_type = Declare_options_func_args::Call_type::S_LOAD_VALS_AS_IF_PARSED;
2040 m_declare_opts_func(args);
2048 args.
m_call_type = Declare_options_func_args::Call_type::S_COMPARE_PARSED_VALS;
2050 m_declare_opts_func(args);
2052 log_values(
"post-loading (perhaps baseline or rewound) candidate config", &m_values_candidate,
log::Sev::S_TRACE);
2055template<
typename Value_set>
2062 FLOW_LOG_INFO(
"Option_set[" << *
this <<
"]: State PARSING: Entering state CANONICAL. "
2063 "Values payload finalized. Details follow (TRACE log level).");
2064 log_values(
"entering-CANONICAL-state finalized config", &m_values_candidate,
log::Sev::S_TRACE);
2070 for (
const auto& pair : m_iterable_values_candidate)
2072 const auto& name = pair.first;
2073 FLOW_LOG_INFO(
"Option_set[" << *
this <<
"]: Detected change in option named [" << name <<
"].");
2076 if (change_detected)
2078 *change_detected = (!m_iterable_values_candidate.empty());
2084 m_values = m_values_candidate;
2085 m_iterable_values_candidate.clear();
2088template<
typename Value_set>
2093 FLOW_LOG_INFO(
"Option_set[" << *
this <<
"]: State PARSING: Rejecting candidate payload built; "
2094 "reverting to state CANONICAL.");
2096 m_iterable_values_candidate.clear();
2101template<
typename Value_set>
2104 validate_values(values(), success_or_null);
2107template<
typename Value_set>
2110 const auto candidate = values_candidate();
2111 assert(candidate &&
"Do not invoke validate_values_candidate() in CANONICAL state; only while PARSING.");
2112 validate_values(*candidate, success_or_null);
2115template<
typename Value_set>
2118 bool* success_or_null)
2120 using std::exception;
2123 if (success_or_null)
2127 validate_values(logger_ptr, values_to_validate, declare_opts_func);
2129 catch (
const exception& exc)
2132 *success_or_null =
false;
2135 *success_or_null =
true;
2143 args.
m_call_type = Declare_options_func_args::Call_type::S_VALIDATE_STORED_VALS;
2152 declare_opts_func(args);
2154 catch (
const exception& exc)
2156 FLOW_LOG_WARNING(
"Stand-alone validation check failed: Details: [" << exc.what() <<
"].");
2161template<
typename Value_set>
2164 validate_values(get_logger(), values_to_validate, m_declare_opts_func, success_or_null);
2167template<
typename Value_set>
2170 return os <<
'[' << val.
m_nickname <<
"]@" << &val;
2173template<
typename Value>
2179template<
typename Rep,
typename Period>
2184 using boost::chrono::ceil;
2185 using boost::chrono::nanoseconds;
2186 using boost::chrono::microseconds;
2187 using boost::chrono::milliseconds;
2188 using boost::chrono::seconds;
2189 using boost::chrono::minutes;
2190 using boost::chrono::hours;
2193 using raw_ticks_t = uint64_t;
2196 nanoseconds val_ns{val};
2199 raw_ticks_t raw_abs_ticks = (val_ns.count() < 0) ? (-val_ns.count()) : val_ns.count();
2204 if (raw_abs_ticks == 0)
2206 os << seconds::zero();
2212 const auto try_next_unit = [&](
auto pre_division_dur, raw_ticks_t divide_by) ->
bool
2214 if ((raw_abs_ticks % divide_by) == 0)
2217 raw_abs_ticks /= divide_by;
2225 if (!(try_next_unit(val_ns, 1000)
2226 || try_next_unit(ceil<microseconds>(val), 1000)
2227 || try_next_unit(ceil<milliseconds>(val), 1000)
2228 || try_next_unit(ceil<seconds>(val), 60)
2229 || try_next_unit(ceil<minutes>(val), 60)))
2231 os << ceil<hours>(val);
2235template<
typename Element>
2238 for (
size_t idx = 0; idx != val.size(); ++idx)
2241 value_to_ostream<Element>(os, val[idx]);
2243 if (idx != (val.size() - 1))
2250template<
typename Key>
2256 using boost::regex_match;
2257 using boost::smatch;
2266 smatch matched_groups;
2270 const string member_id_str{member_id};
2272 const bool matched_ok =
2275 assert(matched_ok &&
"Member identifier must look like: <longest possible stuff>[<key to replace>]<the rest>");
2277 constexpr char INDEX_SEP_BEFORE =
'.';
2286 size_t(matched_groups[1].length())}),
2290 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, char sep_replacement='-')
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.
void store(T *target_val, const boost::type_identity_t< T > &val)
Default store(&target_stats.m_val, val) that simply assigns *target_val = val.
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.