Version: SMASH-3.1
smash::Configuration Class Reference

#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:

double sigma = config.take({"General", "SIGMA"});

Note the curly braces in the function call. It is a std::initializer_list of strings. This allows an arbitrary nesting depth via the same function. But as a consequence the keys must all be given as constant strings at compile time.

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.

config.set_value({"General", "SIGMA"}, 3.1415);

If you need to delegate parsing of a section to some object, you can use the Configuration::extract_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.

Attention
As the Configuration is implemented, it does not make sense in practice to have constant instances, because their keys could not be taken and their destruction would lead to an exception being thrown. However, it still makes perfectly sense to have constant methods (think e.g. of a const Configuration& being passed to a function).

Definition at line 276 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  ParseError
 Thrown for YAML parse errors. More...
 
class  Value
 Return type of Configuration::take that automatically determines the target type. 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...
 
Configurationoperator= (const Configuration &)=delete
 Prevent Configuration objects from being copy-assigned. More...
 
 Configuration (Configuration &&)
 Provide class with move constructor. More...
 
Configurationoperator= (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...
 
Value take (std::initializer_list< const char * > keys)
 The default interface for SMASH to read configuration values. More...
 
template<typename T >
take (std::initializer_list< const char * > keys, T default_value)
 
Value read (std::initializer_list< const char * > keys) const
 Additional interface for SMASH to read configuration values without removing them. More...
 
template<typename T >
read (std::initializer_list< const char * > keys, T default_value)
 
template<typename T >
void set_value (std::initializer_list< const char * > keys, T &&value)
 Overwrite the value of the specified YAML node. More...
 
void remove_all_entries_in_section_but_one (const std::string &key, std::initializer_list< const char * > section={})
 Remove all entries in the given section except for key. More...
 
Configuration extract_sub_configuration (std::initializer_list< const char * > keys, Configuration::GetEmpty empty_if_not_existing=Configuration::GetEmpty::No)
 Create a new configuration from a then-removed section of the present object. More...
 
bool has_value_including_empty (std::initializer_list< const char * > keys) const
 Return whether there is a (maybe empty) value behind the requested keys. More...
 
bool has_value (std::initializer_list< const char * > keys) const
 Return whether there is a non-empty value behind the requested keys. 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 subobject that has its root node at the given node. More...
 
YAML::Node find_node_creating_it_if_not_existing (std::vector< const char * > 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< const char * > keys) const
 Descend in the YAML tree from the given node using the provided keys. 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...
 

Member Enumeration Documentation

◆ GetEmpty

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 971 of file configuration.h.

971 { Yes, No };
@ Yes
Print only final-state particles.
@ No
Print initial, intermediate and final-state particles.

◆ Is

Return type of Configuration::validate which conveys more information that simply a two-state boolean variable.

Enumerator
Invalid 
Deprecated 
Valid 

Definition at line 977 of file configuration.h.

977 { Invalid, Deprecated, Valid };
@ Invalid
Unused, only in the code for internal logic.

Constructor & Destructor Documentation

◆ Configuration() [1/7]

smash::Configuration::Configuration ( const std::filesystem::path &  path)
explicit

Read config.yaml from the specified path.

Parameters
[in]pathThe directory where the SMASH config files are located.

Definition at line 122 of file configuration.cc.

123  : Configuration(path, "config.yaml") {}
Configuration(const std::filesystem::path &path)
Read config.yaml from the specified path.

◆ Configuration() [2/7]

smash::Configuration::Configuration ( const std::filesystem::path &  path,
const std::filesystem::path &  filename 
)
explicit

Read a YAML config file from the specified path.

Parameters
[in]pathThe directory where the SMASH config files are located.
[in]filenameThe filename (without path) of the YAML config file, in case you don't want the default "config.yaml".

Definition at line 126 of file configuration.cc.

127  {
128  const auto file_path = path / filename;
129  if (!std::filesystem::exists(file_path)) {
130  throw FileDoesNotExist("The configuration file was expected at '" +
131  file_path.native() +
132  "', but the file does not exist.");
133  }
134  if (has_crlf_line_ending(read_all(std::ifstream((file_path))))) {
135  throw std::runtime_error(
136  "The configuration file has CR LF line endings. Please use LF "
137  "line endings.");
138  }
139  try {
140  root_node_ = YAML::LoadFile(file_path.native());
141  } catch (YAML::ParserException &e) {
142  if (e.msg == "illegal map value" || e.msg == "end of map not found") {
143  const auto line = std::to_string(e.mark.line + 1);
144  throw ParseError("YAML parse error at\n" + file_path.native() + ':' +
145  line + ": " + e.msg +
146  " (check that the indentation of map keys matches)");
147  }
148  throw;
149  }
150 }
YAML::Node root_node_
The general_config.yaml contents - fully parsed.
bool has_crlf_line_ending(const std::string in)
Check if a line in the string ends with \r\n.
std::string read_all(std::istream &&input)
Utility function to read a complete input stream (e.g.

◆ Configuration() [3/7]

smash::Configuration::Configuration ( const char *  yaml,
const char  sflag 
)
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.

Parameters
[in]yamlYAML formatted configuration data.
[in]sflagcontrol flag InitializeFromYAMLString.

Definition at line 1004 of file configuration.h.

1004  {
1005  if (sflag == InitializeFromYAMLString) {
1006  merge_yaml(yaml);
1007  } else {
1008  throw std::runtime_error(
1009  "Unknown control flag in Configuration constructor"
1010  " with a YAML formatted string. Please, use"
1011  " Configuration::InitializeFromYAMLString.");
1012  }
1013  }
void merge_yaml(const std::string &yaml)
Merge the configuration in yaml into the existing tree.
static const char InitializeFromYAMLString
Flag to mark initialization with a YAML formatted string.

◆ Configuration() [4/7]

smash::Configuration::Configuration ( const char *  yaml)
inlineexplicit
Unit tests can use this constructor to get a Configuration object from a built-in string.This function is only available to tests and should never be used/needed in actual SMASH code. The intention is to avoid creating a mock object for Configuration to test other classes of SMASH.

Definition at line 1024 of file configuration.h.

1024  : root_node_(YAML::Load(yaml)) {
1025  if (root_node_.IsNull())
1026  root_node_ = YAML::Node{YAML::NodeType::Map};
1027  }

◆ Configuration() [5/7]

smash::Configuration::Configuration ( const Configuration )
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.

◆ Configuration() [6/7]

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.

Note
Since the class has the peculiar behavior that all keys must be parsed before it gets destroyed (otherwise an exception is thrown), it is important to manually implement the move operations, in order to ensure that objects that are moved from result cleared and their destruction is not leading to any throw. This is not guaranteed if the special members are defaulted to the compiler generated versions.

Definition at line 152 of file configuration.cc.

153  : root_node_(std::move(other.root_node_)),
154  uncaught_exceptions_(std::move(other.uncaught_exceptions_)) {
155  other.root_node_.reset();
156  other.uncaught_exceptions_ = 0;
157 }
int uncaught_exceptions_
Counter to be able to optionally throw in destructor.

◆ ~Configuration()

smash::Configuration::~Configuration ( )
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 170 of file configuration.cc.

170  {
171  // Make sure that stack unwinding is not taking place befor throwing
172  if (std::uncaught_exceptions() == uncaught_exceptions_) {
173  // In this scenario is fine to throw
174  if (root_node_.size() != 0) {
175  throw std::logic_error(
176  "Configuration object destroyed with unused keys:\n" + to_string());
177  }
178  }
179  /* If this destructor is called during stack unwinding, it is irrelevant
180  that the Configuration has not be completely parsed. */
181 }
std::string to_string() const
Return a string of the current YAML tree.

◆ Configuration() [7/7]

smash::Configuration::Configuration ( const YAML::Node &  node)
inlineprivate

Create a subobject that has its root node at the given node.

Note
This constructor is not explicit because it can be called only from inside Configuration and by making it explicit a return would require the copy constructor.

Definition at line 1272 of file configuration.h.

1273  : root_node_(YAML::Clone(node)) {}

Member Function Documentation

◆ operator=() [1/2]

Configuration& smash::Configuration::operator= ( const Configuration )
delete

Prevent Configuration objects from being copy-assigned.

See copy constructor Configuration(const Configuration &) for more information.

◆ operator=() [2/2]

Configuration & smash::Configuration::operator= ( Configuration &&  other)

Provide class with move assignment operator.

See move constructor Configuration(Configuration &&) for more information.

Definition at line 159 of file configuration.cc.

159  {
160  // YAML does not offer != operator between nodes
161  if (!(root_node_ == other.root_node_)) {
162  root_node_ = std::move(other.root_node_);
163  uncaught_exceptions_ = std::move(other.uncaught_exceptions_);
164  other.root_node_.reset();
165  other.uncaught_exceptions_ = 0;
166  }
167  return *this;
168 }

◆ merge_yaml()

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.

Parameters
[in]yamlA string with YAML (or JSON) content that is to be merged.

Definition at line 183 of file configuration.cc.

183  {
184  try {
185  root_node_ |= YAML::Load(yaml);
186  } catch (YAML::ParserException &e) {
187  if (e.msg == "illegal map value" || e.msg == "end of map not found") {
188  const auto line = std::to_string(e.mark.line + 1);
189  throw ParseError("YAML parse error in:\n" + yaml + "\nat line " + line +
190  ": " + e.msg +
191  " (check that the indentation of map keys matches)");
192  }
193  throw;
194  }
195 }

◆ list_upmost_nodes()

std::vector< std::string > smash::Configuration::list_upmost_nodes ( )

Lists all YAML::Nodes from the configuration setup.

Definition at line 197 of file configuration.cc.

197  {
198  std::vector<std::string> r;
199  r.reserve(root_node_.size());
200  for (auto i : root_node_) {
201  r.emplace_back(i.first.Scalar());
202  }
203  return r;
204 }

◆ take() [1/2]

Configuration::Value smash::Configuration::take ( std::initializer_list< const char * >  keys)

The default interface for SMASH to read configuration values.

The function returns the value at the specified keys and removes it from the Configuration object. Therefore, a subsequent call to take or has_value with the same keys returns an undefined value / false. By removing the value, the Configuration object keeps track which settings were never read.

Note
If taking a key leaves the parent key without a value, then this is in turn removed and so on. From a performance point of view, it might be argued that this is not needed to be checkend and done at every 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.
Parameters
[in]keysYou can pass an arbitrary number of keys inside curly braces, following the nesting structure in the config file. For example, given
  Group:
      Key: Value
call
string value = config.take({"Group", "Key"});
to read the value. This will make the key "Group" also be removed from the configuration, since it remains without any value.
Returns
A proxy object that converts to the correct type automatically on assignment.

Definition at line 206 of file configuration.cc.

207  {
208  assert(keys.size() > 0);
209  /* Here we want to descend the YAML tree but not all the way to the last key,
210  because we need the node associated to the previous to last key in order to
211  remove the taken key. */
212  auto last_key_it = keys.end() - 1;
213  auto previous_to_last_node = find_existing_node({keys.begin(), last_key_it});
214  auto to_be_returned{previous_to_last_node};
215  descend_one_existing_level(to_be_returned, *last_key_it);
216  if (!previous_to_last_node || !to_be_returned) {
217  throw std::invalid_argument(
218  "Attempt to take value of a not existing key: " + join_quoted(keys));
219  }
220  previous_to_last_node.value().remove(*last_key_it);
222  return {to_be_returned.value(), *last_key_it};
223 }
std::optional< YAML::Node > find_existing_node(std::vector< const char * > keys) const
Descend in the YAML tree from the given node using the provided keys.
void descend_one_existing_level(std::optional< YAML::Node > &node, std::string_view key)
Reset the passed in node to that one at the provided key, which is expected to exist in the node.
std::string join_quoted(std::initializer_list< const char * > keys)
Build a string with a list of keys as specified in the code.
YAML::Node remove_empty_maps(YAML::Node root)
Remove all empty maps of a YAML::Node.

◆ take() [2/2]

template<typename T >
T smash::Configuration::take ( std::initializer_list< const char * >  keys,
default_value 
)
inline
See also
take

Definition at line 1129 of file configuration.h.

1129  {
1130  if (has_value(keys)) {
1131  return take(keys);
1132  }
1133  return default_value;
1134  }
bool has_value(std::initializer_list< const char * > keys) const
Return whether there is a non-empty value behind the requested keys.
Value take(std::initializer_list< const char * > keys)
The default interface for SMASH to read configuration values.

◆ read() [1/2]

Configuration::Value smash::Configuration::read ( std::initializer_list< const char * >  keys) const

Additional interface for SMASH to read configuration values without removing them.

The function returns the value at the specified keys but does not remove it from the Configuration object. Semantically, this means the value was not used.

Parameters
[in]keysYou can pass an arbitrary number of keys inside curly braces, following the nesting structure in the config file.
Returns
A proxy object that converts to the correct type automatically on assignment.

Definition at line 225 of file configuration.cc.

226  {
227  auto found_node = find_existing_node(keys);
228  if (found_node) {
229  return {found_node.value(), keys.begin()[keys.size() - 1]};
230  } else {
231  throw std::invalid_argument(
232  "Attempt to read value of a not existing key: " + join_quoted(keys));
233  }
234 }

◆ read() [2/2]

template<typename T >
T smash::Configuration::read ( std::initializer_list< const char * >  keys,
default_value 
)
inline
See also
read

Definition at line 1154 of file configuration.h.

1154  {
1155  if (has_value(keys)) {
1156  return read(keys);
1157  }
1158  return default_value;
1159  }
Value read(std::initializer_list< const char * > keys) const
Additional interface for SMASH to read configuration values without removing them.

◆ set_value()

template<typename T >
void smash::Configuration::set_value ( std::initializer_list< const char * >  keys,
T &&  value 
)
inline

Overwrite the value of the specified YAML node.

Parameters
[in]keysYou can pass an arbitrary number of keys inside curly braces, following the nesting structure in the config file.
[in]valueAn arbitrary value that yaml-cpp can convert into YAML representation. Any builtin type, strings, maps, and vectors can be used here.

Definition at line 1171 of file configuration.h.

1171  {
1172  auto node = find_node_creating_it_if_not_existing(keys);
1173  node = std::forward<T>(value);
1174  }
YAML::Node find_node_creating_it_if_not_existing(std::vector< const char * > keys) const
Descend in and if needed modify the YAML tree from the given node using the provided keys.

◆ remove_all_entries_in_section_but_one()

void smash::Configuration::remove_all_entries_in_section_but_one ( const std::string &  key,
std::initializer_list< const char * >  section = {} 
)

Remove all entries in the given section except for key.

Parameters
[in]keyThe key of the map entry to keep.
[in]sectionYou 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 236 of file configuration.cc.

237  {
238  auto found_node = find_existing_node(section);
239  if (found_node) {
240  std::vector<std::string> to_remove{};
241  bool key_exists = false;
242  for (auto i : found_node.value()) {
243  if (i.first.Scalar() != key) {
244  to_remove.push_back(i.first.Scalar());
245  } else {
246  key_exists = true;
247  }
248  }
249  if (!key_exists) {
250  std::string section_string{" section "};
251  if (section.size() > 0) {
252  section_string += join_quoted(section) + " ";
253  } else {
254  section_string = " top-level" + section_string;
255  }
256  throw std::invalid_argument("Attempt to remove all keys in" +
257  section_string +
258  "except not existing one: \"" + key + "\"");
259  } else {
260  for (auto i : to_remove) {
261  found_node.value().remove(i);
262  }
263  }
264  } else {
265  throw std::invalid_argument(
266  "Attempt to remove entries in not existing section: " +
267  join_quoted(section));
268  }
269 }

◆ extract_sub_configuration()

Configuration smash::Configuration::extract_sub_configuration ( std::initializer_list< const char * >  keys,
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.

Parameters
[in]keysYou can pass an arbitrary number of keys inside curly braces, following the nesting structure in the config file.
[in]empty_if_not_existingSpecify Configuration::GetEmpty::Yes if you want an empty Configuration in case the requested section does not exist.
Exceptions
std::runtime_errorif the method is used
  • to access a scalar or sequence value;
  • to access a key that has no value or is an empty map;
  • to access a not existing key (unless explicitly allowed).
Returns
A new Configuration containing the chosen section.

Definition at line 271 of file configuration.cc.

273  {
274  // Same logic as in take method
275  assert(keys.size() > 0);
276  auto last_key_it = keys.end() - 1;
277  auto previous_to_section_node =
278  find_existing_node({keys.begin(), last_key_it});
279  auto sub_conf_root_node{previous_to_section_node};
280  descend_one_existing_level(sub_conf_root_node, *last_key_it);
281  if (!previous_to_section_node || !sub_conf_root_node) {
282  if (empty_if_not_existing == Configuration::GetEmpty::Yes)
283  return Configuration(YAML::Node{});
284  else
285  throw std::runtime_error("Attempt to extract not existing section " +
286  join_quoted(keys));
287  }
288  /* Here sub_conf_root_node cannot be a nullopt, since if it was the function
289  would have returned before and it cannot be that previous_to_section_node
290  is nullopt and sub_conf_root_node is not */
291  else if (sub_conf_root_node->IsNull() || // NOLINT[whitespace/newline]
292  (sub_conf_root_node->IsMap() && sub_conf_root_node->size() == 0)) {
293  // Here we put together the cases of a key without value or with
294  // an empty map {} as value (no need at the moment to distinguish)
295  throw std::runtime_error("Attempt to extract empty section " +
296  join_quoted(keys));
297  } else if (sub_conf_root_node->IsMap() && sub_conf_root_node->size() != 0) {
298  Configuration sub_config{*sub_conf_root_node};
299  previous_to_section_node->remove(*last_key_it);
301  return sub_config;
302  } else { // sequence or scalar or any future new YAML type
303  throw std::runtime_error("Tried to extract configuration section at " +
304  join_quoted(keys) +
305  " to get a key value. Use take instead!");
306  }
307 }

◆ has_value_including_empty()

bool smash::Configuration::has_value_including_empty ( std::initializer_list< const char * >  keys) const

Return whether there is a (maybe empty) value behind the requested keys.

Parameters
[in]keysList of keys to be checked for

Definition at line 309 of file configuration.cc.

310  {
311  const auto found_node = find_existing_node(keys);
312  return found_node.has_value();
313 }

◆ has_value()

bool smash::Configuration::has_value ( std::initializer_list< const char * >  keys) const

Return whether there is a non-empty value behind the requested keys.

Parameters
[in]keysList of keys to be checked for

Definition at line 315 of file configuration.cc.

315  {
316  const auto found_node = find_existing_node(keys);
317  return found_node.has_value() && !(found_node.value().IsNull());
318 }

◆ is_empty()

bool smash::Configuration::is_empty ( ) const
inline
Returns
true if the object is empty;
false if at least one key exists.

Definition at line 1230 of file configuration.h.

1230 { return root_node_.size() == 0; }

◆ to_string()

std::string smash::Configuration::to_string ( ) const

Return a string of the current YAML tree.

Definition at line 320 of file configuration.cc.

320  {
321  std::stringstream s;
322  s << root_node_;
323  return s.str();
324 }

◆ clear()

void smash::Configuration::clear ( )
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 1243 of file configuration.h.

1243 { root_node_.reset(); }

◆ validate()

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.

Note
Here a full validation is done by default and all keys are checked, although the validation might be shortened by returning 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.
Parameters
[in]full_validationWhether all keys are checked or not.
Returns
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 585 of file configuration.cc.

585  {
588  Is validation_result{Is::Valid};
589  for (const auto &key_labels : list) {
590  Is key_state = validate_key(key_labels);
591  if (full_validation) {
592  accumulate_validation(validation_result, key_state);
593  } else {
594  if (key_state != Is::Valid)
595  return key_state;
596  }
597  }
598  return validation_result;
599 }
Is
Return type of Configuration::validate which conveys more information that simply a two-state boolean...
void adjust_list_of_labels_dealing_with_keys_taken_as_maps(std::vector< KeyLabels > &list_of_input_key_labels)
Remove last labels of keys that are taken as maps in SMASH and remove duplicates from the resulting l...
void accumulate_validation(Configuration::Is &result_so_far, Configuration::Is new_value)
Utility function to accumulate validation results of keys.
Configuration::Is validate_key(const KeyLabels &labels)
Given some YAML labels (assumed to be in order from the top section), it is checked whether any valid...
auto get_list_of_labels_per_key_in_yaml_tree(const YAML::Node &root_node)
Create a list of lists of key labels present in the passed YAML node considered to be the root one of...

◆ find_node_creating_it_if_not_existing()

YAML::Node smash::Configuration::find_node_creating_it_if_not_existing ( std::vector< const char * >  keys) const
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.

Parameters
[in]keysKeys that will be possibly added to the YAML tree.
Returns
Node in the tree reached by using the provided keys.

Definition at line 339 of file configuration.cc.

340  {
341  assert(keys.size() > 0);
342  YAML::Node node{root_node_};
343  for (const auto &key : keys) {
344  // See comments in descend_one_existing_level function
345  node.reset(node[key]);
346  }
347  return node;
348 }

◆ find_existing_node()

std::optional< YAML::Node > smash::Configuration::find_existing_node ( std::vector< const char * >  keys) const
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.

Parameters
[in]keysKeys that will be used to descend the YAML tree.
Returns
std::optional<YAML::Node> containing the node in the tree reached by using the provided keys, if it exists;
std::nullopt otherwise.
Note
It has been decided to return an optional value rather than throwing an exception because this method is going to be used in other methods like 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 326 of file configuration.cc.

327  {
328  /* Here we do not assert(keys.size()>0) and allow to pass in an empty vector,
329  in which case the passed in YAML:Node is simply returned. This might happen
330  e.g. in the take or extract_sub_configuration methods if called with a
331  label of a key at top level of the configuration file. */
332  std::optional<YAML::Node> node{root_node_};
333  for (const auto &key : keys) {
334  descend_one_existing_level(node, key);
335  }
336  return node;
337 }

Member Data Documentation

◆ InitializeFromYAMLString

const char smash::Configuration::InitializeFromYAMLString = 'S'
static

Flag to mark initialization with a YAML formatted string.

Definition at line 965 of file configuration.h.

◆ root_node_

YAML::Node smash::Configuration::root_node_ {YAML::NodeType::Map}
private

The general_config.yaml contents - fully parsed.

Definition at line 1315 of file configuration.h.

◆ uncaught_exceptions_

int smash::Configuration::uncaught_exceptions_ {std::uncaught_exceptions()}
private

Counter to be able to optionally throw in destructor.

Definition at line 1318 of file configuration.h.


The documentation for this class was generated from the following files: