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.
 
 
 
 

302 lines
10 KiB

#ifndef STORM_SETTINGS_SETTINGS_H_
#define STORM_SETTINGS_SETTINGS_H_
#include <iostream>
#include <sstream>
#include <list>
#include <utility>
#include <functional>
#include <unordered_map>
#include <vector>
#include <memory>
#include "src/settings/Option.h"
#include "src/settings/OptionBuilder.h"
#include "src/settings/ArgumentBase.h"
#include "src/settings/Argument.h"
#include "src/settings/ArgumentBuilder.h"
#include "src/settings/ArgumentType.h"
#include "src/settings/ArgumentTypeInferationHelper.h"
// Exceptions that should be catched when performing a parsing run
#include "src/exceptions/OptionParserException.h"
namespace storm {
/*!
* @brief Contains Settings class and associated methods.
*
* The settings namespace contains the Settings class some friend methods like instance().
*/
namespace settings {
class Settings;
typedef std::function<bool (Settings*)> ModuleRegistrationFunction_t;
typedef bool (*stringValidationFunction_t)(const std::string);
typedef bool (*integerValidationFunction_t)(const int_fast64_t);
typedef bool (*unsignedIntegerValidationFunction_t)(const uint_fast64_t);
typedef bool (*doubleValidationFunction_t)(const double);
typedef bool (*booleanValidationFunction_t)(const bool);
typedef std::pair<std::string, std::string> stringPair_t;
typedef std::pair<bool, std::string> fromStringAssignmentResult_t;
class Destroyer;
/*!
* @brief Settings class with command line parser and type validation
*
*
* It is meant to be used as a singleton. Call
* @code storm::settings::Settings::getInstance() @endcode
* to initialize it and obtain an instance.
*
* This class can be customized by other parts of the software using
* option modules. An option module can be anything that implements the
* interface specified by registerModule() and does a static initialization call to this function.
*/
class Settings {
public:
static bool registerNewModule(ModuleRegistrationFunction_t registrationFunction);
/*!
* This parses the command line of the application and matches it to all prior registered options
* @throws OptionParserException
*/
static void parse(int const argc, char const * const argv[]);
std::vector<std::shared_ptr<Option>> const& getOptions() const {
return this->optionPointers;
}
// PUBLIC INTERFACE OF OPTIONSACCUMULATOR (now internal)
/*!
* Returns true IFF an option with the specified longName exists.
*/
bool containsOptionByLongName(std::string const& longName) const {
return this->containsLongName(longName);
}
/*!
* Returns true IFF an option with the specified shortName exists.
*/
bool containsOptionByShortName(std::string const& shortName) const {
return this->containsLongName(shortName);
}
/*!
* Returns a reference to the Option with the specified longName.
* Throws an Exception of Type IllegalArgumentException if there is no such Option.
*/
Option const& getOptionByLongName(std::string const& longName) const {
return this->getByLongName(longName);
}
/*!
* Returns a reference to the Option with the specified shortName.
* Throws an Exception of Type IllegalArgumentException if there is no such Option.
*/
Option const& getOptionByShortName(std::string const& shortName) const {
return this->getByShortName(shortName);
}
/*!
* Adds the given option to the set of known options.
* Unifying with existing options is done automatically.
* Ownership of the Option is handed over when calling this function!
* Returns a reference to the settings instance
* @throws OptionUnificationException
*/
Settings& addOption(Option* option);
/*!
* Returns true iff there is an Option with the specified longName and it has been set
* @return bool true if the option exists and has been set
* @throws InvalidArgumentException
*/
bool isSet(std::string const& longName) const {
return this->getByLongName(longName).getHasOptionBeenSet();
}
/*!
* Sets the Option with the specified longName
* This function requires the Option to have no arguments
* This is for TESTING only and should not be used outside of the testing code!
* @throws InvalidArgumentException
*/
void set(std::string const& longName) const {
return this->getByLongName(longName).setHasOptionBeenSet();
}
/*
* This generated a list of all registered options and their arguments together with descriptions and defaults.
* @return A std::string containing the help text, delimited by \n
*/
std::string getHelpText() const;
static Settings* getInstance();
friend class Destroyer;
private:
/*!
* @brief Private constructor.
*
* This constructor is private, as noone should be able to create
* an instance manually, one should always use the
* newInstance() method.
*/
Settings() {
//
}
/*!
* @brief Private destructor.
*
* This destructor should be private, as noone should be able to destroy a singleton.
* The object is automatically destroyed when the program terminates by the destroyer.
*/
virtual ~Settings() {
this->instance = nullptr;
}
void parseCommandLine(int const argc, char const * const argv[]);
/*!
* The map holding the information regarding registered options and their types
*/
std::unordered_map<std::string, std::shared_ptr<Option>> options;
/*!
* The vector holding a pointer to all options
*/
std::vector<std::shared_ptr<Option>> optionPointers;
/*!
* The map holding the information regarding registered options and their short names
*/
std::unordered_map<std::string, std::string> shortNames;
/*!
* @brief actual instance of this class.
*/
static Settings* instance;
/*!
* @brief Destroyer object.
*/
static Destroyer destroyer;
// Helper functions
stringPair_t splitOptionString(std::string const& option);
bool hasAssignment(std::string const& option);
void handleAssignment(std::string const& longOptionName, std::vector<std::string> arguments);
std::vector<std::string> argvToStringArray(int const argc, char const * const argv[]);
std::vector<bool> scanForOptions(std::vector<std::string> const& arguments);
bool checkArgumentSyntaxForOption(std::string const& argvString);
/*!
* Returns true IFF this accumulator contains an option with the specified longName.
*/
bool containsLongName(std::string const& longName) const {
return (this->options.find(storm::utility::StringHelper::stringToLower(longName)) != this->options.end());
}
/*!
* Returns true IFF this accumulator contains an option with the specified shortName.
*/
bool containsShortName(std::string const& shortName) const {
return (this->shortNames.find(storm::utility::StringHelper::stringToLower(shortName)) != this->shortNames.end());
}
/*!
* Returns a reference to the Option with the specified longName.
* Throws an Exception of Type InvalidArgumentException if there is no such Option.
*/
Option& getByLongName(std::string const& longName) const {
auto longNameIterator = this->options.find(storm::utility::StringHelper::stringToLower(longName));
if (longNameIterator == this->options.end()) {
throw storm::exceptions::IllegalArgumentException() << "This program does not contain an Option named \"" << longName << "\"!";
}
return *longNameIterator->second.get();
}
/*!
* Returns a pointer to the Option with the specified longName.
* Throws an Exception of Type InvalidArgumentException if there is no such Option.
* @throws InvalidArgumentException
*/
Option* getPtrByLongName(std::string const& longName) const {
auto longNameIterator = this->options.find(storm::utility::StringHelper::stringToLower(longName));
if (longNameIterator == this->options.end()) {
throw storm::exceptions::IllegalArgumentException() << "This program does not contain an Option named \"" << longName << "\"!";
}
return longNameIterator->second.get();
}
/*!
* Returns a reference to the Option with the specified shortName.
* Throws an Exception of Type InvalidArgumentException if there is no such Option.
*/
Option& getByShortName(std::string const& shortName) const {
auto shortNameIterator = this->shortNames.find(storm::utility::StringHelper::stringToLower(shortName));
if (shortNameIterator == this->shortNames.end()) {
throw storm::exceptions::IllegalArgumentException() << "This program does not contain an Option with ShortName \"" << shortName << "\"!";
}
return *(this->options.find(shortNameIterator->second)->second.get());
}
/*!
* Returns a pointer to the Option with the specified shortName.
* Throws an Exception of Type InvalidArgumentException if there is no such Option.
*/
Option* getPtrByShortName(std::string const& shortName) const {
auto shortNameIterator = this->shortNames.find(storm::utility::StringHelper::stringToLower(shortName));
if (shortNameIterator == this->shortNames.end()) {
throw storm::exceptions::IllegalArgumentException() << "This program does not contain an Option with ShortName \"" << shortName << "\"!";
}
return this->options.find(shortNameIterator->second)->second.get();
}
};
/*!
* @brief Destroyer class for singleton object of Settings.
*
* The sole purpose of this class is to clean up the singleton object
* instance of Settings. The Settings class has a static member of this
* Destroyer type that gets cleaned up when the program terminates. In
* it's destructor, this object will remove the Settings instance.
*/
class Destroyer {
public:
Destroyer(): settingsInstance(nullptr) {
this->settingsInstance = storm::settings::Settings::getInstance();
}
/*!
* @brief Destructor.
*
* Free Settings::inst.
*/
virtual ~Destroyer() {
if (this->settingsInstance != nullptr) {
std::cout << "Destroying Settings Instance..." << std::endl;
this->settingsInstance->instance = nullptr;
// The C++11 Method of Singleton deletes its instance on its own
//delete this->settingsInstance;
this->settingsInstance = nullptr;
}
}
private:
storm::settings::Settings* settingsInstance;
};
} // namespace settings
} // namespace storm
#endif //