#include <configuration.h>
Interface to the SMASH configuration files.
The configuration is created from a YAML file and then stores a nested map of maps (normally a tree, but YAML allows it to be cyclic - even though we don't want that feature). Since the resource owned by the object is a YAML::Node
that handle memory in a similar way as a pointer does, it is forbidden (nor should it be needed) to copy instances of this class, while moving is fine (see special members documentation for more information).
The typical usage of a Configuration is to create it, consume (i.e. take
) all its values and let it being destructed. Since this is the contact point with SMASH input file, the class is meant to be strict in its usage, so that it is possible to help the inexpert user, who might being using a wrong input file and/or e.g. specify an unused key hoping in an effect that indeed does not occur. Therefore, it is imposed that all keys must be parsed before an instance gets destroyed. If this is not the case, an exception will be thrown.
For the typical usage in SMASH one needs to read the value once. In that case, use the Configuration::take function, for example:
Note that only Key objects can be taken. This is done on purpose, because all SMASH allowed keys are gathered as static members of the InputKeys class. This allows calls like config.take(InputKeys::key_name)
(where of course an existing member should be used).
The opposite operation of take
is the Configuration::set_value method, which has a similar syntax, but needs the new value to be assigned, e.g.
If you need to delegate parsing of a section to some object, you can use the Configuration::extract_complete_sub_configuration method, which is taking a full section and returning a new, distinct Configuration instance.
Last but not least, the Configuration::validate method is used by SMASH to check that all given keys are allowed in the present version of the codebase. This is achieved by querying the "database" InputKeys class.
const Configuration&
being passed to a function). Definition at line 284 of file configuration.h.
Classes | |
struct | FileDoesNotExist |
Thrown if the file does not exist. More... | |
struct | IncorrectTypeInAssignment |
Thrown when the types in the config file and C++ don't match. More... | |
struct | isMap |
Utility type trait (general case) for the take and read public methods. More... | |
struct | isMap< std::map< Key, Value > > |
Utility type trait (special case) for the take and read public methods. More... | |
struct | ParseError |
Thrown for YAML parse errors. More... | |
struct | TakeSameKeyTwice |
Thrown if a Key is taken twice. More... | |
class | Value |
Proxy object to be used when taking or reading keys in the configuration. More... | |
Public Types | |
enum class | GetEmpty { Yes , No } |
Flag to tune method(s) behavior such that it is descriptive from the caller side. More... | |
enum class | Is { Invalid , Deprecated , Valid } |
Return type of Configuration::validate which conveys more information that simply a two-state boolean variable. More... | |
Public Member Functions | |
Configuration (const std::filesystem::path &path) | |
Read config.yaml from the specified path. More... | |
Configuration (const std::filesystem::path &path, const std::filesystem::path &filename) | |
Read a YAML config file from the specified path. More... | |
Configuration (const char *yaml, const char sflag) | |
Initialize configuration with a YAML formatted string. More... | |
Configuration (const char *yaml) | |
Configuration (const Configuration &)=delete | |
Prevent Configuration objects from being copied. More... | |
Configuration & | operator= (const Configuration &)=delete |
Prevent Configuration objects from being copy-assigned. More... | |
Configuration (Configuration &&) | |
Provide class with move constructor. More... | |
Configuration & | operator= (Configuration &&) |
Provide class with move assignment operator. More... | |
~Configuration () noexcept(false) | |
Destroy the object, optionally throwing if not all keys were taken. More... | |
void | merge_yaml (const std::string &yaml) |
Merge the configuration in yaml into the existing tree. More... | |
std::vector< std::string > | list_upmost_nodes () |
Lists all YAML::Nodes from the configuration setup. More... | |
template<typename T > | |
T | take (const Key< T > &key) |
The default interface for SMASH to read configuration values. More... | |
template<typename T > | |
T | take (const Key< T > &key, T default_value) |
Alternative method to take a key value, specifying the default value. More... | |
template<typename T > | |
T | read (const Key< T > &key) const |
Additional interface for SMASH to read configuration values without removing them. More... | |
template<typename T > | |
T | read (const Key< T > &key, T default_value) |
Alternative method to read a key value, specifying the default value. More... | |
template<typename T , typename U = remove_cvref_t<T>, typename std::enable_if_t< std::is_convertible_v< T, U >, bool > = true> | |
void | set_value (Key< U > key, T &&value) |
Overwrite the value of the YAML node corresponding to the specified key. More... | |
void | remove_all_entries_in_section_but_one (const std::string &key, KeyLabels section={}) |
Remove all entries in the given section except for key . More... | |
Configuration | extract_sub_configuration (KeyLabels section, Configuration::GetEmpty empty_if_not_existing=Configuration::GetEmpty::No) |
Create a new configuration from a then-removed section of the present object. More... | |
Configuration | extract_complete_sub_configuration (KeyLabels section, Configuration::GetEmpty empty_if_not_existing=Configuration::GetEmpty::No) |
Alternative method to extract a sub-configuration, which retains the labels from the top-level in the returned object instead of dropping them. More... | |
void | enclose_into_section (KeyLabels section) |
Enclose the configuration into the given section. More... | |
template<typename T > | |
bool | has_key (const Key< T > &key) const |
Return whether the configuration has a (possibly empty) non-map key. More... | |
template<typename T > | |
bool | has_value (const Key< T > &key) const |
Return whether there is a non-empty value behind the requested key (which is supposed not to refer to a section). More... | |
bool | has_section (const KeyLabels &labels) const |
Return whether there is a (possibly empty) section with the given labels. More... | |
bool | is_empty () const |
std::string | to_string () const |
Return a string of the current YAML tree. More... | |
void | clear () |
Erase the Configuration content. More... | |
Is | validate (bool full_validation=true) const |
Validate content of configuration in terms of YAML keys. More... | |
Static Public Attributes | |
static const char | InitializeFromYAMLString = 'S' |
Flag to mark initialization with a YAML formatted string. More... | |
Private Member Functions | |
Configuration (const YAML::Node &node) | |
Create a sub-object that has its root node at the given node. More... | |
YAML::Node | find_node_creating_it_if_not_existing (std::vector< std::string_view > keys) const |
Descend in and if needed modify the YAML tree from the given node using the provided keys. More... | |
std::optional< YAML::Node > | find_existing_node (std::vector< std::string_view > keys) const |
Descend in the YAML tree from the given node using the provided keys. More... | |
Value | take (std::vector< std::string_view > labels) |
This is the implementation detail to take a key. More... | |
Value | read (std::vector< std::string_view > labels) const |
This is the implementation detail to read a key. More... | |
bool | did_key_exist_and_was_it_already_taken (const KeyLabels &labels) const |
Find out whether a key has been already taken. More... | |
Private Attributes | |
YAML::Node | root_node_ {YAML::NodeType::Map} |
The general_config.yaml contents - fully parsed. More... | |
int | uncaught_exceptions_ {std::uncaught_exceptions()} |
Counter to be able to optionally throw in destructor. More... | |
std::vector< KeyLabels > | existing_keys_already_taken_ {} |
List of taken keys to throw on taking same key twice. More... | |
|
strong |
Flag to tune method(s) behavior such that it is descriptive from the caller side.
For example, see extract_sub_configuration.
Enumerator | |
---|---|
Yes | |
No |
Definition at line 324 of file configuration.h.
|
strong |
Return type of Configuration::validate which conveys more information that simply a two-state boolean variable.
Enumerator | |
---|---|
Invalid | |
Deprecated | |
Valid |
Definition at line 330 of file configuration.h.
|
explicit |
Read config.yaml from the specified path.
[in] | path | The directory where the SMASH config files are located. |
Definition at line 125 of file configuration.cc.
|
explicit |
Read a YAML config file from the specified path.
[in] | path | The directory where the SMASH config files are located. |
[in] | filename | The filename (without path) of the YAML config file, in case you don't want the default "config.yaml". |
Definition at line 129 of file configuration.cc.
|
inlineexplicit |
Initialize configuration with a YAML formatted string.
This is useful in 3-rd party application where we may not be able or willing to read in external files.
[in] | yaml | YAML formatted configuration data. |
[in] | sflag | control flag InitializeFromYAMLString. |
Definition at line 357 of file configuration.h.
|
inlineexplicit |
Definition at line 377 of file configuration.h.
|
delete |
Prevent Configuration objects from being copied.
Underneath, the resource is a YAML::Node
and since this handles memory in a similar way as a pointer would do, copying an object would make several instances point to the same memory and it would make it difficult to use this object correctly. Therefore, copies are not allowed.
smash::Configuration::Configuration | ( | Configuration && | other | ) |
Provide class with move constructor.
In contrast to copying, moving is fine, since this keeps the owner of the resource unique.
Definition at line 155 of file configuration.cc.
|
noexcept |
Destroy the object, optionally throwing if not all keys were taken.
This is a way to enforce that the object has to be consumed (i.e. completely parsed) during its lifetime. Since this object might be destructed during stack unwinding, the destructor has to throw only if it is safe to do so and the uncaught_exceptions_ member is used to properly implement this behavior.
Definition at line 179 of file configuration.cc.
|
inlineprivate |
Create a sub-object that has its root node at the given node.
Definition at line 1488 of file configuration.h.
|
delete |
Prevent Configuration objects from being copy-assigned.
See copy constructor Configuration(const Configuration &) for more information.
Configuration & smash::Configuration::operator= | ( | Configuration && | other | ) |
Provide class with move assignment operator.
See move constructor Configuration(Configuration &&) for more information.
Definition at line 165 of file configuration.cc.
void smash::Configuration::merge_yaml | ( | const std::string & | yaml | ) |
Merge the configuration in yaml
into the existing tree.
The function parses the string in yaml
into its internal tree representation. Then it merges the nodes from the new tree into the existing tree. The merge resolves conflicts by taking the value from yaml
.
[in] | yaml | A string with YAML (or JSON) content that is to be merged. |
Definition at line 192 of file configuration.cc.
std::vector< std::string > smash::Configuration::list_upmost_nodes | ( | ) |
Lists all YAML::Nodes from the configuration setup.
Definition at line 206 of file configuration.cc.
|
inline |
The default interface for SMASH to read configuration values.
The function returns the value at the specified Key
and removes its labels from the Configuration object. Therefore, a subsequent call to the take
or has_value
methods with the same Key
throws or returns false
respectively. By removing the value, the Configuration object keeps track which keys were never taken.
take
operation and it might be done once for all. However, on one hand it is a natural behaviour to expect and on the other hand this is hardly going to be an application bottle-neck.take
returns the default value when the key is not present in the configuration, it is important to make it throw if an existing key is attempted to be taken twice. Otherwise it would happen that taking any existing key would return the user-defined value the first time and taking it again would return the key default value. This is a misleading behaviour we want to avoid. However, a key can be taken several times if it exists at take time. For example, taking a key, setting its value and taking it again is a valid behaviour.[in] | key | The input key that should be taken. This is usually one of the InputKeys static members, i.e. one of the allowed keys. Of course, any Key would work. For example, given Group: Key: 42then Key key<int>{{"Group", "Key"}, {"1.0"}}; string value = config.take(key);will take the value. This will make the key "Group" also be removed from the configuration, since it remains without any value. |
TakeSameKeyTwice | if a key was already previously taken. |
std::invalid_argument | if a key without a default is taken but it is absent in the configuration. |
Definition at line 500 of file configuration.h.
|
inline |
Alternative method to take a key value, specifying the default value.
T | The type of the key to be taken |
key | The key to be taken |
default_value | The default value to be returned if the key is not present in the configuration |
std::logic_error | If the key has not a default value declared as dependent on external entities. |
Definition at line 543 of file configuration.h.
|
inline |
Additional interface for SMASH to read configuration values without removing them.
The function returns the value of the specified Key
but does not remove it from the Configuration object. Semantically, this means the value was not used.
Also this method returns the default value of the key (or an error if none is available), if the key is not present in the configuration.
[in] | key | The input key that should be taken. |
std::invalid_argument | if a key without a default is taken but it is absent in the configuration. |
Definition at line 579 of file configuration.h.
|
inline |
Alternative method to read a key value, specifying the default value.
T | The type of the key to be read |
key | The key to be read |
default_value | The default value to be returned if the key is not present in the configuration |
std::logic_error | If the key has not a default value declared as dependent on external entities. |
Definition at line 618 of file configuration.h.
|
inline |
Overwrite the value of the YAML node corresponding to the specified key.
[in] | key | The input key that should be changed. |
[in] | value | An arbitrary value that yaml-cpp can convert into YAML representation. Any builtin type, strings, maps, and vectors can be used here. Of course, this has to match the Key type passed as first argument. |
T | The type of the value to be assigned to the Key. |
U | The type of the key value. This is by default T but it has been allowed to be different from it, as long as it is convertible to T. This enables e.g. to set a key with a string value using a const char* second argument. |
T
might be deduced to a constant and/or reference type. Definition at line 655 of file configuration.h.
void smash::Configuration::remove_all_entries_in_section_but_one | ( | const std::string & | key, |
KeyLabels | section = {} |
||
) |
Remove all entries in the given section except for key
.
[in] | key | The key of the map entry to keep. |
[in] | section | You can pass an arbitrary number of keys inside curly braces, following the nesting structure in the config file, in order to specify the section where to delete entries. Omitting the section is equivalent to specifying {} and the top-level section is understood. |
Definition at line 258 of file configuration.cc.
Configuration smash::Configuration::extract_sub_configuration | ( | KeyLabels | section, |
Configuration::GetEmpty | empty_if_not_existing = Configuration::GetEmpty::No |
||
) |
Create a new configuration from a then-removed section of the present object.
This method is meant to be used to deal with sections only, i.e. it will throw if used to extract a key value that is not a section (namely a map in YAML language). Use take for that purpose, instead.
[in] | section | You can pass an arbitrary number of keys inside curly braces, following the nesting structure in the config file. |
[in] | empty_if_not_existing | Specify Configuration::GetEmpty::Yes if you want an empty Configuration in case the requested section does not exist. |
std::runtime_error | if the method is used
|
Configuration
containing the chosen section. Definition at line 293 of file configuration.cc.
Configuration smash::Configuration::extract_complete_sub_configuration | ( | KeyLabels | section, |
Configuration::GetEmpty | empty_if_not_existing = Configuration::GetEmpty::No |
||
) |
Alternative method to extract a sub-configuration, which retains the labels from the top-level in the returned object instead of dropping them.
Definition at line 330 of file configuration.cc.
void smash::Configuration::enclose_into_section | ( | KeyLabels | section | ) |
Enclose the configuration into the given section.
section | The section in which to enclose the configuration. |
Definition at line 338 of file configuration.cc.
|
inline |
Return whether the configuration has a (possibly empty) non-map key.
Although YAML keys can have maps as value, we rather refer to those as sections and we do not consider them as key in the SMASH database sense. A key has then either a scalar or sequence value.
[in] | key | The key to be checked for. |
Definition at line 724 of file configuration.h.
|
inline |
Return whether there is a non-empty value behind the requested key
(which is supposed not to refer to a section).
If there is a section with the same labels as the provided key has, this function returns false
.
[in] | key | The key to be checked for. |
Definition at line 738 of file configuration.h.
|
inline |
Return whether there is a (possibly empty) section with the given labels.
[in] | labels | The labels of the section to be checked for. |
Definition at line 750 of file configuration.h.
|
inline |
true
if the object is empty; false
if at least one key exists. Definition at line 759 of file configuration.h.
std::string smash::Configuration::to_string | ( | ) | const |
Return a string
of the current YAML tree.
Definition at line 360 of file configuration.cc.
|
inline |
Erase the Configuration content.
This function is useful e.g. in tests to clean up not taken keys that would trigger an exception being thrown at by the destructor.
Definition at line 772 of file configuration.h.
Configuration::Is smash::Configuration::validate | ( | bool | full_validation = true | ) | const |
Validate content of configuration in terms of YAML keys.
A warning or error message is printed for deprecated or invalid keys, respectively, together with information about SMASH versions, if possible.
false
as soon as an invalid key is found. However, a full validation is more user-friendly, since as much information as possible about the input file is provided.[in] | full_validation | Whether all keys are checked or not. |
Is::Valid
if the object contains valid keys only; Is::Deprecated
if the object is valid but has deprecated key(s); Is::Invalid
if the object contains at least one invalid key. Definition at line 625 of file configuration.cc.
|
private |
Descend in and if needed modify the YAML tree from the given node using the provided keys.
After this call nodes corresponding to the passed keys are guaranteed to exist in the tree.
[in] | keys | Keys that will be possibly added to the YAML tree. |
Definition at line 379 of file configuration.cc.
|
private |
Descend in the YAML tree from the given node using the provided keys.
This function must not use the YAML::Node subscript operator, which is at the very bottom level creating an undefined node in the YAML tree, hence "wasting" some memory. Note that the fact that this method is marked as const does not forbid to use the access operator on root_node_
, because of how the YAML library works. We want the tree to be completely untouched by this method.
[in] | keys | Keys that will be used to descend the YAML tree. |
std::optional<YAML::Node>
containing the node in the tree reached by using the provided keys, if it exists; std::nullopt
otherwise.has_value
and putting there a try-catch block would probably cause a performance cost that can be avoided (exceptions on the exceptional path are expensive). Definition at line 366 of file configuration.cc.
|
private |
This is the implementation detail to take a key.
Having a non-templated method for it it allows for defining the method in the source file, which isn't possible for a template.
[in] | labels | the labels of the key to be taken |
Value
of the keystd::runtime_error | if the key does not exist |
Definition at line 215 of file configuration.cc.
|
private |
This is the implementation detail to read a key.
Having a non-templated method for it it allows for defining the method in the source file, which isn't possible for a template.
[in] | labels | the labels of the key to be read |
Value
of the keystd::runtime_error | if the key does not exist |
Definition at line 245 of file configuration.cc.
|
inlineprivate |
Find out whether a key has been already taken.
labels | The labels of the key to be checked |
true
if the key was already taken, false
otherwise. Definition at line 1574 of file configuration.h.
|
static |
Flag to mark initialization with a YAML formatted string.
Definition at line 318 of file configuration.h.
|
private |
The general_config.yaml contents - fully parsed.
Definition at line 1581 of file configuration.h.
|
private |
Counter to be able to optionally throw in destructor.
Definition at line 1584 of file configuration.h.
|
private |
List of taken keys to throw on taking same key twice.
Definition at line 1587 of file configuration.h.