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