ChimeraTK-ApplicationCore  04.01.00
ConfigReader.cc
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2 // SPDX-License-Identifier: LGPL-3.0-or-later
3 #include "ConfigReader.h"
4 
5 #include "TestFacility.h"
6 #include "VariableGroup.h"
7 #include <libxml++/libxml++.h>
8 
9 #include <filesystem>
10 #include <iostream>
11 
12 namespace ChimeraTK {
13 
14  template<typename Element>
15  static Element prefix(std::string s, Element e) {
16  e.name = s + e.name;
17  return e;
18  }
19 
20  static std::unique_ptr<xmlpp::DomParser> createDomParser(const std::string& fileName);
21  static std::string root(const std::string& flattened_name);
22  static std::string branchWithoutRoot(const std::string& flattened_name);
23  static std::string branch(const std::string& flattened_name);
24  static std::string leaf(const std::string& flattened_name);
25 
26  struct Variable {
27  std::string name;
28  std::string type;
29  std::string value;
30  };
31 
32  struct Array {
33  std::string name;
34  std::string type;
35  std::map<size_t, std::string> values;
36  };
37 
38  using VariableList = std::vector<Variable>;
39  using ArrayList = std::vector<Array>;
40 
41  class ConfigParser {
42  std::string _fileName;
43  std::unique_ptr<xmlpp::DomParser> _parser;
44  std::unique_ptr<VariableList> _variableList;
45  std::unique_ptr<ArrayList> _arrayList;
46 
47  public:
48  explicit ConfigParser(const std::string& fileName) : _fileName(fileName), _parser(createDomParser(fileName)) {}
49 
50  std::unique_ptr<VariableList> getVariableList();
51  std::unique_ptr<ArrayList> getArrayList();
52 
53  private:
54  std::tuple<std::unique_ptr<VariableList>, std::unique_ptr<ArrayList>> parse();
55  xmlpp::Element* getRootNode(xmlpp::DomParser& parser);
56  [[noreturn]] void error(const std::string& message);
57  bool isVariable(const xmlpp::Element* element);
58  bool isArray(const xmlpp::Element* element);
59  bool isModule(const xmlpp::Element* element);
60  static Variable parseVariable(const xmlpp::Element* element);
61  Array parseArray(const xmlpp::Element* element);
62  void parseModule(const xmlpp::Element* element, std::string parent_name);
63 
64  void validateValueNode(const xmlpp::Element* valueElement);
65  std::map<size_t, std::string> gettArrayValues(const xmlpp::Element* element);
66  };
67 
68  class ModuleTree : public VariableGroup {
69  public:
71 
72  ChimeraTK::Module* lookup(const std::string& flattened_module_name);
73  std::list<std::string> getChildList() { return _childrenInOrder; }
74 
75  // Prevent any modification of the ModuleTree by lookup(), which otherwise will do a lazy-create
76  // Will be called on the top-level module tree once the parsing is done
77  void seal();
78 
79  private:
80  void addChildNode(const std::string& name) {
81  if(_children.find(name) == _children.end()) {
82  _children[name] = std::make_unique<ModuleTree>(this, name, "");
83  _childrenInOrder.push_back(name);
84  }
85  }
86 
87  ChimeraTK::ModuleTree* get(const std::string& flattened_name);
88 
89  std::unordered_map<std::string, std::unique_ptr<ModuleTree>> _children;
90 
91  // Helper list to be able to return the child modules in the order they were found in the XML file
92  std::list<std::string> _childrenInOrder;
93 
94  // Whether the ConfigReader will be modified by lookup() or not.
95  bool _sealed{false};
96  };
97 
98  /********************************************************************************************************************/
99 
101  struct FunctorFill {
102  FunctorFill(ConfigReader* theOwner, const std::string& theType, const std::string& theName,
103  const std::string& theValue, bool& isProcessed)
104  : owner(theOwner), type(theType), name(theName), value(theValue), processed(isProcessed) {
105  processed = false;
106  }
107 
108  template<typename PAIR>
109  void operator()(PAIR&) const {
110  // extract the user type from the pair
111  using T = typename PAIR::first_type;
112 
113  // skip this type, if not matching the type string in the config file
114  if(type != boost::fusion::at_key<T>(owner->_typeMap)) {
115  return;
116  }
117 
118  owner->createVar<T>(name, value);
119  processed = true;
120  }
121 
123  const std::string &type, &name, &value;
124  bool& processed; // must be a non-const reference, since we want to return
125  // this to the caller
126  };
127 
128  /********************************************************************************************************************/
129 
132  ArrayFunctorFill(ConfigReader* theOwner, const std::string& theType, const std::string& theName,
133  const std::map<size_t, std::string>& theValues, bool& isProcessed)
134  : owner(theOwner), type(theType), name(theName), values(theValues), processed(isProcessed) {
135  processed = false;
136  }
137 
138  template<typename PAIR>
139  void operator()(PAIR&) const {
140  // extract the user type from the pair
141  using T = typename PAIR::first_type;
142 
143  // skip this type, if not matching the type string in the config file
144  if(type != boost::fusion::at_key<T>(owner->_typeMap)) {
145  return;
146  }
147 
149  processed = true;
150  }
151 
153  const std::string &type, &name;
154  const std::map<size_t, std::string>& values;
155  bool& processed; // must be a non-const reference, since we want to return
156  // this to the caller
157  };
158 
159  /********************************************************************************************************************/
160 
162  FunctorGetTypeForName(const ConfigReader* theOwner, std::string const& theName, std::string& theType)
163  : owner(theOwner), name(theName), type(theType) {}
164 
165  template<typename PAIR>
166  bool operator()(PAIR const& pair) const {
167  // extract the user type from the pair
168  using T = typename PAIR::first_type;
169 
170  size_t numberOfMatches{pair.second.count(name)};
171  assert(numberOfMatches <= 1);
172  bool hasMatch{numberOfMatches == 1};
173 
174  if(hasMatch) {
175  type = boost::fusion::at_key<T>(owner->_typeMap);
176  }
177 
178  return hasMatch;
179  }
180 
182  const std::string& name;
183  std::string& type;
184  };
185 
186  /********************************************************************************************************************/
187 
188  void ConfigReader::checkVariable(std::string const& name, std::string const& typeOfThis) const {
189  std::string typeOfVar;
190 
191  bool varExists = boost::fusion::any(_variableMap.table, FunctorGetTypeForName{this, name, typeOfVar});
192 
193  if(!varExists) {
194  auto msg = "ConfigReader: Cannot find a scalar configuration variable of the name '" + name +
195  "' in the config file '" + _fileName + "'.";
196  std::cerr << msg << std::endl;
197  throw(ChimeraTK::logic_error(msg));
198  }
199 
200  if(typeOfVar != typeOfThis) {
201  auto msg = "ConfigReader: Attempting to read scalar configuration variable '" + name + "' with type '" +
202  typeOfThis + "'. This does not match type '" + typeOfVar + "' defined in the config file.";
203  std::cerr << msg << std::endl;
204  throw(ChimeraTK::logic_error(msg));
205  }
206  }
207 
208  /********************************************************************************************************************/
209 
210  void ConfigReader::checkArray(std::string const& name, std::string const& typeOfThis) const {
211  std::string typeOfVar;
212 
213  bool varExists = boost::fusion::any(_arrayMap.table, FunctorGetTypeForName{this, name, typeOfVar});
214 
215  if(!varExists) {
216  throw(ChimeraTK::logic_error("ConfigReader: Cannot find a array "
217  "configuration variable of the name '" +
218  name + "' in the config file '" + _fileName + "'."));
219  }
220 
221  if(typeOfVar != typeOfThis) {
222  throw(ChimeraTK::logic_error("ConfigReader: Attempting to read array configuration variable '" + name +
223  "' with type '" + typeOfThis + "'. This does not match type '" + typeOfVar +
224  "' defined in the config file."));
225  }
226  }
227 
228  /********************************************************************************************************************/
229 
230  template<typename T>
231  void ConfigReader::createVar(const std::string& name, const std::string& value) {
232  T convertedValue = ChimeraTK::userTypeToUserType<T>(value);
233 
234  auto moduleName = branch(name);
235  auto varName = leaf(name);
236  auto* varOwner = _moduleTree->lookup(moduleName);
237 
238  // place the variable onto the vector
239  std::unordered_map<std::string, ConfigReader::Var<T>>& theMap = boost::fusion::at_key<T>(_variableMap.table);
240  theMap.emplace(std::make_pair(name, ConfigReader::Var<T>(varOwner, varName, convertedValue)));
241  }
242 
243  /********************************************************************************************************************/
244 
245  /********************************************************************************************************************/
246 
247  template<typename T>
248  void ConfigReader::createArray(const std::string& name, const std::map<size_t, std::string>& values) {
249  std::vector<T> Tvalues;
250 
251  size_t expectedIndex = 0;
252  for(const auto& value : values) {
253  // check index (std::map should be ordered by the index)
254  if(value.first != expectedIndex) {
255  parsingError("Array index " + std::to_string(expectedIndex) + " not found, but " + std::to_string(value.first) +
256  " was. "
257  "Sparse arrays are not supported!");
258  }
259  ++expectedIndex;
260 
261  // convert value into user type
262  T convertedValue = ChimeraTK::userTypeToUserType<T>(value.second);
263 
264  // store value in vector
265  Tvalues.push_back(convertedValue);
266  }
267 
268  auto moduleName = branch(name);
269  auto arrayName = leaf(name);
270  auto* arrayOwner = _moduleTree->lookup(moduleName);
271 
272  // place the variable onto the vector
273  std::unordered_map<std::string, ConfigReader::Array<T>>& theMap = boost::fusion::at_key<T>(_arrayMap.table);
274  theMap.emplace(std::make_pair(name, ConfigReader::Array<T>(arrayOwner, arrayName, Tvalues)));
275  }
276 
277  /********************************************************************************************************************/
278 
279  ConfigReader::ConfigReader(ModuleGroup* owner, const std::string& name, const std::string& fileName,
280  const std::unordered_set<std::string>& tags)
281  : ApplicationModule(owner, name, "Configuration read from file '" + fileName + "'", tags), _fileName(fileName),
282  _moduleTree(std::make_unique<ModuleTree>(this, ".", "")) {
284 
285  bool replacingDefaultConfig = false;
286  if(appConfig != nullptr) {
287  // We have an appconfig (either the default one, or the first one after that to be created) and there is another
288  // one we bail out because we do not know what to do. The default one will have disabled itself (which sets the
289  // owner to nullptr)
290  if(appConfig->getOwner() != nullptr) {
291  throw ChimeraTK::logic_error("More than one explicit ConfigReader instances found. Unclear how to continue."
292  " Please update your application.");
293  }
294  std::cout << "Using your own ConfigReader module is deprecated. Please use the Application built-in config reader"
295  << " by naming your configuration file " << appConfig->_fileName << std::endl;
296  replacingDefaultConfig = true;
298  }
299 
300  bool doDisable = false;
301 
302  try {
303  construct(fileName);
304  }
305  catch(ChimeraTK::runtime_error& ex) {
306  if(replacingDefaultConfig) {
307  // Re-throw error, backwards compatible
308  throw ChimeraTK::logic_error(ex.what());
309  }
310 
311  doDisable = true;
312 
313  std::cout << "Could not load configuration " << fileName << ", assuming no configuration wanted." << std::endl;
314  }
315 
316  // Create scalar variables set via TestFacility
317  for(auto& pairPathnameValue : TestFacility::_configScalars) {
318  auto pathname = std::string(pairPathnameValue.first).substr(1); // strip leading slash from RegisterPath
319  auto value = pairPathnameValue.second;
320  doDisable = false;
321  std::visit(
322  [&](auto v) {
323  using UserType = decltype(v);
324  auto moduleName = branch(pathname);
325  auto varName = leaf(pathname);
326  auto* varOwner = _moduleTree->lookup(moduleName);
327  auto& theMap = boost::fusion::at_key<UserType>(_variableMap.table);
328  theMap[pathname] = ConfigReader::Var<UserType>(varOwner, varName, v);
329  },
330  value);
331  }
333 
334  // Create array variables set via TestFacility
335  for(auto& pairPathnameValue : TestFacility::_configArrays) {
336  auto pathname = std::string(pairPathnameValue.first).substr(1);
337  auto& value = pairPathnameValue.second;
338  doDisable = false;
339  std::visit(
340  [&](const auto& v) {
341  using UserType = typename std::remove_reference<decltype(v)>::type::value_type;
342  auto moduleName = branch(pathname);
343  auto arrayName = leaf(pathname);
344  auto* arrayOwner = _moduleTree->lookup(moduleName);
345  auto& theMap = boost::fusion::at_key<UserType>(_arrayMap.table);
346  theMap[pathname] = ConfigReader::Array<UserType>(arrayOwner, arrayName, v);
347  },
348  value);
349  }
350 
351  if(doDisable) {
352  disable();
353  }
354  }
355 
356  /********************************************************************************************************************/
357 
358  void ConfigReader::construct(const std::string& fileName) {
359  auto fillVariableMap = [this](const Variable& var) {
360  bool processed{false};
361  boost::fusion::for_each(_variableMap.table, FunctorFill(this, var.type, var.name, var.value, processed));
362  if(!processed) {
363  parsingError("Incorrect value '" + var.type + "' for attribute 'type' of the 'variable' tag.");
364  }
365  };
366 
367  auto fillArrayMap = [this](const ChimeraTK::Array& arr) {
368  // create accessor and store array value in map using functor
369  bool processed{false};
370  boost::fusion::for_each(_arrayMap.table, ArrayFunctorFill(this, arr.type, arr.name, arr.values, processed));
371  if(!processed) {
372  parsingError("Incorrect value '" + arr.type + "' for attribute 'type' of the 'variable' tag.");
373  }
374  };
375 
376  auto parser = ConfigParser(fileName);
377  auto v = parser.getVariableList();
378  auto a = parser.getArrayList();
379 
380  for(const auto& var : *v) {
381  fillVariableMap(var);
382  }
383  for(const auto& arr : *a) {
384  fillArrayMap(arr);
385  }
386 
387  // Stop all modification of moduleTree after reading in the configuration
388  _moduleTree->seal();
389  }
390 
391  // workaround for std::unique_ptr static assert.
392  ConfigReader::~ConfigReader() = default;
393 
394  /********************************************************************************************************************/
395 
396  void ConfigReader::parsingError(const std::string& message) {
397  throw ChimeraTK::logic_error("ConfigReader: Error parsing the config file '" + _fileName + "': " + message);
398  }
399 
400  /********************************************************************************************************************/
401 
402  std::list<std::string> ConfigReader::getModules(const std::string& path) const {
403  auto* module = _moduleTree->lookup(path);
404  if(!module) {
405  return {};
406  }
407 
408  if(module == this) {
409  return _moduleTree->getChildList();
410  }
411 
412  auto* castedModule = dynamic_cast<ModuleTree*>(module);
413  return castedModule->getChildList();
414  }
415 
416  /********************************************************************************************************************/
417 
420  explicit FunctorSetValues(ConfigReader* theOwner) : owner(theOwner) {}
421 
422  template<typename PAIR>
423  void operator()(PAIR&) const {
424  // get user type and vector
425  using T = typename PAIR::first_type;
426  std::unordered_map<std::string, ConfigReader::Var<T>>& theMap =
427  boost::fusion::at_key<T>(owner->_variableMap.table);
428 
429  // iterate vector and set values
430  for(auto& pair : theMap) {
431  auto& var = pair.second;
432  var.accessor = var.value;
433  var.accessor.write();
434  }
435  }
436 
438  };
439 
440  /********************************************************************************************************************/
441 
444  explicit FunctorSetValuesArray(ConfigReader* theOwner) : owner(theOwner) {}
445 
446  template<typename PAIR>
447  void operator()(PAIR&) const {
448  // get user type and vector
449  using T = typename PAIR::first_type;
450  std::unordered_map<std::string, ConfigReader::Array<T>>& theMap =
451  boost::fusion::at_key<T>(owner->_arrayMap.table);
452 
453  // iterate vector and set values
454  for(auto& pair : theMap) {
455  auto& var = pair.second;
456  var.accessor = var.value;
457  var.accessor.write();
458  }
459  }
460 
462  };
463 
464  /********************************************************************************************************************/
465 
467  boost::fusion::for_each(_variableMap.table, FunctorSetValues(this));
468  boost::fusion::for_each(_arrayMap.table, FunctorSetValuesArray(this));
469  }
470 
471  /********************************************************************************************************************/
472 
473  ChimeraTK::Module* ModuleTree::lookup(const std::string& flattened_module_name) {
474  // Root node, return pointer to the ConfigReader
475  if(flattened_module_name.empty()) {
476  return dynamic_cast<Module*>(_owner);
477  }
478  // else look up the tree
479  return get(flattened_module_name);
480  }
481 
482  /********************************************************************************************************************/
483 
485  _sealed = true;
486  for(auto& [k, v] : _children) {
487  v->seal();
488  }
489  }
490 
491  /********************************************************************************************************************/
492 
493  ChimeraTK::ModuleTree* ModuleTree::get(const std::string& flattened_name) {
494  auto root_name = root(flattened_name);
495  auto remaining_branch_name = branchWithoutRoot(flattened_name);
496 
497  ModuleTree* module{nullptr};
498 
499  auto r = _children.find(root_name);
500  if(r == _children.end() && !_sealed) {
501  addChildNode(root_name);
502  }
503 
504  try {
505  if(!remaining_branch_name.empty()) {
506  module = _children.at(root_name)->get(remaining_branch_name);
507  }
508  else {
509  module = _children.at(root_name).get();
510  }
511  }
512  catch(std::out_of_range&) {
513  assert(_sealed);
514  }
515 
516  return module;
517  }
518 
519  /********************************************************************************************************************/
520 
521  std::unique_ptr<VariableList> ConfigParser::getVariableList() {
522  if(_variableList == nullptr) {
523  std::tie(_variableList, _arrayList) = parse();
524  }
525  return std::move(_variableList);
526  }
527 
528  /********************************************************************************************************************/
529 
530  std::unique_ptr<ArrayList> ConfigParser::getArrayList() {
531  if(_arrayList != nullptr) {
532  std::tie(_variableList, _arrayList) = parse();
533  }
534  return std::move(_arrayList);
535  }
536 
537  /********************************************************************************************************************/
538 
539  std::tuple<std::unique_ptr<VariableList>, std::unique_ptr<ArrayList>> ConfigParser::parse() {
540  auto* const root = getRootNode(*_parser);
541  if(root->get_name() != "configuration") {
542  error("Expected 'configuration' tag instead of: " + root->get_name());
543  }
544 
545  // start with clean lists: parseModule accumulates elements into these.
546  _variableList = std::make_unique<VariableList>();
547  _arrayList = std::make_unique<ArrayList>();
548 
549  const auto* element = dynamic_cast<const xmlpp::Element*>(root);
550  std::string parent_module_name;
551  parseModule(element, parent_module_name);
552 
553  return std::tuple<std::unique_ptr<VariableList>, std::unique_ptr<ArrayList>>{
554  std::move(_variableList), std::move(_arrayList)};
555  }
556 
557  /********************************************************************************************************************/
558 
559  void ConfigParser::parseModule(const xmlpp::Element* element, std::string parent_name) {
560  auto module_name = (element->get_name() == "configuration") // root node gets special treatment
561  ?
562  "" :
563  element->get_attribute("name")->get_value() + "/";
564 
565  parent_name += module_name;
566 
567  for(const auto& child : element->get_children()) {
568  element = dynamic_cast<const xmlpp::Element*>(child);
569  if(!element) {
570  continue; // ignore if not an element (e.g. comment)
571  }
572  if(isVariable(element)) {
573  _variableList->emplace_back(prefix(parent_name, parseVariable(element)));
574  }
575  else if(isArray(element)) {
576  _arrayList->emplace_back(prefix(parent_name, parseArray(element)));
577  }
578  else if(isModule(element)) {
579  parseModule(element, parent_name);
580  }
581  else {
582  error("Unknown tag: " + element->get_name());
583  }
584  }
585  }
586 
587  /********************************************************************************************************************/
588 
589  Variable ConfigParser::parseVariable(const xmlpp::Element* element) {
590  auto name = element->get_attribute("name")->get_value();
591  auto type = element->get_attribute("type")->get_value();
592  auto value = element->get_attribute("value")->get_value();
593  return Variable{name, type, value};
594  }
595 
596  /********************************************************************************************************************/
597 
598  Array ConfigParser::parseArray(const xmlpp::Element* element) {
599  auto name = element->get_attribute("name")->get_value();
600  auto type = element->get_attribute("type")->get_value();
601  std::map<size_t, std::string> values = gettArrayValues(element);
602  return Array{name, type, values};
603  }
604 
605  /********************************************************************************************************************/
606 
607  xmlpp::Element* ConfigParser::getRootNode(xmlpp::DomParser& parser) {
608  auto* root = parser.get_document()->get_root_node();
609  if(root->get_name() != "configuration") {
610  error("Expected 'configuration' tag instead of: " + root->get_name());
611  }
612  return root;
613  }
614 
615  /********************************************************************************************************************/
616 
617  void ConfigParser::error(const std::string& message) {
618  throw ChimeraTK::logic_error("ConfigReader: Error parsing the config file '" + _fileName + "': " + message);
619  }
620 
621  /********************************************************************************************************************/
622 
623  bool ConfigParser::isVariable(const xmlpp::Element* element) {
624  if((element->get_name() == "variable") && element->get_attribute("value")) {
625  // validate variable node
626  if(!element->get_attribute("name")) {
627  error("Missing attribute 'name' for the 'variable' tag.");
628  }
629  else if(!element->get_attribute("type")) {
630  error("Missing attribute 'type' for the 'variable' tag.");
631  }
632  return true;
633  }
634  return false;
635  }
636 
637  /********************************************************************************************************************/
638 
639  bool ConfigParser::isArray(const xmlpp::Element* element) {
640  if((element->get_name() == "variable") && !element->get_attribute("value")) {
641  // validate array node
642  if(!element->get_attribute("name")) {
643  error("Missing attribute 'name' for the 'variable' tag.");
644  }
645  else if(!element->get_attribute("type")) {
646  error("Missing attribute 'type' for the 'variable' tag.");
647  }
648  return true;
649  }
650  return false;
651  }
652 
653  /********************************************************************************************************************/
654 
655  bool ConfigParser::isModule(const xmlpp::Element* element) {
656  if(element->get_name() == "module") {
657  if(!element->get_attribute("name")) {
658  error("Missing attribute 'name' for the 'module' tag.");
659  }
660  return true;
661  }
662  return false;
663  }
664 
665  /********************************************************************************************************************/
666 
667  std::map<size_t, std::string> ConfigParser::gettArrayValues(const xmlpp::Element* element) {
668  bool valueFound = false;
669  std::map<size_t, std::string> values;
670 
671  for(const auto& valueChild : element->get_children()) {
672  const auto* valueElement = dynamic_cast<const xmlpp::Element*>(valueChild);
673  if(!valueElement) {
674  continue; // ignore comments etc.
675  }
676  validateValueNode(valueElement);
677  valueFound = true;
678 
679  auto* index = valueElement->get_attribute("i");
680  auto* value = valueElement->get_attribute("v");
681 
682  // get index as number and store value as a string
683  size_t intIndex;
684  try {
685  intIndex = std::stoi(index->get_value());
686  }
687  catch(std::exception& e) {
688  error("Cannot parse string '" + std::string(index->get_value()) + "' as an index number: " + e.what());
689  }
690  values[intIndex] = value->get_value();
691  }
692  // make sure there is at least one value
693  if(!valueFound) {
694  error("Each variable must have a value, either specified as an attribute or as child tags.");
695  }
696  return values;
697  }
698 
699  /********************************************************************************************************************/
700 
701  void ConfigParser::validateValueNode(const xmlpp::Element* valueElement) {
702  if(valueElement->get_name() != "value") {
703  error("Expected 'value' tag instead of: " + valueElement->get_name());
704  }
705  if(!valueElement->get_attribute("i")) {
706  error("Missing attribute 'index' for the 'value' tag.");
707  }
708  if(!valueElement->get_attribute("v")) {
709  error("Missing attribute 'value' for the 'value' tag.");
710  }
711  }
712 
713  /********************************************************************************************************************/
714 
715  std::unique_ptr<xmlpp::DomParser> createDomParser(const std::string& fileName) {
716  // Check beforehand to avoid weird unsuppressable "I/O Warning" message from libxml2
717 
718  if(!std::filesystem::exists(fileName)) {
719  throw ChimeraTK::runtime_error("ConfigReader: " + fileName + " does not exist");
720  }
721 
722  try {
723  return std::make_unique<xmlpp::DomParser>(fileName);
724  }
725  catch(xmlpp::exception& e) {
726  throw ChimeraTK::logic_error("ConfigReader: Error opening the config file '" + fileName + "': " + e.what());
727  }
728  }
729 
730  /********************************************************************************************************************/
731 
732  std::string root(const std::string& flattened_name) {
733  auto pos = flattened_name.find_first_of('/');
734  pos = (pos == std::string::npos) ? flattened_name.size() : pos;
735  return flattened_name.substr(0, pos);
736  }
737 
738  /********************************************************************************************************************/
739 
740  std::string branchWithoutRoot(const std::string& flattened_name) {
741  auto pos = flattened_name.find_first_of('/');
742  pos = (pos == std::string::npos) ? flattened_name.size() : pos + 1;
743  return flattened_name.substr(pos, flattened_name.size());
744  }
745 
746  /********************************************************************************************************************/
747 
748  std::string branch(const std::string& flattened_name) {
749  auto pos = flattened_name.find_last_of('/');
750  pos = (pos == std::string::npos) ? 0 : pos;
751  return flattened_name.substr(0, pos);
752  }
753 
754  /********************************************************************************************************************/
755 
756  std::string leaf(const std::string& flattened_name) {
757  auto pos = flattened_name.find_last_of('/');
758  return flattened_name.substr(pos + 1, flattened_name.size());
759  }
760 
761  /********************************************************************************************************************/
762 
763 } // namespace ChimeraTK
ChimeraTK::ConfigReader::_moduleTree
std::unique_ptr< ModuleTree > _moduleTree
List to hold VariableNodes corresponding to xml modules.
Definition: ConfigReader.h:150
ChimeraTK::FunctorFill
Functor to fill variableMap.
Definition: ConfigReader.cc:101
ChimeraTK::Application::_defaultConfigReader
ConfigReader * _defaultConfigReader
Definition: Application.h:287
ChimeraTK::FunctorFill::FunctorFill
FunctorFill(ConfigReader *theOwner, const std::string &theType, const std::string &theName, const std::string &theValue, bool &isProcessed)
Definition: ConfigReader.cc:102
ChimeraTK::ConfigReader::parsingError
void parsingError(const std::string &message)
throw a parsing error with more information
Definition: ConfigReader.cc:396
ChimeraTK::ConfigReader
Generic module to read an XML config file and provide the defined values as constant variables.
Definition: ConfigReader.h:113
drawModuleConnections.root
root
Definition: drawModuleConnections.py:66
ChimeraTK::Module::appConfig
static ConfigReader & appConfig()
Obtain the ConfigReader instance of the application.
Definition: Module.cc:251
ChimeraTK::ArrayFunctorFill::values
const std::map< size_t, std::string > & values
Definition: ConfigReader.cc:154
ChimeraTK::Variable
Definition: ConfigReader.cc:26
ChimeraTK::ModuleTree::seal
void seal()
Definition: ConfigReader.cc:484
ConfigReader.h
ChimeraTK::FunctorGetTypeForName::FunctorGetTypeForName
FunctorGetTypeForName(const ConfigReader *theOwner, std::string const &theName, std::string &theType)
Definition: ConfigReader.cc:162
ChimeraTK::Module::getOwner
EntityOwner * getOwner() const
Definition: Module.h:96
ChimeraTK::FunctorGetTypeForName::type
std::string & type
Definition: ConfigReader.cc:183
ChimeraTK::ConfigParser::ConfigParser
ConfigParser(const std::string &fileName)
Definition: ConfigReader.cc:48
ChimeraTK::ModuleTree::getChildList
std::list< std::string > getChildList()
Definition: ConfigReader.cc:73
ChimeraTK::ArrayFunctorFill::processed
bool & processed
Definition: ConfigReader.cc:155
VariableGroup.h
ChimeraTK::ModuleGroup
Definition: ModuleGroup.h:16
ChimeraTK::FunctorSetValuesArray::operator()
void operator()(PAIR &) const
Definition: ConfigReader.cc:447
ChimeraTK::Array::values
std::map< size_t, std::string > values
Definition: ConfigReader.cc:35
ChimeraTK::ConfigParser::getVariableList
std::unique_ptr< VariableList > getVariableList()
Definition: ConfigReader.cc:521
ChimeraTK::ArrayFunctorFill::ArrayFunctorFill
ArrayFunctorFill(ConfigReader *theOwner, const std::string &theType, const std::string &theName, const std::map< size_t, std::string > &theValues, bool &isProcessed)
Definition: ConfigReader.cc:132
pybind11::module
module_ module
Definition: PyModuleGroup.h:12
ChimeraTK::Variable::name
std::string name
Definition: ConfigReader.cc:27
ChimeraTK::ConfigReader::createVar
void createVar(const std::string &name, const std::string &value)
Create an instance of Var<T> and place it on the variableMap.
Definition: ConfigReader.cc:231
ChimeraTK::VariableGroup::VariableGroup
VariableGroup()=default
Default constructor: Allows late initialisation of VariableGroups (e.g.
ChimeraTK::FunctorGetTypeForName::name
const std::string & name
Definition: ConfigReader.cc:182
ChimeraTK::ConfigReader::ConfigReader
ConfigReader(ModuleGroup *owner, const std::string &name, const std::string &fileName, const std::unordered_set< std::string > &tags={})
Definition: ConfigReader.cc:279
ChimeraTK::ConfigReader::checkVariable
void checkVariable(std::string const &name, std::string const &type) const
Check if variable exists in the config and if type of var name in the config file matches the given t...
Definition: ConfigReader.cc:188
ChimeraTK::ConfigReader::createArray
void createArray(const std::string &name, const std::map< size_t, std::string > &values)
Create an instance of Array<T> and place it on the arrayMap.
Definition: ConfigReader.cc:248
ChimeraTK::ModuleTree::lookup
ChimeraTK::Module * lookup(const std::string &flattened_module_name)
Definition: ConfigReader.cc:473
ChimeraTK::ConfigReader::_arrayMap
ChimeraTK::TemplateUserTypeMapNoVoid< MapOfArray > _arrayMap
Type-depending map of vectors of arrays.
Definition: ConfigReader.h:209
ChimeraTK::Application::getInstance
static Application & getInstance()
Obtain instance of the application.
Definition: Application.cc:261
ChimeraTK::FunctorGetTypeForName::operator()
bool operator()(PAIR const &pair) const
Definition: ConfigReader.cc:166
ChimeraTK::ArrayFunctorFill
Functor to fill variableMap for arrays.
Definition: ConfigReader.cc:131
ChimeraTK::FunctorSetValues
Functor to set values to the scalar accessors.
Definition: ConfigReader.cc:419
ChimeraTK::ConfigReader::Var
Class holding the value and the accessor for one configuration variable.
Definition: ConfigReader.h:157
ChimeraTK::ConfigParser::getArrayList
std::unique_ptr< ArrayList > getArrayList()
Definition: ConfigReader.cc:530
ChimeraTK::Variable::type
std::string type
Definition: ConfigReader.cc:28
ChimeraTK::Array::name
std::string name
Definition: ConfigReader.cc:33
ChimeraTK::FunctorSetValues::operator()
void operator()(PAIR &) const
Definition: ConfigReader.cc:423
ChimeraTK::ApplicationModule
Definition: ApplicationModule.h:24
ChimeraTK::FunctorFill::name
const std::string & name
Definition: ConfigReader.cc:123
ChimeraTK::ModuleTree
Definition: ConfigReader.cc:68
ChimeraTK::VariableGroup
Definition: VariableGroup.h:22
ChimeraTK::Variable::value
std::string value
Definition: ConfigReader.cc:29
ChimeraTK::ConfigReader::prepare
void prepare() override
Prepare the execution of the module.
Definition: ConfigReader.cc:466
ChimeraTK::ConfigReader::~ConfigReader
~ConfigReader() override
ChimeraTK::ConfigReader::getModules
std::list< std::string > getModules(const std::string &path={}) const
Returns a list of names of modules which are direct children of path.
Definition: ConfigReader.cc:402
ChimeraTK::ArrayFunctorFill::operator()
void operator()(PAIR &) const
Definition: ConfigReader.cc:139
ChimeraTK::TestFacility::_configScalars
static std::map< ChimeraTK::RegisterPath, ChimeraTK::UserTypeVariantNoVoid > _configScalars
Definition: TestFacility.h:140
ChimeraTK::FunctorSetValues::FunctorSetValues
FunctorSetValues(ConfigReader *theOwner)
Definition: ConfigReader.cc:420
ChimeraTK::ConfigReader::_fileName
std::string _fileName
File name.
Definition: ConfigReader.h:147
ChimeraTK::ConfigParser
Definition: ConfigReader.cc:41
ChimeraTK::Module::_owner
EntityOwner * _owner
Owner of this instance.
Definition: Module.h:139
ChimeraTK::VariableList
std::vector< Variable > VariableList
Definition: ConfigReader.cc:38
ChimeraTK::ConfigReader::_typeMap
ChimeraTK::SingleTypeUserTypeMapNoVoid< const char * > _typeMap
Map assigning string type identifyers to C++ types.
Definition: ConfigReader.h:212
ChimeraTK::ArrayFunctorFill::type
const std::string & type
Definition: ConfigReader.cc:153
ChimeraTK::FunctorFill::type
const std::string & type
Definition: ConfigReader.cc:123
ChimeraTK::FunctorSetValuesArray::FunctorSetValuesArray
FunctorSetValuesArray(ConfigReader *theOwner)
Definition: ConfigReader.cc:444
ChimeraTK::ConfigReader::_variableMap
ChimeraTK::TemplateUserTypeMapNoVoid< MapOfVar > _variableMap
Type-depending map of vectors of variables.
Definition: ConfigReader.h:201
ChimeraTK::FunctorFill::value
const std::string & value
Definition: ConfigReader.cc:123
TestFacility.h
ChimeraTK::FunctorFill::processed
bool & processed
Definition: ConfigReader.cc:124
ChimeraTK::ArrayFunctorFill::name
const std::string & name
Definition: ConfigReader.cc:153
ChimeraTK::Array::type
std::string type
Definition: ConfigReader.cc:34
ChimeraTK::TestFacility::_configArrays
static std::map< ChimeraTK::RegisterPath, ChimeraTK::UserTypeTemplateVariantNoVoid< Vector > > _configArrays
Definition: TestFacility.h:146
ChimeraTK::FunctorGetTypeForName::owner
const ConfigReader * owner
Definition: ConfigReader.cc:181
ChimeraTK::FunctorGetTypeForName
Definition: ConfigReader.cc:161
ChimeraTK::FunctorFill::owner
ConfigReader * owner
Definition: ConfigReader.cc:122
ChimeraTK::ConfigReader::Array
Class holding the values and the accessor for one configuration array.
Definition: ConfigReader.h:169
ChimeraTK::FunctorSetValuesArray::owner
ConfigReader * owner
Definition: ConfigReader.cc:461
ChimeraTK::ConfigReader::construct
void construct(const std::string &fileName)
Helper function to avoid code duplication in constructors.
Definition: ConfigReader.cc:358
ChimeraTK::Array
Definition: ConfigReader.cc:32
ChimeraTK::FunctorSetValuesArray
Functor to set values to the array accessors.
Definition: ConfigReader.cc:443
ChimeraTK
InvalidityTracer application module.
Definition: spec_dataValidityPropagation.dox:2
ChimeraTK::FunctorFill::operator()
void operator()(PAIR &) const
Definition: ConfigReader.cc:109
ChimeraTK::ConfigReader::checkArray
void checkArray(std::string const &name, std::string const &type) const
Check if array exists in the config and if type of array name in the config file matches the given ty...
Definition: ConfigReader.cc:210
ChimeraTK::ArrayList
std::vector< Array > ArrayList
Definition: ConfigReader.cc:39
ChimeraTK::Module::disable
void disable()
Disable the module such that it is not part of the Application.
Definition: Module.cc:257
ChimeraTK::Module
Base class for ApplicationModule and DeviceModule, to have a common interface for these module types.
Definition: Module.h:21
ChimeraTK::ArrayFunctorFill::owner
ConfigReader * owner
Definition: ConfigReader.cc:152
ChimeraTK::FunctorSetValues::owner
ConfigReader * owner
Definition: ConfigReader.cc:437