OGS
ConfigTree-impl.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4// IWYU pragma: private, include "ConfigTree.h"
5
6#include <exception>
7#include <sstream>
8#include <utility>
9#include <vector>
10
11#include "ConfigTree.h"
12#include "DemangleTypeInfo.h"
13#include "StringTools.h"
14
15namespace BaseLib
16{
18template <typename Iterator>
19class Range
20{
21public:
22 explicit Range(Iterator begin, Iterator end)
23 : begin_(std::move(begin)), end_(std::move(end))
24 {
25 }
26
27 Iterator begin() const { return begin_; }
28 Iterator end() const { return end_; }
29 std::size_t size() const { return std::distance(begin_, end_); }
30 bool empty() const { return size() == 0; }
31
32private:
33 Iterator begin_;
34 Iterator end_;
35};
36
58{
59public:
60 Child(Child&& other) noexcept
61 : ct_(std::move(other.ct_)), accessed_(other.accessed_)
62 {
63 }
64 Child(Child const&) = delete;
65
66 ConfigTree const* operator->() const
67 {
68 accessed_ = true;
69 return &ct_;
70 }
71 ConfigTree const& operator*() const
72 {
73 accessed_ = true;
74 return ct_;
75 }
76
88 {
89 // ct_.tree_ == nullptr means this Child was moved from (the moved-to
90 // Child owns the subtree now); std::uncaught_exceptions() > 0 mirrors
91 // ConfigTree's own destructor, which stays silent during unwinding.
92 if (!accessed_ && ct_.tree_ != nullptr &&
93 std::uncaught_exceptions() == 0)
94 {
95 ct_.warning(
96 "This child, returned by getAllChildren(), has not been "
97 "read.");
98 ct_.tree_ = nullptr; // skip the subtree's own redundant check
99 }
100 }
101
102private:
103 friend class ConfigTree;
104 explicit Child(ConfigTree&& ct) : ct_(std::move(ct)) {}
105
109 mutable bool accessed_ = false;
110};
111
112template <typename T>
113T ConfigTree::getConfigParameter(std::string const& param) const
114{
115 if (auto p = getConfigParameterOptional<T>(param))
116 {
117 return *p;
118 }
119
120 error("Key <" + param + "> has not been found");
121}
122
123template <typename T>
124T ConfigTree::getConfigParameter(std::string const& param,
125 T const& default_value) const
126{
127 if (auto p = getConfigParameterOptional<T>(param))
128 {
129 return *p;
130 }
131
132 return default_value;
133}
134
135template <typename T>
137 std::string const& param) const
138{
139 checkUnique(param);
140
141 return getConfigParameterOptionalImpl(param, static_cast<T*>(nullptr));
142}
143
144template <typename T>
146 std::string const& param, T* /*unused*/) const
147{
148 if (auto p = getConfigSubtreeOptional(param))
149 {
150 return p->getValue<T>();
151 }
152
153 return std::nullopt;
154}
155
156template <typename T>
157std::optional<std::vector<T>> ConfigTree::getConfigParameterOptionalImpl(
158 std::string const& param, std::vector<T>* /*unused*/) const
159{
160 if (auto p = getConfigSubtreeOptional(param))
161 {
162 std::string const raw = p->getValue<std::string>();
163
164 std::size_t bad_idx = 0;
165 if (auto parsed = BaseLib::tryParseVector<T>(raw, &bad_idx))
166 {
167 return parsed; // OK
168 }
169
170 // preserve original error wording & token index
171 error("Value for key <" + param + "> `" + shortString(raw) +
172 "' not convertible to a vector of the desired type."
173 " Could not convert token no. " +
174 std::to_string(bad_idx) + ".");
175 return std::nullopt; // not reached
176 }
177
178 return std::nullopt;
179}
180
181template <typename T>
183 std::string const& param) const
184{
185 checkUnique(param);
186 markVisited<T>(param, Attr::TAG, true);
187
188 auto p = tree_->equal_range(param);
189 return Range<ValueIterator<T>>(ValueIterator<T>(p.first, param, *this),
190 ValueIterator<T>(p.second, param, *this));
191}
192
193template <typename T>
194T ConfigTree::peekConfigParameter(std::string const& param) const
195{
196 checkKeyname(param);
197
198 if (auto p = tree_->get_child_optional(param))
199 {
200 try
201 {
202 return p->get_value<T>();
203 }
204 catch (boost::property_tree::ptree_bad_data const&)
205 {
206 error("Value for key <" + param + "> `" + shortString(p->data()) +
207 "' not convertible to the desired type.");
208 }
209 }
210 else
211 {
212 error("Key <" + param + "> has not been found");
213 }
214}
215
216template <typename T>
218{
219 if (have_read_data_)
220 {
221 error("The data of this subtree has already been read.");
222 }
223
224 have_read_data_ = true;
225
226 if (auto v = tree_->get_value_optional<T>())
227 {
228 return *v;
229 }
230 error("Value `" + shortString(tree_->data()) +
231 "' is not convertible to the desired type.");
232}
233
234template <typename T>
235T ConfigTree::getConfigAttribute(std::string const& attr) const
236{
237 if (auto a = getConfigAttributeOptional<T>(attr))
238 {
239 return *a;
240 }
241
242 error("Did not find XML attribute with name '" + attr + "'.");
243}
244
245template <typename T>
246T ConfigTree::getConfigAttribute(std::string const& attr,
247 T const& default_value) const
248{
249 if (auto a = getConfigAttributeOptional<T>(attr))
250 {
251 return *a;
252 }
253
254 return default_value;
255}
256
257template <typename T>
259 std::string const& attr) const
260{
261 checkUniqueAttr(attr);
262 auto& ct = markVisited<T>(attr, Attr::ATTR, true);
263
264 if (auto attrs = tree_->get_child_optional("<xmlattr>"))
265 {
266 if (auto a = attrs->get_child_optional(attr))
267 {
268 ++ct.count; // count only if attribute has been found
269 if (auto v = a->get_value_optional<T>())
270 {
271 return std::make_optional(*v);
272 }
273 error("Value for XML attribute '" + attr + "' `" +
274 shortString(a->data()) +
275 "' not convertible to the desired type.");
276 }
277 }
278
279 return std::nullopt;
280}
281
282template <typename T>
284 Attr const is_attr,
285 bool const peek_only) const
286{
287 auto const type = std::type_index(typeid(T));
288
289 auto p = visited_params_.emplace(std::make_pair(is_attr, key),
290 CountType{peek_only ? 0 : 1, type});
291
292 if (!p.second)
293 { // no insertion happened
294 auto& v = p.first->second;
295 if (v.type == type)
296 {
297 if (!peek_only)
298 {
299 ++v.count;
300 }
301 }
302 else
303 {
304 error("There already was an attempt to obtain key <" + key +
305 "> with type '" + BaseLib::demangle(v.type.name()) +
306 "' (now: '" + type.name() + "').");
307 }
308 }
309
310 return p.first->second;
311}
312
313} // namespace BaseLib
Child(Child &&other) noexcept
Child(Child const &)=delete
ConfigTree const * operator->() const
ConfigTree const & operator*() const
T peekConfigParameter(std::string const &param) const
void checkUniqueAttr(std::string const &attr) const
Asserts that the attribute attr has not been read yet.
std::map< KeyType, CountType > visited_params_
Definition ConfigTree.h:677
static std::string shortString(std::string const &s)
returns a short string at suitable for error/warning messages
void error(std::string const &message) const
std::optional< ConfigTree > getConfigSubtreeOptional(std::string const &root) const
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.
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:583
CountType & markVisited(std::string const &key, Attr const is_attr, bool peek_only) const
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
PTree const * tree_
The wrapped tree.
Definition ConfigTree.h:659
void checkKeyname(std::string const &key) const
Checks if key complies with the rules [a-z0-9_].
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
std::string demangle(const char *mangled_name)
std::optional< std::vector< T > > tryParseVector(std::string const &raw, std::size_t *bad_token_idx)
Definition StringTools.h:86