From 8c20fe7ad69f9e3d56f1b0a35b733de621608cc6 Mon Sep 17 00:00:00 2001 From: vargheseg <vargheseg@users.noreply.github.com> Date: Mon, 15 Apr 2019 10:45:59 +0200 Subject: [PATCH] refactor ConfigParser implementation --- Modules/include/ConfigReader.h | 3 +- Modules/src/ConfigReader.cc | 236 +++++++++++++++++++-------------- 2 files changed, 138 insertions(+), 101 deletions(-) diff --git a/Modules/include/ConfigReader.h b/Modules/include/ConfigReader.h index b8478a80..cd566e7c 100644 --- a/Modules/include/ConfigReader.h +++ b/Modules/include/ConfigReader.h @@ -61,7 +61,8 @@ namespace ChimeraTK { /** File name */ std::string _fileName; - + + /** List to hold VariableNodes corresponding to xml modules **/ std::unique_ptr<ModuleList> _moduleList; /** throw a parsing error with more information */ diff --git a/Modules/src/ConfigReader.cc b/Modules/src/ConfigReader.cc index 8de8b8cd..82c00cea 100644 --- a/Modules/src/ConfigReader.cc +++ b/Modules/src/ConfigReader.cc @@ -5,18 +5,14 @@ namespace ChimeraTK { - -static std::unique_ptr<xmlpp::DomParser> createDomParser(const std::string &fileName); - -template <typename List> -void prefix(std::string s, List& varList){ - for(auto &var: varList){ - var.name = s + var.name; - } +template <typename Element> static Element prefix(std::string s, Element e) { + e.name = s + e.name; + return e; } -std::string parent(std::string flattened_name); -std::string leaf(std::string flattened_name); +static std::unique_ptr<xmlpp::DomParser> createDomParser(const std::string &fileName); +static std::string branch(std::string flattened_name); +static std::string leaf(std::string flattened_name); struct Variable { std::string name; @@ -55,8 +51,7 @@ private: bool isModule(const xmlpp::Element *element); Variable parseVariable(const xmlpp::Element *element); Array parseArray(const xmlpp::Element *element); - std::tuple<std::unique_ptr<VariableList>, std::unique_ptr<ArrayList>> - parseModule(const xmlpp::Element *element); + void parseModule(const xmlpp::Element *element, std::string parent_name); void validateValueNode(const xmlpp::Element *valueElement); std::map<size_t, std::string> gettArrayValues(const xmlpp::Element * element); @@ -79,8 +74,9 @@ struct FunctorFill { FunctorFill(ConfigReader *owner, const std::string &type, const std::string &name, const std::string &value, bool &processed) - : _owner(owner), _type(type), _name(name), _value(value), - _processed(processed) {} + : _owner(owner), _type(type), _name(name), _value(value), _processed(processed) { + _processed = false; + } template <typename PAIR> void operator()(PAIR &) const { // extract the user type from the pair @@ -98,9 +94,6 @@ struct FunctorFill { const std::string &_type, &_name, &_value; bool &_processed; // must be a non-const reference, since we want to return // this to the caller - - typedef boost::fusion::pair<std::string, ConfigReader::Var<std::string>> - StringPair; }; /*********************************************************************************************************************/ @@ -111,8 +104,9 @@ struct FunctorFill { const std::string &name, const std::map<size_t, std::string> &values, bool &processed) - : _owner(owner), _type(type), _name(name), _values(values), - _processed(processed) {} + : _owner(owner), _type(type), _name(name), _values(values),_processed(processed) { + _processed = false; + } template <typename PAIR> void operator()(PAIR &) const { // extract the user type from the pair @@ -131,9 +125,6 @@ struct FunctorFill { const std::map<size_t, std::string> &_values; bool &_processed; // must be a non-const reference, since we want to return // this to the caller - - typedef boost::fusion::pair<std::string, ConfigReader::Var<std::string>> - StringPair; }; /*********************************************************************************************************************/ @@ -153,10 +144,12 @@ struct FunctorFill { stream >> convertedValue; } - // place the variable onto the vector - auto moduleName = parent(name); + + auto moduleName = branch(name); auto varName = leaf(name); auto varOwner = _moduleList->lookup(moduleName); + + // place the variable onto the vector std::map<std::string, ConfigReader::Var<T>>& theMap = boost::fusion::at_key<T>(variableMap.table); theMap.emplace(std::make_pair(name, ConfigReader::Var<T>(varOwner, varName, convertedValue))); } @@ -165,10 +158,12 @@ struct FunctorFill { template<> void ConfigReader::createVar<std::string>(const std::string& name, const std::string& value) { - // place the variable onto the vector - auto moduleName = parent(name); + + auto moduleName = branch(name); auto varName = leaf(name); auto varOwner = _moduleList->lookup(moduleName); + + // place the variable onto the vector std::map<std::string, ConfigReader::Var<std::string>>& theMap = boost::fusion::at_key<std::string>(variableMap.table); theMap.emplace(std::make_pair(name, ConfigReader::Var<std::string>(varOwner, varName, value))); } @@ -207,13 +202,14 @@ struct FunctorFill { Tvalues.push_back(convertedValue); } - // place the variable onto the vector - auto module_name = parent(name); - auto array_name = leaf(name); - auto arrayOwner = _moduleList->lookup(module_name); + auto moduleName = branch(name); + auto arrayName = leaf(name); + auto arrayOwner = _moduleList->lookup(moduleName); + + // place the variable onto the vector std::map<std::string, ConfigReader::Array<T>>& theMap = boost::fusion::at_key<T>(arrayMap.table); - theMap.emplace(std::make_pair( name, ConfigReader::Array<T>(arrayOwner, array_name, Tvalues))); + theMap.emplace(std::make_pair( name, ConfigReader::Array<T>(arrayOwner, arrayName, Tvalues))); } /*********************************************************************************************************************/ @@ -236,13 +232,14 @@ struct FunctorFill { Tvalues.push_back(it->second); } - // place the variable onto the vector - auto module_name = parent(name); - auto array_name = leaf(name); - auto arrayOwner = _moduleList->lookup(module_name); + auto moduleName = branch(name); + auto arrayName = leaf(name); + auto arrayOwner = _moduleList->lookup(moduleName); + + // place the variable onto the vector std::map<std::string, ConfigReader::Array<std::string>>& theMap = boost::fusion::at_key<std::string>(arrayMap.table); - theMap.emplace(std::make_pair( name, ConfigReader::Array<std::string>(arrayOwner, array_name, Tvalues))); + theMap.emplace(std::make_pair( name, ConfigReader::Array<std::string>(arrayOwner, arrayName, Tvalues))); } /*********************************************************************************************************************/ @@ -286,6 +283,7 @@ struct FunctorFill { } } + // workaround for std::unique_ptr static assert. ConfigReader::~ConfigReader() = default; /********************************************************************************************************************/ @@ -352,15 +350,16 @@ struct FunctorFill { return get(flattened_module_name); } +/*********************************************************************************************************************/ + ChimeraTK::Module *ModuleList::get(std::string flattened_name) { if (flattened_name == "") { return owner_; } auto e = map_.find(flattened_name); - if (e == map_.end()) { auto module_name = leaf(flattened_name); - auto owner = get(parent(flattened_name)); + auto owner = get(branch(flattened_name)); map_[flattened_name] = ChimeraTK::VariableGroup(owner, module_name, ""); return &map_[flattened_name]; @@ -368,24 +367,17 @@ struct FunctorFill { return &e->second; } - std::string parent(std::string flattened_name) { - auto pos = flattened_name.find_last_of('/'); - pos = (pos == std::string::npos) ? 0 : pos; - return flattened_name.substr(0, pos); - } - - std::string leaf(std::string flattened_name) { - auto pos = flattened_name.find_last_of('/'); - return flattened_name.substr(pos + 1, flattened_name.size()); - } +/*********************************************************************************************************************/ -std::unique_ptr<VariableList> ConfigParser::getVariableList() { + std::unique_ptr<VariableList> ConfigParser::getVariableList() { if (variableList_ == nullptr) { std::tie(variableList_, arrayList_) = parse(); } return std::move(variableList_); } +/*********************************************************************************************************************/ + std::unique_ptr<ArrayList> ConfigParser::getArrayList() { if (arrayList_ != nullptr) { std::tie(variableList_, arrayList_) = parse(); @@ -393,23 +385,35 @@ std::unique_ptr<ArrayList> ConfigParser::getArrayList() { return std::move(arrayList_); } -std::tuple<std::unique_ptr<VariableList>, std::unique_ptr<ArrayList>> ConfigParser::parse(){ - const auto root = getRootNode(*parser_); - if(root->get_name() != "configuration") { - error("Expected 'configuration' tag instead of: " + root->get_name()); - } - const xmlpp::Element *element = dynamic_cast<const xmlpp::Element *>(root); - return parseModule(element); -} +/*********************************************************************************************************************/ std::tuple<std::unique_ptr<VariableList>, std::unique_ptr<ArrayList>> -ConfigParser::parseModule(const xmlpp::Element * element) { - auto module_name = (element->get_name() == "configuration") +ConfigParser::parse() { + const auto root = getRootNode(*parser_); + if (root->get_name() != "configuration") { + error("Expected 'configuration' tag instead of: " + root->get_name()); + } + + //start with clean lists: parseModule accumulates elements into these. + variableList_ = std::make_unique<VariableList>(); + arrayList_ = std::make_unique<ArrayList>(); + + const xmlpp::Element *element = dynamic_cast<const xmlpp::Element *>(root); + std::string parent_module_name = ""; + parseModule(element, parent_module_name); + + return std::tuple<std::unique_ptr<VariableList>, std::unique_ptr<ArrayList>>{std::move(variableList_), std::move(arrayList_)}; +} + +/*********************************************************************************************************************/ + +void ConfigParser::parseModule(const xmlpp::Element * element, std::string parent_name) { + auto module_name = (element->get_name() == + "configuration") // root node gets special treatment ? "" : element->get_attribute("name")->get_value() + "/"; - auto v = std::make_unique<VariableList>(); - auto a = std::make_unique<ArrayList>(); + parent_name+=module_name; for (const auto &child : element->get_children()) { element = dynamic_cast<const xmlpp::Element *>(child); @@ -417,27 +421,40 @@ ConfigParser::parseModule(const xmlpp::Element * element) { continue; // ignore if not an element (e.g. comment) } else if (isVariable(element)) { - v->push_back(parseVariable(element)); + variableList_->emplace_back(prefix(parent_name, parseVariable(element))); } else if (isArray(element)) { - a->push_back(parseArray(element)); + arrayList_->emplace_back(prefix(parent_name, parseArray(element))); } else if (isModule(element)) { - std::unique_ptr<VariableList>tmp_var; - std::unique_ptr<ArrayList>tmp_arr; - std::tie(tmp_var, tmp_arr) = parseModule(element); - v->insert(v->end(), tmp_var->begin(), tmp_var->end()); - a->insert(a->end(), tmp_arr->begin(), tmp_arr->end()); + parseModule(element, parent_name); } else { error("Unknown tag: " + element->get_name()); } } - prefix(module_name, *v); - prefix(module_name, *a); - return std::pair<std::unique_ptr<VariableList>, std::unique_ptr<ArrayList>>{std::move(v), std::move(a)}; } +/*********************************************************************************************************************/ + +Variable ConfigParser::parseVariable(const xmlpp::Element *element) { + auto name = element->get_attribute("name")->get_value(); + auto type = element->get_attribute("type")->get_value(); + auto value = element->get_attribute("value")->get_value(); + return Variable{name, type, value}; +} + +/*********************************************************************************************************************/ + +Array ConfigParser::parseArray(const xmlpp::Element *element) { + auto name = element->get_attribute("name")->get_value(); + auto type = element->get_attribute("type")->get_value(); + std::map<size_t, std::string> values = gettArrayValues(element); + return Array{name, type, values}; +} + +/*********************************************************************************************************************/ + xmlpp::Element* ConfigParser::getRootNode(xmlpp::DomParser& parser){ auto root = parser.get_document()->get_root_node(); if(root->get_name() != "configuration") { @@ -446,63 +463,60 @@ xmlpp::Element* ConfigParser::getRootNode(xmlpp::DomParser& parser){ return root; } +/*********************************************************************************************************************/ + void ConfigParser::error(const std::string &message) { throw ChimeraTK::logic_error("ConfigReader: Error parsing the config file '" + fileName_ + "': " + message); } +/*********************************************************************************************************************/ + bool ConfigParser::isVariable(const xmlpp::Element *element) { if ((element->get_name() == "variable") && element->get_attribute("value")) { + + // validate variable node + if (!element->get_attribute("name")) { + error("Missing attribute 'name' for the 'variable' tag."); + } else if (!element->get_attribute("type")) { + error("Missing attribute 'type' for the 'variable' tag."); + } return true; } else { return false; } } +/*********************************************************************************************************************/ + bool ConfigParser::isArray(const xmlpp::Element *element) { if ((element->get_name() == "variable") && !element->get_attribute("value")) { + + // validate array node + if (!element->get_attribute("name")) { + error("Missing attribute 'name' for the 'variable' tag."); + } else if (!element->get_attribute("type")) { + error("Missing attribute 'type' for the 'variable' tag."); + } return true; } else { return false; } } +/*********************************************************************************************************************/ + bool ConfigParser::isModule(const xmlpp::Element *element) { if (element->get_name() == "module") { + if (!element->get_attribute("name")) { + error("Missing attribute 'name' for the 'module' tag."); + } return true; } else { return false; } } -Variable ConfigParser::parseVariable(const xmlpp::Element *element) { - - // validate variable node - if (!element->get_attribute("name")) { - error("Missing attribute 'name' for the 'variable' tag."); - } else if (!element->get_attribute("type")) { - error("Missing attribute 'type' for the 'variable' tag."); - } - - auto name = element->get_attribute("name")->get_value(); - auto type = element->get_attribute("type")->get_value(); - auto value = element->get_attribute("value")->get_value(); - return Variable{name, type, value}; -} - -Array ConfigParser::parseArray(const xmlpp::Element *element) { - - // validate array node - if (!element->get_attribute("name")) { - error("Missing attribute 'name' for the 'variable' tag."); - } else if (!element->get_attribute("type")) { - error("Missing attribute 'type' for the 'variable' tag."); - } - - auto name = element->get_attribute("name")->get_value(); - auto type = element->get_attribute("type")->get_value(); - std::map<size_t, std::string> values = gettArrayValues(element); - return Array{name, type, values}; -} +/*********************************************************************************************************************/ std::map<size_t, std::string> ConfigParser::gettArrayValues(const xmlpp::Element * element) { bool valueFound = false; @@ -534,6 +548,8 @@ std::map<size_t, std::string> ConfigParser::gettArrayValues(const xmlpp::Element return values; } +/*********************************************************************************************************************/ + void ConfigParser::validateValueNode(const xmlpp::Element* valueElement){ if (valueElement->get_name() != "value") { error("Expected 'value' tag instead of: " + valueElement->get_name()); @@ -546,6 +562,8 @@ void ConfigParser::validateValueNode(const xmlpp::Element* valueElement){ } } +/*********************************************************************************************************************/ + std::unique_ptr<xmlpp::DomParser> createDomParser(const std::string &fileName){ try { return std::make_unique<xmlpp::DomParser>(fileName); @@ -553,4 +571,22 @@ std::unique_ptr<xmlpp::DomParser> createDomParser(const std::string &fileName){ throw ChimeraTK::logic_error( "ConfigReader: Error opening the config file '" + fileName + "': " + e.what()); } } + +/*********************************************************************************************************************/ + +std::string branch(std::string flattened_name) { + auto pos = flattened_name.find_last_of('/'); + pos = (pos == std::string::npos) ? 0 : pos; + return flattened_name.substr(0, pos); +} + + +/*********************************************************************************************************************/ +std::string leaf(std::string flattened_name) { + auto pos = flattened_name.find_last_of('/'); + return flattened_name.substr(pos + 1, flattened_name.size()); +} + +/*********************************************************************************************************************/ + } // namespace ChimeraTK -- GitLab