Version: SMASH-1.5
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).

For the typical usage in SMASH one needs to read the value once. In that case, use the Configuration::take function:

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.

If you need to access the configuration values from a run-time string you can use Configuration::operator[]. This returns a Configuration object that references the respective sub-tree.

By taking values (instead of just reading), the configuration object should be empty at the end of the initialization. If the object is not empty, SMASH will print a warning (using Configuration::unused_values_report). This can be important for the user to discover typos in his configuration file (or command line parameters).

Definition at line 313 of file configuration.h.

Collaboration diagram for smash::Configuration:
[legend]

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 Member Functions

 Configuration (const bf::path &path)
 Reads config.yaml from the specified path. More...
 
 Configuration (const bf::path &path, const bf::path &filename)
 Reads a YAML config file from the specified path. More...
 
 Configuration (const char *yaml)
 
 Configuration (const Configuration &)=default
 If you want to copy this you're doing it wrong. More...
 
Configurationoperator= (const Configuration &)=default
 If you want to copy this you're doing it wrong. More...
 
 Configuration (Configuration &&)=default
 Moving is fine. More...
 
Configurationoperator= (Configuration &&)=default
 Moving is fine. 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)
 
void remove_all_but (const std::string &key)
 Removes all entries in the map except for key. More...
 
template<typename T >
Configuration operator[] (T &&key)
 Access to the YAML::Node behind the requested keys. More...
 
template<typename T >
Configurationoperator= (T &&value)
 Assignment overwrites the value of the current YAML node. More...
 
bool has_value_including_empty (std::initializer_list< const char *> keys) const
 Returns if there is a (maybe empty) value behind the requested keys. More...
 
bool has_value (std::initializer_list< const char *> keys) const
 Returns whether there is a non-empty value behind the requested keys. More...
 
std::string unused_values_report () const
 Returns a string listing the key/value pairs that have not been taken yet. More...
 
std::string to_string () const
 Returns a YAML string of the current tree. More...
 

Private Member Functions

 Configuration (const YAML::Node &node)
 Creates a subobject that has its root node at the given node. More...
 

Private Attributes

YAML::Node root_node_
 the general_config.yaml contents - fully parsed More...
 

Constructor & Destructor Documentation

◆ Configuration() [1/6]

smash::Configuration::Configuration ( const bf::path &  path)
explicit

Reads config.yaml from the specified path.

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

Definition at line 98 of file configuration.cc.

99  : Configuration(path, "config.yaml") {}
Configuration(const bf::path &path)
Reads config.yaml from the specified path.

◆ Configuration() [2/6]

smash::Configuration::Configuration ( const bf::path &  path,
const bf::path &  filename 
)
explicit

Reads 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 102 of file configuration.cc.

