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