Flow 1.0.0
Flow project: Public API.
|
The core config-parsing facility, which builds parsing/comparison/output capabilities on top of a given simple config-holding object, of the type Value_set
, a template argument to this class template.
More...
#include <option_set.hpp>
Classes | |
struct | Declare_options_func_args |
Internal-use structure to use with Declare_options_func callback. More... | |
Public Types | |
using | Values = Value_set |
Short-hand for the template parameter type Value_set . More... | |
using | Values_ptr = typename Values::Const_ptr |
Short-hand for ref-counted pointer to an immutable Value_set (config payload storable in an Option_set). More... | |
using | Mutable_values_ptr = typename Values::Ptr |
Short-hand for ref-counted pointer to a mutable Values (config payload storable in an Option_set). | |
using | Declare_options_func = Function< void(const Declare_options_func_args &args)> |
Short-hand for the ever-important callback passed to the main Option_set constructor. More... | |
Public Types inherited from flow::cfg::Option_set_base | |
enum class | Declare_options_func_call_type { S_FILL_PARSING_ROLE_OPT_TABLE , S_FILL_OUTPUT_HELP_ROLE_OPT_TABLE , S_FILL_OUTPUT_CURRENT_ROLE_OPT_TABLE , S_COMPARE_PARSED_VALS , S_LOAD_VALS_AS_IF_PARSED , S_VALIDATE_STORED_VALS } |
Internal-use type to use with Option_set::Declare_options_func callback. More... | |
Public Member Functions | |
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 declared by synchronously invoking the callback declare_opts_func() . More... | |
const Values & | values () const |
Externally immutable internally stored canonical (current) config values as last constructed or parsed, whichever happened more recently. More... | |
Mutable_values_ptr | mutable_values_copy () const |
Convenience method that heap-allocates a copy of the internally stored values() and wraps in a ref-counted handle suitable for speedy passing around the rest of the application. More... | |
const Values * | values_candidate () const |
Returns null in CANONICAL state; or in PARSING state a pointer to the not-yet-canonical values after the last successful parse_*() API call. More... | |
void | validate_values (bool *success_or_null=0) const |
Validates the current contents of values() using the validators *this Option_set<Value_set> is configured to use via constructor. More... | |
void | validate_values (const Values &values_to_validate, bool *success_or_null=0) const |
Validates an arbitrary Value_set , using the same validators *this Option_set<Value_set> is configured to use when parsing config sources. More... | |
void | validate_values_candidate (bool *success_or_null=0) const |
Equivalent to validate_values(success_or_null) but validates *values_candidate() instead of values(). More... | |
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, at some point perhaps initialized or parsed by *this , to the given stream. More... | |
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(). More... | |
void | help_to_ostream (std::ostream &os) const |
Prints a multi-line help message about the set of options that *this can parse. More... | |
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(). More... | |
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 form of the given file in the file-system. More... | |
void | parse_direct_values (const Values &src_values) |
Enters into (from CANONICAL state) or continues in PARSING state by simply setting *values_candidate() to equal the Values payload given as an argument. More... | |
void | canonicalize_candidate (bool *change_detected=0) |
In PARSING state enters CANONICAL state, finalizing values() from values_candidate(). More... | |
void | reject_candidate () |
In PARSING state, returns to CANONICAL state, as if no parse attempts have occurred. More... | |
template<typename Value > | |
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_CFG_OPTION_SET_DECLARE_OPTION() (see Option_set main constructor doc header). More... | |
template<typename Value > | |
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_CFG_OPTION_SET_DECLARE_OPTION() (see Option_set main constructor doc header). More... | |
template<typename Value > | |
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_CFG_OPTION_SET_DECLARE_OPTION() (see Option_set main constructor doc header). More... | |
template<typename Value > | |
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_CFG_OPTION_SET_DECLARE_OPTION() (see Option_set main constructor doc header). More... | |
bool | null () const |
Return true if and only if the option-declaring function passed to the constructor declared no options. More... | |
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. More... | |
Public Member Functions inherited from flow::log::Log_context | |
Log_context (Logger *logger=0) | |
Constructs Log_context by storing the given pointer to a Logger and a null Component. More... | |
template<typename Component_payload > | |
Log_context (Logger *logger, Component_payload component_payload) | |
Constructs Log_context by storing the given pointer to a Logger and a new Component storing the specified generically typed payload (an enum value). More... | |
Log_context (const Log_context &src) | |
Copy constructor that stores equal Logger* and Component values as the source. More... | |
Log_context (Log_context &&src) | |
Move constructor that makes this equal to src , while the latter becomes as-if default-constructed. More... | |
Log_context & | operator= (const Log_context &src) |
Assignment operator that behaves similarly to the copy constructor. More... | |
Log_context & | operator= (Log_context &&src) |
Move assignment operator that behaves similarly to the move constructor. More... | |
void | swap (Log_context &other) |
Swaps Logger pointers and Component objects held by *this and other . More... | |
Logger * | get_logger () const |
Returns the stored Logger pointer, particularly as many FLOW_LOG_*() macros expect. More... | |
const Component & | get_log_component () const |
Returns reference to the stored Component object, particularly as many FLOW_LOG_*() macros expect. More... | |
Static Public Member Functions | |
static void | validate_values (log::Logger *logger_ptr, const Values &values_to_validate, const Declare_options_func &declare_opts_func, bool *success_or_null=0) |
Validates an arbitrary Value_set , as parseable by an Option_set<Value_set> , according to the given option-registering function suitable for Option_set<Value_set> constructor. More... | |
Static Public Member Functions inherited from flow::cfg::Option_set_base | |
template<typename Value > | |
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_CFG_OPTION_SET_DECLARE_OPTION() (see Option_set main constructor doc header). More... | |
template<typename Value > | |
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_CFG_OPTION_SET_DECLARE_OPTION() (see Option_set main constructor doc header). More... | |
Public Attributes | |
const std::string | m_nickname |
See nickname ctor arg. | |
Related Functions | |
(Note that these are not member functions.) | |
template<typename Value_set > | |
std::ostream & | operator<< (std::ostream &os, const Option_set< Value_set > &val) |
Serializes (briefly) an Option_set to a standard output stream. More... | |
Additional Inherited Members | |
Protected Types inherited from flow::cfg::Option_set_base | |
using | Opt_table = opts::options_description |
Short-hand for boost.program_options config options description, each of which is used for parsing and/or describing (to humans) one or more config option/its value. More... | |
Static Protected Member Functions inherited from flow::cfg::Option_set_base | |
template<typename Value > | |
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_parsing() and others, in code that will throw an exception with a human-useful message if that validator function indicates the Value passed to it is invalid; else will no-op. More... | |
The core config-parsing facility, which builds parsing/comparison/output capabilities on top of a given simple config-holding object, of the type Value_set
, a template argument to this class template.
Value_set
(named however you want, of course) struct
. The values stored therein must be reasonably deep-copyable; must have standard-stream <<
and >>
operators; and must reasonably implement ==
comparison. Value_set
itself must be copy-constructible and copy-assignable in a reasonable way. Lastly, and very importantly, the no-arg ctor Value_set()
must initialize all configured members to reasonable defaults: it is not possible to declare options as "required."Value_set
shall derive from util::Shared_ptr_alias_holder. (Don't worry: it's easy.)Value_set
, which officially turns them into options.Option_set()
ctor doc header; but essentially this function shall use FLOW_CFG_OPTION_SET_DECLARE_OPTION() macro to enumerate every parseable member, turning it into an option managed by the containing Option_set.Value_set
. Composition via directly nested, and nested via pointer, struct
s is supported. See FLOW_CFG_OPTION_SET_DECLARE_OPTION() doc header for details.)Option_set<Value_set>
, and use parse_config_file() (or any other parse_*()
methods that might exist) to parse things at will.Value_set()
. It returns a reference to immutable internally stored Value_set
.parse_*()
) either enters or continues PARSING state. In this state *values_candidate()
starts equal to values(); and is then potentially modified by each parse_*()
operation.canonicalize_candidate()
to set values() to *values_candidate()
, thus canonicalizing the parsed values, and return to CANONICAL state.parse_*()
or validate_values*()
fails, or any manual check of values_candidate() fails, one might want to instead call reject_candidate() to discard any parse attempts and return to CANONICAL state.parse_*()
from actual config source(s). (It would be trivial to save a previous state using values() to be that baseline state.)A typical expected scenario – although more complex ones can be devised – and one assumed by Config_manager – is to have 2 struct
s of config; one for static and one for dynamic config, the latter being something that can be parsed-into repeatedly over time, as new config is delivered to the process. In that case one would use one Option_set<Static_value_set>
and one Option_set<Dynamic_value_set>
and invoke their parsing at appropriate times (1+ times for the latter, once for the former). It is also possible to allow, on startup, to read both sets from the same config source(s) (e.g., a static config file); then read the dynamic Option_set<>
from the dynamic config source(s) once (for any initial dynamic values overriding the initial baseline static ones); and after that accept any further updates of the latter config source(s), as they come in (e.g., if the dynamic config file is modified externally). The allow_unregistered
argument to parse_*()
allows 2+ Option_set<>
s to share one config file.
Option validation mandatorily occurs in the following places.
parse_*()
is invoked, the config source (e.g., config file in case of parse_config_file()) may have plainly illegal contents, such as an option expecting a number but receiving alphanumerics, or a syntax error. This will cause parse_*()
to indicate error.ARG_bool_validate_expr
argument to FLOW_CFG_OPTION_SET_DECLARE_OPTION() when declaring the options (see above). This is somewhat reminiscent of writing assert()
conditions. If a validator fails, parse*()
will transparently fail, not dissimilarly to what happens if some line is straight-up illegal (previous bullet point).However this is likely insufficient validation in at least some use cases. You should also concern yourself with the following.
parse_*()
that scans+parses strings) will only validate (via individual-option-validator checks) values actually present in the config source. Defaults (from Value_set()
) or baseline values (from parse_direct_values()) are not mandatorily checked. If one performs no additional validation calls, it will not be possible to know of bad defaults or baseline values, and one can canonicalize_candidate() invalid values. This is allowed, for flexibility, but in most cases one will want to reject_candidate() instead. The following abilities are provided to resolve this. For flexibility we do not here enforce any particular approach. It is your reponsibility to trace the possibilities. (For example Config_manager chooses certain conventions as it marshals various Option_set
s.)Value_set
) themselves, call validate_values(bool*)
overload – just after construction. (Informally: This is a stringent convention. It is possible to instead establish the convention wherein intentionally invalid defaults are allowed, to force that a config source must specify such values explicitly. In that case: one would not call validate_values() this way but rather... see next bullet point.)Value_set
. You are free to call validate_values_candidate() right after it to detect problems, if it suits your needs. (Informally: Whether this is necessary really depends on your setup, including the source of the values applied – which may have already been validated – and whether you're going to be calling validate_values_candidate() before canonicalizing anyway.)*values_candidate()
. If you find problems call reject_candidate() instead.assert()
-style, a string representation of the condition that failed).Lastly, and optionally, you may validate a given Value_set
object "offline," meaning outside of any Option_set<Value_set>
– which need not even exist or ever parse anything; only the function fitting Option_set::Declare_options_func must exist, as-if for Option_set
ctor. Simply call a validate_values() API on your object; it will yield failure given at least 1 invalid value. This can be useful, at least, when setting values manually through assignment (perhaps in a simpler program not requiring external config; or when unit-testing); just because you aren't parsing it through Option_set does not mean you don't want to sanity-check it for validity.
For dynamic options, it may be necessary to detect whether the set of option values has changed or even individual changes (and then, in many cases, invoke config-changed hooks). Option_set is designed with this in mind, as it is able to provide such checks without forcing the user to write an operator==(Value_set, Value_set)
(a laborious and error-prone procedure).
Change detection occurs at the canonicalize_candidate() stage. That is, once you've parsed all the different config sources in a parse pass, canonicalize_candidate() will scan for changes. As of this writing that method will optionally return a Boolean indicating whether at least one value changed vs. the canonical values(). It is possible to add an API for detecting individual option changes. As I write this, it doesn't exist, but it may be added after I write this. Option_set is eminently capable of it; and in fact it at least logs an INFO message for each option that has changed, at canonicalize_candidate() time.
Input of configurable values in Value_set
is required to be able to parse the corresponding options (parse_*()). Output thereof is required in:
Value_set
, but if none is specified, it will log the canonical one (values()).For input (parsing), every configurable value in Value_set
must have an istream>>
operator.
For output (in help and current-values output), every such value must have an ostream<<
operator. In addition, it is sometimes desirable to further massage output in config help/current-values output but not in a general ostream<<
operator for that type. (E.g., you would not want to, or be able to usually, override stream output for std::string
or chrono::duration
.) To do this, provide a specialization or overload of the free function cfg::value_to_ostream<Value_set>()
. Its generic implementation simply forwards to ostream<<
, but you can do something different. As of this writing we already provide an overload for cfg::value_to_ostream<chrono::duration<...>>
, which will automatically print the duration (which is typically stored in nanoseconds) in the coarsest possible units that would lose no precision (e.g., 60billion nanoseconds => "1 minute").
Firstly, it is recommended to store all durations in your Value_set
as util::Fine_duration instead of using coarser units like chrono::seconds()
or even chrono::milliseconds()
. This tends to lead to more consistent and maintainable code, in the author's (ygoldfel) opinion, as util::Fine_duration can store durations expressed in essentially any units, without losing precision; does use the same underlying storage type – int64_t
– and hence presents no performance or overflow difficulties (usually); and changing the desired units of a duration config value is fairly common. Simply put Fine_duration
supports 99.99999999% of units and use cases without perf overhead. In addition, value_to_ostream<>
is overloaded in such a way as to output Fine_duration
members of Value_set
in the most convenient possible units – automagically. So you're in no way forcing humans to work with nanoseconds: you can use any units in input and in code.
chrono
type); and indeed should specify units. E.g., "5 ms" and "5 milliseconds" will both work. Since util::Fine_duration is in nanoseconds internally, almost any conceivable units (from "hours" to "nanoseconds") are accepted equally well as inputs in config sources.Secondly, when working with non-durations, specify units as a suffix in the member name.
_bytes
or _b
shall be omitted._kb
, _mb
, etc., knowing that this stands for KiB (1024), MiB (1024^2), etc. In the rare case that actual KILObytes, etc., are needed, spell it out: _kilob
, _megab
, etc._kib
, etc., only because the convention in the relevant organization(s) is quite strong to say KB for KiB, etc._hr
, _min
, _sec
, _msec
, _usec
, _nsec
. Please still use chrono::duration
, though, even if you chose something other than Fine_duration
. (Do not use an integer type.)Value_set | The value type stored inside *this , and returned by values(). Requirements on this type are at least informally explained above. |
using flow::cfg::Option_set< Value_set >::Declare_options_func = Function<void (const Declare_options_func_args& args)> |
Short-hand for the ever-important callback passed to the main Option_set constructor.
The user of the class need not understand the meanings of the args, because the FLOW_CFG_OPTION_SET_DECLARE_OPTION() macro will take care of using them properly.
using flow::cfg::Option_set< Value_set >::Values = Value_set |
Short-hand for the template parameter type Value_set
.
E.g.: Cool_option_set::Values
, where one aliased Cool_option_set
to Option_set<Cool_value_set>
.
using flow::cfg::Option_set< Value_set >::Values_ptr = typename Values::Const_ptr |
Short-hand for ref-counted pointer to an immutable Value_set
(config payload storable in an Option_set).
The name is not, say, Const_values_ptr
, because we would expect such objects to be passed around in const
form most of the time, including when made accessible from within a config-holding API. When a mutable Values is desired, one would typically create it from an Option_set by using mutable_values_copy().
|
explicit |
Constructs an option set in CANONICAL state with a default-valued values() payload and options declared by synchronously invoking the callback declare_opts_func()
.
See below for details on the latter.
Post-condition: values()
is equal to Values()
; values_candidate() is null (so the state is initially CANONICAL). (Therefore Value_set
no-args ctor must by definition be written so as to initialize all its relevant members to their defaults. Recall Value_set
is a template parameter type with certain requirements.)
Use parse_*()
(once per config source) and canonicalize_candidate()
(once) to move to PARSING state and back to CANONICAL state respectively.
declare_opts_func()
callbackdeclare_opts_func
above denotes an internally saved callback move()
d from the corresponding arg declare_opts_func_moved
. declare_opts_func()
is also invoked synchronously from within various relevant output APIs; their doc headers mention it. (E.g., invoking stream output os << *this
will call declare_opts_func()
.)
Informally, the callback must declare every parseable (and therefore stream-printable-semantic-description-having) option, linking it to some data member within a target Values
whose address is passed to the callback as an arg; in a consistent order; and as many times through the lifetime of *this
(including during this ctor) as *this
deems necessary. Use FLOW_CFG_OPTION_SET_DECLARE_OPTION() to describe all the options. Formally, it must follow the following exact rules:
{ body }
must name its args exactly as shown in the value of the Declare_options_func alias.Values
, always in the same order and the same N. Clues as to how this works:m_
member.logger_ptr | Logger to use for subsequently logging. |
nickname | Brief string used for logging subsequently. |
declare_opts_func_moved | See above. |
void flow::cfg::Option_set< Value_set >::canonicalize_candidate | ( | bool * | change_detected = 0 | ) |
In PARSING state enters CANONICAL state, finalizing values() from values_candidate().
Any cumulative changes are INFO-logged on a per-changed-option basis; and if at least one option's value indeed changed then *change_detected
is set to true
(else false
). (Leave the arg null, if you do not care.)
change_detected | If null, ignored; otherwise *change_detected is set to true if a setting changed; else false . |
void flow::cfg::Option_set< Value_set >::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_CFG_OPTION_SET_DECLARE_OPTION() (see Option_set main constructor doc header).
Value | Type of the value inside a Values object. It must be reasonably copyable; and it must be supported by some version (including specialization(s) and overload(s)) of value_to_ostream(). |
name | See declare_option_for_parsing(). |
value_default | Default value to show to the user. |
description | The description text to show to the user. |
void flow::cfg::Option_set< Value_set >::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_CFG_OPTION_SET_DECLARE_OPTION() (see Option_set main constructor doc header).
Value | Type of the value inside a Values object. It must be reasonably copyable. |
name | Main option name: as specified by the user in a config source. As of this writing FLOW_CFG_OPTION_SET_DECLARE_OPTION() uses macro magic to automatically form this from the identifier name within a Values object (e.g., Value_set::m_cool_option => "cool-option"). |
target_value | When deserializing a value from a config source, the bits shall be written there. This must point inside m_values_candidate . |
value_default_if_no_acc | Usually – with regular (accumulating) options – null; otherwise pointer to the default value for *target_value (as from Values() ), inside m_values_default . In the latter case (non-null) this indicates this is an option marked by the user as non-accumulating (see FLOW_CFG_OPTION_SET_DECLARE_OPTION_NO_ACC() and similar), meaning each time a config source (e.g., a file) is parsed *target_value is first reset to this default; then overwritten with the value in the config source if, else left at the default. An accumulating option in the latter case would instead keep its existing value already in *target_value . |
validator_func_moved | Function F, such that F(V) shall be called from parse_*() when this option's successfully parsed value V is being validated before final storage in m_values_candidate . Return false if the validation shall fail; otherwise return true . |
validator_cond_str | String containing the Boolean code that validator_func_moved() would need to evaluate to true to pass validation. As of this writing FLOW_CFG_OPTION_SET_DECLARE_OPTION() uses macro magic to automatically form this from a Boolean expression fragment. |
void flow::cfg::Option_set< Value_set >::help_to_ostream | ( | std::ostream & | os | ) | const |
Prints a multi-line help message about the set of options that *this
can parse.
This should typically be preceded by a newline but not followed by one, unless one desires a blank line there.
os | Stream to which to serialize. |
void flow::cfg::Option_set< Value_set >::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_CFG_OPTION_SET_DECLARE_OPTION() (see Option_set main constructor doc header).
Value | Type of the value inside a Values object. It must have a meaningful = operation. |
name | See declare_option_for_parsing(). |
target_value | Target value inside m_values_candidate . |
source_value | Value to load into *target_value (as-if it was parsed from a config source). |
void flow::cfg::Option_set< Value_set >::log_help | ( | util::String_view | summary, |
log::Sev | sev = log::Sev::S_INFO |
||
) | const |
Logs a multi-line help message using help_to_ostream().
summary | Brief summary of the help message. |
sev | Severity to use for the log message. |
void flow::cfg::Option_set< Value_set >::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().
values_or_null | See values_to_ostream(). |
summary | Brief summary of what this payload represents. |
sev | Severity to use for the log message. |
Option_set< Value_set >::Mutable_values_ptr flow::cfg::Option_set< Value_set >::mutable_values_copy |
Convenience method that heap-allocates a copy of the internally stored values()
and wraps in a ref-counted handle suitable for speedy passing around the rest of the application.
bool flow::cfg::Option_set< Value_set >::null |
Return true
if and only if the option-declaring function passed to the constructor declared no options.
This value is always the same for a given *this
.
While likely of little value when the user instantiates an Option_set directly, this can be useful in generic meta-programming, wherein multiple Option_set
s might be instantiated at compile time, but the coder doesn't know how many while coding. For example Config_manager uses null() to bypass confusingly-logging parse_config_file() calls on empty Option_set objects, such as if a static config set has no dynamic config counterpart.
const boost::unordered_set< std::string > & flow::cfg::Option_set< Value_set >::option_names |
Returns set of all option names declared by the option-declaring function passed to the constructor.
This can be useful to supply to parse_config_file(), for example, when parsing another Option_set from the same file: then other options can be passed to that function as not causing a parse error if encountered; hence 2 or more Option_set
s can parse_config_file() the same file despite having disjoint option name sets – yet totally extraneous options in none of the Option_set
s would cause an error as desired.
This returns the same value (and reference) each time it is called.
void flow::cfg::Option_set< Value_set >::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 form of the given file in the file-system.
On success values_candidate() is updated; on failure it is untouched.
On failure throws an exception, if success_or_null
is null; otherwise set *success_or_null
to false
. On success simply returns or sets *success_or_null
to true
respectively. Information is logged regardless.
A failure may occur due to invalid contents in the config source. A failure may occur due to a validator condition failed (see FLOW_CFG_OPTION_SET_DECLARE_OPTION()).
However: the latter applies only to settings actually specified in cfg_path
file. Any default or baseline or otherwise-previously-set, but not overridden in cfg_path
, values are not validated – neither before nor after scanning cfg_path
. You are, however, free to do so by next (or previously, or both) invoking validate_values_candidate(). (If "previously," and not yet in PARSING state, then use validate_values().) See Validation in class doc header for discussion.
cfg_path | Path to parse. |
allow_unregistered | If true , if an unknown option is encountered it may be allowed (not considered a failure), subject to allowed_unregistered_opts_or_empty , though an INFO message is still logged for each; if false it is an error like any other illegal config setting. One reason for true is if another Option_set<> will be parsed from the same config source. Another is if there could be forward- or backward-compatibility concerns. |
allowed_unregistered_opts_or_empty | Meaningful only if allow_unregistered == true , this is the list of all option names (compared case-sensitively) that will not cause a validation error; or empty to allow all unknown options. |
success_or_null | If null exceptions mark failure; otherwise the pointed-to value shall indicate success or failure. |
void flow::cfg::Option_set< Value_set >::parse_direct_values | ( | const Values & | src_values | ) |
Enters into (from CANONICAL state) or continues in PARSING state by simply setting *values_candidate()
to equal the Values payload given as an argument.
Typically precedes other parse_*()
calls such as parse_config_file(). If already in PARSING state, note that any changes accumulated in *values_candidate()
so far will be overwritten entirely.
The values in src_values
are not checked for validity according to the validators configured in the FLOW_CFG_OPTION_SET_DECLARE_OPTION() invocations in declare_opts_func()
passed to ctor. You are, however, free to do so by next invoking validate_values_candidate(). See Validation in class doc header for discussion.
This is useful, particularly, when one plans to repeatedly apply updates to one *this
, but a certain baseline state is desired before each update. Consider the example of an Option_set that stores dynamically changeable values. Suppose each update consists only of a single parse_config_file(F)
call, where F
is some file that might get changed at various times to deliver dynamic updates. Then consider this series:
values() == Values()
(default).parse_config_file(F)
, followed by canonicalize_candidate(). End state: values()
== defaults + changes in file F
at time 1.parse_config_file(F)
, followed by canonicalize_candidate(). End state: values()
== defaults + changes in file F
at time 1 + changes in file F
at time 2.In this case values() is incrementally changed by each dynamic update, as the file F
keeps changing. E.g., if at time 1 it contained only option A, and at time 2 it contained only option B, then values() would contain both time-1 option A value and time-2 option B value – even though the file F
at time 2 contains only the latter. This might be what you want, but since it's fully incremental, there are some usability landmines. Mainly: If one looks at F
contents at any given time, they can't know what the resulting state would be; it depends on what updates preceded it.
To resolve this, one can save a baseline state of values() by copy; and then apply it via this parse_direct_values() call before parsing the file in each dynamic update. The baseline state could just be defaults (Values()
), or it could come from some special "baseline" config file that is not F
which one knows to never change. (Such a file could also typically store static config managed by a separate Option_set.)
So then the sequence might become not parse_config_file(), canonicalize_candidate(), parse_config_file(), canonicalize_candidate(), ...; but rather:
parse_config_file(B)
, canonicalize_candidate().Values baseline
.parse_direct_values(baseline)
, parse_config_file(F)
, canonicalize_candidate().parse_direct_values(baseline)
, parse_config_file(F)
, canonicalize_candidate().parse_direct_values(baseline)
, parse_config_file(F)
, canonicalize_candidate().parse_direct_values(baseline)
here is a no-op but included for clarity/symmetry, as usually one would just do the same thing for each update.)It is also sometimes desirable to "rewind" the state of values_candidate() (by first memorizing it, then parse_config_file() or similar, then if some value in the resulting value set indicates the file should not apply after all, parse_direct_values() to "undo." Config_manager uses it when its multi-source feature is engaged – commit = false
.)
src_values | The values set loaded into *values_candidate() , as-if parsed from some config source. |
void flow::cfg::Option_set< Value_set >::reject_candidate |
In PARSING state, returns to CANONICAL state, as if no parse attempts have occurred.
In CANONICAL state, a no-op. Calling this is typically a good idea when a parse_*()
attempt indicates failure.
void flow::cfg::Option_set< Value_set >::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_CFG_OPTION_SET_DECLARE_OPTION() (see Option_set main constructor doc header).
Value | Type of the value inside a Values object. It must have a meaningful == operation. |
name | See declare_option_for_parsing(). |
canonical_value | Current value in m_values . |
void flow::cfg::Option_set< Value_set >::validate_values | ( | bool * | success_or_null = 0 | ) | const |
Validates the current contents of values() using the validators *this
Option_set<Value_set>
is configured to use via constructor.
If at least one option is invalid according to a validator declared by a FLOW_CFG_OPTION_SET_DECLARE_OPTION() invocation in declare_opts_func()
, then this function shall indicate failure; else success.
On failure throws an exception, if success_or_null
is null; otherwise set *success_or_null
to false
. On success simply returns or sets *success_or_null
to true
respectively. In the exception case the message will indicate every reasonable detail about the option value that went wrong. This info is logged regardless.
Informally, the use case driving the presence of this overload is discussed in the Validation section of our class doc header; see that. To restate: If you want to stringently ensure the defaults are themselves valid, simply invoke this right after construction, at which point values() are by definition at their defaults.
success_or_null | If null exceptions mark failure; otherwise the pointed-to value shall indicate success or failure. |
void flow::cfg::Option_set< Value_set >::validate_values | ( | const Values & | values_to_validate, |
bool * | success_or_null = 0 |
||
) | const |
Validates an arbitrary Value_set
, using the same validators *this
Option_set<Value_set>
is configured to use when parsing config sources.
This essentially means using the static
overload and passing to it declare_opts_func
equal to the one earlier passed by the user to *this
constructor. The success/failure semantics are identical to the other overload's (see that doc header).
You can also use the static
overload, if you aren't at all parsing from config sources but still want to validate.
values_to_validate | The values in this structure shall be validated in the same way as they are upon this->parse_*() ing from a config source. |
success_or_null | If null exceptions mark failure; otherwise the pointed-to value shall indicate success or failure. |
|
static |
Validates an arbitrary Value_set
, as parseable by an Option_set<Value_set>
, according to the given option-registering function suitable for Option_set<Value_set>
constructor.
If at least one option is invalid according to a validator declared by a FLOW_CFG_OPTION_SET_DECLARE_OPTION() invocation in declare_opts_func()
, then this function shall indicate failure; else success.
On failure throws an exception, if success_or_null
is null; otherwise set *success_or_null
to false
. On success simply returns or sets *success_or_null
to true
respectively. In the exception case the message will indicate every reasonable detail about the option value that went wrong. This info is logged regardless.
Use this, at least, if you've filled out a Value_set
through manual assignment or some other source, rather than parsing through an Option_set – and don't even use an Option_set, as you don't parse from config – but still want to check it for validity.
You can also use the non-static
overload to reuse the Declare_options_func passed to an existing parsing-capable Option_set<Value_set>
.
logger_ptr | Logger to use for subsequently logging. |
values_to_validate | The values in this structure shall be validated in the same way as they are upon parsing by a hypothetical Option_set<Value_set> into whose ctor the same declare_opts_func were passed. |
declare_opts_func | See Option_set constructor. |
success_or_null | If null exceptions mark failure; otherwise the pointed-to value shall indicate success or failure. |
void flow::cfg::Option_set< Value_set >::validate_values_candidate | ( | bool * | success_or_null = 0 | ) | const |
Equivalent to validate_values(success_or_null)
but validates *values_candidate()
instead of values().
Behavior is undefined (assertion may trip) if not in PARSING mode currently (i.e., values_candidate() is null).
Informally, the use case driving the presence of this overload is discussed in the Validation section of our class doc header; see that. To restate: If you want to ensure no invalid defaults or baseline values have "gotten through" in the current PARSING state, then invoke this – particularly just ahead of the decision to either canonicalize_candidate() or reject_candidate().
success_or_null | If null exceptions mark failure; otherwise the pointed-to value shall indicate success or failure. |
const Value_set & flow::cfg::Option_set< Value_set >::values |
Externally immutable internally stored canonical (current) config values as last constructed or parsed, whichever happened more recently.
const Value_set * flow::cfg::Option_set< Value_set >::values_candidate |
Returns null in CANONICAL state; or in PARSING state a pointer to the not-yet-canonical values after the last successful parse_*()
API call.
Rationale: It is supplied publicly in case the caller wans to log it or something; or perhaps to check for current state (CANONICAL if and only it returns null).
void flow::cfg::Option_set< Value_set >::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, at some point perhaps initialized or parsed by *this
, to the given stream.
This should typically be preceded by a newline but not followed by one, unless one desires a blank line there.
os | Stream to which to serialize. |
values_or_null | Values to serialize; if null then we act as-if it's &(values()) . |
|
related |
Serializes (briefly) an Option_set to a standard output stream.
Value_set | See Option_set doc header. |
os | Stream to which to serialize. |
val | Value to serialize. |
os
.