102  {
103  const auto file_path = path / filename;
104  if (!bf::exists(file_path)) {
105  throw FileDoesNotExist("The configuration file was expected at '" +
106  file_path.native() +
107  "', but the file does not exist.");
108  }
109  if (has_crlf_line_ending(read_all(bf::ifstream((file_path))))) {
110  throw std::runtime_error(
111  "The configuration file has CR LF line endings. Please use LF "
112  "line endings.");
113  }
114  try {
115  root_node_ = YAML::LoadFile(file_path.native());
116  } catch (YAML::ParserException &e) {
117  if (e.msg == "illegal map value" || e.msg == "end of map not found") {
118  const auto line = std::to_string(e.mark.line + 1);
119  throw ParseError("YAML parse error at\n" + file_path.native() + ':' +
120  line + ": " + e.msg +
121  " (check that the indentation of map keys matches)");
122  }
123  throw;
124  }
125 
126  if (!root_node_["decaymodes"].IsDefined()) {
127  root_node_["decaymodes"] = decaymodes_txt::data;
128  }
129  if (!root_node_["particles"].IsDefined()) {
130  root_node_["particles"] = particles_txt::data;
131  }
132 }
bool has_crlf_line_ending(const std::string in)
Check if a line in the string ends with \r\n.
YAML::Node root_node_
the general_config.yaml contents - fully parsed
std::string read_all(std::istream &&input)
Utility function to read a complete input stream (e.g.
Here is the call graph for this function:

◆ Configuration() [3/6]

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

809 : root_node_(YAML::Load(yaml)) {}
YAML::Node root_node_
the general_config.yaml contents - fully parsed

◆ Configuration() [4/6]

smash::Configuration::Configuration ( const Configuration )
default

If you want to copy this you're doing it wrong.

◆ Configuration() [5/6]

smash::Configuration::Configuration ( Configuration &&  )
default

Moving is fine.

◆ Configuration() [6/6]

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

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

965  : root_node_(node) {}
YAML::Node root_node_
the general_config.yaml contents - fully parsed

Member Function Documentation

◆ operator=() [1/3]

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

If you want to copy this you're doing it wrong.

◆ operator=() [2/3]

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

Moving is fine.

◆ 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 134 of file configuration.cc.

134  {
135  try {
136  root_node_ |= YAML::Load(yaml);
137  } catch (YAML::ParserException &e) {
138  if (e.msg == "illegal map value" || e.msg == "end of map not found") {
139  const auto line = std::to_string(e.mark.line + 1);
140  throw ParseError("YAML parse error in:\n" + yaml + "\nat line " + line +
141  ": " + e.msg +
142  " (check that the indentation of map keys matches)");
143  }
144  throw;
145  }
146 }
YAML::Node root_node_
the general_config.yaml contents - fully parsed
Here is the caller graph for this function:

◆ list_upmost_nodes()

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

Lists all YAML::Nodes from the configuration setup.

Definition at line 148 of file configuration.cc.

148  {
149  std::vector<std::string> r;
150  for (auto i : root_node_) {
151  r.emplace_back(i.first.Scalar());
152  }
153  return r;
154 }
YAML::Node root_node_
the general_config.yaml contents - fully parsed

◆ 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.

Parameters
[in]keysYou can pass an arbitrary number of keys inside curly braces, following the nesting structure in the config file. Example:
Group:
    Key: Value
Call
string value = config.take({"Group", "Key"});
to read the value.
Returns
A proxy object that converts to the correct type automatically on assignment.

Definition at line 156 of file configuration.cc.

157  {
158  assert(keys.size() > 0);
159  auto node = root_node_;
160  auto keyIt = begin(keys);
161  std::size_t i = 0;
162  for (; i < keys.size() - 1; ++i, ++keyIt) {
163  // Node::reset does what you might expect Node::operator= to do. But
164  // operator= assigns a value to the node. So
165  // node = node[*keyIt]
166  // leads to modification of the data structure, not simple traversal.
167  node.reset(node[*keyIt]);
168  }
169  const auto r = node[*keyIt];
170  node.remove(*keyIt);
171  return {r, keys.begin()[keys.size() - 1]};
172 }
YAML::Node root_node_
the general_config.yaml contents - fully parsed
Here is the caller graph for this function:

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

862  {
863  if (has_value(keys)) {
864  return take(keys);
865  }
866  return default_value;
867  }
bool has_value(std::initializer_list< const char *> keys) const
Returns 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.
Here is the call graph for this function:

◆ 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 174 of file configuration.cc.

175  {
176  return {find_node_at(root_node_, keys), keys.begin()[keys.size() - 1]};
177 }
YAML::Node find_node_at(YAML::Node node, std::initializer_list< const char *> keys)
Finds a node, copies its structure and replaces the previous keys by the newly provided keys...
YAML::Node root_node_
the general_config.yaml contents - fully parsed
Here is the call graph for this function:
Here is the caller graph for this function:

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

887  {
888  if (has_value(keys)) {
889  return read(keys);
890  }
891  return default_value;
892  }
Value read(std::initializer_list< const char *> keys) const
Additional interface for SMASH to read configuration values without removing them.
bool has_value(std::initializer_list< const char *> keys) const
Returns whether there is a non-empty value behind the requested keys.
Here is the call graph for this function:

◆ remove_all_but()

void smash::Configuration::remove_all_but ( const std::string &  key)

Removes all entries in the map except for key.

Parameters
[in]keyThe key of the map entry to keep.

Definition at line 179 of file configuration.cc.

179  {
180  std::vector<std::string> to_remove;
181  for (auto i : root_node_) {
182  if (i.first.Scalar() != key) {
183  to_remove.push_back(i.first.Scalar());
184  }
185  }
186  for (auto i : to_remove) {
187  root_node_.remove(i);
188  }
189 }
YAML::Node root_node_
the general_config.yaml contents - fully parsed
Here is the caller graph for this function:

◆ operator[]()

template<typename T >
Configuration smash::Configuration::operator[] ( T &&  key)
inline

Access to the YAML::Node behind the requested keys.

If you want to read a value use the read function above. Use the subscript operator if you want to assign a new value. The YAML::Node class will automatically convert the data you assign to a string representation suitable for the YAML file.

Parameters
[in]keyThe name of the key to be looked up
Returns
An opaque object that can be assigned to.
See also
take
read

Definition at line 916 of file configuration.h.

916  {
917  return root_node_[std::forward<T>(key)];
918  }
YAML::Node root_node_
the general_config.yaml contents - fully parsed

◆ operator=() [3/3]

template<typename T >
Configuration& smash::Configuration::operator= ( T &&  value)
inline

Assignment overwrites the value of the current YAML node.

Parameters
[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 928 of file configuration.h.

928  {
929  root_node_ = std::forward<T>(value);
930  return *this;
931  }
YAML::Node root_node_
the general_config.yaml contents - fully parsed

◆ has_value_including_empty()

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

Returns if there is a (maybe empty) value behind the requested keys.

Parameters
[in]keysList of keys to be checked for

Definition at line 191 of file configuration.cc.

192  {
193  const auto n = find_node_at(root_node_, keys);
194  return n.IsDefined();
195 }
YAML::Node find_node_at(YAML::Node node, std::initializer_list< const char *> keys)
Finds a node, copies its structure and replaces the previous keys by the newly provided keys...
YAML::Node root_node_
the general_config.yaml contents - fully parsed
constexpr int n
Neutron.
Here is the call graph for this function:

◆ has_value()

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

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

Parameters
[in]keysList of keys to be checked for

Definition at line 197 of file configuration.cc.

197  {
198  const auto n = find_node_at(root_node_, keys);
199  return n.IsDefined() && (!n.IsNull());
200 }
YAML::Node find_node_at(YAML::Node node, std::initializer_list< const char *> keys)
Finds a node, copies its structure and replaces the previous keys by the newly provided keys...
YAML::Node root_node_
the general_config.yaml contents - fully parsed
constexpr int n
Neutron.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ unused_values_report()

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

Returns a string listing the key/value pairs that have not been taken yet.

Definition at line 202 of file configuration.cc.

202  {
203  std::stringstream s;
205  return s.str();
206 }
YAML::Node remove_empty_maps(YAML::Node root)
Removes all empty maps of a YAML::Node.
YAML::Node root_node_
the general_config.yaml contents - fully parsed
Here is the call graph for this function:
Here is the caller graph for this function:

◆ to_string()

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

Returns a YAML string of the current tree.

This differs from the above in that it does not remove empty maps.

Definition at line 208 of file configuration.cc.

208  {
209  std::stringstream s;
210  s << root_node_;
211  return s.str();
212 }
YAML::Node root_node_
the general_config.yaml contents - fully parsed
Here is the caller graph for this function:

Member Data Documentation

◆ root_node_

YAML::Node smash::Configuration::root_node_
private

the general_config.yaml contents - fully parsed

Definition at line 968 of file configuration.h.


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