You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

301 lines
10 KiB

  1. #ifndef STORM_SETTINGS_SETTINGS_H_
  2. #define STORM_SETTINGS_SETTINGS_H_
  3. #include <iostream>
  4. #include <sstream>
  5. #include <list>
  6. #include <utility>
  7. #include <functional>
  8. #include <unordered_map>
  9. #include <vector>
  10. #include <memory>
  11. #include "src/settings/Option.h"
  12. #include "src/settings/OptionBuilder.h"
  13. #include "src/settings/ArgumentBase.h"
  14. #include "src/settings/Argument.h"
  15. #include "src/settings/ArgumentBuilder.h"
  16. #include "src/settings/ArgumentType.h"
  17. #include "src/settings/ArgumentTypeInferationHelper.h"
  18. // Exceptions that should be catched when performing a parsing run
  19. #include "src/exceptions/OptionParserException.h"
  20. namespace storm {
  21. /*!
  22. * @brief Contains Settings class and associated methods.
  23. *
  24. * The settings namespace contains the Settings class some friend methods like instance().
  25. */
  26. namespace settings {
  27. class Settings;
  28. typedef std::function<bool (Settings*)> ModuleRegistrationFunction_t;
  29. typedef bool (*stringValidationFunction_t)(const std::string);
  30. typedef bool (*integerValidationFunction_t)(const int_fast64_t);
  31. typedef bool (*unsignedIntegerValidationFunction_t)(const uint_fast64_t);
  32. typedef bool (*doubleValidationFunction_t)(const double);
  33. typedef bool (*booleanValidationFunction_t)(const bool);
  34. typedef std::pair<std::string, std::string> stringPair_t;
  35. typedef std::pair<bool, std::string> fromStringAssignmentResult_t;
  36. class Destroyer;
  37. /*!
  38. * @brief Settings class with command line parser and type validation
  39. *
  40. *
  41. * It is meant to be used as a singleton. Call
  42. * @code storm::settings::Settings::getInstance() @endcode
  43. * to initialize it and obtain an instance.
  44. *
  45. * This class can be customized by other parts of the software using
  46. * option modules. An option module can be anything that implements the
  47. * interface specified by registerModule() and does a static initialization call to this function.
  48. */
  49. class Settings {
  50. public:
  51. static bool registerNewModule(ModuleRegistrationFunction_t registrationFunction);
  52. /*!
  53. * This parses the command line of the application and matches it to all prior registered options
  54. * @throws OptionParserException
  55. */
  56. static void parse(int const argc, char const * const argv[]);
  57. std::vector<std::shared_ptr<Option>> const& getOptions() const {
  58. return this->optionPointers;
  59. }
  60. // PUBLIC INTERFACE OF OPTIONSACCUMULATOR (now internal)
  61. /*!
  62. * Returns true IFF an option with the specified longName exists.
  63. */
  64. bool containsOptionByLongName(std::string const& longName) const {
  65. return this->containsLongName(longName);
  66. }
  67. /*!
  68. * Returns true IFF an option with the specified shortName exists.
  69. */
  70. bool containsOptionByShortName(std::string const& shortName) const {
  71. return this->containsLongName(shortName);
  72. }
  73. /*!
  74. * Returns a reference to the Option with the specified longName.
  75. * Throws an Exception of Type IllegalArgumentException if there is no such Option.
  76. */
  77. Option const& getOptionByLongName(std::string const& longName) const {
  78. return this->getByLongName(longName);
  79. }
  80. /*!
  81. * Returns a reference to the Option with the specified shortName.
  82. * Throws an Exception of Type IllegalArgumentException if there is no such Option.
  83. */
  84. Option const& getOptionByShortName(std::string const& shortName) const {
  85. return this->getByShortName(shortName);
  86. }
  87. /*!
  88. * Adds the given option to the set of known options.
  89. * Unifying with existing options is done automatically.
  90. * Ownership of the Option is handed over when calling this function!
  91. * Returns a reference to the settings instance
  92. * @throws OptionUnificationException
  93. */
  94. Settings& addOption(Option* option);
  95. /*!
  96. * Returns true iff there is an Option with the specified longName and it has been set
  97. * @return bool true if the option exists and has been set
  98. * @throws InvalidArgumentException
  99. */
  100. bool isSet(std::string const& longName) const {
  101. return this->getByLongName(longName).getHasOptionBeenSet();
  102. }
  103. /*!
  104. * Sets the Option with the specified longName
  105. * This function requires the Option to have no arguments
  106. * This is for TESTING only and should not be used outside of the testing code!
  107. * @throws InvalidArgumentException
  108. */
  109. void set(std::string const& longName) const {
  110. return this->getByLongName(longName).setHasOptionBeenSet();
  111. }
  112. /*
  113. * This generated a list of all registered options and their arguments together with descriptions and defaults.
  114. * @return A std::string containing the help text, delimited by \n
  115. */
  116. std::string getHelpText() const;
  117. static Settings* getInstance();
  118. friend class Destroyer;
  119. private:
  120. /*!
  121. * @brief Private constructor.
  122. *
  123. * This constructor is private, as noone should be able to create
  124. * an instance manually, one should always use the
  125. * newInstance() method.
  126. */
  127. Settings() {
  128. //
  129. }
  130. /*!
  131. * @brief Private destructor.
  132. *
  133. * This destructor should be private, as noone should be able to destroy a singleton.
  134. * The object is automatically destroyed when the program terminates by the destroyer.
  135. */
  136. virtual ~Settings() {
  137. this->instance = nullptr;
  138. }
  139. void parseCommandLine(int const argc, char const * const argv[]);
  140. /*!
  141. * The map holding the information regarding registered options and their types
  142. */
  143. std::unordered_map<std::string, std::shared_ptr<Option>> options;
  144. /*!
  145. * The vector holding a pointer to all options
  146. */
  147. std::vector<std::shared_ptr<Option>> optionPointers;
  148. /*!
  149. * The map holding the information regarding registered options and their short names
  150. */
  151. std::unordered_map<std::string, std::string> shortNames;
  152. /*!
  153. * @brief actual instance of this class.
  154. */
  155. static Settings* instance;
  156. /*!
  157. * @brief Destroyer object.
  158. */
  159. static Destroyer destroyer;
  160. // Helper functions
  161. stringPair_t splitOptionString(std::string const& option);
  162. bool hasAssignment(std::string const& option);
  163. void handleAssignment(std::string const& longOptionName, std::vector<std::string> arguments);
  164. std::vector<std::string> argvToStringArray(int const argc, char const * const argv[]);
  165. std::vector<bool> scanForOptions(std::vector<std::string> const& arguments);
  166. bool checkArgumentSyntaxForOption(std::string const& argvString);
  167. /*!
  168. * Returns true IFF this accumulator contains an option with the specified longName.
  169. */
  170. bool containsLongName(std::string const& longName) const {
  171. return (this->options.find(storm::utility::StringHelper::stringToLower(longName)) != this->options.end());
  172. }
  173. /*!
  174. * Returns true IFF this accumulator contains an option with the specified shortName.
  175. */
  176. bool containsShortName(std::string const& shortName) const {
  177. return (this->shortNames.find(storm::utility::StringHelper::stringToLower(shortName)) != this->shortNames.end());
  178. }
  179. /*!
  180. * Returns a reference to the Option with the specified longName.
  181. * Throws an Exception of Type InvalidArgumentException if there is no such Option.
  182. */
  183. Option& getByLongName(std::string const& longName) const {
  184. auto longNameIterator = this->options.find(storm::utility::StringHelper::stringToLower(longName));
  185. if (longNameIterator == this->options.end()) {
  186. throw storm::exceptions::IllegalArgumentException() << "This program does not contain an Option named \"" << longName << "\"!";
  187. }
  188. return *longNameIterator->second.get();
  189. }
  190. /*!
  191. * Returns a pointer to the Option with the specified longName.
  192. * Throws an Exception of Type InvalidArgumentException if there is no such Option.
  193. * @throws InvalidArgumentException
  194. */
  195. Option* getPtrByLongName(std::string const& longName) const {
  196. auto longNameIterator = this->options.find(storm::utility::StringHelper::stringToLower(longName));
  197. if (longNameIterator == this->options.end()) {
  198. throw storm::exceptions::IllegalArgumentException() << "This program does not contain an Option named \"" << longName << "\"!";
  199. }
  200. return longNameIterator->second.get();
  201. }
  202. /*!
  203. * Returns a reference to the Option with the specified shortName.
  204. * Throws an Exception of Type InvalidArgumentException if there is no such Option.
  205. */
  206. Option& getByShortName(std::string const& shortName) const {
  207. auto shortNameIterator = this->shortNames.find(storm::utility::StringHelper::stringToLower(shortName));
  208. if (shortNameIterator == this->shortNames.end()) {
  209. throw storm::exceptions::IllegalArgumentException() << "This program does not contain an Option with ShortName \"" << shortName << "\"!";
  210. }
  211. return *(this->options.find(shortNameIterator->second)->second.get());
  212. }
  213. /*!
  214. * Returns a pointer to the Option with the specified shortName.
  215. * Throws an Exception of Type InvalidArgumentException if there is no such Option.
  216. */
  217. Option* getPtrByShortName(std::string const& shortName) const {
  218. auto shortNameIterator = this->shortNames.find(storm::utility::StringHelper::stringToLower(shortName));
  219. if (shortNameIterator == this->shortNames.end()) {
  220. throw storm::exceptions::IllegalArgumentException() << "This program does not contain an Option with ShortName \"" << shortName << "\"!";
  221. }
  222. return this->options.find(shortNameIterator->second)->second.get();
  223. }
  224. };
  225. /*!
  226. * @brief Destroyer class for singleton object of Settings.
  227. *
  228. * The sole purpose of this class is to clean up the singleton object
  229. * instance of Settings. The Settings class has a static member of this
  230. * Destroyer type that gets cleaned up when the program terminates. In
  231. * it's destructor, this object will remove the Settings instance.
  232. */
  233. class Destroyer {
  234. public:
  235. Destroyer(): settingsInstance(nullptr) {
  236. this->settingsInstance = storm::settings::Settings::getInstance();
  237. }
  238. /*!
  239. * @brief Destructor.
  240. *
  241. * Free Settings::inst.
  242. */
  243. virtual ~Destroyer() {
  244. if (this->settingsInstance != nullptr) {
  245. std::cout << "Destroying Settings Instance..." << std::endl;
  246. this->settingsInstance->instance = nullptr;
  247. // The C++11 Method of Singleton deletes its instance on its own
  248. //delete this->settingsInstance;
  249. this->settingsInstance = nullptr;
  250. }
  251. }
  252. private:
  253. storm::settings::Settings* settingsInstance;
  254. };
  255. } // namespace settings
  256. } // namespace storm
  257. #endif //