/** * \file * \copyright * Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org) * Distributed under a Modified BSD License. * See accompanying file LICENSE.txt or * http://www.opengeosys.org/project/license * */ #include "ConfigTree.h" #include #include namespace BaseLib { //! Wraps a pair of iterators for use as a range in range-based for-loops. template class Range { public: explicit Range(Iterator begin, Iterator end) : _begin(std::move(begin)), _end(std::move(end)) {} Iterator begin() const { return _begin; } Iterator end() const { return _end; } std::size_t size() const { return std::distance(_begin, _end); } bool empty() const { return size() == 0; } private: Iterator _begin; Iterator _end; }; template T ConfigTree:: getConfigParameter(std::string const& param) const { if (auto p = getConfigParameterOptional(param)) { return *p; } error("Key <" + param + "> has not been found"); } template T ConfigTree:: getConfigParameter(std::string const& param, T const& default_value) const { if (auto p = getConfigParameterOptional(param)) { return *p; } return default_value; } template std::optional ConfigTree::getConfigParameterOptional( std::string const& param) const { checkUnique(param); return getConfigParameterOptionalImpl(param, static_cast(nullptr)); } template std::optional ConfigTree::getConfigParameterOptionalImpl( std::string const& param, T* /*unused*/) const { if (auto p = getConfigSubtreeOptional(param)) { return p->getValue(); } return std::nullopt; } template std::optional> ConfigTree::getConfigParameterOptionalImpl( std::string const& param, std::vector* /*unused*/) const { if (auto p = getConfigSubtreeOptional(param)) { std::istringstream sstr{p->getValue()}; std::vector result; T value; while (sstr >> value) { result.push_back(value); } if (!sstr.eof()) // The stream is not read until the end, must be an // error. result contains number of read values. { error("Value for key <" + param + "> `" + shortString(sstr.str()) + "' not convertible to a vector of the desired type." " Could not convert token no. " + std::to_string(result.size() + 1) + "."); return std::nullopt; } return std::make_optional(result); } return std::nullopt; } template Range > ConfigTree:: getConfigParameterList(std::string const& param) const { checkUnique(param); markVisited(param, Attr::TAG, true); auto p = _tree->equal_range(param); return Range >( ValueIterator(p.first, param, *this), ValueIterator(p.second, param, *this)); } template T ConfigTree:: peekConfigParameter(std::string const& param) const { checkKeyname(param); if (auto p = _tree->get_child_optional(param)) { try { return p->get_value(); } catch (boost::property_tree::ptree_bad_data const&) { error("Value for key <" + param + "> `" + shortString(p->data()) + "' not convertible to the desired type."); } } else { error("Key <" + param + "> has not been found"); } } template void ConfigTree:: checkConfigParameter(std::string const& param, T const& value) const { if (getConfigParameter(param) != value) { error("The value of key <" + param + "> is not the expected one."); } } template void ConfigTree:: checkConfigParameter(std::string const& param, Ch const* value) const { if (getConfigParameter(param) != value) { error("The value of key <" + param + "> is not the expected one."); } } template T ConfigTree:: getValue() const { 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()) { return *v; } error("Value `" + shortString(_tree->data()) + "' is not convertible to the desired type."); } template T ConfigTree:: getConfigAttribute(std::string const& attr) const { if (auto a = getConfigAttributeOptional(attr)) { return *a; } error("Did not find XML attribute with name '" + attr + "'."); } template T ConfigTree::getConfigAttribute(std::string const& attr, T const& default_value) const { if (auto a = getConfigAttributeOptional(attr)) { return *a; } return default_value; } template std::optional ConfigTree::getConfigAttributeOptional( std::string const& attr) const { checkUniqueAttr(attr); auto& ct = markVisited(attr, Attr::ATTR, true); if (auto attrs = _tree->get_child_optional("")) { if (auto a = attrs->get_child_optional(attr)) { ++ct.count; // count only if attribute has been found if (auto v = a->get_value_optional()) { return std::make_optional(*v); } error("Value for XML attribute '" + attr + "' `" + shortString(a->data()) + "' not convertible to the desired type."); } } return std::nullopt; } template ConfigTree::CountType& ConfigTree:: markVisited(std::string const& key, Attr const is_attr, bool const peek_only) const { auto const type = std::type_index(typeid(T)); auto p = _visited_params.emplace(std::make_pair(is_attr, key), CountType{peek_only ? 0 : 1, type}); if (!p.second) { // no insertion happened auto& v = p.first->second; if (v.type == type) { if (!peek_only) { ++v.count; } } else { error("There already was an attempt to obtain key <" + key + "> with type '" + v.type.name() + "' (now: '" + type.name() + "')."); } } return p.first->second; } } // namespace BaseLib