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