diff --git a/BaseLib/ConfigTreeNew.cpp b/BaseLib/ConfigTreeNew.cpp index eed2bfb36cbc5a245404b78893d8222a5a817a0c..8373a7facfcd5350ebc456cc4f1bf3b2b389c77c 100644 --- a/BaseLib/ConfigTreeNew.cpp +++ b/BaseLib/ConfigTreeNew.cpp @@ -54,37 +54,21 @@ ConfigTreeNew(ConfigTreeNew && other) ConfigTreeNew::~ConfigTreeNew() { - if (!_tree) return; - - for (auto const& p : *_tree) - { - markVisitedDecrement(p.first); - } - - for (auto const& p : _visited_params) - { - if (p.second.count > 0) { - warning("Key <" + p.first + "> has been read " + std::to_string(p.second.count) - + " time(s) more than it was present in the configuration tree."); - } else if (p.second.count < 0) { - warning("Key <" + p.first + "> has been read " + std::to_string(-p.second.count) - + " time(s) less than it was present in the configuration tree."); - } - } + checkFullyRead(); } ConfigTreeNew& ConfigTreeNew:: operator=(ConfigTreeNew&& other) { - _tree = other._tree; - other._tree = nullptr; - _path = other._path; - _visited_params = std::move(other._visited_params); + checkFullyRead(); - // TODO Caution: That might be a very nontrivial operation (copying a std::function). - _onerror = other._onerror; - _onwarning = other._onwarning; + _tree = other._tree; + other._tree = nullptr; + _path = std::move(other._path); + _visited_params = std::move(other._visited_params); + _onerror = std::move(other._onerror); + _onwarning = std::move(other._onwarning); return *this; } @@ -236,4 +220,26 @@ markVisitedDecrement(std::string const& key) const } } +void +ConfigTreeNew::checkFullyRead() const +{ + if (!_tree) return; + + for (auto const& p : *_tree) + { + markVisitedDecrement(p.first); + } + + for (auto const& p : _visited_params) + { + if (p.second.count > 0) { + warning("Key <" + p.first + "> has been read " + std::to_string(p.second.count) + + " time(s) more than it was present in the configuration tree."); + } else if (p.second.count < 0) { + warning("Key <" + p.first + "> has been read " + std::to_string(-p.second.count) + + " time(s) less than it was present in the configuration tree."); + } + } +} + } diff --git a/BaseLib/ConfigTreeNew.h b/BaseLib/ConfigTreeNew.h index a14748733b21bf773bd6935cd61b5791f4f52bb3..50f55b8ea91e9b0abfbbd9a09cd54a9b96bc931b 100644 --- a/BaseLib/ConfigTreeNew.h +++ b/BaseLib/ConfigTreeNew.h @@ -192,8 +192,6 @@ public: //! used anymore! ConfigTreeNew(ConfigTreeNew && other); - ConfigTreeNew() = delete; - //! copying is not compatible with the semantics of this class ConfigTreeNew& operator=(ConfigTreeNew const&) = delete; @@ -364,6 +362,10 @@ private: //! and the number of times it exists in the ConfigTree void markVisitedDecrement(std::string const& key) const; + //! Helper method that checks if the top level of this tree has + //! been red entirely (and not too often). + void checkFullyRead() const; + //! returns a short string at suitable for error/warning messages static std::string shortString(std::string const& s); @@ -375,6 +377,11 @@ private: //! A map key -> (count, type) keeping track which parameters have been read how often //! and which datatype they have. + //! + //! This member will be written to when reading from the config tree. + //! Therefore it has to be mutable in order to be able to read from + //! constant instances, e.g., those passed as constant references to + //! temporaries. mutable std::map<std::string, CountType> _visited_params; Callback _onerror; diff --git a/Tests/BaseLib/TestConfigTree.cpp b/Tests/BaseLib/TestConfigTree.cpp index 250ac3e15dc5367aa04bfb30e86c720236653711..7b5bb62362e05c8be7ce8cea9c27468ce2b5a2d9 100644 --- a/Tests/BaseLib/TestConfigTree.cpp +++ b/Tests/BaseLib/TestConfigTree.cpp @@ -400,7 +400,7 @@ TEST(BaseLibConfigTree, ConfigTreeStringLiterals) } // String literals are somewhat special for template classes -TEST(BaseLibConfigTree, ConfigTreeMove) +TEST(BaseLibConfigTree, ConfigTreeMoveConstruct) { const char xml[] = "<s>test</s>" @@ -428,3 +428,36 @@ TEST(BaseLibConfigTree, ConfigTreeMove) DO_EXPECT(cbs, false, false); } +// String literals are somewhat special for template classes +TEST(BaseLibConfigTree, ConfigTreeMoveAssign) +{ + const char xml[] = + "<s>test</s>" + "<t>Test</t>"; + + boost::property_tree::ptree ptree; + std::istringstream xml_str(xml); + read_xml(xml_str, ptree); + + Callbacks cbs; + { + BaseLib::ConfigTreeNew conf(ptree, cbs.get_error_cb(), cbs.get_warning_cb()); + + EXPECT_EQ("test", conf.getConfParam<std::string>("s", "XX")); + DO_EXPECT(cbs, false, false); + + BaseLib::ConfigTreeNew conf2(ptree, cbs.get_error_cb(), cbs.get_warning_cb()); + conf2 = std::move(conf); + // Expect warning because config tree has not been traversed + // entirely before. + DO_EXPECT(cbs, false, true); + + EXPECT_EQ("XX", conf2.getConfParam<std::string>("n", "XX")); + DO_EXPECT(cbs, false, false); + + conf2.checkConfParam("t", "Test"); + DO_EXPECT(cbs, false, false); + } // ConfigTree destroyed here + DO_EXPECT(cbs, false, false); +} +