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>
150{
151 if (have_read_data_)
152 {
153 error("The data of this subtree has already been read.");
154 }
155
156 have_read_data_ = true;
157
158 if (auto v = tree_->get_value_optional<T>())
159 {
160 return *v;
161 }
162 error("Value `" + shortString(tree_->data()) +
163 "' is not convertible to the desired type.");
164}
165
166template <typename T>
167T ConfigTree::getConfigAttribute(std::string const& attr) const
168{
169 if (auto a = getConfigAttributeOptional<T>(attr))
170 {
171 return *a;
172 }
173
174 error("Did not find XML attribute with name '" + attr + "'.");
175}
176
177template <typename T>
178T ConfigTree::getConfigAttribute(std::string const& attr,
179 T const& default_value) const
180{
181 if (auto a = getConfigAttributeOptional<T>(attr))
182 {
183 return *a;
184 }
185
186 return default_value;
187}
188
189template <typename T>
191 std::string const& attr) const
192{
193 checkUniqueAttr(attr);
194 auto& ct = markVisited<T>(attr, Attr::ATTR, true);
195
196 if (auto attrs = tree_->get_child_optional("<xmlattr>"))
197 {
198 if (auto a = attrs->get_child_optional(attr))
199 {
200 ++ct.count; // count only if attribute has been found
201 if (auto v = a->get_value_optional<T>())
202 {
203 return std::make_optional(*v);
204 }
205 error("Value for XML attribute '" + attr + "' `" +
206 shortString(a->data()) +
207 "' not convertible to the desired type.");
208 }
209 }
210
211 return std::nullopt;
212}
213
214template <typename T>
216 Attr const is_attr,
217 bool const peek_only) const
218{
219 auto const type = std::type_index(typeid(T));
220
221 auto p = visited_params_.emplace(std::make_pair(is_attr, key),
222 CountType{peek_only ? 0 : 1, type});
223
224 if (!p.second)
225 { // no insertion happened
226 auto& v = p.first->second;
227 if (v.type == type)
228 {
229 if (!peek_only)
230 {
231 ++v.count;
232 }
233 }
234 else
235 {
236 error("There already was an attempt to obtain key <" + key +
237 "> with type '" + v.type.name() + "' (now: '" + type.name() +
238 "').");
239 }
240 }
241
242 return p.first->second;
243}
244
245} // namespace BaseLib
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:666
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:572
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:648
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.
Definition ConfigTree.h:48
Range(Iterator begin, Iterator end)
bool empty() const
Iterator end() const
Iterator begin() const
std::size_t size() const