Version: SMASH-2.0
configuration.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2019
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #include "smash/configuration.h"
11 
12 #include <cstdio>
13 #include <string>
14 #include <vector>
15 
16 #include <yaml-cpp/yaml.h> // NOLINT(build/include_order)
17 #include <boost/filesystem.hpp>
18 #include <boost/filesystem/fstream.hpp>
19 
21 #include "smash/inputfunctions.h"
22 
23 namespace smash {
24 
25 // internal helper functions
26 namespace {
36 YAML::Node find_node_at(YAML::Node node,
37  std::initializer_list<const char *> keys) {
38  assert(keys.size() > 0);
39  for (auto key : keys) {
40  // see comment in take on Node::reset
41  node.reset(node[key]);
42  }
43  return node;
44 }
45 
52 YAML::Node remove_empty_maps(YAML::Node root) {
53  if (root.IsMap()) {
54  std::vector<std::string> to_remove(root.size());
55  for (auto n : root) {
56  remove_empty_maps(n.second);
57  if ((n.second.IsMap() || n.second.IsSequence()) && n.second.size() == 0) {
58  to_remove.emplace_back(n.first.Scalar());
59  }
60  }
61  for (const auto &key : to_remove) {
62  root.remove(key);
63  }
64  }
65  return root;
66 }
67 
75 YAML::Node operator|=(YAML::Node a, const YAML::Node &b) {
76  if (b.IsMap()) {
77  for (auto n0 : b) {
78  a[n0.first.Scalar()] |= n0.second;
79  }
80  } else {
81  a = b;
82  }
83  return a;
84 }
85 
86 } // unnamed namespace
87 
88 // Default constructor
89 Configuration::Configuration(const bf::path &path)
90  : Configuration(path, "config.yaml") {}
91 
92 // Constructor checking for validity of input
93 Configuration::Configuration(const bf::path &path, const bf::path &filename) {
94  const auto file_path = path / filename;
95  if (!bf::exists(file_path)) {
96  throw FileDoesNotExist("The configuration file was expected at '" +
97  file_path.native() +
98  "', but the file does not exist.");
99  }
100  if (has_crlf_line_ending(read_all(bf::ifstream((file_path))))) {
101  throw std::runtime_error(
102  "The configuration file has CR LF line endings. Please use LF "
103  "line endings.");
104  }
105  try {
106  root_node_ = YAML::LoadFile(file_path.native());
107  } catch (YAML::ParserException &e) {
108  if (e.msg == "illegal map value" || e.msg == "end of map not found") {
109  const auto line = std::to_string(e.mark.line + 1);
110  throw ParseError("YAML parse error at\n" + file_path.native() + ':' +
111  line + ": " + e.msg +
112  " (check that the indentation of map keys matches)");
113  }
114  throw;
115  }
116 }
117 
118 void Configuration::merge_yaml(const std::string &yaml) {
119  try {
120  root_node_ |= YAML::Load(yaml);
121  } catch (YAML::ParserException &e) {
122  if (e.msg == "illegal map value" || e.msg == "end of map not found") {
123  const auto line = std::to_string(e.mark.line + 1);
124  throw ParseError("YAML parse error in:\n" + yaml + "\nat line " + line +
125  ": " + e.msg +
126  " (check that the indentation of map keys matches)");
127  }
128  throw;
129  }
130 }
131 
132 std::vector<std::string> Configuration::list_upmost_nodes() {
133  std::vector<std::string> r;
134  for (auto i : root_node_) {
135  r.emplace_back(i.first.Scalar());
136  }
137  return r;
138 }
139 
141  std::initializer_list<const char *> keys) {
142  assert(keys.size() > 0);
143  auto node = root_node_;
144  auto keyIt = begin(keys);
145  std::size_t i = 0;
146  for (; i < keys.size() - 1; ++i, ++keyIt) {
147  // Node::reset does what you might expect Node::operator= to do. But
148  // operator= assigns a value to the node. So
149  // node = node[*keyIt]
150  // leads to modification of the data structure, not simple traversal.
151  node.reset(node[*keyIt]);
152  }
153  const auto r = node[*keyIt];
154  node.remove(*keyIt);
155  return {r, keys.begin()[keys.size() - 1]};
156 }
157 
159  std::initializer_list<const char *> keys) const {
160  return {find_node_at(root_node_, keys), keys.begin()[keys.size() - 1]};
161 }
162 
163 void Configuration::remove_all_but(const std::string &key) {
164  std::vector<std::string> to_remove;
165  for (auto i : root_node_) {
166  if (i.first.Scalar() != key) {
167  to_remove.push_back(i.first.Scalar());
168  }
169  }
170  for (auto i : to_remove) {
171  root_node_.remove(i);
172  }
173 }
174 
176  std::initializer_list<const char *> keys) const {
177  const auto n = find_node_at(root_node_, keys);
178  return n.IsDefined();
179 }
180 
181 bool Configuration::has_value(std::initializer_list<const char *> keys) const {
182  const auto n = find_node_at(root_node_, keys);
183  return n.IsDefined() && (!n.IsNull());
184 }
185 
187  std::stringstream s;
189  return s.str();
190 }
191 
192 std::string Configuration::to_string() const {
193  std::stringstream s;
194  s << root_node_;
195  return s.str();
196 }
197 
198 } // namespace smash
smash
Definition: action.h:24
smash::anonymous_namespace{configuration.cc}::operator|=
YAML::Node operator|=(YAML::Node a, const YAML::Node &b)
Merge two YAML::Nodes.
Definition: configuration.cc:75
smash::Configuration::list_upmost_nodes
std::vector< std::string > list_upmost_nodes()
Lists all YAML::Nodes from the configuration setup.
Definition: configuration.cc:132
smash::Configuration::root_node_
YAML::Node root_node_
the general_config.yaml contents - fully parsed
Definition: configuration.h:1215
smash::Configuration::read
Value read(std::initializer_list< const char * > keys) const
Additional interface for SMASH to read configuration values without removing them.
Definition: configuration.cc:158
smash::Configuration::to_string
std::string to_string() const
Returns a YAML string of the current tree.
Definition: configuration.cc:192
smash::has_crlf_line_ending
bool has_crlf_line_ending(const std::string in)
Check if a line in the string ends with \r\n.
Definition: inputfunctions.h:91
smash::Configuration::unused_values_report
std::string unused_values_report() const
Returns a string listing the key/value pairs that have not been taken yet.
Definition: configuration.cc:186
smash::Configuration::has_value
bool has_value(std::initializer_list< const char * > keys) const
Returns whether there is a non-empty value behind the requested keys.
Definition: configuration.cc:181
smash::Configuration::ParseError
Definition: configuration.h:477
smash::anonymous_namespace{configuration.cc}::remove_empty_maps
YAML::Node remove_empty_maps(YAML::Node root)
Removes all empty maps of a YAML::Node.
Definition: configuration.cc:52
smash::Configuration
Interface to the SMASH configuration files.
Definition: configuration.h:464
forwarddeclarations.h
smash::Configuration::Configuration
Configuration(const bf::path &path)
Reads config.yaml from the specified path.
Definition: configuration.cc:89
smash::Configuration::Value
Return type of Configuration::take that automatically determines the target type.
Definition: configuration.h:496
smash::read_all
std::string read_all(std::istream &&input)
Utility function to read a complete input stream (e.g.
Definition: inputfunctions.h:80
smash::Configuration::merge_yaml
void merge_yaml(const std::string &yaml)
Merge the configuration in yaml into the existing tree.
Definition: configuration.cc:118
configuration.h
smash::Configuration::take
Value take(std::initializer_list< const char * > keys)
The default interface for SMASH to read configuration values.
Definition: configuration.cc:140
smash::Configuration::FileDoesNotExist
Definition: configuration.h:485
smash::Configuration::has_value_including_empty
bool has_value_including_empty(std::initializer_list< const char * > keys) const
Returns if there is a (maybe empty) value behind the requested keys.
Definition: configuration.cc:175
smash::pdg::n
constexpr int n
Neutron.
Definition: pdgcode_constants.h:30
smash::Configuration::remove_all_but
void remove_all_but(const std::string &key)
Removes all entries in the map except for key.
Definition: configuration.cc:163
inputfunctions.h
smash::anonymous_namespace{configuration.cc}::find_node_at
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.
Definition: configuration.cc:36