14#include <forward_list> 
   22template class boost::property_tree::basic_ptree<std::string, std::string,
 
   39    : top_level_tree_(std::make_shared<
PTree>(std::move(top_level_tree))),
 
   40      tree_(top_level_tree_.get()),
 
   41      filename_(std::move(filename)),
 
   42      onerror_(std::move(error_cb)),
 
   43      onwarning_(std::move(warning_cb))
 
   47        OGS_FATAL(
"ConfigTree: No valid error handler provided.");
 
   51        OGS_FATAL(
"ConfigTree: No valid warning handler provided.");
 
 
   56                       std::string 
const& root)
 
   57    : top_level_tree_(parent.top_level_tree_),
 
   60      filename_(parent.filename_),
 
   61      onerror_(parent.onerror_),
 
   62      onwarning_(parent.onwarning_)
 
 
   68    : top_level_tree_(std::move(other.top_level_tree_)),
 
   70      path_(std::move(other.path_)),
 
   71      filename_(std::move(other.filename_)),
 
   72      visited_params_(std::move(other.visited_params_)),
 
   73      have_read_data_(other.have_read_data_),
 
   74      onerror_(std::move(other.onerror_)),
 
   75      onwarning_(std::move(other.onwarning_))
 
   77    other.tree_ = 
nullptr;
 
 
   82    if (std::uncaught_exceptions() > 0)
 
   94    catch (std::exception& e)
 
   96        ERR(
"{:s}", e.what());
 
 
  107    other.tree_ = 
nullptr;
 
  108    path_ = std::move(other.path_);
 
  112    onerror_ = std::move(other.onerror_);
 
 
  121    if (ct.hasChildren())
 
  123        error(
"Requested parameter <" + param + 
"> actually is a subtree.");
 
 
  129    std::string 
const& param)
 const 
  132    if (ct && ct->hasChildren())
 
  134        error(
"Requested parameter <" + param + 
"> actually is a subtree.");
 
 
  140    const std::string& param)
 const 
  145    auto p = 
tree_->equal_range(param);
 
 
  152                                      std::string_view 
const value)
 const 
  155    if (parameter_value != value)
 
  157        error(
"For the tag <" + param + 
"> expected to read value '" +
 
  158              value.data() + 
"', but got '" + parameter_value + 
"'.");
 
 
  166        return std::move(*t);
 
  168    error(
"Key <" + root + 
"> has not been found.");
 
 
  172    std::string 
const& root)
 const 
  176    if (
auto subtree = 
tree_->get_child_optional(root))
 
 
  186    std::string 
const& root)
 const 
  191    auto p = 
tree_->equal_range(root);
 
 
  201    bool peek_only = 
tree_->find(param) == 
tree_->not_found();
 
 
  211    bool peek_only = !
tree_->get_child_optional(
"<xmlattr>." + attr);
 
 
  221    auto p = 
tree_->equal_range(param);
 
  222    for (
auto it = p.first; it != p.second; ++it)
 
 
  232        "ConfigTree: The error handler does not break out of the normal " 
 
  242                         const std::string& message)
 
  244    OGS_FATAL(
"ConfigTree: In file `{:s}' at path <{:s}>: {:s}", filename, path,
 
 
  249                           const std::string& message)
 
  251    WARN(
"ConfigTree: In file `{:s}' at path <{:s}>: {:s}", filename, path,
 
 
  262    ERR(
"ConfigTree: There have been errors when parsing the configuration " 
  270    OGS_FATAL(
"There have been errors when parsing the configuration file(s).");
 
 
  275    const std::size_t maxlen = 100;
 
  277    if (s.size() < maxlen)
 
  282    return s.substr(0, maxlen - 3) + 
"...";
 
 
  289        error(
"Search for empty key.");
 
  293        error(
"Key <" + key + 
"> starts with an illegal character.");
 
  295    else if (key.find_first_not_of(
key_chars, 1) != std::string::npos)
 
  297        error(
"Key <" + key + 
"> contains illegal characters.");
 
  299    else if (key.find(
"__") != std::string::npos)
 
  305        error(
"Key <" + key + 
"> contains double underscore.");
 
 
  310                                  const std::string& p2)
 const 
  314        error(
"Second path to be joined is empty.");
 
 
  331        error(
"Key <" + key + 
"> has already been processed.");
 
 
  339    if (attr.find(
':') != std::string::npos)
 
  341        auto pos = 
decltype(std::string::npos){0};
 
  349            pos = attr2.find_first_of(
":ABCDEFGHIJKLMNOPQRSTUVWXYZ", pos);
 
  350            if (pos != std::string::npos)
 
  354        } 
while (pos != std::string::npos);
 
  365        error(
"Attribute '" + attr + 
"' has already been processed.");
 
 
  371                                               bool const peek_only)
 const 
 
  377                                      std::string 
