LCOV - code coverage report
Current view: top level - tarch/configuration - ParseConfiguration.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 76.4 % 110 84
Test Date: 2026-08-21 15:14:06 Functions: 100.0 % 20 20

            Line data    Source code
       1              : // Copyright (C) 2015 Technische Universitaet Muenchen
       2              : // This file is part of the Mamico project. For conditions of distribution
       3              : // and use, please see the copyright notice in Mamico's main folder, or at
       4              : // www5.in.tum.de/mamico
       5              : #ifndef _TARCH_CONFIGURATION_PARSECONFIGURATION_H_
       6              : #define _TARCH_CONFIGURATION_PARSECONFIGURATION_H_
       7              : #include "tarch/la/Vector.h"
       8              : #include "tarch/tinyxml2/tinyxml2.h"
       9              : #include <cstdlib>
      10              : #include <filesystem>
      11              : #include <iostream>
      12              : #include <sstream>
      13              : 
      14              : namespace tarch {
      15              : namespace configuration {
      16              : 
      17              : /**     interface for configuration using tinyxml2
      18              :  *  @author Philipp Neumann
      19              :  */
      20              : class ParseConfiguration {
      21              : public:
      22              :   /**
      23              :    * Container for the XML configuration for MaMiCo
      24              :    * (Manages the memory of the associated XML document and provides a pointer to the configuration root)
      25              :    */
      26              :   class XMLConfiguration {
      27              :   private:
      28           20 :     XMLConfiguration(tinyxml2::XMLNode* _root, tinyxml2::XMLError _error) : root(_root), error(_error) {}
      29              : 
      30              :   public:
      31              :     /**
      32              :      * Root of the loaded MaMiCo configuration
      33              :      */
      34              :     tinyxml2::XMLNode* const root;
      35              : 
      36              :     /**
      37              :      * Status of loading the XML document
      38              :      */
      39              :     tinyxml2::XMLError const error;
      40              : 
      41              :     /**
      42              :      * Loads the MaMiCo configuration from a file (with or without XML root node)
      43              :      * @param filename
      44              :      */
      45           20 :     static XMLConfiguration load(const std::string filename) {
      46           20 :       tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
      47           20 :       tinyxml2::XMLError error = doc->LoadFile(filename.c_str());
      48           20 :       tinyxml2::XMLNode* root = doc->FirstChildElement("scenario-configuration");
      49           20 :       if (root == NULL) {
      50           16 :         root = doc;
      51           16 :         std::cout << "No root node <scenario-configuration> found in configuration file. (Using legacy format without XML root node.)" << std::endl;
      52              :       }
      53           20 :       return XMLConfiguration(root, error);
      54              :     }
      55              : 
      56           20 :     ~XMLConfiguration() { delete root->GetDocument(); }
      57              :   };
      58              : 
      59              :   /** parses an xml configuration file, and stores the information in the object
      60              :    *config
      61              :    *    @tparam Configuration
      62              :    */
      63            8 :   template <class Configuration> static void parseConfiguration(const std::string filename, const std::string topleveltag, Configuration& config) {
      64            8 :     XMLConfiguration xmlConfig = XMLConfiguration::load(filename);
      65            8 :     tinyxml2::XMLElement* node = xmlConfig.root->FirstChildElement(topleveltag.c_str());
      66            8 :     if (node == NULL) {
      67            0 :       std::cout << "Could not read input file " << filename << " (missing or invalid)" << std::endl;
      68            0 :       exit(EXIT_FAILURE);
      69              :     }
      70            8 :     config.parseSubtag(node);
      71            8 :   }
      72              : 
      73              :   /** reads a double value at node "node" with tag "tag" and stores the result
      74              :    *in "storage". the program is exited if the value cannot be read.
      75              :    *    @param storage
      76              :    *    @param node
      77              :    *    @param tag
      78              :    */
      79           56 :   static void readDoubleMandatory(double& storage, tinyxml2::XMLElement* node, std::string tag) {
      80           56 :     double value;
      81           56 :     if (node->QueryDoubleAttribute(tag.c_str(), &value) != tinyxml2::XML_SUCCESS) {
      82            0 :       std::cout << "Error while reading mandatory argument " << tag << " of XML element " << node->Name() << std::endl;
      83            0 :       exit(EXIT_FAILURE);
      84              :     } else {
      85           56 :       storage = value;
      86              :     }
      87           56 :   }
      88              : 
      89              :   /** reads a double value at node "node" with tag "tag" and stores the result
      90              :    *in "storage". the program continues and only stores the result in "storage"
      91              :    *if "tag" is existent
      92              :    *    @param storage
      93              :    *    @param node
      94              :    *    @param tag
      95              :    */
      96           12 :   static void readDoubleOptional(double& storage, tinyxml2::XMLElement* node, std::string tag) {
      97           12 :     double value;
      98           12 :     int result = node->QueryDoubleAttribute(tag.c_str(), &value);
      99           12 :     if (result == tinyxml2::XML_NO_ATTRIBUTE) {
     100              :       // nop
     101            8 :     } else if (result == tinyxml2::XML_WRONG_ATTRIBUTE_TYPE) {
     102            0 :       std::cout << "Error while reading optional argument " << tag << " of XML element " << node->Name() << std::endl;
     103            0 :       exit(EXIT_FAILURE);
     104              :     } else {
     105            8 :       storage = value;
     106              :     }
     107           12 :   }
     108              : 
     109              :   /** reads a int value at node "node" with tag "tag" and stores the result in
     110              :    *"storage". the program is exited if the value cannot be read.
     111              :    *    @param storage
     112              :    *    @param node
     113              :    *    @param tag
     114              :    */
     115           76 :   static void readIntMandatory(int& storage, tinyxml2::XMLElement* node, std::string tag) {
     116           76 :     int value;
     117           76 :     if (node->QueryIntAttribute(tag.c_str(), &value) != tinyxml2::XML_SUCCESS) {
     118            0 :       std::cout << "Error while reading mandatory argument " << tag << " of XML element " << node->Name() << std::endl;
     119            0 :       exit(EXIT_FAILURE);
     120              :     } else {
     121           76 :       storage = value;
     122              :     }
     123           76 :   }
     124              : 
     125              :   /** reads a int value at node "node" with tag "tag" and stores the result in
     126              :    *"storage". the program continues and only stores the result in "storage" if
     127              :    *"tag" is existent
     128              :    *    @param storage
     129              :    *    @param node
     130              :    *    @param tag
     131              :    */
     132            4 :   static void readIntOptional(int& storage, tinyxml2::XMLElement* node, std::string tag) {
     133            4 :     int value;
     134            4 :     int result = node->QueryIntAttribute(tag.c_str(), &value);
     135            4 :     if (result == tinyxml2::XML_NO_ATTRIBUTE) {
     136              :       // nop
     137            4 :     } else if (result == tinyxml2::XML_WRONG_ATTRIBUTE_TYPE) {
     138            0 :       std::cout << "Error while reading optional argument " << tag << " of XML element " << node->Name() << std::endl;
     139            0 :       exit(EXIT_FAILURE);
     140              :     } else {
     141            4 :       storage = value;
     142              :     }
     143            4 :   }
     144              : 
     145              :   /** reads a bool value at node "node" with tag "tag" and stores the result in
     146              :    *"storage". the program is exited if the value cannot be read.
     147              :    *    @param storage
     148              :    *    @param node
     149              :    *    @param tag
     150              :    */
     151           68 :   static void readBoolMandatory(bool& storage, tinyxml2::XMLElement* node, std::string tag) {
     152           68 :     const char* myTextChar = node->Attribute(tag.c_str());
     153           68 :     if (myTextChar == NULL) {
     154            0 :       std::cout << "Error: mandatory bool " << tag << " could not be found!" << std::endl;
     155            0 :       exit(EXIT_FAILURE);
     156              :     }
     157           68 :     std::string myText(myTextChar);
     158           68 :     if (myText == "yes") {
     159           48 :       storage = true;
     160           20 :     } else if (myText == "no") {
     161           20 :       storage = false;
     162              :     } else {
     163            0 :       std::cout << "Error while reading bool optional argument: Argument can "
     164            0 :                    "only be yes or no!"
     165            0 :                 << std::endl;
     166            0 :       exit(EXIT_FAILURE);
     167              :     }
     168           68 :   }
     169              : 
     170              :   /** reads a bool value at node "node" with tag "tag" and stores the result in
     171              :    *"storage". the program continues and only stores the result in "storage" if
     172              :    *"tag" is existent
     173              :    *    @param storage
     174              :    *    @param node
     175              :    *    @param tag
     176              :    */
     177           36 :   static void readBoolOptional(bool& storage, tinyxml2::XMLElement* node, std::string tag) {
     178           36 :     const char* myTextChar = node->Attribute(tag.c_str());
     179           36 :     if (myTextChar == NULL) {
     180           32 :       return;
     181              :     }
     182            4 :     std::string myText(myTextChar);
     183            4 :     if (myText == "yes") {
     184            0 :       storage = true;
     185            4 :     } else if (myText == "no") {
     186            4 :       storage = false;
     187              :     } else {
     188            0 :       std::cout << "Error while reading bool optional argument: Argument can "
     189            0 :                    "only be yes or no!"
     190            0 :                 << std::endl;
     191            0 :       exit(EXIT_FAILURE);
     192              :     }
     193            4 :   }
     194              : 
     195              :   /** reads a string value at node "node" with tag "tag" and stores the result
     196              :    *in "storage". the program is exited if the value cannot be read.
     197              :    *    @param storage
     198              :    *    @param node
     199              :    *    @param tag
     200              :    */
     201          160 :   static void readStringMandatory(std::string& storage, tinyxml2::XMLElement* node, std::string tag) {
     202          160 :     const char* myText = node->Attribute(tag.c_str());
     203          160 :     if (myText == NULL) {
     204            0 :       std::cout << "Error while reading mandatory argument " << tag << " of XML element " << node->Name() << std::endl;
     205            0 :       exit(EXIT_FAILURE);
     206              :     } else {
     207          160 :       storage = std::string(myText);
     208              :     }
     209          160 :   }
     210              : 
     211              :   /** reads a string value at node "node" with tag "tag" and stores the result
     212              :    *in "storage". the program continues and only stores the result in "storage"
     213              :    *if "tag" is existent
     214              :    *    @param storage
     215              :    *    @param node
     216              :    *    @param tag
     217              :    */
     218            8 :   static void readStringOptional(std::string& storage, tinyxml2::XMLElement* node, std::string tag) {
     219            8 :     const char* myText = node->Attribute(tag.c_str());
     220            8 :     if (myText != NULL) {
     221            0 :       storage = std::string(myText);
     222              :     }
     223            8 :   }
     224              : 
     225              :   /** reads with ";"-separated entry "tag" with "size" entries and returns the
     226              :    *corresponding vector on success
     227              :    *    @tparam T Data type
     228              :    *    @tparam Size size of the entry
     229              :    *    @param result
     230              :    *    @param myText
     231              :    */
     232           48 :   template <unsigned int size, class T> static void readVector(tarch::la::Vector<size, T>& result, const char* myText) {
     233           48 :     std::string input(myText);
     234          188 :     for (unsigned int i = 0; i < size; i++) {
     235              :       // search for first non-whitespace entry in this vector entry
     236          140 :       std::size_t first = input.find_first_not_of(" ");
     237              :       // search for end of this vector component, typically denoted by ";"
     238              :       // -> if this is the last entry, then npos is accepted as well
     239          140 :       std::size_t last = input.find_first_of(";");
     240              :       // for debugging
     241              :       // std::cout << first << ", " << last << std::endl;
     242          140 :       if ((i == size - 1) && (last == std::string::npos)) {
     243          140 :         last = input.size();
     244              :       }
     245              : 
     246          140 :       std::stringstream ss(input.substr(first, last - first));
     247              :       // for debugging
     248              :       // std::cout << ss.str() << std::endl;
     249          140 :       ss >> result[i];
     250          140 :       if (i < size - 1) {
     251           92 :         input = input.substr(last + 1, input.size() - last - 1);
     252              :       }
     253              :     }
     254           48 :   }
     255              : 
     256              :   /** reads with ";"-separated entry "tag" with "size" entries and returns the
     257              :    *corresponding vector on success
     258              :    *    @tparam T Data type
     259              :    *    @tparam Size size of the entry
     260              :    *    @param result
     261              :    *    @param node
     262              :    *    @param tag
     263              :    */
     264           48 :   template <unsigned int size, class T> static void readVectorMandatory(tarch::la::Vector<size, T>& result, tinyxml2::XMLElement* node, std::string tag) {
     265           48 :     const char* myText = node->Attribute(tag.c_str());
     266           48 :     if (myText == NULL) {
     267            0 :       std::cout << "Error while reading mandatory argument " << tag << " of XML element " << node->Name() << std::endl;
     268            0 :       exit(EXIT_FAILURE);
     269              :     }
     270           48 :     readVector<size, T>(result, myText);
     271           48 :   }
     272              : 
     273              :   /** reads with ";"-separated entry "tag" with "size" entries and returns the
     274              :    *corresponding vector on success
     275              :    *if "tag" is existent
     276              :    *    @tparam T Data type
     277              :    *    @tparam Size size of the entry
     278              :    *    @param result
     279              :    *    @param node
     280              :    *    @param tag
     281              :    */
     282              :   template <unsigned int size, class T> static void readVectorOptional(tarch::la::Vector<size, T>& result, tinyxml2::XMLElement* node, std::string tag) {
     283              :     const char* myText = node->Attribute(tag.c_str());
     284              :     if (myText != NULL) {
     285              :       readVector<size, T>(result, myText);
     286              :     }
     287              :   }
     288              : };
     289              : } // namespace configuration
     290              : } // namespace tarch
     291              : #endif
        

Generated by: LCOV version 2.0-1