More documentation around Configuration/ConfigDefinition

pull/1186/head
Stephen Shelton 4 years ago
parent 8352de7bd4
commit 8160c13458
No known key found for this signature in database
GPG Key ID: EE4BADACCE8B631C

@ -77,7 +77,7 @@ Configuration::generateINIConfig(bool useValues)
visitDefinitions(section, [&](const std::string& name, const ConfigDefinition_ptr& def) { visitDefinitions(section, [&](const std::string& name, const ConfigDefinition_ptr& def) {
if (useValues and def->numFound > 0) if (useValues and def->numFound > 0)
{ {
oss << name << "=" << def->writeValue(false) << "\n"; oss << name << "=" << def->valueAsString(false) << "\n";
} }
else else
{ {

@ -13,7 +13,10 @@
namespace llarp namespace llarp
{ {
/// non-templated base class for all config definition types. /// A base class for specifying config options and their constraints. The basic to/from string
/// type functions are provided pure-virtual. The type-aware implementations which implement these
/// functions are templated classes. One reason for providing a non-templated base class is so
/// that they can all be mixed into the same containers (albiet as pointers).
struct ConfigDefinitionBase struct ConfigDefinitionBase
{ {
ConfigDefinitionBase(std::string section_, ConfigDefinitionBase(std::string section_,
@ -24,17 +27,25 @@ namespace llarp
virtual virtual
~ConfigDefinitionBase() {} ~ConfigDefinitionBase() {}
/// subclasses should provide their default value as a string /// Subclasses should provide their default value as a string
///
/// @return the option's default value represented as a string
virtual std::string virtual std::string
defaultValueAsString() = 0; defaultValueAsString() = 0;
/// subclasses should parse and store the provided input /// Subclasses should parse and store the provided input
///
/// @param input is the string input to interpret
virtual void virtual void
parseValue(const std::string& input) = 0; parseValue(const std::string& input) = 0;
/// subclasess should write their parsed value (not default value) as a string /// Subclasess should write their parsed value as a string, optionally falling back to any
/// specified default if `useDefault` is true.
///
/// @param useDefault should specify whether to fallback to default when possible
/// @return the option's value as a string
virtual std::string virtual std::string
writeValue(bool useDefault) = 0; valueAsString(bool useDefault) = 0;
std::string section; std::string section;
std::string name; std::string name;
@ -43,9 +54,21 @@ namespace llarp
size_t numFound = 0; size_t numFound = 0;
}; };
/// The primary type-aware implementation of ConfigDefinitionBase, this templated class allows
/// for implementations which can use the std::ostringstream and std::istringstream for to/from
/// string functionality.
///
/// Note that types (T) used as template parameters here must be used verbatim when calling
/// Configuration::getConfigValue(). Similar types such as uint32_t and int32_t cannot be mixed.
template<typename T> template<typename T>
struct ConfigDefinition : public ConfigDefinitionBase struct ConfigDefinition : public ConfigDefinitionBase
{ {
/// Constructor. Arguments are passed directly to ConfigDefinitionBase. Also accepts a default
/// value, which is used in the following situations:
///
/// 1) as the return value for getValue() if there is no parsed value and required==false
/// 2) as the output in defaultValueAsString(), used to generate config files
/// 3) as the output in valueAsString(), used to generate config files
ConfigDefinition(std::string section_, ConfigDefinition(std::string section_,
std::string name_, std::string name_,
bool required_, bool required_,
@ -56,6 +79,10 @@ namespace llarp
{ {
} }
/// Returns the parsed value, if available. Otherwise, provides the default value if the option
/// is not required. Otherwise, returns an empty optional.
///
/// @return an optional with the parsed value, the default value, or no value.
nonstd::optional<T> nonstd::optional<T>
getValue() const getValue() const
{ {
@ -68,7 +95,7 @@ namespace llarp
} }
std::string std::string
defaultValueAsString() defaultValueAsString() override
{ {
std::ostringstream oss; std::ostringstream oss;
if (defaultValue.has_value()) if (defaultValue.has_value())
@ -78,7 +105,7 @@ namespace llarp
} }
void void
parseValue(const std::string& input) parseValue(const std::string& input) override
{ {
if (not multiValued and parsedValue.has_value()) if (not multiValued and parsedValue.has_value())
{ {
@ -102,7 +129,7 @@ namespace llarp
} }
std::string std::string
writeValue(bool useDefault) valueAsString(bool useDefault) override
{ {
std::ostringstream oss; std::ostringstream oss;
if (parsedValue.has_value()) if (parsedValue.has_value())
@ -126,15 +153,46 @@ namespace llarp
// map of section-name to map-of-definitions // map of section-name to map-of-definitions
using SectionMap = std::unordered_map<std::string, DefinitionMap>; using SectionMap = std::unordered_map<std::string, DefinitionMap>;
/// A configuration holds an ordered set of ConfigDefinitions defining the allowable values and /// A Configuration holds an ordered set of ConfigDefinitions defining the allowable values and
/// their constraints and an optional set defining overrides of those values (e.g. the results /// their constraints (specified through calls to addConfigOption()).
/// of a parsed config file). ///
/// The layout and grouping of the config options are modelled after the INI file format; each
/// option has a name and is grouped under a section. Duplicate option names are allowed only if
/// they exist in a different section. The configuration can be serialized in the INI file format
/// using the generateINIConfig() function.
///
/// Configured values (e.g. those encountered when parsing a file) can be provided through calls
/// to addConfigValue(). These take a std::string as a value, which is automatically parsed.
///
/// The Configuration can be used to print out a full config string (or file), including fields
/// with defaults and optionally fields which have a specified value (values provided through
/// calls to addConfigValue()).
struct Configuration { struct Configuration {
SectionMap m_definitions; SectionMap m_definitions;
/// Spefify the parameters and type of a configuration option. The parameters are members of
/// ConfigDefinitionBase; the type is inferred from ConfigDefinition's template parameter T.
///
/// This function should be called for every option that this Configuration supports, and should
/// be done before any other interractions involving that option.
///
/// @param def should be a unique_ptr to a valid subclass of ConfigDefinitionBase
/// @return `*this` for chaining calls
/// @throws std::invalid_argument if the option already exists
Configuration& Configuration&
addConfigOption(ConfigDefinition_ptr def); addConfigOption(ConfigDefinition_ptr def);
/// Specify a config value for the given section and name. The value should be a valid string
/// representing the type used by the option (e.g. the type provided when addConfigOption() was
/// called).
///
/// If the specified option doesn't exist, an exception will be thrown. Otherwise, the option's
/// parsedValue() will be invoked, and should throw an exception if the string can't be parsed.
///
/// @param section is the section this value resides in
/// @param name is the name of the value
/// @return `*this` for chaining calls
/// @throws if the option doesn't exist or the provided string isn't parseable
Configuration& Configuration&
addConfigValue(string_view section, addConfigValue(string_view section,
string_view name, string_view name,

Loading…
Cancel
Save