Browse Source
Added my initial implementation of Settings
Added my initial implementation of Settings
Former-commit-id: 5da4b7604f
tempestpy_adaptions
PBerger
12 years ago
24 changed files with 2087 additions and 502 deletions
-
2CMakeLists.txt
-
23src/exceptions/ArgumentUnificationException.h
-
18src/exceptions/IllegalArgumentException.h
-
23src/exceptions/IllegalArgumentTypeException.h
-
23src/exceptions/IllegalArgumentValueException.h
-
25src/exceptions/IllegalFunctionCallException.h
-
26src/exceptions/InternalTypeErrorException.h
-
23src/exceptions/OptionParserException.h
-
23src/exceptions/OptionUnificationException.h
-
259src/settings/Argument.h
-
110src/settings/ArgumentBase.h
-
292src/settings/ArgumentBuilder.h
-
52src/settings/ArgumentType.h
-
152src/settings/ArgumentTypeInferationHelper.h
-
256src/settings/Option.h
-
142src/settings/OptionBuilder.h
-
48src/settings/OptionsAccumulator.cpp
-
120src/settings/OptionsAccumulator.h
-
195src/settings/Settings.cpp
-
210src/settings/Settings.h
-
4src/storm.cpp
-
234src/utility/Settings.cpp
-
266src/utility/Settings.h
-
63src/utility/StringHelper.h
@ -0,0 +1,23 @@ |
|||
/* |
|||
* ArgumentUnificationException.h |
|||
* |
|||
* Created on: 19.07.2013 |
|||
* Author: Philipp Berger |
|||
*/ |
|||
|
|||
#ifndef STORM_EXCEPTIONS_ARGUMENTUNIFICATIONEXCEPTION_H_ |
|||
#define STORM_EXCEPTIONS_ARGUMENTUNIFICATIONEXCEPTION_H_ |
|||
|
|||
#include "src/exceptions/BaseException.h" |
|||
|
|||
namespace storm { |
|||
|
|||
namespace exceptions { |
|||
|
|||
STORM_EXCEPTION_DEFINE_NEW(ArgumentUnificationException) |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
#endif /* STORM_EXCEPTIONS_ARGUMENTUNIFICATIONEXCEPTION_H_ */ |
@ -0,0 +1,18 @@ |
|||
#ifndef STORM_EXCEPTIONS_ILLEGALARGUMENTEXCEPTION_H_ |
|||
#define STORM_EXCEPTIONS_ILLEGALARGUMENTEXCEPTION_H_ |
|||
|
|||
#include "src/exceptions/BaseException.h" |
|||
|
|||
namespace storm { |
|||
|
|||
namespace exceptions { |
|||
|
|||
/*! |
|||
* @brief This exception is thrown when a parameter is invalid or illegal in this context |
|||
*/ |
|||
STORM_EXCEPTION_DEFINE_NEW(IllegalArgumentException) |
|||
|
|||
} // namespace exceptions |
|||
|
|||
} // namespace storm |
|||
#endif // STORM_EXCEPTIONS_ILLEGALARGUMENTEXCEPTION_H_ |
@ -0,0 +1,23 @@ |
|||
/* |
|||
* IllegalArgumentTypeException.h |
|||
* |
|||
* Created on: 10.08.2013 |
|||
* Author: Philipp Berger |
|||
*/ |
|||
|
|||
#ifndef STORM_EXCEPTIONS_ILLEGALARGUMENTTYPEEXCEPTION_H_ |
|||
#define STORM_EXCEPTIONS_ILLEGALARGUMENTTYPEEXCEPTION_H_ |
|||
|
|||
#include "src/exceptions/BaseException.h" |
|||
|
|||
namespace storm { |
|||
|
|||
namespace exceptions { |
|||
|
|||
STORM_EXCEPTION_DEFINE_NEW(IllegalArgumentTypeException) |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
#endif /* STORM_EXCEPTIONS_ILLEGALARGUMENTTYPEEXCEPTION_H_ */ |
@ -0,0 +1,23 @@ |
|||
/* |
|||
* IllegalArgumentValueException.h |
|||
* |
|||
* Created on: 10.08.2013 |
|||
* Author: Philipp Berger |
|||
*/ |
|||
|
|||
#ifndef STORM_EXCEPTIONS_ILLEGALARGUMENTVALUEEXCEPTION_H_ |
|||
#define STORM_EXCEPTIONS_ILLEGALARGUMENTVALUEEXCEPTION_H_ |
|||
|
|||
#include "src/exceptions/BaseException.h" |
|||
|
|||
namespace storm { |
|||
|
|||
namespace exceptions { |
|||
|
|||
STORM_EXCEPTION_DEFINE_NEW(IllegalArgumentValueException) |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
#endif /* STORM_EXCEPTIONS_ILLEGALARGUMENTVALUEEXCEPTION_H_ */ |
@ -0,0 +1,25 @@ |
|||
/* |
|||
* IllegalFunctionCallException.h |
|||
* |
|||
* Created on: 09.08.2013 |
|||
* Author: Philipp Berger |
|||
*/ |
|||
|
|||
#ifndef STORM_EXCEPTIONS_ILLEGALFUNCTIONCALLEXCEPTION_H_ |
|||
#define STORM_EXCEPTIONS_ILLEGALFUNCTIONCALLEXCEPTION_H_ |
|||
|
|||
#include "src/exceptions/BaseException.h" |
|||
|
|||
namespace storm { |
|||
|
|||
namespace exceptions { |
|||
|
|||
/*! |
|||
* @brief This exception is thrown when a function call is not allowed in this context |
|||
*/ |
|||
STORM_EXCEPTION_DEFINE_NEW(IllegalFunctionCallException) |
|||
|
|||
} // namespace exceptions |
|||
|
|||
} // namespace storm |
|||
#endif // STORM_EXCEPTIONS_ILLEGALFUNCTIONCALLEXCEPTION_H_ |
@ -0,0 +1,26 @@ |
|||
/* |
|||
* InternalTypeErrorException.h |
|||
* |
|||
* Created on: 09.08.2013 |
|||
* Author: Philipp Berger |
|||
*/ |
|||
|
|||
#ifndef STORM_EXCEPTIONS_INTERNALTYPEERROREXCEPTION_H_ |
|||
#define STORM_EXCEPTIONS_INTERNALTYPEERROREXCEPTION_H_ |
|||
|
|||
#include "src/exceptions/BaseException.h" |
|||
|
|||
namespace storm { |
|||
|
|||
namespace exceptions { |
|||
|
|||
/*! |
|||
* @brief This exception is thrown when an internal function observes an unknown state or type, e.g. a missing case statement. |
|||
*/ |
|||
STORM_EXCEPTION_DEFINE_NEW(InternalTypeErrorException) |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
#endif /* STORM_EXCEPTIONS_INTERNALTYPEERROREXCEPTION_H_ */ |
@ -0,0 +1,23 @@ |
|||
/* |
|||
* OptionParserException.h |
|||
* |
|||
* Created on: 23.08.2013 |
|||
* Author: Philipp Berger |
|||
*/ |
|||
|
|||
#ifndef STORM_EXCEPTIONS_OPTIONPARSEREXCEPTION_H_ |
|||
#define STORM_EXCEPTIONS_OPTIONPARSEREXCEPTION_H_ |
|||
|
|||
#include "src/exceptions/BaseException.h" |
|||
|
|||
namespace storm { |
|||
|
|||
namespace exceptions { |
|||
|
|||
STORM_EXCEPTION_DEFINE_NEW(OptionParserException) |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
#endif /* STORM_EXCEPTIONS_OPTIONPARSEREXCEPTION_H_ */ |
@ -0,0 +1,23 @@ |
|||
/* |
|||
* OptionUnificationException.h |
|||
* |
|||
* Created on: 21.08.2013 |
|||
* Author: Philipp Berger |
|||
*/ |
|||
|
|||
#ifndef STORM_EXCEPTIONS_OPTIONUNIFICATIONEXCEPTION_H_ |
|||
#define STORM_EXCEPTIONS_OPTIONUNIFICATIONEXCEPTION_H_ |
|||
|
|||
#include "src/exceptions/BaseException.h" |
|||
|
|||
namespace storm { |
|||
|
|||
namespace exceptions { |
|||
|
|||
STORM_EXCEPTION_DEFINE_NEW(OptionUnificationException) |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
#endif /* STORM_EXCEPTIONS_OPTIONUNIFICATIONEXCEPTION_H_ */ |
@ -0,0 +1,259 @@ |
|||
#ifndef STORM_SETTINGS_ARGUMENT_H_ |
|||
#define STORM_SETTINGS_ARGUMENT_H_ |
|||
|
|||
#include <iostream> |
|||
#include <sstream> |
|||
#include <string> |
|||
#include <list> |
|||
#include <utility> |
|||
#include <functional> |
|||
#include <unordered_map> |
|||
#include <vector> |
|||
#include <memory> |
|||
|
|||
#include "src/settings/ArgumentBase.h" |
|||
#include "src/settings/ArgumentType.h" |
|||
#include "src/settings/ArgumentTypeInferationHelper.h" |
|||
#include "src/utility/StringHelper.h" |
|||
#include "src/exceptions/ArgumentUnificationException.h" |
|||
#include "src/exceptions/IllegalArgumentValueException.h" |
|||
#include "src/exceptions/IllegalFunctionCallException.h" |
|||
|
|||
namespace storm { |
|||
namespace settings { |
|||
template<typename T> |
|||
class Argument : public ArgumentBase { |
|||
public: |
|||
typedef std::function<bool (const T, std::string&)> userValidationFunction_t; |
|||
|
|||
/* |
|||
T argumentValue; |
|||
ArgumentType argumentType; |
|||
|
|||
std::vector<userValidationFunction_t> userValidationFunction; |
|||
|
|||
T defaultValue; |
|||
bool hasDefaultValue; |
|||
*/ |
|||
|
|||
Argument(std::string const& argumentName, std::string const& argumentDescription, std::vector<userValidationFunction_t> const& validationFunctions, bool isOptional): ArgumentBase(argumentName, argumentDescription, isOptional), argumentType(ArgumentTypeInferation::inferToEnumType<T>()), userValidationFunction(validationFunctions), hasDefaultValue(false) { |
|||
if (isOptional) { |
|||
throw storm::exceptions::IllegalArgumentException() << "Error: The Argument \"" << argumentName << "\" is flaged as optional but no default value was given!"; |
|||
} |
|||
} |
|||
|
|||
Argument(std::string const& argumentName, std::string const& argumentDescription, std::vector<userValidationFunction_t> const& validationFunctions, bool isOptional, T defaultValue): ArgumentBase(argumentName, argumentDescription, isOptional), argumentType(ArgumentTypeInferation::inferToEnumType<T>()), userValidationFunction(validationFunctions), hasDefaultValue(true), defaultValue(defaultValue) { |
|||
|
|||
} |
|||
|
|||
Argument(Argument const& other) : ArgumentBase(other.argumentName, other.argumentDescription, other.isOptional), argumentType(other.argumentType), hasDefaultValue(other.hasDefaultValue), defaultValue(other.defaultValue) { |
|||
this->userValidationFunction.reserve(other.userValidationFunction.size()); |
|||
for (auto i = 0; i < other.userValidationFunction.size(); ++i) { |
|||
this->userValidationFunction.push_back(userValidationFunction_t(other.userValidationFunction.at(i))); |
|||
} |
|||
} |
|||
|
|||
virtual ~Argument() { |
|||
std::cout << "Destructing an Argument: " << this->getArgumentName() << " of Type " << ArgumentTypeHelper::toString(this->getArgumentType()) << std::endl; |
|||
|
|||
this->userValidationFunction.clear(); |
|||
this->argumentType = ArgumentType::Invalid; |
|||
} |
|||
|
|||
virtual ArgumentBase* clone() const override { |
|||
return new Argument(*this); |
|||
} |
|||
|
|||
assignmentResult_t fromStringValue(std::string const& fromStringValue) override { |
|||
bool conversionOk = false; |
|||
T newValue = this->convertFromString(fromStringValue, &conversionOk); |
|||
if (!conversionOk) { |
|||
std::string message("Could not convert the given String into ArgumentType Format (\""); |
|||
message.append(ArgumentTypeHelper::toString(this->argumentType)); |
|||
message.append("\")!"); |
|||
return std::make_pair(false, message); |
|||
} |
|||
return this->fromTypeValue(newValue); |
|||
} |
|||
|
|||
assignmentResult_t fromTypeValue(T const& newValue) { |
|||
std::string errorText = ""; |
|||
if (!this->validateForEach(newValue, errorText)) { |
|||
// The Conversion failed or a user defined Validation Function was given and it rejected the Input. |
|||
return std::make_pair(false, errorText); |
|||
} |
|||
this->argumentValue = newValue; |
|||
this->hasBeenSet = true; |
|||
return std::make_pair(true, "Success"); |
|||
} |
|||
|
|||
virtual ArgumentType getArgumentType() const override { |
|||
return this->argumentType; |
|||
} |
|||
|
|||
template <typename S> |
|||
void unify(Argument<S> &rhs) { |
|||
if (this->getArgumentType() != rhs.getArgumentType()) { |
|||
// LOG |
|||
throw storm::exceptions::ArgumentUnificationException() << "Error while unifying Argument \"" << this->getArgumentName() << "\" and Argument \"" << rhs.getArgumentName() << "\": Type Missmatch: \"" << ArgumentTypeHelper::toString(this->getArgumentType()) << "\" against \"" << ArgumentTypeHelper::toString(rhs.getArgumentType()) << "\""; |
|||
} |
|||
|
|||
if (this->getIsOptional() != rhs.getIsOptional()) { |
|||
// LOG |
|||
throw storm::exceptions::ArgumentUnificationException() << "Error while unifying Argument \"" << this->getArgumentName() << "\" and Argument \"" << rhs.getArgumentName() << "\": IsOptional Missmatch!"; |
|||
} |
|||
|
|||
if (this->getHasDefaultValue() != rhs.getHasDefaultValue()) { |
|||
// LOG |
|||
throw storm::exceptions::ArgumentUnificationException() << "Error while unifying Argument \"" << this->getArgumentName() << "\" and Argument \"" << rhs.getArgumentName() << "\": defaultValue Missmatch!"; |
|||
} |
|||
|
|||
if (this->getArgumentDescription().compare(rhs.getArgumentDescription()) != 0) { |
|||
// LOG Warning: Descriptions of unified arguments do not match |
|||
} |
|||
|
|||
if (this->getArgumentName().compare(rhs.getArgumentName()) != 0) { |
|||
// LOG Warning: Names of unified arguments do not match |
|||
} |
|||
|
|||
// Add Validation functions |
|||
userValidationFunction.insert(userValidationFunction.end(), rhs.userValidationFunction.begin(), rhs.userValidationFunction.end()); |
|||
|
|||
// Re-Add the Default Value to check for errors |
|||
this->setDefaultValue(this->defaultValue); |
|||
} |
|||
|
|||
T getArgumentValue() const { |
|||
if (!this->getHasBeenSet()) { |
|||
// LOG |
|||
throw storm::exceptions::IllegalFunctionCallException() << "Error: Called getArgumentValue() on Argument \"" << this->getArgumentName() << "\", but it was never set and does not contain a default value."; |
|||
} |
|||
return this->argumentValue; |
|||
} |
|||
|
|||
virtual bool getHasDefaultValue() const override { |
|||
return this->hasDefaultValue; |
|||
} |
|||
|
|||
std::string const& getDefaultValue() { |
|||
return this->defaultValue; |
|||
} |
|||
|
|||
void setFromDefaultValue() override { |
|||
if (!this->hasDefaultValue) { |
|||
throw storm::exceptions::IllegalFunctionCallException() << "Error: The Argument \"" << this->getArgumentName() << "\" (" << this->getArgumentDescription() << ") was asked to set its default value but none was set!"; |
|||
} |
|||
// this call also sets the hasBeenSet flag |
|||
assignmentResult_t result = this->fromTypeValue(this->defaultValue); |
|||
if (!result.first) { |
|||
throw storm::exceptions::IllegalArgumentValueException() << "Error: While parsing a given configuration the Argument \"" << this->getArgumentName() << "\" (" << this->getArgumentDescription() << ") could not receive its Default Value as it was rejected by its Validation Functions with message: " << result.second; |
|||
} |
|||
} |
|||
|
|||
virtual std::string getValueAsString() const override { |
|||
switch (this->argumentType) { |
|||
case ArgumentType::String: |
|||
return ArgumentTypeInferation::inferToString(ArgumentType::String, this->argumentValue); |
|||
case ArgumentType::Boolean: { |
|||
bool iValue = ArgumentTypeInferation::inferToBoolean(ArgumentType::Boolean, this->argumentValue); |
|||
if (iValue) { |
|||
return "true"; |
|||
} else { |
|||
return "false"; |
|||
} |
|||
|
|||
} |
|||
default: |
|||
return this->convertToString(this->argumentValue); |
|||
|
|||
} |
|||
} |
|||
|
|||
virtual int_fast64_t getValueAsInteger() const override { |
|||
switch (this->argumentType) { |
|||
case ArgumentType::Integer: |
|||
return ArgumentTypeInferation::inferToInteger(ArgumentType::Integer, this->argumentValue); |
|||
default: |
|||
throw storm::exceptions::IllegalFunctionCallException() << "Error: getValueAsInteger() was called on Argument \"" << getArgumentName() << "\" of Type \"" << ArgumentTypeHelper::toString(getArgumentType()) << "\"!"; |
|||
|
|||
} |
|||
} |
|||
|
|||
virtual uint_fast64_t getValueAsUnsignedInteger() const override { |
|||
switch (this->argumentType) { |
|||
case ArgumentType::UnsignedInteger: |
|||
return ArgumentTypeInferation::inferToUnsignedInteger(ArgumentType::UnsignedInteger, this->argumentValue); |
|||
default: |
|||
throw storm::exceptions::IllegalFunctionCallException() << "Error: getValueAsUnsignedInteger() was called on Argument \"" << getArgumentName() << "\" of Type \"" << ArgumentTypeHelper::toString(getArgumentType()) << "\"!"; |
|||
|
|||
} |
|||
} |
|||
|
|||
virtual double getValueAsDouble() const override { |
|||
switch (this->argumentType) { |
|||
case ArgumentType::Double: |
|||
return ArgumentTypeInferation::inferToDouble(ArgumentType::Double, this->argumentValue); |
|||
default: |
|||
throw storm::exceptions::IllegalFunctionCallException() << "Error: getValueAsDouble() was called on Argument \"" << getArgumentName() << "\" of Type \"" << ArgumentTypeHelper::toString(getArgumentType()) << "\"!"; |
|||
|
|||
} |
|||
} |
|||
|
|||
virtual bool getValueAsBoolean() const override { |
|||
switch (this->argumentType) { |
|||
case ArgumentType::Boolean: |
|||
return ArgumentTypeInferation::inferToBoolean(ArgumentType::Boolean, this->argumentValue); |
|||
default: |
|||
throw storm::exceptions::IllegalFunctionCallException() << "Error: getValueAsBoolean() was called on Argument \"" << getArgumentName() << "\" of Type \"" << ArgumentTypeHelper::toString(getArgumentType()) << "\"!"; |
|||
|
|||
} |
|||
} |
|||
private: |
|||
T argumentValue; |
|||
ArgumentType argumentType; |
|||
|
|||
std::vector<userValidationFunction_t> userValidationFunction; |
|||
|
|||
T defaultValue; |
|||
bool hasDefaultValue; |
|||
|
|||
void setDefaultValue(T const& newDefault) { |
|||
std::string errorText = ""; |
|||
if (!this->validateForEach(newDefault, errorText)) { |
|||
// A user defined Validation Function was given and it rejected the Input. |
|||
// LOG |
|||
throw storm::exceptions::IllegalArgumentValueException() << "Illegal Default Value for Argument \"" << this->getArgumentName() << "\".\nThe Validation Function rejected the Value: " << errorText; |
|||
} |
|||
this->defaultValue = newDefault; |
|||
this->hasDefaultValue = true; |
|||
} |
|||
|
|||
void unsetDefaultValue() { |
|||
this->hasDefaultValue = false; |
|||
} |
|||
|
|||
std::string convertToString(T const& t) const { |
|||
std::ostringstream stream; |
|||
stream << t; |
|||
return stream.str(); |
|||
} |
|||
|
|||
T convertFromString(std::string const& s, bool* ok = nullptr) const { |
|||
return storm::settings::ArgumentBase::ArgumentHelper::convertFromString<T>(s, ok); |
|||
} |
|||
|
|||
bool validateForEach(T const& value, std::string& errorMessageTarget) const { |
|||
bool result = true; |
|||
|
|||
for (auto lambda: this->userValidationFunction) { |
|||
result = result && lambda(value, errorMessageTarget); |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
|
|||
}; |
|||
} |
|||
} |
|||
|
|||
#endif // STORM_SETTINGS_ARGUMENT_H_ |
@ -0,0 +1,110 @@ |
|||
#ifndef STORM_SETTINGS_ARGUMENTBASE_H_ |
|||
#define STORM_SETTINGS_ARGUMENTBASE_H_ |
|||
|
|||
#include <iostream> |
|||
#include <string> |
|||
|
|||
#include "ArgumentType.h" |
|||
#include "src/utility/StringHelper.h" |
|||
|
|||
namespace storm { |
|||
namespace settings { |
|||
|
|||
typedef std::pair<bool, std::string> assignmentResult_t; |
|||
|
|||
class ArgumentBase { |
|||
public: |
|||
ArgumentBase(std::string const& argumentName, std::string const& argumentDescription, bool isOptional) : isOptional(isOptional), hasBeenSet(false), argumentName(argumentName), argumentDescription(argumentDescription) {} |
|||
virtual ~ArgumentBase() { |
|||
std::cout << "Destructing an ArgumentBase." << std::endl; |
|||
} |
|||
virtual ArgumentType getArgumentType() const = 0; |
|||
|
|||
virtual bool getIsOptional() const { |
|||
return this->isOptional; |
|||
} |
|||
|
|||
std::string const& getArgumentName() const { |
|||
return this->argumentName; |
|||
} |
|||
|
|||
std::string const& getArgumentDescription() const { |
|||
return this->argumentDescription; |
|||
} |
|||
|
|||
virtual bool getHasDefaultValue() const = 0; |
|||
virtual bool getHasBeenSet() const { |
|||
return this->hasBeenSet; |
|||
} |
|||
|
|||
virtual void setFromDefaultValue() = 0; |
|||
virtual assignmentResult_t fromStringValue(std::string const& fromStringValue) = 0; |
|||
virtual ArgumentBase* clone() const = 0; |
|||
|
|||
virtual std::string getValueAsString() const = 0; |
|||
virtual int_fast64_t getValueAsInteger() const = 0; |
|||
virtual uint_fast64_t getValueAsUnsignedInteger() const = 0; |
|||
virtual double getValueAsDouble() const = 0; |
|||
virtual bool getValueAsBoolean() const = 0; |
|||
protected: |
|||
bool isOptional; |
|||
bool hasBeenSet; |
|||
|
|||
std::string argumentName; |
|||
std::string argumentDescription; |
|||
|
|||
class ArgumentHelper { |
|||
public: |
|||
template <typename S> |
|||
static S convertFromString(std::string const& s, bool* ok = nullptr); |
|||
private: |
|||
ArgumentHelper() {} |
|||
ArgumentHelper(ArgumentHelper& other) {} |
|||
~ArgumentHelper() {} |
|||
}; |
|||
}; |
|||
|
|||
template <typename S> S ArgumentBase::ArgumentHelper::convertFromString(std::string const& s, bool* ok) { |
|||
std::istringstream stream(s); |
|||
S t; |
|||
if (ok != nullptr) { |
|||
*ok = (stream >> t) && (stream >> std::ws).eof(); |
|||
} else { |
|||
stream >> t; |
|||
} |
|||
return t; |
|||
} |
|||
|
|||
template <> inline bool ArgumentBase::ArgumentHelper::convertFromString<bool>(std::string const& s, bool* ok) { |
|||
static const std::string lowerTrueString = "true"; |
|||
static const std::string lowerFalseString = "false"; |
|||
static const std::string lowerYesString = "yes"; |
|||
static const std::string lowerNoString = "no"; |
|||
|
|||
std::string lowerInput = storm::utility::StringHelper::stringToLower(s); |
|||
|
|||
if (s.compare(lowerTrueString) == 0 || s.compare(lowerYesString) == 0) { |
|||
if (ok != nullptr) { |
|||
*ok = true; |
|||
} |
|||
return true; |
|||
} else if (s.compare(lowerFalseString) == 0 || s.compare(lowerNoString) == 0) { |
|||
if (ok != nullptr) { |
|||
*ok = true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
std::istringstream stream(s); |
|||
bool t; |
|||
if (ok != nullptr) { |
|||
*ok = (stream >> t) && (stream >> std::ws).eof(); |
|||
} else { |
|||
stream >> t; |
|||
} |
|||
return t; |
|||
} |
|||
} |
|||
} |
|||
|
|||
#endif // STORM_SETTINGS_ARGUMENTBASE_H_ |
@ -0,0 +1,292 @@ |
|||
#ifndef STORM_SETTINGS_ARGUMENTBUILDER_H_ |
|||
#define STORM_SETTINGS_ARGUMENTBUILDER_H_ |
|||
|
|||
#include <iostream> |
|||
#include <sstream> |
|||
#include <list> |
|||
#include <utility> |
|||
#include <functional> |
|||
#include <unordered_map> |
|||
#include <vector> |
|||
#include <memory> |
|||
#include <string> |
|||
|
|||
#include "ArgumentType.h" |
|||
#include "ArgumentTypeInferationHelper.h" |
|||
#include "ArgumentBase.h" |
|||
#include "Argument.h" |
|||
|
|||
#include "src/exceptions/IllegalFunctionCallException.h" |
|||
#include "src/exceptions/IllegalArgumentTypeException.h" |
|||
|
|||
namespace storm { |
|||
namespace settings { |
|||
|
|||
class ArgumentBuilder { |
|||
public: |
|||
~ArgumentBuilder() {} |
|||
|
|||
template<class T> |
|||
static std::function<bool (T const, std::string&)> rangeValidatorIncluding(T const lowerBound, T const upperBound) { |
|||
return std::bind([](T const lowerBound, T const upperBound, T const value, std::string& errorMessageTarget) -> bool { |
|||
bool lowerBoundCondition = (lowerBound <= value); |
|||
bool upperBoundCondition = (value <= upperBound); |
|||
if (!lowerBoundCondition) { |
|||
std::ostringstream stream; |
|||
stream << " Lower Bound Condition not met: " << lowerBound << " is not <= " << value; |
|||
errorMessageTarget.append(stream.str()); |
|||
} |
|||
if (!upperBoundCondition) { |
|||
std::ostringstream stream; |
|||
stream << " Upper Bound Condition not met: " << value << " is not <= " << upperBound; |
|||
errorMessageTarget.append(stream.str()); |
|||
} |
|||
return (lowerBoundCondition && upperBoundCondition); |
|||
}, lowerBound, upperBound, std::placeholders::_1, std::placeholders::_2); |
|||
} |
|||
template<class T> |
|||
static std::function<bool (T const, std::string&)> rangeValidatorExcluding(T const lowerBound, T const upperBound) { |
|||
return std::bind([](T const lowerBound, T const upperBound, T const value, std::string& errorMessageTarget) -> bool { |
|||
bool lowerBoundCondition = (lowerBound < value); |
|||
bool upperBoundCondition = (value < upperBound); |
|||
if (!lowerBoundCondition) { |
|||
std::ostringstream stream; |
|||
stream << " Lower Bound Condition not met: " << lowerBound << " is not < " << value; |
|||
errorMessageTarget.append(stream.str()); |
|||
} |
|||
if (!upperBoundCondition) { |
|||
std::ostringstream stream; |
|||
stream << " Upper Bound Condition not met: " << value << " is not < " << upperBound; |
|||
errorMessageTarget.append(stream.str()); |
|||
} |
|||
return (lowerBoundCondition && upperBoundCondition); |
|||
}, lowerBound, upperBound, std::placeholders::_1, std::placeholders::_2); |
|||
} |
|||
|
|||
/* |
|||
Preparation Functions for all ArgumentType's |
|||
|
|||
Resets all internal attributes |
|||
*/ |
|||
static ArgumentBuilder createStringArgument(std::string const& argumentName, std::string const& argumentDescription) { |
|||
ArgumentBuilder ab(ArgumentType::String, argumentName, argumentDescription); |
|||
return ab; |
|||
} |
|||
|
|||
static ArgumentBuilder createIntegerArgument(std::string const& argumentName, std::string const& argumentDescription) { |
|||
ArgumentBuilder ab(ArgumentType::Integer, argumentName, argumentDescription); |
|||
return ab; |
|||
} |
|||
|
|||
static ArgumentBuilder createUnsignedIntegerArgument(std::string const& argumentName, std::string const& argumentDescription) { |
|||
ArgumentBuilder ab(ArgumentType::UnsignedInteger, argumentName, argumentDescription); |
|||
return ab; |
|||
} |
|||
|
|||
static ArgumentBuilder createDoubleArgument(std::string const& argumentName, std::string const& argumentDescription) { |
|||
ArgumentBuilder ab(ArgumentType::Double, argumentName, argumentDescription); |
|||
return ab; |
|||
} |
|||
|
|||
static ArgumentBuilder createBooleanArgument(std::string const& argumentName, std::string const& argumentDescription) { |
|||
ArgumentBuilder ab(ArgumentType::Boolean, argumentName, argumentDescription); |
|||
return ab; |
|||
} |
|||
|
|||
ArgumentBuilder& setName(std::string const& newName) { |
|||
this->argumentName = newName; |
|||
return *this; |
|||
} |
|||
|
|||
ArgumentBuilder& setDescription(std::string const& newDescription) { |
|||
this->argumentDescription = newDescription; |
|||
return *this; |
|||
} |
|||
|
|||
ArgumentBuilder& setIsOptional(bool isOptional) { |
|||
this->isOptional = isOptional; |
|||
return *this; |
|||
} |
|||
#define PPCAT_NX(A, B) A ## B |
|||
#define PPCAT(A, B) PPCAT_NX(A, B) |
|||
#define MACROaddValidationFunction(funcName, funcType) ArgumentBuilder& PPCAT(addValidationFunction, funcName) (storm::settings::Argument< funcType >::userValidationFunction_t userValidationFunction) { \ |
|||
if (this->argumentType != ArgumentType::funcName) { \ |
|||
throw storm::exceptions::IllegalFunctionCallException() << "Error: You tried adding a Validation-Function for a \"" << ArgumentTypeHelper::toString(ArgumentType::funcName) << "\" Argument, but this Argument is configured to be of Type \"" << ArgumentTypeHelper::toString(this->argumentType) << "\"."; \ |
|||
} \ |
|||
( PPCAT(this->userValidationFunction_, funcName) ).push_back(userValidationFunction); \ |
|||
std::string errorMessageTarget = ""; \ |
|||
if (this->hasDefaultValue && !this->validateDefaultForEach(errorMessageTarget)) { \ |
|||
throw storm::exceptions::IllegalArgumentValueException() << "Error: You tried adding a Validation-Function for an Argument which has a Default Value set which is rejected by this Validation-Function:\r\n" << errorMessageTarget; \ |
|||
} \ |
|||
return *this; \ |
|||
} |
|||
|
|||
MACROaddValidationFunction(String, std::string) |
|||
MACROaddValidationFunction(Integer, int_fast64_t) |
|||
MACROaddValidationFunction(UnsignedInteger, uint_fast64_t) |
|||
MACROaddValidationFunction(Double, double) |
|||
MACROaddValidationFunction(Boolean, bool) |
|||
|
|||
|
|||
#define MACROsetDefaultValue(funcName, funcType) ArgumentBuilder& PPCAT(setDefaultValue, funcName) (funcType const& defaultValue) { \ |
|||
if (this->argumentType != ArgumentType::funcName) { \ |
|||
throw storm::exceptions::IllegalFunctionCallException() << "Error: You tried adding a default Value for a \"" << ArgumentTypeHelper::toString(ArgumentType::String) << "\" Argument, but this Argument is configured to be of Type \"" << ArgumentTypeHelper::toString(this->argumentType) << "\"."; \ |
|||
} \ |
|||
PPCAT(this->defaultValue_, funcName) = defaultValue; \ |
|||
std::string errorMessageTarget = ""; \ |
|||
if (!this->validateDefaultForEach(errorMessageTarget)) { \ |
|||
throw storm::exceptions::IllegalArgumentValueException() << "Error: You tried adding a default Value for an Argument, but a Validation Function rejected it:\r\n" << errorMessageTarget; \ |
|||
} \ |
|||
this->hasDefaultValue = true; \ |
|||
return *this; \ |
|||
} |
|||
|
|||
MACROsetDefaultValue(String, std::string) |
|||
MACROsetDefaultValue(Integer, int_fast64_t) |
|||
MACROsetDefaultValue(UnsignedInteger, uint_fast64_t) |
|||
MACROsetDefaultValue(Double, double) |
|||
MACROsetDefaultValue(Boolean, bool) |
|||
|
|||
ArgumentBase* build() { |
|||
if (this->hasBeenBuild) { |
|||
// LOG |
|||
throw storm::exceptions::IllegalFunctionCallException() << "Error: Called build() on an instance of ArgumentBuilder which has already build an Instance."; |
|||
} |
|||
this->hasBeenBuild = true; |
|||
switch (this->argumentType) { |
|||
case ArgumentType::String: { |
|||
if (this->hasDefaultValue) { |
|||
return dynamic_cast<ArgumentBase*>(new Argument<std::string>(this->argumentName, this->argumentDescription, userValidationFunction_String, this->isOptional, this->defaultValue_String)); |
|||
} else { |
|||
return dynamic_cast<ArgumentBase*>(new Argument<std::string>(this->argumentName, this->argumentDescription, userValidationFunction_String, this->isOptional)); |
|||
} |
|||
break; |
|||
} |
|||
case ArgumentType::Integer: |
|||
if (this->hasDefaultValue) { |
|||
return dynamic_cast<ArgumentBase*>(new Argument<int_fast64_t>(this->argumentName, this->argumentDescription, userValidationFunction_Integer, this->isOptional, this->defaultValue_Integer)); |
|||
} else { |
|||
return dynamic_cast<ArgumentBase*>(new Argument<int_fast64_t>(this->argumentName, this->argumentDescription, userValidationFunction_Integer, this->isOptional)); |
|||
} |
|||
break; |
|||
case ArgumentType::UnsignedInteger: |
|||
if (this->hasDefaultValue) { |
|||
return dynamic_cast<ArgumentBase*>(new Argument<uint_fast64_t>(this->argumentName, this->argumentDescription, userValidationFunction_UnsignedInteger, this->isOptional, this->defaultValue_UnsignedInteger)); |
|||
} else { |
|||
return dynamic_cast<ArgumentBase*>(new Argument<uint_fast64_t>(this->argumentName, this->argumentDescription, userValidationFunction_UnsignedInteger, this->isOptional)); |
|||
} |
|||
break; |
|||
case ArgumentType::Double: |
|||
if (this->hasDefaultValue) { |
|||
return dynamic_cast<ArgumentBase*>(new Argument<double>(this->argumentName, this->argumentDescription, userValidationFunction_Double, this->isOptional, this->defaultValue_Double)); |
|||
} else { |
|||
return dynamic_cast<ArgumentBase*>(new Argument<double>(this->argumentName, this->argumentDescription, userValidationFunction_Double, this->isOptional)); |
|||
} |
|||
break; |
|||
case ArgumentType::Boolean: |
|||
if (this->hasDefaultValue) { |
|||
return dynamic_cast<ArgumentBase*>(new Argument<bool>(this->argumentName, this->argumentDescription, userValidationFunction_Boolean, this->isOptional, this->defaultValue_Boolean)); |
|||
} else { |
|||
return dynamic_cast<ArgumentBase*>(new Argument<bool>(this->argumentName, this->argumentDescription, userValidationFunction_Boolean, this->isOptional)); |
|||
} |
|||
break; |
|||
default: |
|||
// LOG |
|||
throw storm::exceptions::InternalTypeErrorException() << "Error: Missing Case in ArgumentBuilder's switch/case Code."; |
|||
} |
|||
} |
|||
private: |
|||
ArgumentBuilder(ArgumentType argumentType, std::string const& argumentName, std::string const& argumentDescription) : hasBeenBuild(false), argumentType(argumentType), argumentName(argumentName), argumentDescription(argumentDescription), isOptional(false), hasDefaultValue(false) { |
|||
// |
|||
} |
|||
ArgumentBuilder(ArgumentBuilder& other) : hasBeenBuild(other.hasBeenBuild), argumentType(other.argumentType), argumentName(other.argumentName), argumentDescription(other.argumentDescription), isOptional(other.isOptional), |
|||
defaultValue_String(other.defaultValue_String), defaultValue_Integer(other.defaultValue_Integer), defaultValue_UnsignedInteger(other.defaultValue_UnsignedInteger), defaultValue_Double(other.defaultValue_Double), defaultValue_Boolean(other.defaultValue_Boolean), |
|||
hasDefaultValue(other.hasDefaultValue) { |
|||
// Copy all userFunctions |
|||
for (auto i = 0; i < userValidationFunction_String.size(); ++i) { |
|||
this->userValidationFunction_String.push_back(storm::settings::Argument<std::string>::userValidationFunction_t(other.userValidationFunction_String.at(i))); |
|||
} |
|||
for (auto i = 0; i < userValidationFunction_Integer.size(); ++i) { |
|||
this->userValidationFunction_Integer.push_back(storm::settings::Argument<int_fast64_t>::userValidationFunction_t(other.userValidationFunction_Integer.at(i))); |
|||
} |
|||
for (auto i = 0; i < userValidationFunction_UnsignedInteger.size(); ++i) { |
|||
this->userValidationFunction_UnsignedInteger.push_back(storm::settings::Argument<uint_fast64_t>::userValidationFunction_t(other.userValidationFunction_UnsignedInteger.at(i))); |
|||
} |
|||
for (auto i = 0; i < userValidationFunction_Double.size(); ++i) { |
|||
this->userValidationFunction_Double.push_back(storm::settings::Argument<double>::userValidationFunction_t(other.userValidationFunction_Double.at(i))); |
|||
} |
|||
for (auto i = 0; i < userValidationFunction_Boolean.size(); ++i) { |
|||
this->userValidationFunction_Boolean.push_back(storm::settings::Argument<bool>::userValidationFunction_t(other.userValidationFunction_Boolean.at(i))); |
|||
} |
|||
} |
|||
|
|||
bool hasBeenBuild; |
|||
|
|||
ArgumentType argumentType; |
|||
|
|||
std::string argumentName; |
|||
std::string argumentDescription; |
|||
|
|||
/* |
|||
enum class ArgumentType { |
|||
Invalid, String, Integer, UnsignedInteger, Double, Boolean |
|||
}; |
|||
*/ |
|||
|
|||
std::vector<storm::settings::Argument<std::string>::userValidationFunction_t> userValidationFunction_String; |
|||
std::vector<storm::settings::Argument<int_fast64_t>::userValidationFunction_t> userValidationFunction_Integer; |
|||
std::vector<storm::settings::Argument<uint_fast64_t>::userValidationFunction_t> userValidationFunction_UnsignedInteger; |
|||
std::vector<storm::settings::Argument<double>::userValidationFunction_t> userValidationFunction_Double; |
|||
std::vector<storm::settings::Argument<bool>::userValidationFunction_t> userValidationFunction_Boolean; |
|||
|
|||
bool isOptional; |
|||
|
|||
std::string defaultValue_String; |
|||
int_fast64_t defaultValue_Integer; |
|||
uint_fast64_t defaultValue_UnsignedInteger; |
|||
double defaultValue_Double; |
|||
bool defaultValue_Boolean; |
|||
|
|||
bool hasDefaultValue; |
|||
|
|||
bool validateDefaultForEach(std::string& errorMessageTarget) { |
|||
bool result = true; |
|||
|
|||
switch (this->argumentType) { |
|||
case ArgumentType::String: |
|||
for (auto lambda: this->userValidationFunction_String) { |
|||
result = result && lambda(this->defaultValue_String, errorMessageTarget); |
|||
} |
|||
break; |
|||
case ArgumentType::Integer: |
|||
for (auto lambda: this->userValidationFunction_Integer) { |
|||
result = result && lambda(this->defaultValue_Integer, errorMessageTarget); |
|||
} |
|||
break; |
|||
case ArgumentType::UnsignedInteger: |
|||
for (auto lambda: this->userValidationFunction_UnsignedInteger) { |
|||
result = result && lambda(this->defaultValue_UnsignedInteger, errorMessageTarget); |
|||
} |
|||
break; |
|||
case ArgumentType::Double: |
|||
for (auto lambda: this->userValidationFunction_Double) { |
|||
result = result && lambda(this->defaultValue_Double, errorMessageTarget); |
|||
} |
|||
break; |
|||
case ArgumentType::Boolean: |
|||
for (auto lambda: this->userValidationFunction_Boolean) { |
|||
result = result && lambda(this->defaultValue_Boolean, errorMessageTarget); |
|||
} |
|||
break; |
|||
default: |
|||
// LOG |
|||
throw storm::exceptions::InternalTypeErrorException() << "Error: Missing Case in ArgumentBuilder's switch/case Code."; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
}; |
|||
} |
|||
} |
|||
|
|||
#endif // STORM_SETTINGS_ARGUMENTBUILDER_H_ |
@ -0,0 +1,52 @@ |
|||
#ifndef STORM_SETTINGS_ARGUMENTTYPE_H_ |
|||
#define STORM_SETTINGS_ARGUMENTTYPE_H_ |
|||
|
|||
#include "src/exceptions/InternalTypeErrorException.h" |
|||
|
|||
namespace storm { |
|||
namespace settings { |
|||
enum class ArgumentType { |
|||
Invalid, String, Integer, UnsignedInteger, Double, Boolean |
|||
}; |
|||
|
|||
class ArgumentTypeHelper { |
|||
public: |
|||
static std::string const& toString(ArgumentType argumentType) { |
|||
static std::string argumentTypeInvalid = "Invalid"; |
|||
static std::string argumentTypeString = "String"; |
|||
static std::string argumentTypeInteger = "Integer"; |
|||
static std::string argumentTypeUnsignedInteger = "UnsignedInteger"; |
|||
static std::string argumentTypeDouble = "Double"; |
|||
static std::string argumentTypeBoolean = "Boolean"; |
|||
|
|||
switch (argumentType) { |
|||
case ArgumentType::Invalid: |
|||
return argumentTypeInvalid; |
|||
break; |
|||
case ArgumentType::String: |
|||
return argumentTypeString; |
|||
break; |
|||
case ArgumentType::Integer: |
|||
return argumentTypeInteger; |
|||
break; |
|||
case ArgumentType::UnsignedInteger: |
|||
return argumentTypeUnsignedInteger; |
|||
break; |
|||
case ArgumentType::Double: |
|||
return argumentTypeDouble; |
|||
break; |
|||
case ArgumentType::Boolean: |
|||
return argumentTypeBoolean; |
|||
break; |
|||
default: |
|||
throw storm::exceptions::InternalTypeErrorException() << "ERROR:\n" << "Missing a Switch Case in the ArgumentTypeHelper!\n" << "It seems there is a new ArgumentType, but it was not added to the Helper Class!"; |
|||
} |
|||
} |
|||
private: |
|||
ArgumentTypeHelper() {} |
|||
~ArgumentTypeHelper() {} |
|||
}; |
|||
} |
|||
} |
|||
|
|||
#endif // STORM_SETTINGS_ARGUMENTTYPE_H_ |
@ -0,0 +1,152 @@ |
|||
/* |
|||
* ArgumentTypeInferationHelper.h |
|||
* |
|||
* Created on: 19.07.2013 |
|||
* Author: Philipp Berger |
|||
* Static Lookup Helper that detects whether the given Template Type is valid. |
|||
*/ |
|||
|
|||
#ifndef STORM_SETTINGS_ARGUMENTTYPEINFERATIONHELPER_H_ |
|||
#define STORM_SETTINGS_ARGUMENTTYPEINFERATIONHELPER_H_ |
|||
|
|||
#include <cstdint> |
|||
#include <string> |
|||
|
|||
#include "ArgumentType.h" |
|||
#include "src/exceptions/InternalTypeErrorException.h" |
|||
|
|||
namespace storm { |
|||
namespace settings { |
|||
class ArgumentTypeInferation { |
|||
public: |
|||
// Specialized function template that infers the Type of T to our local enum |
|||
template <typename T> |
|||
static ArgumentType inferToEnumType(); |
|||
|
|||
// Specialized function templates that allow casting using the Enum Class as Target |
|||
template <typename T> static std::string inferToString(ArgumentType argumentType, T value); |
|||
template <typename T> static int_fast64_t inferToInteger(ArgumentType argumentType, T value); |
|||
template <typename T> static uint_fast64_t inferToUnsignedInteger(ArgumentType argumentType, T value); |
|||
template <typename T> static double inferToDouble(ArgumentType argumentType, T value); |
|||
template <typename T> static bool inferToBoolean(ArgumentType argumentType, T value); |
|||
|
|||
private: |
|||
ArgumentTypeInferation(); |
|||
~ArgumentTypeInferation(); |
|||
}; |
|||
|
|||
/* |
|||
* All functions related to the EnumType Inferation from the Template Parameter |
|||
*/ |
|||
template <typename T> |
|||
ArgumentType ArgumentTypeInferation::inferToEnumType() { |
|||
// "Missing Template Specialization Case in ArgumentTypeInferation" |
|||
throw storm::exceptions::InternalTypeErrorException() << "ERROR:\n" << "Missing a Template Specialization Case in the ArgumentTypeInferationHelper!\n" << "It seems you tried to use a new, non-standard Type as a Settings Parameter-Type!"; |
|||
|
|||
return ArgumentType::Invalid; |
|||
} |
|||
|
|||
template <> inline ArgumentType ArgumentTypeInferation::inferToEnumType<std::string>() { |
|||
return ArgumentType::String; |
|||
} |
|||
template <> inline ArgumentType ArgumentTypeInferation::inferToEnumType<int_fast64_t>() { |
|||
return ArgumentType::Integer; |
|||
} |
|||
template <> inline ArgumentType ArgumentTypeInferation::inferToEnumType<uint_fast64_t>() { |
|||
return ArgumentType::UnsignedInteger; |
|||
} |
|||
template <> inline ArgumentType ArgumentTypeInferation::inferToEnumType<double>() { |
|||
return ArgumentType::Double; |
|||
} |
|||
template <> inline ArgumentType ArgumentTypeInferation::inferToEnumType<bool>() { |
|||
return ArgumentType::Boolean; |
|||
} |
|||
|
|||
/* |
|||
* All functions related to the conversion to std::string based on the Template and Enum Type |
|||
*/ |
|||
template <typename T> |
|||
std::string ArgumentTypeInferation::inferToString(ArgumentType argumentType, T value) { |
|||
throw storm::exceptions::InternalTypeErrorException() << "ERROR:\n " << "inferToString was called on a non-string Template Object to cast to " << ArgumentTypeHelper::toString(argumentType) << "!"; |
|||
|
|||
return std::string(); |
|||
} |
|||
|
|||
template <> inline std::string ArgumentTypeInferation::inferToString<std::string>(ArgumentType argumentType, std::string value) { |
|||
if (argumentType != ArgumentType::String) { |
|||
throw storm::exceptions::InternalTypeErrorException() << "ERROR:\n " << "inferToString was called on a string Template Object to cast to " << ArgumentTypeHelper::toString(argumentType) << "!"; |
|||
} |
|||
return value; |
|||
} |
|||
|
|||
/* |
|||
* All functions related to the conversion to int_fast64_t based on the Template and Enum Type |
|||
*/ |
|||
template <typename T> |
|||
int_fast64_t ArgumentTypeInferation::inferToInteger(ArgumentType argumentType, T value) { |
|||
throw storm::exceptions::InternalTypeErrorException() << "ERROR:\n " << "inferToInteger was called on a non-int_fast64_t Template Object to cast to " << ArgumentTypeHelper::toString(argumentType) << "!"; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
template <> inline int_fast64_t ArgumentTypeInferation::inferToInteger<int_fast64_t>(ArgumentType argumentType, int_fast64_t value) { |
|||
if (argumentType != ArgumentType::Integer) { |
|||
throw storm::exceptions::InternalTypeErrorException() << "ERROR:\n " << "inferToInteger was called on an int_fast64_t Template Object to cast to " << ArgumentTypeHelper::toString(argumentType) << "!"; |
|||
} |
|||
return value; |
|||
} |
|||
|
|||
/* |
|||
* All functions related to the conversion to uint_fast64_t based on the Template and Enum Type |
|||
*/ |
|||
template <typename T> |
|||
uint_fast64_t ArgumentTypeInferation::inferToUnsignedInteger(ArgumentType argumentType, T value) { |
|||
throw storm::exceptions::InternalTypeErrorException() << "ERROR:\n " << "inferToUnsignedInteger was called on a non-uint_fast64_t Template Object to cast to " << ArgumentTypeHelper::toString(argumentType) << "!"; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
template <> inline uint_fast64_t ArgumentTypeInferation::inferToUnsignedInteger<uint_fast64_t>(ArgumentType argumentType, uint_fast64_t value) { |
|||
if (argumentType != ArgumentType::UnsignedInteger) { |
|||
throw storm::exceptions::InternalTypeErrorException() << "ERROR:\n " << "inferToUnsignedInteger was called on an uint_fast64_t Template Object to cast to " << ArgumentTypeHelper::toString(argumentType) << "!"; |
|||
} |
|||
return value; |
|||
} |
|||
|
|||
/* |
|||
* All functions related to the conversion to double based on the Template and Enum Type |
|||
*/ |
|||
template <typename T> |
|||
double ArgumentTypeInferation::inferToDouble(ArgumentType argumentType, T value) { |
|||
throw storm::exceptions::InternalTypeErrorException() << "ERROR:\n " << "inferToDouble was called on a non-double Template Object to cast to " << ArgumentTypeHelper::toString(argumentType) << "!"; |
|||
|
|||
return 0.0; |
|||
} |
|||
|
|||
template <> inline double ArgumentTypeInferation::inferToDouble<double>(ArgumentType argumentType, double value) { |
|||
if (argumentType != ArgumentType::Double) { |
|||
throw storm::exceptions::InternalTypeErrorException() << "ERROR:\n " << "inferToDouble was called on a double Template Object to cast to " << ArgumentTypeHelper::toString(argumentType) << "!"; |
|||
} |
|||
return value; |
|||
} |
|||
|
|||
/* |
|||
* All functions related to the conversion to bool based on the Template and Enum Type |
|||
*/ |
|||
template <typename T> |
|||
bool ArgumentTypeInferation::inferToBoolean(ArgumentType argumentType, T value) { |
|||
throw storm::exceptions::InternalTypeErrorException() << "ERROR:\n " << "inferToBoolean was called on a non-bool Template Object to cast to " << ArgumentTypeHelper::toString(argumentType) << "!"; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
template <> inline bool ArgumentTypeInferation::inferToBoolean<bool>(ArgumentType argumentType, bool value) { |
|||
if (argumentType != ArgumentType::Boolean) { |
|||
throw storm::exceptions::InternalTypeErrorException() << "ERROR:\n " << "inferToBoolean was called on a bool Template Object to cast to " << ArgumentTypeHelper::toString(argumentType) << "!"; |
|||
} |
|||
return value; |
|||
} |
|||
} |
|||
} |
|||
|
|||
#endif // STORM_SETTINGS_ARGUMENTTYPEINFERATIONHELPER_H_ |
@ -0,0 +1,256 @@ |
|||
/* |
|||
* Option.h |
|||
* |
|||
* Created on: 11.08.2013 |
|||
* Author: Philipp Berger |
|||
*/ |
|||
|
|||
#ifndef STORM_SETTINGS_OPTION_H_ |
|||
#define STORM_SETTINGS_OPTION_H_ |
|||
|
|||
#include <iostream> |
|||
#include <string> |
|||
#include <cstdint> |
|||
#include <cctype> |
|||
#include <vector> |
|||
#include <memory> |
|||
#include <algorithm> |
|||
#include <unordered_set> |
|||
|
|||
#include "ArgumentType.h" |
|||
#include "ArgumentBase.h" |
|||
#include "Argument.h" |
|||
|
|||
#include "src/utility/StringHelper.h" |
|||
#include "src/exceptions/IllegalArgumentException.h" |
|||
#include "src/exceptions/OptionUnificationException.h" |
|||
|
|||
namespace storm { |
|||
namespace settings { |
|||
|
|||
class Option { |
|||
public: |
|||
/* |
|||
std::string longName; |
|||
std::string shortName; |
|||
std::string description; |
|||
std::string moduleName; |
|||
|
|||
bool isRequired; |
|||
bool hasBeenSet; |
|||
|
|||
std::vector<std::shared_ptr<ArgumentBase>> arguments; |
|||
*/ |
|||
Option(std::string const& moduleName, std::string const& longOptionName, std::string const& shortOptionName, std::string const& optionDescription, bool isOptionRequired) |
|||
: longName(longOptionName), shortName(shortOptionName), description(optionDescription), moduleName(moduleName), isRequired(isOptionRequired), hasBeenSet(false) { |
|||
validateFields(); |
|||
} |
|||
|
|||
Option(std::string const& moduleName, std::string const& longOptionName, std::string const& shortOptionName, std::string const& optionDescription, bool isOptionRequired, std::vector<std::shared_ptr<ArgumentBase>> const& optionArguments) |
|||
: longName(longOptionName), shortName(shortOptionName), description(optionDescription), moduleName(moduleName), isRequired(isOptionRequired), hasBeenSet(false) { |
|||
// Copy all Arguments |
|||
this->arguments.reserve(optionArguments.size()); |
|||
for (auto i = 0; i < optionArguments.size(); ++i) { |
|||
// Clone gives a deep copy |
|||
this->arguments.push_back(std::shared_ptr<ArgumentBase>(optionArguments.at(i).get()->clone())); |
|||
} |
|||
|
|||
isArgumentsVectorValid(this->arguments); |
|||
|
|||
validateFields(); |
|||
} |
|||
|
|||
Option(Option const& other): longName(other.longName), shortName(other.shortName), description(other.description), moduleName(other.moduleName), isRequired(other.isRequired), hasBeenSet(other.hasBeenSet) { |
|||
// Copy all Arguments |
|||
this->arguments.reserve(other.arguments.size()); |
|||
for (auto i = 0; i < other.arguments.size(); ++i) { |
|||
// Clone gives a deep copy |
|||
this->arguments.push_back(std::shared_ptr<ArgumentBase>(other.arguments.at(i).get()->clone())); |
|||
} |
|||
|
|||
isArgumentsVectorValid(this->arguments); |
|||
|
|||
validateFields(); |
|||
} |
|||
|
|||
~Option() { |
|||
std::cout << "Destructing an Option." << std::endl; |
|||
|
|||
this->arguments.clear(); |
|||
this->argumentNameMap.clear(); |
|||
} |
|||
|
|||
Option* clone() const { |
|||
return new Option(*this); |
|||
} |
|||
|
|||
void unify(Option& other) { |
|||
if (this->getLongName().compare(other.getLongName()) != 0) { |
|||
// LOG |
|||
throw storm::exceptions::OptionUnificationException() << "Error: Could not unify Option \"" << getLongName() << "\" because the Names are different (\"" << getLongName() << "\" vs. \"" << other.getLongName() << "\")!"; |
|||
} |
|||
if (this->getShortName().compare(other.getShortName()) != 0) { |
|||
// LOG |
|||
throw storm::exceptions::OptionUnificationException() << "Error: Could not unify Option \"" << getLongName() << "\" because the Shortnames are different (\"" << getShortName() << "\" vs. \"" << other.getShortName() << "\")!"; |
|||
} |
|||
|
|||
if (this->getArgumentCount() != other.getArgumentCount()) { |
|||
// LOG |
|||
throw storm::exceptions::OptionUnificationException() << "Error: Could not unify Option \"" << getLongName() << "\" because the Argument Counts are different!"; |
|||
} |
|||
for(auto i = 0; i != this->arguments.size(); i++) { |
|||
ArgumentBase* A = this->arguments.at(i).get(); |
|||
ArgumentBase* B = other.arguments.at(i).get(); |
|||
|
|||
if (A->getArgumentType() != B->getArgumentType()) { |
|||
// LOG |
|||
throw storm::exceptions::OptionUnificationException() << "Error: Could not unify Option \"" << getLongName() << "\" because the Argument Types at Index " << i << " are different!"; |
|||
} |
|||
|
|||
switch (A->getArgumentType()) { |
|||
case ArgumentType::String: |
|||
static_cast<storm::settings::Argument<std::string>*>(A)->unify(*static_cast<storm::settings::Argument<std::string>*>(B)); |
|||
break; |
|||
case ArgumentType::Integer: |
|||
static_cast<storm::settings::Argument<int_fast64_t>*>(A)->unify(*static_cast<storm::settings::Argument<int_fast64_t>*>(B)); |
|||
break; |
|||
case ArgumentType::UnsignedInteger: |
|||
static_cast<storm::settings::Argument<uint_fast64_t>*>(A)->unify(*static_cast<storm::settings::Argument<uint_fast64_t>*>(B)); |
|||
break; |
|||
case ArgumentType::Double: |
|||
static_cast<storm::settings::Argument<double>*>(A)->unify(*static_cast<storm::settings::Argument<double>*>(B)); |
|||
break; |
|||
case ArgumentType::Boolean: |
|||
static_cast<storm::settings::Argument<bool>*>(A)->unify(*static_cast<storm::settings::Argument<bool>*>(B)); |
|||
break; |
|||
default: |
|||
// LOG |
|||
throw storm::exceptions::InternalTypeErrorException() << "Error: Missing Case in ArgumentBuilder's switch/case Code."; |
|||
} |
|||
} |
|||
|
|||
if (this->getModuleName().compare(other.getModuleName()) != 0) { |
|||
this->moduleName.append(", ").append(other.getModuleName()); |
|||
} |
|||
} |
|||
|
|||
uint_fast64_t getArgumentCount() const { |
|||
return this->arguments.size(); |
|||
} |
|||
|
|||
ArgumentBase& getArgument(uint_fast64_t argumentIndex) const { |
|||
if (argumentIndex >= getArgumentCount()) { |
|||
// LOG |
|||
throw storm::exceptions::IllegalArgumentException() << "Error: Option::getArgument(): argumentIndex out of bounds!"; |
|||
} |
|||
return *this->arguments.at(argumentIndex).get(); |
|||
} |
|||
|
|||
/*! |
|||
* Returns a reference to the Argument with the specified longName. |
|||
* Throws an Exception of Type IllegalArgumentException if there is no such Option. |
|||
*/ |
|||
ArgumentBase const& getArgumentByName(std::string const& argumentName) const { |
|||
auto argumentIterator = this->argumentNameMap.find(storm::utility::StringHelper::stringToLower(argumentName)); |
|||
|
|||
if (argumentIterator == this->argumentNameMap.end()) { |
|||
// LOG |
|||
throw storm::exceptions::IllegalArgumentException() << "The Option \"" << this->getLongName() << "\" does not contain an Argument with Name \"" << argumentName << "\"!"; |
|||
} |
|||
|
|||
return *argumentIterator->second.get(); |
|||
} |
|||
|
|||
std::string const& getLongName() const { |
|||
return this->longName; |
|||
} |
|||
|
|||
std::string const& getShortName() const { |
|||
return this->shortName; |
|||
} |
|||
|
|||
std::string const& getDescription() const { |
|||
return this->description; |
|||
} |
|||
|
|||
std::string const& getModuleName() const { |
|||
return this->moduleName; |
|||
} |
|||
|
|||
bool getIsRequired() const { |
|||
return this->isRequired; |
|||
} |
|||
|
|||
bool getHasOptionBeenSet() const { |
|||
return this->hasBeenSet; |
|||
} |
|||
|
|||
void setHasOptionBeenSet() { |
|||
this->hasBeenSet = true; |
|||
} |
|||
private: |
|||
std::string longName; |
|||
std::string shortName; |
|||
std::string description; |
|||
std::string moduleName; |
|||
|
|||
bool isRequired; |
|||
bool hasBeenSet; |
|||
|
|||
std::vector<std::shared_ptr<ArgumentBase>> arguments; |
|||
|
|||
std::unordered_map<std::string, std::shared_ptr<ArgumentBase>> argumentNameMap; |
|||
|
|||
void validateFields() const { |
|||
if (longName.empty()) { |
|||
throw storm::exceptions::IllegalArgumentException() << "Error: Tried constructing an Option with an empty longName field!"; |
|||
} |
|||
|
|||
if (moduleName.empty()) { |
|||
throw storm::exceptions::IllegalArgumentException() << "Error: Tried constructing an Option with an empty moduleName field!"; |
|||
} |
|||
|
|||
bool longNameContainsNonAlpha = std::find_if(longName.begin(), longName.end(), [](char c) { return !std::isalpha(c); }) != longName.end(); |
|||
bool shortNameContainsNonAlpha = std::find_if(shortName.begin(), shortName.end(), [](char c) { return !std::isalpha(c); }) != shortName.end(); |
|||
|
|||
if (longNameContainsNonAlpha) { |
|||
throw storm::exceptions::IllegalArgumentException() << "Error: Tried constructing an Option with a longName that contains non-alpha characters!"; |
|||
} |
|||
if (shortNameContainsNonAlpha) { |
|||
throw storm::exceptions::IllegalArgumentException() << "Error: Tried constructing an Option with a shortName that contains non-alpha characters!"; |
|||
} |
|||
} |
|||
|
|||
bool isArgumentsVectorValid(std::vector<std::shared_ptr<ArgumentBase>> const& arguments) { |
|||
bool lastEntryWasOptional = false; |
|||
std::unordered_set<std::string> argumentNameSet; |
|||
for (auto i = arguments.begin(); i != arguments.end(); ++i) { |
|||
bool isCurrentArgumentOptional = i->get()->getIsOptional(); |
|||
// If this Option is optional, all arguments must have default values |
|||
if (!this->isRequired && !i->get()->getHasDefaultValue()) { |
|||
// LOG |
|||
throw storm::exceptions::IllegalArgumentException() << "Error: The Argument Vector specified for Option \"" << getLongName() << "\" is invalid!\nIt contains an argument without a default value, but the containing option is optional and therefor requires all arguments to provide default values."; |
|||
} |
|||
|
|||
if (!isCurrentArgumentOptional && lastEntryWasOptional) { |
|||
// LOG |
|||
throw storm::exceptions::IllegalArgumentException() << "Error: The Argument Vector specified for Option \"" << getLongName() << "\" is invalid!\nIt contains a non-optional argument AFTER an optional argument."; |
|||
} |
|||
std::string lowerArgumentName = storm::utility::StringHelper::stringToLower(i->get()->getArgumentName()); |
|||
if (argumentNameSet.find(lowerArgumentName) != argumentNameSet.end()) { |
|||
// LOG |
|||
throw storm::exceptions::IllegalArgumentException() << "Error: The Argument Vector specified for Option \"" << getLongName() << "\" is invalid!\nIt contains two arguments with the same name."; |
|||
} |
|||
argumentNameSet.insert(lowerArgumentName); |
|||
|
|||
// This copies the Name to the Name Lookup Map |
|||
argumentNameMap.insert(std::make_pair(lowerArgumentName, std::shared_ptr<ArgumentBase>(*i))); |
|||
lastEntryWasOptional = isCurrentArgumentOptional; |
|||
} |
|||
return true; |
|||
} |
|||
}; |
|||
} |
|||
} |
|||
|
|||
#endif // STORM_SETTINGS_OPTION_H_ |
@ -0,0 +1,142 @@ |
|||
/* |
|||
* OptionBuilder.h |
|||
* |
|||
* Created on: 11.08.2013 |
|||
* Author: Philipp Berger |
|||
*/ |
|||
|
|||
#ifndef STORM_SETTINGS_OPTIONBUILDER_H_ |
|||
#define STORM_SETTINGS_OPTIONBUILDER_H_ |
|||
|
|||
#include <iostream> |
|||
#include <string> |
|||
#include <cstdint> |
|||
#include <vector> |
|||
#include <memory> |
|||
#include <unordered_set> |
|||
|
|||
#include "ArgumentType.h" |
|||
#include "ArgumentBase.h" |
|||
#include "Option.h" |
|||
|
|||
#include "src/exceptions/IllegalArgumentException.h" |
|||
#include "src/exceptions/IllegalFunctionCallException.h" |
|||
|
|||
namespace storm { |
|||
namespace settings { |
|||
|
|||
class OptionBuilder { |
|||
public: |
|||
OptionBuilder(std::string const& newOptionModuleName, std::string const& newOptionLongName, std::string const& newOptionShortName, std::string const& newOptionDescription): longName(newOptionLongName), shortName(newOptionShortName), description(newOptionDescription), moduleName(newOptionModuleName), isRequired(false), isBuild(false) {} |
|||
|
|||
~OptionBuilder() { |
|||
std::cout << "Destructing an OptionBuilder." << std::endl; |
|||
} |
|||
|
|||
OptionBuilder& setLongName(std::string const& newLongName) { |
|||
this->longName = newLongName; |
|||
|
|||
return *this; |
|||
} |
|||
|
|||
std::string const& getLongName() const { |
|||
return this->longName; |
|||
} |
|||
|
|||
OptionBuilder& setShortName(std::string const& newShortName) { |
|||
this->shortName = newShortName; |
|||
|
|||
return *this; |
|||
} |
|||
|
|||
std::string const& getShortName() const { |
|||
return this->shortName; |
|||
} |
|||
|
|||
OptionBuilder& setDescription(std::string const& newDescription) { |
|||
this->description = newDescription; |
|||
|
|||
return *this; |
|||
} |
|||
|
|||
std::string const& getDescription() const { |
|||
return this->description; |
|||
} |
|||
|
|||
OptionBuilder& setModuleName(std::string const& newModuleName) { |
|||
this->moduleName = newModuleName; |
|||
|
|||
return *this; |
|||
} |
|||
|
|||
std::string const& getModuleName() const { |
|||
return this->moduleName; |
|||
} |
|||
|
|||
OptionBuilder& setIsRequired(bool newIsRequired) { |
|||
this->isRequired = newIsRequired; |
|||
|
|||
return *this; |
|||
} |
|||
|
|||
bool getIsRequired() const { |
|||
return this->isRequired; |
|||
} |
|||
|
|||
OptionBuilder& addArgument(ArgumentBase* newArgument) { |
|||
// For automatic management of newArgument's lifetime |
|||
std::shared_ptr<ArgumentBase> argumentPtr(newArgument); |
|||
if (this->isBuild) { |
|||
// LOG |
|||
throw storm::exceptions::IllegalFunctionCallException() << "Error: Called addArgument() on an instance of OptionBuilder which has already build an Instance."; |
|||
} |
|||
|
|||
if (newArgument->getArgumentType() == ArgumentType::Invalid) { |
|||
// LOG |
|||
throw storm::exceptions::InternalTypeErrorException() << "Error: Could not add Argument to Option \"" << getLongName() << "\" because its Type is Invalid!"; |
|||
} |
|||
|
|||
if (!newArgument->getIsOptional() && (this->arguments.size() > 0) && (this->arguments.at(this->arguments.size() - 1).get()->getIsOptional())) { |
|||
// LOG |
|||
throw storm::exceptions::IllegalArgumentException() << "Error: Could not add Non-Optional Argument to Option \"" << getLongName() << "\" because it already contains an optional argument! Please note that after an optional argument has been added only arguments which are also optional can be appended."; |
|||
} |
|||
|
|||
std::string lowerArgumentName = storm::utility::StringHelper::stringToLower(newArgument->getArgumentName()); |
|||
if (argumentNameSet.find(lowerArgumentName) != argumentNameSet.end()) { |
|||
// LOG |
|||
throw storm::exceptions::IllegalArgumentException() << "Error: Could not add Argument with Name \"" << newArgument->getArgumentName() << "\" to Option \"" << getLongName() << "\" because it already contains an argument with the same name! Please note that all argument names must be unique in its respective option."; |
|||
} |
|||
argumentNameSet.insert(lowerArgumentName); |
|||
|
|||
this->arguments.push_back(std::shared_ptr<ArgumentBase>(argumentPtr)); |
|||
|
|||
return *this; |
|||
} |
|||
|
|||
Option* build() { |
|||
if (this->isBuild) { |
|||
// LOG |
|||
throw storm::exceptions::IllegalFunctionCallException() << "Error: Called build() on an instance of OptionBuilder which has already build an Instance."; |
|||
} |
|||
|
|||
this->isBuild = true; |
|||
|
|||
return new storm::settings::Option(this->moduleName, this->longName, this->shortName, this->description, this->isRequired, this->arguments); |
|||
} |
|||
private: |
|||
std::string longName; |
|||
std::string shortName; |
|||
std::string description; |
|||
std::string moduleName; |
|||
|
|||
bool isRequired; |
|||
bool isBuild; |
|||
|
|||
std::vector<std::shared_ptr<ArgumentBase>> arguments; |
|||
|
|||
std::unordered_set<std::string> argumentNameSet; |
|||
}; |
|||
} |
|||
} |
|||
|
|||
#endif // STORM_SETTINGS_OPTIONBUILDER_H_ |
@ -0,0 +1,48 @@ |
|||
#include "src/settings/OptionsAccumulator.h"
|
|||
|
|||
/*!
|
|||
* The map holding the information regarding registered options and their types |
|||
*/ |
|||
//std::unordered_map<std::string, std::shared_ptr<Option>> options;
|
|||
|
|||
/*!
|
|||
* The map holding the information regarding registered options and their short names |
|||
*/ |
|||
//std::unordered_map<std::string, std::string> shortNames;
|
|||
|
|||
storm::settings::OptionsAccumulator& storm::settings::OptionsAccumulator::addOption(Option* option) { |
|||
// For automatic management of option's lifetime
|
|||
std::shared_ptr<Option> optionPtr(option); |
|||
|
|||
std::string lowerLongName = storm::utility::StringHelper::stringToLower(option->getLongName()); |
|||
std::string lowerShortName = storm::utility::StringHelper::stringToLower(option->getShortName()); |
|||
|
|||
auto longNameIterator = this->options.find(lowerLongName); |
|||
auto shortNameIterator = this->shortNames.find(lowerShortName); |
|||
|
|||
if (longNameIterator == this->options.end()) { |
|||
// Not found
|
|||
if (!(shortNameIterator == this->shortNames.end())) { |
|||
// There exists an option which uses the same shortname
|
|||
// LOG
|
|||
throw storm::exceptions::OptionUnificationException() << "Error: The Option \"" << shortNameIterator->second << "\" from Module \"" << this->options.find(shortNameIterator->second)->second.get()->getModuleName() << "\" uses the same ShortName as the Option \"" << option->getLongName() << "\" from Module \"" << option->getModuleName() << "\"!"; |
|||
} |
|||
|
|||
// Copy Shared_ptr
|
|||
this->options.insert(std::make_pair(lowerLongName, std::shared_ptr<Option>(optionPtr))); |
|||
this->optionPointers.push_back(std::shared_ptr<Option>(optionPtr)); |
|||
this->shortNames.insert(std::make_pair(lowerShortName, lowerLongName)); |
|||
} else { |
|||
// This will fail if the shortNames are not identical, so no additional checks here.
|
|||
longNameIterator->second.get()->unify(*option); |
|||
} |
|||
|
|||
return *this; |
|||
} |
|||
|
|||
void storm::settings::OptionsAccumulator::join(storm::settings::OptionsAccumulator const& rhs) { |
|||
for (auto it = rhs.options.begin(); it != rhs.options.end(); ++it) { |
|||
// Clone all Options
|
|||
this->addOption(it->second.get()->clone()); |
|||
} |
|||
} |
@ -0,0 +1,120 @@ |
|||
/* |
|||
* OptionsAccumulator.h |
|||
* |
|||
* Created on: 22.08.2013 |
|||
* Author: Philipp Berger |
|||
*/ |
|||
|
|||
#ifndef STORM_SETTINGS_OPTIONSACCUMULATOR_H_ |
|||
#define STORM_SETTINGS_OPTIONSACCUMULATOR_H_ |
|||
|
|||
#include <iostream> |
|||
#include <string> |
|||
#include <functional> |
|||
#include <unordered_map> |
|||
#include <algorithm> |
|||
#include <cstdint> |
|||
#include <vector> |
|||
#include <memory> |
|||
|
|||
#include "src/settings/Option.h" |
|||
|
|||
namespace storm { |
|||
namespace settings { |
|||
class Settings; |
|||
|
|||
|
|||
class OptionsAccumulator { |
|||
public: |
|||
OptionsAccumulator() {} |
|||
~OptionsAccumulator() { |
|||
//this->shortNames.clear(); |
|||
//this->options.clear(); |
|||
} |
|||
|
|||
OptionsAccumulator& addOption(Option* option); |
|||
void join(OptionsAccumulator const& rhs); |
|||
|
|||
friend class storm::settings::Settings; |
|||
private: |
|||
/*! |
|||
* 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; |
|||
|
|||
/*! |
|||
* Returns true IFF this accumulator contains an option with the specified longName. |
|||
*/ |
|||
bool containsLongName(std::string const& longName) { |
|||
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) { |
|||
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) { |
|||
auto longNameIterator = this->options.find(storm::utility::StringHelper::stringToLower(longName)); |
|||
if (longNameIterator == this->options.end()) { |
|||
throw storm::exceptions::IllegalArgumentException() << "This Accumulator 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. |
|||
*/ |
|||
Option* getPtrByLongName(std::string const& longName) { |
|||
auto longNameIterator = this->options.find(storm::utility::StringHelper::stringToLower(longName)); |
|||
if (longNameIterator == this->options.end()) { |
|||
throw storm::exceptions::IllegalArgumentException() << "This Accumulator 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) { |
|||
auto shortNameIterator = this->shortNames.find(storm::utility::StringHelper::stringToLower(shortName)); |
|||
if (shortNameIterator == this->shortNames.end()) { |
|||
throw storm::exceptions::IllegalArgumentException() << "This Accumulator 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) { |
|||
auto shortNameIterator = this->shortNames.find(storm::utility::StringHelper::stringToLower(shortName)); |
|||
if (shortNameIterator == this->shortNames.end()) { |
|||
throw storm::exceptions::IllegalArgumentException() << "This Accumulator does not contain an Option with ShortName \"" << shortName << "\"!"; |
|||
} |
|||
return this->options.find(shortNameIterator->second)->second.get(); |
|||
} |
|||
}; |
|||
} |
|||
} |
|||
|
|||
#endif // STORM_SETTINGS_OPTIONSACCUMULATOR_H_ |
@ -0,0 +1,195 @@ |
|||
#include "Settings.h"
|
|||
|
|||
#include <cstring>
|
|||
#include <cctype>
|
|||
#include <mutex>
|
|||
|
|||
#include "src/exceptions/OptionParserException.h"
|
|||
|
|||
// Static Inits
|
|||
storm::settings::Settings* storm::settings::Settings::instance = nullptr; |
|||
storm::settings::Destroyer storm::settings::Settings::destroyer; |
|||
|
|||
/*!
|
|||
* @brief Create new instance. |
|||
* |
|||
* Creates a new Settings instance and passes the arguments to the constructor of Settings. |
|||
* |
|||
* @param argc should be argc passed to main function |
|||
* @param argv should be argv passed to main function |
|||
* @param filename either NULL or name of config file |
|||
* @return The new instance of Settings. |
|||
*/ |
|||
void storm::settings::Settings::parse(int const argc, char const * const argv[]) { |
|||
storm::settings::Settings* myInstance = storm::settings::Settings::getInstance(); |
|||
myInstance->parseCommandLine(argc, argv); |
|||
} |
|||
|
|||
bool storm::settings::Settings::hasAssignment(std::string const& option) { |
|||
return (option.find_first_of('=', 0) != std::string::npos); |
|||
} |
|||
|
|||
storm::settings::stringPair_t storm::settings::Settings::splitOptionString(std::string const& option) { |
|||
size_t splitLocation = option.find_first_of('=', 0); |
|||
if (splitLocation == std::string::npos) { |
|||
// Second half is empty
|
|||
return std::make_pair(option, ""); |
|||
} else if (splitLocation + 1 >= option.length()) { |
|||
// Remove the = character
|
|||
return std::make_pair(option.substr(0, option.size() - 1), ""); |
|||
} |
|||
return std::make_pair(option.substr(0, splitLocation), option.substr(splitLocation + 1, std::string::npos)); |
|||
} |
|||
|
|||
void storm::settings::Settings::handleAssignment(std::string const& longOptionName, std::vector<std::string> arguments) { |
|||
std::string optionName = storm::utility::StringHelper::stringToLower(longOptionName); |
|||
|
|||
Option* option = this->optionsAccumulator->getPtrByLongName(optionName); |
|||
|
|||
// Mark as Set
|
|||
option->setHasOptionBeenSet(); |
|||
|
|||
uint_fast64_t givenArgsCount = arguments.size(); |
|||
|
|||
if (givenArgsCount > option->getArgumentCount()) { |
|||
throw storm::exceptions::OptionParserException() << "Could not parse Arguments for Option \"" << longOptionName << "\": " << arguments.size() << " Arguments given, but max. " << option->getArgumentCount() << " Arguments expected."; |
|||
} |
|||
|
|||
for (uint_fast64_t i = 0; i < option->getArgumentCount(); ++i) { |
|||
if (i < givenArgsCount) { |
|||
storm::settings::fromStringAssignmentResult_t assignmentResult = option->getArgument(i).fromStringValue(arguments.at(i)); |
|||
if (!assignmentResult.first) { |
|||
// LOG
|
|||
throw storm::exceptions::OptionParserException() << "Could not parse Arguments for Option \"" << longOptionName << "\": Argument " << option->getArgument(i).getArgumentName() << " rejected the given Value \"" << arguments.at(i) << "\" with Message:\r\n" << assignmentResult.second; |
|||
} |
|||
} else { |
|||
// There is no given value for this argument, only optional
|
|||
if (!option->getArgument(i).getIsOptional()) { |
|||
// LOG
|
|||
throw storm::exceptions::OptionParserException() << "Could not parse Arguments for Option \"" << longOptionName << "\": " << arguments.size() << " Arguments given, but more Arguments were expected."; |
|||
} else { |
|||
option->getArgument(i).setFromDefaultValue(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
std::vector<std::string> storm::settings::Settings::argvToStringArray(int const argc, char const * const argv[]) { |
|||
// Ignore argv[0], it contains the program path and name
|
|||
std::vector<std::string> result; |
|||
for (int i = 1; i < argc; ++i) { |
|||
result.push_back(std::string(argv[i])); |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
bool storm::settings::Settings::checkArgumentSyntaxForOption(std::string const& argvString) { |
|||
if (argvString.size() < 2) { |
|||
return false; |
|||
} |
|||
|
|||
if ((argvString.at(0) != '-') || ((argvString.at(1) != '-') && !isalpha(argvString.at(1)))) { |
|||
return false; |
|||
} |
|||
|
|||
for (auto i = 2; i < argvString.size(); ++i) { |
|||
if (!isalpha(argvString.at(i))) { |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
std::vector<bool> storm::settings::Settings::scanForOptions(std::vector<std::string> const& arguments) { |
|||
std::vector<bool> result; |
|||
result.reserve(arguments.size()); |
|||
for (auto it = arguments.cbegin(); it != arguments.cend(); ++it) { |
|||
result.push_back(checkArgumentSyntaxForOption(*it)); |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
void storm::settings::Settings::parseCommandLine(int const argc, char const * const argv[]) { |
|||
std::cout << "Parsing " << argc << " arguments." << std::endl; |
|||
|
|||
std::vector<std::string> stringArgv = argvToStringArray(argc, argv); |
|||
std::vector<bool> optionPositions = scanForOptions(stringArgv); |
|||
|
|||
bool optionActive = false; |
|||
std::string longOptionName; |
|||
std::vector<std::string> argCache; |
|||
for (auto i = 0; i <= stringArgv.size(); ++i) { |
|||
if (i == stringArgv.size()) { |
|||
if (optionActive) { |
|||
this->handleAssignment(longOptionName, argCache); |
|||
argCache.clear(); |
|||
} |
|||
break; |
|||
} else if (optionPositions.at(i)) { |
|||
if (optionActive) { |
|||
this->handleAssignment(longOptionName, argCache); |
|||
argCache.clear(); |
|||
} |
|||
|
|||
std::string const& nextOption = stringArgv.at(i); |
|||
if (nextOption.at(0) == '-' && nextOption.at(1) != '-') { |
|||
// Short Option
|
|||
std::string nextShortOptionName = storm::utility::StringHelper::stringToLower(nextOption.substr(1, nextOption.size() - 1)); |
|||
if (!this->optionsAccumulator->containsShortName(nextShortOptionName)) { |
|||
// LOG
|
|||
throw storm::exceptions::OptionParserException() << "Found an unknown ShortName for an Option: \"" << nextShortOptionName << "\"."; |
|||
} else { |
|||
longOptionName = this->optionsAccumulator->getByShortName(nextShortOptionName).getLongName(); |
|||
optionActive = true; |
|||
} |
|||
} else { |
|||
// Long Option
|
|||
std::string nextLongOptionName = storm::utility::StringHelper::stringToLower(nextOption.substr(2, nextOption.size() - 2)); |
|||
if (!this->optionsAccumulator->containsLongName(nextLongOptionName)) { |
|||
// LOG
|
|||
throw storm::exceptions::OptionParserException() << "Found an unknown LongName for an Option: \"" << nextLongOptionName << "\"."; |
|||
} else { |
|||
longOptionName = this->optionsAccumulator->getByLongName(nextLongOptionName).getLongName(); |
|||
optionActive = true; |
|||
} |
|||
} |
|||
} else if (optionActive) { |
|||
// Next argument for an Option found
|
|||
argCache.push_back(stringArgv.at(i)); |
|||
} else { |
|||
// No Option active and this is no option.
|
|||
// LOG
|
|||
throw storm::exceptions::OptionParserException() << "Found a stray argument while parsing a given configuration: \"" << stringArgv.at(i) << "\" is neither a known Option nor preceeded by an Option."; |
|||
} |
|||
} |
|||
|
|||
for (auto it = this->optionsAccumulator->options.cbegin(); it != this->optionsAccumulator->options.cend(); ++it) { |
|||
if (!it->second.get()->getHasOptionBeenSet()) { |
|||
if (it->second.get()->getIsRequired()) { |
|||
throw storm::exceptions::OptionParserException() << "Option \"" << it->second.get()->getLongName() << "\" is marked as required, but was not set!"; |
|||
} else { |
|||
// Set defaults on optional values
|
|||
for (auto i = 0; i < it->second.get()->getArgumentCount(); ++i) { |
|||
it->second.get()->getArgument(i).setFromDefaultValue(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
bool storm::settings::Settings::registerNewModule(ModuleRegistrationFunction_t registrationFunction) { |
|||
Settings* myInstance = Settings::getInstance(); |
|||
return registrationFunction(myInstance->optionsAccumulator); |
|||
} |
|||
|
|||
storm::settings::Settings* storm::settings::Settings::getInstance() { |
|||
// Usually, this would require double-checked locking.
|
|||
// But since C++11, this is the way to go:
|
|||
static storm::settings::Settings pInstance; |
|||
|
|||
return &pInstance; |
|||
} |
|||
|
|||
void storm::settings::Settings::addOptions(OptionsAccumulator const& options) { |
|||
this->optionsAccumulator->join(options); |
|||
} |
@ -0,0 +1,210 @@ |
|||
#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/OptionsAccumulator.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 (OptionsAccumulator*)> 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; |
|||
|
|||
/* |
|||
typedef std::function<bool (std::string const)> stringValidationFunction_t; |
|||
typedef std::function<bool (int_fast64_t const)> integerValidationFunction_t; |
|||
typedef std::function<bool (uint_fast64_t const)> unsignedIntegerValidationFunction_t; |
|||
typedef std::function<bool (double const)> doubleValidationFunction_t; |
|||
typedef std::function<bool (bool const)> booleanValidationFunction_t; |
|||
*/ |
|||
|
|||
class Destroyer; |
|||
|
|||
/*! |
|||
* @brief Wrapper around boost::program_options to handle configuration options. |
|||
* |
|||
* This class uses boost::program_options to read options from the |
|||
* commandline and additionally load options from a file. |
|||
* |
|||
* It is meant to be used as a singleton. Call |
|||
* @code storm::settings::newInstance(argc, argv, filename) @endcode |
|||
* to initialize it and obtain an instance for the first time. |
|||
* Afterwards, use |
|||
* @code storm::settings::instance() @endcode |
|||
* |
|||
* 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(). |
|||
*/ |
|||
class Settings { |
|||
public: |
|||
|
|||
static bool registerNewModule(ModuleRegistrationFunction_t registrationFunction); |
|||
|
|||
/*! |
|||
* Parsing |
|||
*/ |
|||
static void parse(int const argc, char const * const argv[]); |
|||
|
|||
void addOptions(OptionsAccumulator const& options); |
|||
|
|||
std::vector<std::shared_ptr<Option>> const& getOptions() const { |
|||
return this->optionsAccumulator->optionPointers; |
|||
} |
|||
|
|||
// COPY INTERFACE OF OPTIONSACCUMULATOR |
|||
/*! |
|||
* Returns true IFF an option with the specified longName exists. |
|||
*/ |
|||
bool containsOptionByLongName(std::string const& longName) { |
|||
return this->optionsAccumulator->containsLongName(longName); |
|||
} |
|||
|
|||
/*! |
|||
* Returns true IFF an option with the specified shortName exists. |
|||
*/ |
|||
bool containsOptionByShortName(std::string const& shortName) { |
|||
return this->optionsAccumulator->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) { |
|||
return this->optionsAccumulator->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) { |
|||
return this->optionsAccumulator->getByShortName(shortName); |
|||
} |
|||
|
|||
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(): optionsAccumulator(nullptr) { |
|||
this->optionsAccumulator = new OptionsAccumulator(); |
|||
} |
|||
|
|||
/*! |
|||
* @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() { |
|||
delete this->optionsAccumulator; |
|||
this->instance = nullptr; |
|||
} |
|||
|
|||
void parseCommandLine(int const argc, char const * const argv[]); |
|||
|
|||
/*! |
|||
* @brief The registered options |
|||
*/ |
|||
OptionsAccumulator* optionsAccumulator; |
|||
|
|||
/*! |
|||
* @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); |
|||
}; |
|||
|
|||
/*! |
|||
* @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 // |
@ -1,234 +0,0 @@ |
|||
/*
|
|||
* Settings.cpp |
|||
* |
|||
* Created on: 22.11.2012 |
|||
* Author: Gereon Kremer |
|||
*/ |
|||
|
|||
#include "src/utility/Settings.h"
|
|||
|
|||
#include <boost/algorithm/string/join.hpp>
|
|||
#include <utility>
|
|||
#include <map>
|
|||
#include <string>
|
|||
#include <list>
|
|||
|
|||
#include "src/exceptions/BaseException.h"
|
|||
#include "log4cplus/logger.h"
|
|||
#include "log4cplus/loggingmacros.h"
|
|||
extern log4cplus::Logger logger; |
|||
|
|||
|
|||
namespace storm { |
|||
namespace settings { |
|||
|
|||
namespace bpo = boost::program_options; |
|||
|
|||
/*
|
|||
* Static initializers. |
|||
*/ |
|||
std::unique_ptr<bpo::options_description> storm::settings::Settings::desc = nullptr; |
|||
std::string storm::settings::Settings::binaryName = ""; |
|||
storm::settings::Settings* storm::settings::Settings::inst = nullptr; |
|||
|
|||
std::map< std::pair<std::string, std::string>, std::shared_ptr<bpo::options_description> > storm::settings::Settings::modules; |
|||
|
|||
storm::settings::Destroyer storm::settings::Settings::destroyer; |
|||
|
|||
/*!
|
|||
* The constructor fills the option descriptions, parses the |
|||
* command line and the config file and puts the option values to |
|||
* our option mapping. |
|||
* |
|||
* If a configfile is set in the commandline, we load this one. |
|||
* Otherwise, if filename is not NULL, we load this one. Otherwise, |
|||
* we load no config file. |
|||
* |
|||
* @param argc should be argc passed to main function |
|||
* @param argv should be argv passed to main function |
|||
* @param filename either nullptr or name of config file |
|||
*/ |
|||
Settings::Settings(int const argc, char const * const argv[], char const * const filename, bool const sloppy) { |
|||
Settings::binaryName = std::string(argv[0]); |
|||
try { |
|||
// Initially fill description objects.
|
|||
this->initDescriptions(); |
|||
|
|||
// Check module triggers, add corresponding options.
|
|||
std::map< std::string, std::list< std::string > > options; |
|||
|
|||
for (auto it : Settings::modules) { |
|||
options[it.first.first].push_back(it.first.second); |
|||
} |
|||
for (auto it : options) { |
|||
std::stringstream str; |
|||
str << "select " << it.first << " module (" << boost::algorithm::join(it.second, ", ") << ")"; |
|||
|
|||
Settings::desc->add_options() |
|||
(it.first.c_str(), bpo::value<std::string>()->default_value(it.second.front()), str.str().c_str()) |
|||
; |
|||
} |
|||
|
|||
// Perform first parse run.
|
|||
this->firstRun(argc, argv, filename); |
|||
|
|||
// Buffer for items to be deleted.
|
|||
std::list< std::pair< std::string, std::string > > deleteQueue; |
|||
// Check module triggers.
|
|||
for (auto it : Settings::modules) { |
|||
std::pair< std::string, std::string > trigger = it.first; |
|||
if (this->vm.count(trigger.first)) { |
|||
if (this->vm[trigger.first].as<std::string>().compare(trigger.second) == 0) { |
|||
Settings::desc->add(*it.second); |
|||
deleteQueue.push_back(trigger); |
|||
} |
|||
} |
|||
} |
|||
for (auto it : deleteQueue) Settings::modules.erase(it); |
|||
|
|||
// Stop if help is set.
|
|||
if (this->vm.count("help") > 0) { |
|||
return; |
|||
} |
|||
|
|||
// Perform second run.
|
|||
this->secondRun(argc, argv, filename); |
|||
|
|||
// Finalize parsed options, check for specified requirements.
|
|||
if (!sloppy) { |
|||
bpo::notify(this->vm); |
|||
} |
|||
LOG4CPLUS_DEBUG(logger, "Finished loading config."); |
|||
} |
|||
catch (bpo::reading_file const& e) { |
|||
std::cerr << "Could not read config file " << filename << std::endl; |
|||
LOG4CPLUS_ERROR(logger, "Could not read config file"); |
|||
} |
|||
catch (bpo::required_option const& e) { |
|||
throw storm::exceptions::InvalidSettingsException() << "Required option missing"; |
|||
} |
|||
catch (bpo::validation_error const& e) { |
|||
throw storm::exceptions::InvalidSettingsException() << "Validation failed: " << e.what(); |
|||
} |
|||
catch (bpo::invalid_command_line_syntax const& e) { |
|||
throw storm::exceptions::InvalidSettingsException() << e.what(); |
|||
} |
|||
catch (bpo::error const& e) { |
|||
throw storm::exceptions::InvalidSettingsException() << e.what(); |
|||
} |
|||
} |
|||
|
|||
void checkExplicit(const std::vector<std::string>& filenames) { |
|||
if (filenames.size() != 2) { |
|||
throw storm::exceptions::InvalidSettingsException() << "--explicit must be given exactly two filenames"; |
|||
} |
|||
} |
|||
|
|||
/*!
|
|||
* Validates whether the given lemethod matches one of the available ones. |
|||
* Throws an exception of type InvalidSettings in case the selected method is illegal. |
|||
*/ |
|||
static void validateLeMethod(const std::string& lemethod) { |
|||
if ((lemethod != "bicgstab") && (lemethod != "qmr") && (lemethod != "jacobi") && (lemethod != "lscg") && (lemethod != "gmres")) { |
|||
throw exceptions::InvalidSettingsException() << "Argument " << lemethod << " for option 'lemethod' is invalid."; |
|||
} |
|||
} |
|||
|
|||
/*!
|
|||
* Validates whether the given preconditioner matches one of the available ones. |
|||
* Throws an exception of type InvalidSettings in case the selected preconditioner is illegal. |
|||
*/ |
|||
static void validatePreconditioner(const std::string& preconditioner) { |
|||
if ((preconditioner != "ilu") && (preconditioner != "diagonal") && (preconditioner != "ildlt") && (preconditioner != "none")) { |
|||
throw exceptions::InvalidSettingsException() << "Argument " << preconditioner << " for option 'precond' is invalid."; |
|||
} |
|||
} |
|||
|
|||
/*!
|
|||
* Initially fill options_description objects. |
|||
*/ |
|||
void Settings::initDescriptions() { |
|||
LOG4CPLUS_DEBUG(logger, "Initializing descriptions."); |
|||
Settings::desc = std::unique_ptr<bpo::options_description>(new bpo::options_description("Generic Options")); |
|||
Settings::desc->add_options() |
|||
("help,h", "produce help message") |
|||
("verbose,v", "be verbose") |
|||
("debug", "be very verbose, intended for debugging") |
|||
("trace", "be extremely verbose, expect lots of output") |
|||
("logfile,l", bpo::value<std::string>(), "name of the log file") |
|||
("configfile,c", bpo::value<std::string>(), "name of config file") |
|||
("explicit", bpo::value<std::vector<std::string>>()->multitoken()->notifier(&checkExplicit), "name of transition and labeling file") |
|||
("symbolic", bpo::value<std::string>(), "name of prism file") |
|||
("prctl", bpo::value<std::string>(), "text file containing prctl formulas") |
|||
("csl", bpo::value<std::string>(), "text file containing csl formulas") |
|||
("ltl", bpo::value<std::string>(), "text file containing ltl formulas") |
|||
("transrew", bpo::value<std::string>()->default_value(""), "name of transition reward file") |
|||
("staterew", bpo::value<std::string>()->default_value(""), "name of state reward file") |
|||
("fix-deadlocks", "insert self-loops for states without outgoing transitions") |
|||
("lemethod", boost::program_options::value<std::string>()->default_value("gmres")->notifier(&storm::settings::validateLeMethod), "Sets the method used for linear equation solving. Must be in {bicgstab, qmr, lscg, gmres, jacobi}.") |
|||
("maxiter", boost::program_options::value<unsigned>()->default_value(10000), "Sets the maximal number of iterations for iterative equation solving.") |
|||
("precision", boost::program_options::value<double>()->default_value(1e-6), "Sets the precision for iterative equation solving.") |
|||
("precond", boost::program_options::value<std::string>()->default_value("ilu")->notifier(&validatePreconditioner), "Sets the preconditioning technique for linear equation solving. Must be in {ilu, diagonal, ildlt, none}.") |
|||
("relative", boost::program_options::value<bool>()->default_value(true), "Sets whether the relative or absolute error is considered for detecting convergence.") |
|||
("use-heuristic-presolve", boost::program_options::value<bool>()->default_value(false), "Sets whether heuristic methods should be applied to get better initial values for value iteration.") |
|||
("matrixlib", boost::program_options::value<std::string>()->default_value("gmm++"), "Sets which matrix library is to be used for numerical solving.") |
|||
; |
|||
} |
|||
|
|||
/*!
|
|||
* Perform a sloppy parsing run: parse command line and config file (if |
|||
* given), but allow for unregistered options, do not check requirements |
|||
* from options_description objects. |
|||
*/ |
|||
void Settings::firstRun(int const argc, char const * const argv[], char const * const filename) { |
|||
LOG4CPLUS_DEBUG(logger, "Performing first run."); |
|||
// Parse command line.
|
|||
bpo::store(bpo::command_line_parser(argc, argv).options(*(Settings::desc)).allow_unregistered().run(), this->vm); |
|||
|
|||
/*
|
|||
* Load config file if specified. |
|||
*/ |
|||
if (this->vm.count("configfile")) { |
|||
bpo::store(bpo::parse_config_file<char>(this->vm["configfile"].as<std::string>().c_str(), *(Settings::desc)), this->vm, true); |
|||
} else if (filename != NULL) { |
|||
bpo::store(bpo::parse_config_file<char>(filename, *(Settings::desc)), this->vm, true); |
|||
} |
|||
} |
|||
|
|||
/*!
|
|||
* Perform the second parser run: parse command line and config file (if |
|||
* given) and check for unregistered options, requirements from |
|||
* options_description objects. |
|||
*/ |
|||
void Settings::secondRun(int const argc, char const * const argv[], char const * const filename) { |
|||
LOG4CPLUS_DEBUG(logger, "Performing second run."); |
|||
// Parse command line.
|
|||
bpo::store(bpo::command_line_parser(argc, argv).options(*(Settings::desc)).run(), this->vm); |
|||
/*
|
|||
* Load config file if specified. |
|||
*/ |
|||
if (this->vm.count("configfile")) { |
|||
bpo::store(bpo::parse_config_file<char>(this->vm["configfile"].as<std::string>().c_str(), *(Settings::desc)), this->vm, true); |
|||
} else if (filename != NULL) { |
|||
bpo::store(bpo::parse_config_file<char>(filename, *(Settings::desc)), this->vm, true); |
|||
} |
|||
} |
|||
|
|||
|
|||
/*!
|
|||
* Print a short general usage information consisting of the the list of available command line options. |
|||
* |
|||
* Use it like this: |
|||
* @code std::cout << storm::settings::help; @endcode |
|||
*/ |
|||
std::ostream& help(std::ostream& os) { |
|||
os << "Usage: " << storm::settings::Settings::binaryName << " [options] <transition file> <label file>" << std::endl; |
|||
os << *(storm::settings::Settings::desc) << std::endl; |
|||
for (auto it : Settings::modules) { |
|||
os << *(it.second) << std::endl; |
|||
} |
|||
return os; |
|||
} |
|||
|
|||
} // namespace settings
|
|||
} // namespace storm
|
@ -1,266 +0,0 @@ |
|||
/* |
|||
* Settings.h |
|||
* |
|||
* Created on: 22.11.2012 |
|||
* Author: Gereon Kremer |
|||
*/ |
|||
|
|||
#ifndef STORM_SETTINGS_SETTINGS_H_ |
|||
#define STORM_SETTINGS_SETTINGS_H_ |
|||
|
|||
#include <iostream> |
|||
#include <sstream> |
|||
#include <list> |
|||
#include <utility> |
|||
#include <memory> |
|||
#include <boost/program_options.hpp> |
|||
#include "src/exceptions/InvalidSettingsException.h" |
|||
|
|||
namespace storm { |
|||
|
|||
/*! |
|||
* @brief Contains Settings class and associated methods. |
|||
* |
|||
* The settings namespace contains the Settings class some friend methods like instance(). |
|||
*/ |
|||
namespace settings { |
|||
|
|||
namespace bpo = boost::program_options; |
|||
|
|||
class Destroyer; |
|||
|
|||
/*! |
|||
* @brief Wrapper around boost::program_options to handle configuration options. |
|||
* |
|||
* This class uses boost::program_options to read options from the |
|||
* commandline and additionally load options from a file. |
|||
* |
|||
* It is meant to be used as a singleton. Call |
|||
* @code storm::settings::newInstance(argc, argv, filename) @endcode |
|||
* to initialize it and obtain an instance for the first time. |
|||
* Afterwards, use |
|||
* @code storm::settings::instance() @endcode |
|||
* |
|||
* 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(). |
|||
*/ |
|||
class Settings { |
|||
public: |
|||
|
|||
/*! |
|||
* @brief Get value of a generic option. |
|||
*/ |
|||
template <typename T> |
|||
const T& get(std::string const& name) const { |
|||
if (this->vm.count(name) == 0) throw storm::exceptions::InvalidSettingsException() << "Could not read option " << name << "."; |
|||
return this->vm[name].as<T>(); |
|||
} |
|||
|
|||
/*! |
|||
* @brief Get value of string option. |
|||
*/ |
|||
const std::string& getString(std::string const& name) const { |
|||
return this->get<std::string>(name); |
|||
} |
|||
|
|||
/*! |
|||
* @brief Check if an option is set. |
|||
*/ |
|||
const bool isSet(std::string const& name) const { |
|||
return this->vm.count(name) > 0; |
|||
} |
|||
|
|||
/*! |
|||
* @brief Set an option. |
|||
*/ |
|||
void set(std::string const& name) { |
|||
bpo::variable_value val; |
|||
this->vm.insert(std::make_pair(name, val)); |
|||
} |
|||
|
|||
/*! |
|||
* @brief Set value for an option. |
|||
*/ |
|||
template <typename T> |
|||
void set(std::string const& name, T const& value) { |
|||
bpo::variable_value val(value, false); |
|||
this->vm.erase(name); |
|||
this->vm.insert(std::make_pair(name, val)); |
|||
} |
|||
|
|||
/*! |
|||
* @brief Register a new module. |
|||
* |
|||
* A new settings module can be registered via |
|||
* @code |
|||
* storm::settings::Settings::registerModule<storm::ModuleClass>(); |
|||
* @endcode |
|||
* This has to be done before any parsing takes place, i.e. before newInstance() is called. |
|||
* |
|||
* This function implicitly defines the following interface for any SettingsModule: |
|||
* @code |
|||
* static std::string getModuleName(); |
|||
* static std::pair< std::string, std::string > getOptionTrigger(); |
|||
* static void putOptions(boost::program_options::options_description*); |
|||
* @endcode |
|||
* |
|||
* The semantic is the following: |
|||
* If the trigger <a,b> is true, i.e. if option a is set to b, |
|||
* the options_description object will be added to the internal |
|||
* option object. |
|||
* |
|||
* Furthermore, it will generate the option specified by the |
|||
* trigger. |
|||
* |
|||
* The functions could look like this: |
|||
* @code |
|||
* static std::string getModuleName() { return "Backend A"; } |
|||
* static std::pair<std::string, std::string> getOptionTrigger() { |
|||
* return std::pair<std::string, std::string>("backend", "a"); |
|||
* } |
|||
* static void putOptions(boost::program_options::options_description* desc) { |
|||
* desc->add_options()("foo", "bar"); |
|||
* } |
|||
* @endcode |
|||
*/ |
|||
template <typename T> |
|||
static void registerOptions() { |
|||
// Get trigger values. |
|||
std::string const& name = T::getName(); |
|||
// Build description name. |
|||
std::stringstream str; |
|||
str << "Options for " << name << ":"; |
|||
std::shared_ptr<bpo::options_description> desc = std::shared_ptr<bpo::options_description>(new bpo::options_description(str.str())); |
|||
// Put options into description. |
|||
T::putOptions(desc.get()); |
|||
// Store module. |
|||
// Settings::modules[name] = desc; |
|||
} |
|||
|
|||
friend std::ostream& help(std::ostream& os); |
|||
friend std::ostream& helpConfigfile(std::ostream& os); |
|||
friend Settings* instance(); |
|||
friend Settings* newInstance(int const argc, char const * const argv[], char const * const filename, bool const sloppy = false); |
|||
friend 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(int const argc, char const * const argv[], char const * const filename, bool const sloppy); |
|||
|
|||
/*! |
|||
* @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. |
|||
*/ |
|||
~Settings() {} |
|||
|
|||
/*! |
|||
* @brief Initialize options_description object. |
|||
*/ |
|||
void initDescriptions(); |
|||
|
|||
/*! |
|||
* @brief Perform first parser run |
|||
*/ |
|||
void firstRun(int const argc, char const * const argv[], char const * const filename); |
|||
|
|||
/*! |
|||
* @brief Perform second parser run. |
|||
*/ |
|||
void secondRun(int const argc, char const * const argv[], char const * const filename); |
|||
|
|||
/*! |
|||
* @brief Collecting option descriptions. |
|||
*/ |
|||
static std::unique_ptr<bpo::options_description> desc; |
|||
|
|||
/*! |
|||
* @brief Contains option descriptions for all modules. |
|||
*/ |
|||
static std::map< std::pair<std::string, std::string>, std::shared_ptr<bpo::options_description>> modules; |
|||
|
|||
/*! |
|||
* @brief option mapping. |
|||
*/ |
|||
bpo::variables_map vm; |
|||
|
|||
/*! |
|||
* @brief name of binary |
|||
*/ |
|||
static std::string binaryName; |
|||
|
|||
/*! |
|||
* @brief actual instance of this class. |
|||
*/ |
|||
static Settings* inst; |
|||
|
|||
/*! |
|||
* @brief Destroyer object. |
|||
*/ |
|||
static Destroyer destroyer; |
|||
}; |
|||
|
|||
/*! |
|||
* @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: |
|||
/*! |
|||
* @brief Destructor. |
|||
* |
|||
* Free Settings::inst. |
|||
*/ |
|||
~Destroyer() { |
|||
if (Settings::inst != nullptr) { |
|||
delete Settings::inst; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
/*! |
|||
* @brief Print usage help. |
|||
*/ |
|||
std::ostream& help(std::ostream& os); |
|||
|
|||
/*! |
|||
* @brief Return current instance. |
|||
* |
|||
* @return The current instance of Settings created by newInstance(). |
|||
*/ |
|||
inline Settings* instance() { |
|||
return Settings::inst; |
|||
} |
|||
|
|||
/*! |
|||
* @brief Create new instance. |
|||
* |
|||
* Creates a new Settings instance and passes the arguments to the constructor of Settings. |
|||
* |
|||
* @param argc should be argc passed to main function |
|||
* @param argv should be argv passed to main function |
|||
* @param filename either NULL or name of config file |
|||
* @return The new instance of Settings. |
|||
*/ |
|||
inline Settings* newInstance(int const argc, char const * const argv[], char const * const filename, bool const sloppy) { |
|||
if (Settings::inst != nullptr) delete Settings::inst; |
|||
Settings::inst = new Settings(argc, argv, filename, sloppy); |
|||
return Settings::inst; |
|||
} |
|||
|
|||
} // namespace settings |
|||
} // namespace storm |
|||
|
|||
#endif // STORM_SETTINGS_SETTINGS_H_ |
@ -0,0 +1,63 @@ |
|||
/* |
|||
* StringHelper.h |
|||
* |
|||
* Created on: 01.09.2013 |
|||
* Author: Philipp Berger |
|||
*/ |
|||
|
|||
#ifndef STORM_UTILITY_STRINGHELPER_H_ |
|||
#define STORM_UTILITY_STRINGHELPER_H_ |
|||
|
|||
#include <iostream> |
|||
#include <string> |
|||
#include <functional> |
|||
#include <algorithm> |
|||
|
|||
|
|||
namespace storm { |
|||
namespace utility { |
|||
|
|||
class StringHelper { |
|||
public: |
|||
/*! |
|||
* Returns the String, transformed with toLower. |
|||
*/ |
|||
static std::string stringToLower(std::string const& sourceString) { |
|||
std::string targetString; |
|||
targetString.resize(sourceString.size()); |
|||
std::transform(sourceString.begin(), sourceString.end(), targetString.begin(), ::tolower); |
|||
|
|||
return targetString; |
|||
} |
|||
|
|||
/*! |
|||
* Returns the String, transformed with toUpper. |
|||
*/ |
|||
static std::string stringToUpper(std::string const& sourceString) { |
|||
std::string targetString; |
|||
targetString.resize(sourceString.size()); |
|||
std::transform(sourceString.begin(), sourceString.end(), targetString.begin(), ::toupper); |
|||
|
|||
return targetString; |
|||
} |
|||
|
|||
/*! |
|||
* Returns true IFF the two Strings are equal. |
|||
*/ |
|||
static bool compareIgnoreCase(std::string const& A, std::string const& B) { |
|||
std::string stringA; |
|||
std::string stringB; |
|||
std::transform(A.begin(), A.end(), stringA.begin(), ::tolower); |
|||
std::transform(B.begin(), B.end(), stringB.begin(), ::tolower); |
|||
|
|||
return stringA.compare(stringB) == 0; |
|||
} |
|||
private: |
|||
StringHelper() {} |
|||
StringHelper(StringHelper& other) {} |
|||
~StringHelper() {} |
|||
}; |
|||
} |
|||
} |
|||
|
|||
#endif // STORM_UTILITY_STRINGHELPER_H_ |
Write
Preview
Loading…
Cancel
Save
Reference in new issue