Skip to content
Snippets Groups Projects
Commit d5163998 authored by Christoph Lehmann's avatar Christoph Lehmann
Browse files

[BL] intermediate commit

parent 369ca62a
No related branches found
No related tags found
No related merge requests found
...@@ -35,11 +35,10 @@ T ...@@ -35,11 +35,10 @@ T
ConfigTreeNew:: ConfigTreeNew::
getConfParam(std::string const& param) const getConfParam(std::string const& param) const
{ {
auto p = getConfParamOptional<T>(param); if (auto p = getConfParamOptional<T>(param))
if (p) return *p; return *p;
error("Key <" + param + "> has not been found"); error("Key <" + param + "> has not been found");
return T();
} }
template<typename T> template<typename T>
...@@ -47,8 +46,9 @@ T ...@@ -47,8 +46,9 @@ T
ConfigTreeNew:: ConfigTreeNew::
getConfParam(std::string const& param, T const& default_value) const getConfParam(std::string const& param, T const& default_value) const
{ {
auto p = getConfParamOptional<T>(param); if (auto p = getConfParamOptional<T>(param))
if (p) return *p; return *p;
return default_value; return default_value;
} }
...@@ -58,20 +58,9 @@ ConfigTreeNew:: ...@@ -58,20 +58,9 @@ ConfigTreeNew::
getConfParamOptional(std::string const& param) const getConfParamOptional(std::string const& param) const
{ {
checkUnique(param); checkUnique(param);
auto p = _tree->get_child_optional(param);
bool peek_only = p == boost::none; if (auto p = getConfSubtreeOptional(param))
markVisited<T>(param, peek_only); return p->getValue<T>();
if (p) {
auto v = p->get_value_optional<T>();
if (v) {
return v;
} else {
error("Value for key <" + param + "> `" + shortString(p->data())
+ "' not convertible to the desired type.");
}
}
return boost::none; return boost::none;
} }
...@@ -97,20 +86,16 @@ peekConfParam(std::string const& param) const ...@@ -97,20 +86,16 @@ peekConfParam(std::string const& param) const
{ {
checkKeyname(param); checkKeyname(param);
auto p =_tree->get_child_optional(param); if (auto p =_tree->get_child_optional(param)) {
if (!p) {
error("Key <" + param + "> has not been found");
} else {
try { try {
return p->get_value<T>(); return p->get_value<T>();
} catch (boost::property_tree::ptree_bad_data) { } catch (boost::property_tree::ptree_bad_data) {
error("Value for key <" + param + "> `" + shortString(p->data()) error("Value for key <" + param + "> `" + shortString(p->data())
+ "' not convertible to the desired type."); + "' not convertible to the desired type.");
} }
} else {
error("Key <" + param + "> has not been found");
} }
return T();
} }
template<typename T> template<typename T>
...@@ -133,11 +118,55 @@ checkConfParam(std::string const& param, Ch const* value) const ...@@ -133,11 +118,55 @@ checkConfParam(std::string const& param, Ch const* value) const
} }
} }
template<typename T>
T
ConfigTreeNew::
getValue() const
{
// TODO test this
if (_have_read_data) {
error("The data of this subtree has already been read.");
}
_have_read_data = true;
if (auto v = _tree->get_value_optional<T>()) {
return *v;
} else {
error("Value `" + shortString(_tree->data())
+ "' is not convertible to the desired type.");
}
}
template<typename T>
T
ConfigTreeNew::
getAttribute(std::string const& attr) const
{
checkUniqueAttr(attr);
markVisited(attr, true);
if (auto attrs = _tree->get_child_optional("<xmlattr>")) {
if (auto a = attrs->get_child_optional(attr)) {
if (auto v = a->get_value_optional<T>()) {
return *v;
} else {
error("Value for XML attribute \"" + attr + "\" `"
+ shortString(a->data())
+ "' not convertible to the desired type.");
}
} else {
error("No XML attribute named \"" + attr + "\"");
}
} else {
error("This parameter has no XML attributes");
}
}
template<typename T> template<typename T>
ConfigTreeNew::CountType& ConfigTreeNew::CountType&
ConfigTreeNew:: ConfigTreeNew::
markVisited(std::string const& key, bool peek_only) const markVisited(std::string const& key, bool const peek_only) const
{ {
auto const type = std::type_index(typeid(T)); auto const type = std::type_index(typeid(T));
......
...@@ -43,11 +43,12 @@ ConfigTreeNew(PTree const& tree, ConfigTreeNew const& parent, ...@@ -43,11 +43,12 @@ ConfigTreeNew(PTree const& tree, ConfigTreeNew const& parent,
ConfigTreeNew:: ConfigTreeNew::
ConfigTreeNew(ConfigTreeNew && other) ConfigTreeNew(ConfigTreeNew && other)
: _tree(other._tree) : _tree (other._tree)
, _path(other._path) , _path (std::move(other._path))
, _visited_params(std::move(other._visited_params)) , _visited_params(std::move(other._visited_params))
, _onerror(other._onerror) , _have_read_data (other._have_read_data)
, _onwarning(other._onwarning) , _onerror (std::move(other._onerror))
, _onwarning (std::move(other._onwarning))
{ {
other._tree = nullptr; other._tree = nullptr;
} }
...@@ -67,12 +68,23 @@ operator=(ConfigTreeNew&& other) ...@@ -67,12 +68,23 @@ operator=(ConfigTreeNew&& other)
other._tree = nullptr; other._tree = nullptr;
_path = std::move(other._path); _path = std::move(other._path);
_visited_params = std::move(other._visited_params); _visited_params = std::move(other._visited_params);
_have_read_data = other._have_read_data;
_onerror = std::move(other._onerror); _onerror = std::move(other._onerror);
_onwarning = std::move(other._onwarning); _onwarning = std::move(other._onwarning);
return *this; return *this;
} }
ConfigTreeNew
ConfigTreeNew::
getConfParam(std::string const& root) const
{
auto ct = getConfSubtree(root);
if (hasChildren(ct))
error("Requested parameter <" + root + "> actually is a subtree.");
return ct;
}
ConfigTreeNew ConfigTreeNew
ConfigTreeNew:: ConfigTreeNew::
getConfSubtree(std::string const& root) const getConfSubtree(std::string const& root) const
...@@ -81,7 +93,6 @@ getConfSubtree(std::string const& root) const ...@@ -81,7 +93,6 @@ getConfSubtree(std::string const& root) const
return std::move(*t); return std::move(*t);
} else { } else {
error("Key <" + root + "> has not been found."); error("Key <" + root + "> has not been found.");
return ConfigTreeNew(PTree(), *this, ""); // TODO that will crash
} }
} }
...@@ -90,14 +101,13 @@ ConfigTreeNew:: ...@@ -90,14 +101,13 @@ ConfigTreeNew::
getConfSubtreeOptional(std::string const& root) const getConfSubtreeOptional(std::string const& root) const
{ {
checkUnique(root); checkUnique(root);
auto subtree = _tree->get_child_optional(root);
if (subtree) { if (auto subtree = _tree->get_child_optional(root)) {
markVisited(root); markVisited(root, false);
return ConfigTreeNew(*subtree, *this, root); return ConfigTreeNew(*subtree, *this, root);
} else { } else {
markVisited(root, true); markVisited(root, true);
return boost::optional<ConfigTreeNew>(); return boost::none;
} }
} }
...@@ -138,6 +148,7 @@ void ConfigTreeNew::ignoreConfParamAll(const std::string &param) const ...@@ -138,6 +148,7 @@ void ConfigTreeNew::ignoreConfParamAll(const std::string &param) const
void ConfigTreeNew::error(const std::string& message) const void ConfigTreeNew::error(const std::string& message) const
{ {
_onerror(_path, message); _onerror(_path, message);
std::abort();
} }
void ConfigTreeNew::warning(const std::string& message) const void ConfigTreeNew::warning(const std::string& message) const
...@@ -175,6 +186,12 @@ void ConfigTreeNew::checkKeyname(std::string const& key) const ...@@ -175,6 +186,12 @@ void ConfigTreeNew::checkKeyname(std::string const& key) const
error("Key <" + key + "> starts with an illegal character."); error("Key <" + key + "> starts with an illegal character.");
} else if (key.find_first_not_of(key_chars, 1) != std::string::npos) { } else if (key.find_first_not_of(key_chars, 1) != std::string::npos) {
error("Key <" + key + "> contains illegal characters."); error("Key <" + key + "> contains illegal characters.");
} else if (key.find("__") != std::string::npos) {
// This is illegal because we use parameter names to generate doxygen
// page names. Thereby "__" acts as a separator character. Choosing
// other separators is not possible because of observed limitations
// for valid doxygen page names.
error("Key <" + key + "> contains double underscore.");
} }
} }
...@@ -199,9 +216,18 @@ void ConfigTreeNew::checkUnique(const std::string &key) const ...@@ -199,9 +216,18 @@ void ConfigTreeNew::checkUnique(const std::string &key) const
} }
} }
void ConfigTreeNew::checkUniqueAttr(const std::string &attr) const
{
checkKeyname(attr);
if (_visited_params.find("<xmlattr>." + attr) != _visited_params.end()) {
error("Attribute \"" + attr + "\" has already been processed.");
}
}
ConfigTreeNew::CountType& ConfigTreeNew::CountType&
ConfigTreeNew:: ConfigTreeNew::
markVisited(std::string const& key, bool peek_only) const markVisited(std::string const& key, bool const peek_only) const
{ {
return markVisited<ConfigTreeNew>(key, peek_only); return markVisited<ConfigTreeNew>(key, peek_only);
} }
...@@ -220,18 +246,48 @@ markVisitedDecrement(std::string const& key) const ...@@ -220,18 +246,48 @@ markVisitedDecrement(std::string const& key) const
} }
} }
bool
ConfigTreeNew::hasChildren(ConfigTreeNew const& ct) const
{
auto const& tree = *ct._tree;
if (tree.begin() == tree.end())
return false; // no children
if (tree.front().first == "<xmlattr>"
&& (++tree.begin()) == tree.end())
return false; // only attributes
return true;
}
void void
ConfigTreeNew::checkAndInvalidate() ConfigTreeNew::checkAndInvalidate()
{ {
if (!_tree) return; if (!_tree) return;
for (auto const& p : *_tree) // Note: due to a limitation in boost::property_tree it is not possible
{ // to discriminate between <tag></tag> and <tag/> in the input file.
markVisitedDecrement(p.first); // In both cases data() will be empty.
if ((!_have_read_data) && !_tree->data().empty()) {
warning("The immediate data `" + shortString(_tree->data())
+"' of this tag has not been read.");
}
// iterate over children
for (auto const& p : *_tree) {
DBUG("-- %s <%s> ", _path.c_str(), p.first.c_str());
if (p.first != "<xmlattr>") // attributes are handled below
markVisitedDecrement(p.first);
}
// iterate over attributes
if (auto attrs = _tree->get_child_optional("<xmlattr>")) {
for (auto const& p : *attrs) {
markVisitedDecrement("<xmlattr>." + p.first);
// markVisitedDecrement("<xmlattr>");
}
} }
for (auto const& p : _visited_params) for (auto const& p : _visited_params) {
{
if (p.second.count > 0) { if (p.second.count > 0) {
warning("Key <" + p.first + "> has been read " + std::to_string(p.second.count) warning("Key <" + p.first + "> has been read " + std::to_string(p.second.count)
+ " time(s) more than it was present in the configuration tree."); + " time(s) more than it was present in the configuration tree.");
......
...@@ -62,6 +62,9 @@ template<typename Iterator> class Range; ...@@ -62,6 +62,9 @@ template<typename Iterator> class Range;
* possible to read from this class, which configuration parameters are present in the tree. * possible to read from this class, which configuration parameters are present in the tree.
* This restriction, however, is intended, because it provides the possibility to get all * This restriction, however, is intended, because it provides the possibility to get all
* existing configuration parameters from the source code. * existing configuration parameters from the source code.
*
* \todo add usage description
*
*/ */
class ConfigTreeNew final class ConfigTreeNew final
{ {
...@@ -80,7 +83,7 @@ public: ...@@ -80,7 +83,7 @@ public:
explicit SubtreeIterator(Iterator it, std::string const& root, explicit SubtreeIterator(Iterator it, std::string const& root,
ConfigTreeNew const& parent) ConfigTreeNew const& parent)
: _it(it), _root(root), _parent(parent) : _it(it), _tagname(root), _parent(parent)
{} {}
SubtreeIterator& operator++() { SubtreeIterator& operator++() {
...@@ -94,9 +97,9 @@ public: ...@@ -94,9 +97,9 @@ public:
// tell the _parent instance that a subtree now has been parsed. // tell the _parent instance that a subtree now has been parsed.
if (_has_incremented) { if (_has_incremented) {
_has_incremented = false; _has_incremented = false;
_parent.markVisited(_root); _parent.markVisited(_tagname, false);
} }
return ConfigTreeNew(_it->second, _parent, _root); return ConfigTreeNew(_it->second, _parent, _tagname);
} }
bool operator==(SubtreeIterator const& other) const { bool operator==(SubtreeIterator const& other) const {
...@@ -110,7 +113,7 @@ public: ...@@ -110,7 +113,7 @@ public:
private: private:
bool _has_incremented = true; bool _has_incremented = true;
Iterator _it; Iterator _it;
std::string const _root; std::string const _tagname;
ConfigTreeNew const& _parent; ConfigTreeNew const& _parent;
}; };
...@@ -130,7 +133,7 @@ public: ...@@ -130,7 +133,7 @@ public:
explicit ValueIterator(Iterator it, std::string const& root, explicit ValueIterator(Iterator it, std::string const& root,
ConfigTreeNew const& parent) ConfigTreeNew const& parent)
: _it(it), _root(root), _parent(parent) : _it(it), _tagname(root), _parent(parent)
{} {}
ValueIterator<ValueType>& operator++() { ValueIterator<ValueType>& operator++() {
...@@ -144,21 +147,22 @@ public: ...@@ -144,21 +147,22 @@ public:
// tell the _parent instance that a setting now has been parsed. // tell the _parent instance that a setting now has been parsed.
if (_has_incremented) { if (_has_incremented) {
_has_incremented = false; _has_incremented = false;
_parent.markVisited<ValueType>(_root); _parent.markVisited<ValueType>(_tagname, false);
} }
if (_it->second.begin() != _it->second.end()) { if (_it->second.begin() != _it->second.end()) {
_parent.error("Configuration at key " + _root + " has subitems."); // TODO test
return ValueType(); _parent.error("Configuration at key " + _tagname + " has subitems.");
// TODO what about attributes?
} }
auto v = _it->second.get_value_optional<ValueType>(); // TODO maybe better make complete ConfigTree
if (auto v = _it->second.get_value_optional<ValueType>())
if (v) return *v; return *v;
// TODO: change error method // TODO: change error method
_parent.error("Could not get value out of key " + _root + "."); // TODO test
return ValueType(); _parent.error("Could not get value out of key " + _tagname + ".");
} }
bool operator==(ValueIterator<ValueType> const& other) const { bool operator==(ValueIterator<ValueType> const& other) const {
...@@ -172,7 +176,7 @@ public: ...@@ -172,7 +176,7 @@ public:
private: private:
bool _has_incremented = true; bool _has_incremented = true;
Iterator _it; Iterator _it;
std::string const _root; std::string const _tagname;
ConfigTreeNew const& _parent; ConfigTreeNew const& _parent;
}; };
...@@ -261,6 +265,26 @@ public: ...@@ -261,6 +265,26 @@ public:
template<typename T> Range<ValueIterator<T> > template<typename T> Range<ValueIterator<T> >
getConfParamList(std::string const& param) const; getConfParamList(std::string const& param) const;
//! TODO doc
ConfigTreeNew
getConfParam(std::string const& param) const;
//! TODO doc
boost::optional<ConfigTreeNew>
getConfParamOptional(std::string const& param) const;
//! TODO doc
Range<SubtreeIterator>
getConfParamList(std::string const& param) const;
//! TODO doc
template<typename T> T
getValue() const;
//! TODO doc
template<typename T> T
getAttribute(std::string const& attr) const;
/*! Peek at a parameter \c param of type \c T from the configuration tree. /*! Peek at a parameter \c param of type \c T from the configuration tree.
* *
* This method is an exception to the single-read rule. It is meant to be used to * This method is an exception to the single-read rule. It is meant to be used to
...@@ -347,7 +371,7 @@ private: ...@@ -347,7 +371,7 @@ private:
//! Called if an error occurs. Will call the error callback. //! Called if an error occurs. Will call the error callback.
//! This method only acts as a helper method. //! This method only acts as a helper method.
void error(std::string const& message) const; [[noreturn]] void error(std::string const& message) const;
//! Called for printing warning messages. Will call the warning callback. //! Called for printing warning messages. Will call the warning callback.
//! This method only acts as a helper method. //! This method only acts as a helper method.
...@@ -362,6 +386,9 @@ private: ...@@ -362,6 +386,9 @@ private:
//! Asserts that the \c key has not been read yet. //! Asserts that the \c key has not been read yet.
void checkUnique(std::string const& key) const; void checkUnique(std::string const& key) const;
//! TODO doc
void checkUniqueAttr(std::string const& attr) const;
/*! Keeps track of the key \c key and its value type \c T. /*! Keeps track of the key \c key and its value type \c T.
* *
* This method asserts that a key is read always with the same type. * This method asserts that a key is read always with the same type.
...@@ -377,12 +404,15 @@ private: ...@@ -377,12 +404,15 @@ private:
* *
* \c param peek_only if true, do not change the read-count of the given key. * \c param peek_only if true, do not change the read-count of the given key.
*/ */
CountType& markVisited(std::string const& key, bool peek_only = false) const; CountType& markVisited(std::string const& key, bool const peek_only = false) const;
//! Used in the destructor to compute the difference between number of reads of a parameter //! Used in the destructor to compute the difference between number of reads of a parameter
//! and the number of times it exists in the ConfigTree //! and the number of times it exists in the ConfigTree
void markVisitedDecrement(std::string const& key) const; void markVisitedDecrement(std::string const& key) const;
//! TODO doc
bool hasChildren(ConfigTreeNew const& ct) const;
/*! Checks if the top level of this tree has been read entirely (and not too often). /*! Checks if the top level of this tree has been read entirely (and not too often).
* *
* Caution: This method also invalidates the instance, i.e., afterwards it can not * Caution: This method also invalidates the instance, i.e., afterwards it can not
...@@ -399,6 +429,8 @@ private: ...@@ -399,6 +429,8 @@ private:
//! A path printed in error/warning messages. //! A path printed in error/warning messages.
std::string _path; std::string _path;
//! \todo add file name
//! A map key -> (count, type) keeping track which parameters have been read how often //! A map key -> (count, type) keeping track which parameters have been read how often
//! and which datatype they have. //! and which datatype they have.
//! //!
...@@ -408,6 +440,9 @@ private: ...@@ -408,6 +440,9 @@ private:
//! temporaries. //! temporaries.
mutable std::map<std::string, CountType> _visited_params; mutable std::map<std::string, CountType> _visited_params;
//! \todo doc
mutable bool _have_read_data = false;
Callback _onerror; Callback _onerror;
Callback _onwarning; Callback _onwarning;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment