LCOV - code coverage report
Current view: top level - tarch/configuration - ParseConfiguration.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 71 91 78.0 %
Date: 2025-06-25 11:26:37 Functions: 18 18 100.0 %

          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          28 :   static void readDoubleMandatory(double& storage, tinyxml2::XMLElement* node, std::string tag) {
      80          28 :     double value;
      81          28 :     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          28 :       storage = value;
      86             :     }
      87          28 :   }
      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           8 :   static void readDoubleOptional(double& storage, tinyxml2::XMLElement* node, std::string tag) {
      97           8 :     double value;
      98           8 :     int result = node->QueryDoubleAttribute(tag.c_str(), &value);
      99           8 :     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           8 :   }
     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          52 :   static void readIntMandatory(int& storage, tinyxml2::XMLElement* node, std::string tag) {
     116          52 :     int value;
     117          52 :     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          52 :       storage = value;
     122             :     }
     123          52 :   }
     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             :   static void readBoolOptional(bool& storage, tinyxml2::XMLElement* node, std::string tag) {
     178             :     const char* myTextChar = node->Attribute(tag.c_str());
     179             :     if (myTextChar == NULL) {
     180             :       return;
     181             :     }
     182             :     std::string myText(myTextChar);
     183             :     if (myText == "yes") {
     184             :       storage = true;
     185             :     } else if (myText == "no") {
     186             :       storage = false;
     187             :     } else {
     188             :       std::cout << "Error while reading bool optional argument: Argument can "
     189             :                    "only be yes or no!"
     190             :                 << std::endl;
     191             :       exit(EXIT_FAILURE);
     192             :     }
     193             :   }
     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          44 :   static void readStringMandatory(std::string& storage, tinyxml2::XMLElement* node, std::string tag) {
     202          44 :     const char* myText = node->Attribute(tag.c_str());
     203          44 :     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          44 :       storage = std::string(myText);
     208             :     }
     209          44 :   }
     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             :   static void readStringOptional(std::string& storage, tinyxml2::XMLElement* node, std::string tag) {
     219             :     const char* myText = node->Attribute(tag.c_str());
     220             :     if (myText != NULL) {
     221             :       storage = std::string(myText);
     222             :     }
     223             :   }
     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          48 :         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          24 :   template <unsigned int size, class T> static void readVectorMandatory(tarch::la::Vector<size, T>& result, tinyxml2::XMLElement* node, std::string tag) {
     265          24 :     const char* myText = node->Attribute(tag.c_str());
     266          24 :     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          24 :     readVector<size, T>(result, myText);
     271          24 :   }
     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 1.14