OGS
ConfigTree-impl.h
Go to the documentation of this file.
1 
11 #include <sstream>
12 #include <utility>
13 
14 #include "ConfigTree.h"
15 
16 namespace BaseLib
17 {
19 template <typename Iterator>
20 class Range
21 {
22 public:
23  explicit Range(Iterator begin, Iterator end)
24  : begin_(std::move(begin)), end_(std::move(end))
25  {
26  }
27 
28  Iterator begin() const { return begin_; }
29  Iterator end() const { return end_; }
30  std::size_t size() const { return std::distance(begin_, end_); }
31  bool empty() const { return size() == 0; }
32 
33 private:
34  Iterator begin_;
35  Iterator end_;
36 };
37 
38 template <typename T>
39 T ConfigTree::getConfigParameter(std::string const& param) const
40 {
41  if (auto p = getConfigParameterOptional<T>(param))
42  {
43  return *p;
44  }
45 
46  error("Key <" + param + "> has not been found");
47 }
48 
49 template <typename T>
50 T ConfigTree::getConfigParameter(std::string const& param,
51  T const& default_value) const
52 {
53  if (auto p = getConfigParameterOptional<T>(param))
54  {
55  return *p;
56  }
57 
58  return default_value;
59 }
60 
61 template <typename T>
63  std::string const& param) const
64 {
65  checkUnique(param);
66 
67  return getConfigParameterOptionalImpl(param, static_cast<T*>(nullptr));
68 }
69 
70 template <typename T>
72  std::string const& param, T* /*unused*/) const
73 {
74  if (auto p = getConfigSubtreeOptional(param))
75  {
76  return p->getValue<T>();
77  }
78 
79  return std::nullopt;
80 }
81 
82 template <typename T>
83 std::optional<std::vector<T>> ConfigTree::getConfigParameterOptionalImpl(
84  std::string const& param, std::vector<T>* /*unused*/) const
85 {
86  if (auto p = getConfigSubtreeOptional(param))
87  {
88  std::istringstream sstr{p->getValue<std::string>()};
89  std::vector<T> result;
90  T value;
91  while (sstr >> value)
92  {
93  result.push_back(value);
94  }
95  if (!sstr.eof()) // The stream is not read until the end, must be an
96  // error. result contains number of read values.
97  {
98  error("Value for key <" + param + "> `" + shortString(sstr.str()) +
99  "' not convertible to a vector of the desired type."
100  " Could not convert token no. " +
101  std::to_string(result.size() + 1) + ".");
102  return std::nullopt;
103  }
104 
105  return std::make_optional(result);
106  }
107 
108  return std::nullopt;
109 }
110 
111 template <typename T>
113  std::string const& param) const
114 {
115  checkUnique(param);
116  markVisited<T>(param, Attr::TAG, true);
117 
118  auto p = tree_->equal_range(param);
119  return Range<ValueIterator<T>>(ValueIterator<T>(p.first, param, *this),
120  ValueIterator<T>(p.second, param, *this));
121 }
122 
123 template <typename T>
124 T ConfigTree::peekConfigParameter(std::string const& param) const
125 {
126  checkKeyname(param);
127 
128  if (auto p = tree_->get_child_optional(param))
129  {
130  try
131  {
132  return p->get_value<T>();
133  }
134  catch (boost::property_tree::ptree_bad_data const&)
135  {
136  error("Value for key <" + param + "> `" + shortString(p->data()) +
137  "' not convertible to the desired type.");
138  }
139  }
140  else
141  {
142  error("Key <" + param + "> has not been found");
143  }
144 }
145 
146 template <typename T>
147 void ConfigTree::checkConfigParameter(std::string const& param,
148  T const& value) const
149 {
150  if (getConfigParameter<T>(param) != value)
151  {
152  error("The value of key <" + param + "> is not the expected one.");
153  }
154 }
155 
156 template <typename Ch>
157 void ConfigTree::checkConfigParameter(std::string const& param,
158  Ch const* value) const
159 {
160  if (getConfigParameter<std::string>(param) != value)
161  {
162  error("The value of key <" + param + "> is not the expected one.");
163  }
164 }
165 
166 template <typename T>
168 {
169  if (have_read_data_)
170  {
171  error("The data of this subtree has already been read.");
172  }
173 
174  have_read_data_ = true;
175 
176  if (auto v = tree_->get_value_optional<T>())
177  {
178  return *v;
179  }
180  error("Value `" + shortString(tree_->data()) +
181  "' is not convertible to the desired type.");
182 }
183 
184 template <typename T>
185 T ConfigTree::getConfigAttribute(std::string const& attr) const
186 {
187  if (auto a = getConfigAttributeOptional<T>(attr))
188  {
189  return *a;
190  }
191 
192  error("Did not find XML attribute with name '" + attr + "'.");
193 }
194 
195 template <typename T>
196 T ConfigTree::getConfigAttribute(std::string const& attr,
197  T const& default_value) const
198 {
199  if (auto a = getConfigAttributeOptional<T>(attr))
200  {
201  return *a;
202  }
203 
204  return default_value;
205 }
206 
207 template <typename T>
209  std::string const& attr) const
210 {
211  checkUniqueAttr(attr);
212  auto& ct = markVisited<T>(attr, Attr::ATTR, true);
213 
214  if (auto attrs = tree_->get_child_optional("<xmlattr>"))
215  {
216  if (auto a = attrs->get_child_optional(attr))
217  {
218  ++ct.count; // count only if attribute has been found
219  if (auto v = a->get_value_optional<T>())
220  {
221  return std::make_optional(*v);
222  }
223  error("Value for XML attribute '" + attr + "' `" +
224  shortString(a->data()) +
225  "' not convertible to the desired type.");
226  }
227  }
228 
229  return std::nullopt;
230 }
231 
232 template <typename T>
234  Attr const is_attr,
235  bool const peek_only) const
236 {
237  auto const type = std::type_index(typeid(T));
238 
239  auto p = visited_params_.emplace(std::make_pair(is_attr, key),
240  CountType{peek_only ? 0 : 1, type});
241 
242  if (!p.second)
243  { // no insertion happened
244  auto& v = p.first->second;
245  if (v.type == type)
246  {
247  if (!peek_only)
248  {
249  ++v.count;
250  }
251  }
252  else
253  {
254  error("There already was an attempt to obtain key <" + key +
255  "> with type '" + v.type.name() + "' (now: '" + type.name() +
256  "').");
257  }
258  }
259 
260  return p.first->second;
261 }
262 
263 } // namespace BaseLib
T peekConfigParameter(std::string const &param) const
void checkConfigParameter(std::string const &param, T const &value) const
void checkUniqueAttr(std::string const &attr) const
Asserts that the attribute attr has not been read yet.
Definition: ConfigTree.cpp:319
std::map< KeyType, CountType > visited_params_
Definition: ConfigTree.h:659
static std::string shortString(std::string const &s)
returns a short string at suitable for error/warning messages
Definition: ConfigTree.cpp:257
void error(std::string const &message) const
Definition: ConfigTree.cpp:212
std::optional< ConfigTree > getConfigSubtreeOptional(std::string const &root) const
Definition: ConfigTree.cpp:155
std::optional< T > getConfigParameterOptional(std::string const &param) const
void checkUnique(std::string const &key) const
Asserts that the key has not been read yet.
Definition: ConfigTree.cpp:309
T getConfigParameter(std::string const &param) const
T getConfigAttribute(std::string const &attr) const
Attr
Used to indicate if dealing with XML tags or XML attributes.
Definition: ConfigTree.h:570
CountType & markVisited(std::string const &key, Attr const is_attr, bool peek_only) const
boost::property_tree::ptree const * tree_
The wrapped tree.
Definition: ConfigTree.h:641
std::optional< T > getConfigParameterOptionalImpl(std::string const &param, T *) const
Default implementation of reading a value of type T.
Range< ValueIterator< T > > getConfigParameterList(std::string const &param) const
std::optional< T > getConfigAttributeOptional(std::string const &attr) const
void checkKeyname(std::string const &key) const
Checks if key complies with the rules [a-z0-9_].
Definition: ConfigTree.cpp:269
Wraps a pair of iterators for use as a range in range-based for-loops.
Range(Iterator begin, Iterator end)
bool empty() const
Iterator end() const
Iterator begin() const
std::size_t size() const