const& key)
 const 
  379    auto const type = std::type_index(
typeid(
nullptr));
 
  386        auto& v = p.first->second;
 
 
  393    auto const& tree = *
tree_;
 
  394    if (tree.begin() == tree.end())
 
  398    if (tree.front().first == 
"<xmlattr>" && (++tree.begin()) == tree.end())
 
 
  419                "' of this tag has not been read.");
 
  423    for (
auto const& p : *
tree_)
 
  425        if (p.first != 
"<xmlattr>")
 
  432    if (
auto attrs = 
tree_->get_child_optional(
"<xmlattr>"))
 
  434        for (
auto const& p : *attrs)
 
  442        auto const& tag = p.first.second;
 
  443        auto const& count = p.second.count;
 
  445        switch (p.first.first)
 
  450                    warning(
"XML attribute '" + tag + 
"' has been read " +
 
  451                            std::to_string(count) +
 
  452                            " time(s) more than it was present in the " 
  453                            "configuration tree.");
 
  457                    warning(
"XML attribute '" + tag + 
"' has been read " +
 
  458                            std::to_string(-count) +
 
  459                            " time(s) less than it was present in the " 
  460                            "configuration tree.");
 
  466                    warning(
"Key <" + tag + 
"> has been read " +
 
  467                            std::to_string(count) +
 
  468                            " time(s) more than it was present in the " 
  469                            "configuration tree.");
 
  473                    warning(
"Key <" + tag + 
"> has been read " +
 
  474                            std::to_string(-count) +
 
  475                            " time(s) less than it was present in the " 
  476                            "configuration tree.");
 
 
  503        conf->checkAndInvalidate();
 
 
static std::forward_list< std::string > configtree_destructor_error_messages
 
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
 
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
 
void markVisitedDecrement(Attr const is_attr, std::string const &key) const
 
void ignoreConfigParameter(std::string const ¶m) const
 
static void onerror(std::string const &filename, std::string const &path, std::string const &message)
 
void checkAndInvalidate()
 
static void assertNoSwallowedErrors()
Asserts that there have not been any errors reported in the destructor.
 
Callback onwarning_
Custom warning callback.
 
static const char pathseparator
Character separating two path components.
 
void checkUniqueAttr(std::string const &attr) const
Asserts that the attribute attr has not been read yet.
 
std::map< KeyType, CountType > visited_params_
 
static std::string shortString(std::string const &s)
returns a short string at suitable for error/warning messages
 
std::shared_ptr< PTree const  > top_level_tree_
 
void error(std::string const &message) const
 
std::optional< ConfigTree > getConfigSubtreeOptional(std::string const &root) const
 
std::optional< T > getConfigParameterOptional(std::string const ¶m) const
 
void ignoreConfigAttribute(std::string const &attr) const
 
void checkUnique(std::string const &key) const
Asserts that the key has not been read yet.
 
T getConfigParameter(std::string const ¶m) const
 
Attr
Used to indicate if dealing with XML tags or XML attributes.
 
Range< SubtreeIterator > getConfigSubtreeList(std::string const &root) const
 
static const std::string key_chars_start
Set of allowed characters as the first letter of a key name.
 
ConfigTree getConfigSubtree(std::string const &root) const
 
std::string path_
A path printed in error/warning messages.
 
CountType & markVisited(std::string const &key, Attr const is_attr, bool peek_only) const
 
void ignoreConfigParameterAll(std::string const ¶m) const
 
Callback onerror_
Custom error callback.
 
std::string joinPaths(std::string const &p1, std::string const &p2) const
Used to generate the path of a subtree.
 
Range< ValueIterator< T > > getConfigParameterList(std::string const ¶m) const
 
void warning(std::string const &message) const
 
bool hasChildren() const
Checks if this tree has any children.
 
PTree const  * tree_
The wrapped tree.
 
ConfigTree(PTree &&top_level_tree, std::string filename, Callback error_cb, Callback warning_cb)
 
void checkConfigParameter(std::string const ¶m, std::string_view const value) const
 
boost::property_tree::ptree PTree
The tree being wrapped by this class.
 
ConfigTree & operator=(ConfigTree const &)=delete
copying is not compatible with the semantics of this class
 
std::string filename_
The path of the file from which this tree has been read.
 
void checkKeyname(std::string const &key) const
Checks if key complies with the rules [a-z0-9_].
 
std::function< void(const std::string &filename, const std::string &path, const std::string &message)> Callback
 
static void onwarning(std::string const &filename, std::string const &path, std::string const &message)
 
static const std::string key_chars
Set of allowed characters in a key name.
 
Wraps a pair of iterators for use as a range in range-based for-loops.
 
void checkAndInvalidate(ConfigTree &conf)
This is an overloaded member function, provided for convenience. It differs from the above function o...
 
std::string joinPaths(std::string const &pathA, std::string const &pathB)