Browse Source

Further big refactoring of option system.

Former-commit-id: 0567aa4421
tempestpy_adaptions
dehnert 10 years ago
parent
commit
18c0ee1f14
  1. 244
      src/settings/Argument.h
  2. 192
      src/settings/ArgumentBase.h
  3. 253
      src/settings/ArgumentBuilder.h
  4. 61
      src/settings/ArgumentType.h
  5. 163
      src/settings/ArgumentValidators.h
  6. 70
      src/settings/InternalOptionMemento.h
  7. 61
      src/settings/InternalSettingsMemento.h
  8. 302
      src/settings/Option.h
  9. 141
      src/settings/OptionBuilder.h
  10. 63
      src/utility/StringHelper.h

244
src/settings/Argument.h

@ -14,129 +14,99 @@
#include "src/settings/ArgumentBase.h"
#include "src/settings/ArgumentType.h"
#include "src/settings/ArgumentTypeInferationHelper.h"
#include "src/utility/StringHelper.h"
#include "src/exceptions/ExceptionMacros.h"
#include "src/exceptions/ArgumentUnificationException.h"
#include "src/exceptions/IllegalArgumentException.h"
#include "src/exceptions/IllegalArgumentValueException.h"
#include "src/exceptions/IllegalFunctionCallException.h"
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
extern log4cplus::Logger logger;
namespace storm {
namespace settings {
/*!
* This class subclasses the argument base to actually implement the pure virtual functions. This construction
* is necessary so that it becomes easy to store a vector of arguments later despite variing template types, by
* keeping a vector of pointers to the base class.
*/
template<typename T>
class Argument : public ArgumentBase {
public:
typedef std::function<bool (const T, std::string&)> userValidationFunction_t;
typedef T argumentType_t;
/*
T argumentValue;
ArgumentType argumentType;
std::vector<userValidationFunction_t> userValidationFunction;
T defaultValue;
bool hasDefaultValue;
// Introduce shortcuts for validation functions.
typedef std::function<bool (T const&)> userValidationFunction_t;
/*!
* Creates a new argument with the given parameters.
*
* @param name The name of the argument.
* @param description The description of the argument.
* @param validationFunctions A vector of validation functions that are to be executed upon assigning a value
* to this argument.
* @param isOptional A flag indicating whether the argument is optional.
*/
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) {
LOG4CPLUS_ERROR(logger, "Argument::Argument: The Argument \"" << argumentName << "\" is flaged as optional but no default value was given!");
throw storm::exceptions::IllegalArgumentException() << "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), defaultValue(defaultValue), hasDefaultValue(true) {
}
Argument(Argument const& other) : ArgumentBase(other.argumentName, other.argumentDescription, other.isOptional), argumentType(other.argumentType), defaultValue(other.defaultValue), hasDefaultValue(other.hasDefaultValue) {
this->userValidationFunction.reserve(other.userValidationFunction.size());
for (size_t i = 0; i < other.userValidationFunction.size(); ++i) {
this->userValidationFunction.push_back(userValidationFunction_t(other.userValidationFunction.at(i)));
}
}
virtual ~Argument() {
//LOG4CPLUS_DEBUG(logger, "Argument::~Argument: Destructing Argument \"" << this->getArgumentName() << "\" of Type " << ArgumentTypeHelper::toString(this->getArgumentType()));
this->userValidationFunction.clear();
this->argumentType = ArgumentType::Invalid;
Argument(std::string const& name, std::string const& description, std::vector<userValidationFunction_t> const& validationFunctions): ArgumentBase(name, description), argumentValue(), argumentType(ArgumentTypeInferation::inferToEnumType<T>()), validationFunctions(validationFunctions), isOptional(false), defaultValue(), hasDefaultValue(false) {
// Intentionally left empty.
}
/*!
* Creates a new argument with the given parameters.
*
* @param name The name of the argument.
* @param description The description of the argument.
* @param validationFunctions A vector of validation functions that are to be executed upon assigning a value
* to this argument.
* @param isOptional A flag indicating whether the argument is optional.
*/
Argument(std::string const& name, std::string const& description, std::vector<userValidationFunction_t> const& validationFunctions, bool isOptional, T defaultValue): ArgumentBase(argumentName, argumentDescription), argumentValue(), argumentType(ArgumentTypeInferation::inferToEnumType<T>()), validationFunctions(validationFunctions), isOptional(isOptional), defaultValue(defaultValue), hasDefaultValue(true) {
// Intentionally left empty.
}
virtual ArgumentBase* clone() const override {
return new Argument(*this);
virtual bool getIsOptional() const override {
return this->isOptional;
}
assignmentResult_t fromStringValue(std::string const& fromStringValue) override {
bool setFromStringValue(std::string const& fromStringValue) override {
bool conversionOk = false;
T newValue = this->convertFromString(fromStringValue, &conversionOk);
T newValue = ArgumentBase::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 false;
}
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);
bool setFromTypeValue(T const& newValue) {
if (!this->validate(newValue)) {
return false;
}
this->argumentValue = newValue;
this->hasBeenSet = true;
return std::make_pair(true, "Success");
return true;
}
virtual ArgumentType getArgumentType() const override {
virtual ArgumentType getType() const override {
return this->argumentType;
}
/*!
* Checks whether the given argument is compatible with the current one. If not, an exception is thrown.
*
* @param other The other argument with which to check compatibility.
* @return True iff the given argument is compatible with the current one.
*/
template <typename S>
void unify(Argument<S> &rhs) {
if (this->getArgumentType() != rhs.getArgumentType()) {
LOG4CPLUS_ERROR(logger, "Argument::unify: While unifying argument \"" << this->getArgumentName() << "\" and argument \"" << rhs.getArgumentName() << "\": Types do not match (\"" << ArgumentTypeHelper::toString(this->getArgumentType()) << "\" and \"" << ArgumentTypeHelper::toString(rhs.getArgumentType()) << "\").");
throw storm::exceptions::ArgumentUnificationException() << "While unifying Argument \"" << this->getArgumentName() << "\" and argument \"" << rhs.getArgumentName() << "\": Types do not match (\"" << ArgumentTypeHelper::toString(this->getArgumentType()) << "\" and \"" << ArgumentTypeHelper::toString(rhs.getArgumentType()) << "\").";
}
if (this->getIsOptional() != rhs.getIsOptional()) {
LOG4CPLUS_ERROR(logger, "Argument::unify: While unifying argument \"" << this->getArgumentName() << "\" and argument \"" << rhs.getArgumentName() << "\": Both must either be optional or non-optional.");
throw storm::exceptions::ArgumentUnificationException() << "While unifying argument \"" << this->getArgumentName() << "\" and argument \"" << rhs.getArgumentName() << "\": Both must either be optional or non-optional.";
}
if (this->getHasDefaultValue() != rhs.getHasDefaultValue()) {
LOG4CPLUS_ERROR(logger, "Argument::unify: While unifying argument \"" << this->getArgumentName() << "\" and argument \"" << rhs.getArgumentName() << "\": Mismatching default values.");
throw storm::exceptions::ArgumentUnificationException() << "While unifying argument \"" << this->getArgumentName() << "\" and argument \"" << rhs.getArgumentName() << "\": Mismatching default values.";
}
if (this->getArgumentDescription().compare(rhs.getArgumentDescription()) != 0) {
LOG4CPLUS_WARN(logger, "Argument::unify: While unifying argument \"" << this->getArgumentName() << "\" and argument \"" << rhs.getArgumentName() << "\": Mismatching descriptions.");
}
if (this->getArgumentName().compare(rhs.getArgumentName()) != 0) {
LOG4CPLUS_WARN(logger, "Argument::unify: While unifying argument \"" << this->getArgumentName() << "\" and argument \"" << rhs.getArgumentName() << "\": Mismatching descriptions.");
bool isCompatibleWith(Argument<S> const& other) {
LOG_THROW(this->getArgumentType() == other.getArgumentType(), storm::exceptions::ArgumentUnificationException, "Unable to unify the arguments " << this->getArgumentName() << " and " << other.getArgumentName() << ", because they have different types.");
LOG_THROW(this->getIsOptional() != other.getIsOptional(), storm::exceptions::ArgumentUnificationException, "Unable to unify the arguments " << this->getArgumentName() << " and " << other.getArgumentName() << ", because one of them is optional and the other one is not.");
LOG_THROW(this->getHasDefaultValue() != other.getHasDefaultValue(), storm::exceptions::ArgumentUnificationException, "Unable to unify the arguments " << this->getArgumentName() << " and " << other.getArgumentName() << ", because one of them has a default value and the other one does not.");
return true;
}
// 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()) {
LOG4CPLUS_ERROR(logger, "Argument::getArgumentValue: Unable to retrieve argument of option \"" << this->getArgumentName() << "\", because it was never set and does not specify a default value.");
throw storm::exceptions::IllegalFunctionCallException() << "Unable to retrieve argument of option \"" << this->getArgumentName() << "\", because it was never set and does not specify a default value.";
}
/*!
* Retrieves the value of the argument if any has been set. Otherwise, an exception is thrown.
*
* @return The value of the argument.
*/
T const& getArgumentValue() const {
LOG_THROW(this->getHasBeenSet(), storm::exceptions::IllegalFunctionCallException, "Unable to retrieve value of argument, because it was not set.");
return this->argumentValue;
}
@ -144,21 +114,10 @@ namespace storm {
return this->hasDefaultValue;
}
std::string const& getDefaultValue() {
return this->defaultValue;
}
void setFromDefaultValue() override {
if (!this->hasDefaultValue) {
LOG4CPLUS_ERROR(logger, "Argument::setFromDefaultValue: Unable to retrieve default value for argument \"" << this->getArgumentName() << "\" (" << this->getArgumentDescription() << ").");
throw storm::exceptions::IllegalFunctionCallException() << "Unable to retrieve default value for argument \"" << this->getArgumentName() << "\" (" << this->getArgumentDescription() << ").";
}
// this call also sets the hasBeenSet flag
assignmentResult_t result = this->fromTypeValue(this->defaultValue);
if (!result.first) {
LOG4CPLUS_ERROR(logger, "Argument::setFromDefaultValue: Unable to assign default value to argument \"" << this->getArgumentName() << "\" (" << this->getArgumentDescription() << "), because default value was rejected (" << result.second << ").");
throw storm::exceptions::IllegalArgumentValueException() << "Unable to assign default value to argument \"" << this->getArgumentName() << "\" (" << this->getArgumentDescription() << "), because default value was rejected (" << result.second << ").";
}
LOG_THROW(this->hasDefaultValue, storm::exceptions::IllegalFunctionCallException, "Unable to set value from default value, because the argument has none.");
bool result = this->setFromTypeValue(this->defaultValue);
LOG_THROW(result, storm::exceptions::IllegalArgumentValueException, "Unable to assign default value to argument, because it was rejected.");
}
virtual std::string getValueAsString() const override {
@ -172,11 +131,8 @@ namespace storm {
} else {
return "false";
}
}
default:
return this->convertToString(this->argumentValue);
default: return ArgumentBase::convertToString(this->argumentValue);
}
}
@ -184,89 +140,77 @@ namespace storm {
switch (this->argumentType) {
case ArgumentType::Integer:
return ArgumentTypeInferation::inferToInteger(ArgumentType::Integer, this->getArgumentValue());
default: {
LOG4CPLUS_ERROR(logger, "Argument::getValueAsInteger(): Unable to retrieve value of argument \"" << getArgumentName() << "\" of type \"" << ArgumentTypeHelper::toString(getArgumentType()) << "\" as integer.");
throw storm::exceptions::IllegalFunctionCallException() << "Unable to retrieve value of argument \"" << getArgumentName() << "\" of type \"" << ArgumentTypeHelper::toString(getArgumentType()) << "\" as integer.";
}
default: LOG_THROW(false, storm::exceptions::IllegalFunctionCallException, "Unable to retrieve argument value as integer."); break;
}
}
virtual uint_fast64_t getValueAsUnsignedInteger() const override {
switch (this->argumentType) {
case ArgumentType::UnsignedInteger:
return ArgumentTypeInferation::inferToUnsignedInteger(ArgumentType::UnsignedInteger, this->getArgumentValue());
default: {
LOG4CPLUS_ERROR(logger, "Argument::getValueAsUnsignedInteger(): Unable to retrieve value of argument \"" << getArgumentName() << "\" of type \"" << ArgumentTypeHelper::toString(getArgumentType()) << "\" as unsigned integer.");
throw storm::exceptions::IllegalFunctionCallException() << "Unable to retrieve value of argument \"" << getArgumentName() << "\" of type \"" << ArgumentTypeHelper::toString(getArgumentType()) << "\" as unsigned integer.";
}
default: LOG_THROW(false, storm::exceptions::IllegalFunctionCallException, "Unable to retrieve argument value as unsigned integer."); break;
}
}
virtual double getValueAsDouble() const override {
switch (this->argumentType) {
case ArgumentType::Double:
return ArgumentTypeInferation::inferToDouble(ArgumentType::Double, this->getArgumentValue());
default: {
LOG4CPLUS_ERROR(logger, "Argument::getValueAsDouble(): Unable to retrieve value of argument \"" << getArgumentName() << "\" of type \"" << ArgumentTypeHelper::toString(getArgumentType()) << "\" as double.");
throw storm::exceptions::IllegalFunctionCallException() << "Unable to retrieve value of argument \"" << getArgumentName() << "\" of type \"" << ArgumentTypeHelper::toString(getArgumentType()) << "\" as double.";
}
default: LOG_THROW(false, storm::exceptions::IllegalFunctionCallException, "Unable to retrieve argument value as double."); break;
}
}
virtual bool getValueAsBoolean() const override {
switch (this->argumentType) {
case ArgumentType::Boolean:
return ArgumentTypeInferation::inferToBoolean(ArgumentType::Boolean, this->getArgumentValue());
default: {
LOG4CPLUS_ERROR(logger, "Argument::getValueAsBoolean(): Unable to retrieve value of argument \"" << getArgumentName() << "\" of type \"" << ArgumentTypeHelper::toString(getArgumentType()) << "\" as boolean.");
throw storm::exceptions::IllegalFunctionCallException() << "Unable to retrieve value of argument \"" << getArgumentName() << "\" of type \"" << ArgumentTypeHelper::toString(getArgumentType()) << "\" as boolean.";
}
default: LOG_THROW(false, storm::exceptions::IllegalFunctionCallException, "Unable to retrieve argument value as boolean."); break;
}
}
private:
// The value of the argument (in case it has been set).
T argumentValue;
// The type of the argument.
ArgumentType argumentType;
std::vector<userValidationFunction_t> userValidationFunction;
// The validation functions that were registered for this argument.
std::vector<userValidationFunction_t> validationFunctions;
// A flag indicating whether this argument is optional.
bool isOptional;
// The default value for the argument (in case one has been provided).
T defaultValue;
// A flag indicating whether a default value has been provided.
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.
LOG4CPLUS_ERROR(logger, "Argument::setDefaultValue: Illegal default value for argument \"" << this->getArgumentName() << "\"." << std::endl << "The validation function rejected the value (" << errorText << ").");
throw storm::exceptions::IllegalArgumentValueException() << "Illegal default value for argument \"" << this->getArgumentName() << "\". The validation function rejected the value (" << errorText << ").";
}
LOG_THROW(this->validate(newDefault), storm::exceptions::IllegalArgumentValueException, "The default value for the argument did not pass all validation functions.");
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 {
/*!
* Applies all validation functions to the given value and therefore checks the validity of a value for this
* argument.
*
* @param value The value that is to be validated.
* @return True iff the value passed all validation functions successfully.
*/
bool validate(T const& value) const {
bool result = true;
for (auto lambda: this->userValidationFunction) {
result = result && lambda(value, errorMessageTarget);
for (auto const& lambda : validationFunctions) {
result = result && lambda(value);
}
return result;
}
};
}
}

192
src/settings/ArgumentBase.h

@ -3,111 +3,187 @@
#include <iostream>
#include <string>
#include <boost/algorithm/string.hpp>
#include "ArgumentType.h"
#include "src/utility/StringHelper.h"
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
extern log4cplus::Logger logger;
#include "src/settings/ArgumentType.h"
namespace storm {
namespace settings {
typedef std::pair<bool, std::string> assignmentResult_t;
/*!
* This class serves as the (untemplated) base class of argument classes.
*/
class ArgumentBase {
public:
ArgumentBase(std::string const& argumentName, std::string const& argumentDescription, bool isOptional) : isOptional(isOptional), hasBeenSet(false), argumentName(argumentName), argumentDescription(argumentDescription) {}
virtual ~ArgumentBase() {
//LOG4CPLUS_DEBUG(logger, "ArgumentBase::~ArgumentBase: Destructing ArgumentBase \"" << this->getArgumentName() << "\"");
}
virtual ArgumentType getArgumentType() const = 0;
virtual bool getIsOptional() const {
return this->isOptional;
/*!
* Constructs a new argument base with the given name, description and indication whether the argument is
* optional.
*
* @param name The name of the argument.
* @param description A description of the argument.
* @param isOptional A flag indicating whether the argument is optional.
*/
ArgumentBase(std::string const& name, std::string const& description) : hasBeenSet(false), name(name), description(description) {
// Intentionally left empty.
}
std::string const& getArgumentName() const {
return this->argumentName;
/*!
* Retrieves the type of the argument.
*
* @return The type of the argument.
*/
virtual ArgumentType getType() const = 0;
/*!
* Retrieves whether the argument is optional.
*
* @return True iff the argument is optional.
*/
virtual bool getIsOptional() const = 0;
/*!
* Retrieves the name of the argument.
*
* @return The name of the argument.
*/
std::string const& getName() const {
return this->name;
}
std::string const& getArgumentDescription() const {
return this->argumentDescription;
/*!
* Retrieves the description of the argument.
*
* @return The description of the argument.
*/
std::string const& getDescription() const {
return this->description;
}
/*!
* Retrieves whether the argument has a default value.
*
* @return True iff the argument has a default value.
*/
virtual bool getHasDefaultValue() const = 0;
/*!
* Retrieves whether the argument has been set.
*
* @return True iff the argument has been set.
*/
virtual bool getHasBeenSet() const {
return this->hasBeenSet;
}
/*!
* Sets the value of the argument from the default value.
*/
virtual void setFromDefaultValue() = 0;
virtual assignmentResult_t fromStringValue(std::string const& fromStringValue) = 0;
virtual ArgumentBase* clone() const = 0;
/*!
* Tries to set the value of the argument from the given string.
*
* @param stringValue The new value of the argument given as a string.
* @return True iff the assignment was successful.
*/
virtual bool setFromStringValue(std::string const& stringValue) = 0;
/*!
* Retrieves the value of this argument as a string.
*
* @return The value of this argument as a string.
*/
virtual std::string getValueAsString() const = 0;
/*!
* Retrieves the value of this argument as an integer. If the conversion cannot be performed, an exception
* is thrown.
*
* @return The value of this argument as an integer.
*/
virtual int_fast64_t getValueAsInteger() const = 0;
/*!
* Retrieves the value of this argument as an unsigned integer. If the conversion cannot be performed, an
* exception is thrown.
*
* @return The value of this argument as an unsigned integer.
*/
virtual uint_fast64_t getValueAsUnsignedInteger() const = 0;
/*!
* Retrieves the value of this argument as a double. If the conversion cannot be performed, an exception
* is thrown.
*
* @return The value of this argument as an double.
*/
virtual double getValueAsDouble() const = 0;
/*!
* Retrieves the value of this argument as a boolean. If the conversion cannot be performed, an exception
* is thrown.
*
* @return The value of this argument as an boolean.
*/
virtual bool getValueAsBoolean() const = 0;
protected:
bool isOptional;
// A flag indicating whether the argument has been set.
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;
}
// The name of the argument.
std::string name;
// The description of the argument.
std::string description;
/*!
* Converts the given value represented as a string to the type of the template parameter. The second
* is used to signal that the conversion was successful (or not).
*
* @param valueAsString The value to convert.
* @param conversionSuccessful After a call to this function returned, the supplied boolean indicates
* whether the conversion was successful.
*/
template <typename TargetType>
static TargetType convertFromString(std::string const& valueAsString, bool& conversionSuccessful) {
std::istringstream stream(valueAsString);
TargetType t;
conversionSuccessful = (stream >> t) && (stream >> std::ws).eof();
return t;
}
template <> inline bool ArgumentBase::ArgumentHelper::convertFromString<bool>(std::string const& s, bool* ok) {
template <>
static bool 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);
std::string lowerInput = boost::algorithm::to_lower_copy(s);
if (s.compare(lowerTrueString) == 0 || s.compare(lowerYesString) == 0) {
if (ok != nullptr) {
*ok = true;
}
ok = true;
return true;
} else if (s.compare(lowerFalseString) == 0 || s.compare(lowerNoString) == 0) {
if (ok != nullptr) {
*ok = true;
}
ok = true;
return false;
}
std::istringstream stream(s);
bool t;
if (ok != nullptr) {
*ok = (stream >> t) && (stream >> std::ws).eof();
} else {
stream >> t;
}
ok = (stream >> t) && (stream >> std::ws).eof();
return t;
}
template <typename ValueType>
std::string convertToString(ValueType const& value) const {
std::ostringstream stream;
stream << value;
return stream.str();
}
};
}
}

253
src/settings/ArgumentBuilder.h

@ -11,84 +11,104 @@
#include <memory>
#include <string>
#include "ArgumentType.h"
#include "ArgumentTypeInferationHelper.h"
#include "ArgumentBase.h"
#include "Argument.h"
#include "ArgumentValidators.h"
#include "src/settings/ArgumentType.h"
#include "src/settings/ArgumentTypeInferationHelper.h"
#include "src/settings/ArgumentBase.h"
#include "src/settings/Argument.h"
#include "src/settings/ArgumentValidators.h"
#include "src/exceptions/ExceptionMacros.h"
#include "src/exceptions/IllegalFunctionCallException.h"
#include "src/exceptions/IllegalArgumentTypeException.h"
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
extern log4cplus::Logger logger;
namespace storm {
namespace settings {
/*!
* This class serves as an API for creating arguments.
*/
class ArgumentBuilder {
public:
~ArgumentBuilder() {}
/*
Preparation Functions for all ArgumentType's
Resets all internal attributes
/*!
* Creates a string argument with the given parameters.
*
* @param name The name of the argument.
* @param description The description of the argument.
* @return The builder of the argument.
*/
static ArgumentBuilder createStringArgument(std::string const& argumentName, std::string const& argumentDescription) {
ArgumentBuilder ab(ArgumentType::String, argumentName, argumentDescription);
static ArgumentBuilder createStringArgument(std::string const& name, std::string const& description) {
ArgumentBuilder ab(ArgumentType::String, name, argumentDescription);
return ab;
}
static ArgumentBuilder createIntegerArgument(std::string const& argumentName, std::string const& argumentDescription) {
ArgumentBuilder ab(ArgumentType::Integer, argumentName, argumentDescription);
/*!
* Creates an integer argument with the given parameters.
*
* @param name The name of the argument.
* @param description The description of the argument.
* @return The builder of the argument.
*/
static ArgumentBuilder createIntegerArgument(std::string const& name, std::string const& description) {
ArgumentBuilder ab(ArgumentType::Integer, name, description);
return ab;
}
static ArgumentBuilder createUnsignedIntegerArgument(std::string const& argumentName, std::string const& argumentDescription) {
ArgumentBuilder ab(ArgumentType::UnsignedInteger, argumentName, argumentDescription);
/*!
* Creates an unsigned integer argument with the given parameters.
*
* @param name The name of the argument.
* @param description The description of the argument.
* @return The builder of the argument.
*/
static ArgumentBuilder createUnsignedIntegerArgument(std::string const& name, std::string const& description) {
ArgumentBuilder ab(ArgumentType::UnsignedInteger, name, description);
return ab;
}
static ArgumentBuilder createDoubleArgument(std::string const& argumentName, std::string const& argumentDescription) {
ArgumentBuilder ab(ArgumentType::Double, argumentName, argumentDescription);
/*!
* Creates a double argument with the given parameters.
*
* @param name The name of the argument.
* @param description The description of the argument.
* @return The builder of the argument.
*/
static ArgumentBuilder createDoubleArgument(std::string const& name, std::string const& description) {
ArgumentBuilder ab(ArgumentType::Double, name, description);
return ab;
}
static ArgumentBuilder createBooleanArgument(std::string const& argumentName, std::string const& argumentDescription) {
ArgumentBuilder ab(ArgumentType::Boolean, argumentName, argumentDescription);
/*!
* Creates a boolean argument with the given parameters.
*
* @param name The name of the argument.
* @param description The description of the argument.
* @return The builder of the argument.
*/
static ArgumentBuilder createBooleanArgument(std::string const& name, std::string const& description) {
ArgumentBuilder ab(ArgumentType::Boolean, name, description);
return ab;
}
ArgumentBuilder& setName(std::string const& newName) {
this->argumentName = newName;
return *this;
}
ArgumentBuilder& setDescription(std::string const& newDescription) {
this->argumentDescription = newDescription;
return *this;
}
/*!
* Sets whether the argument is to be optional.
*
* @param isOptional A flag that indicates whether the argument is to be optional.
* @return A reference to the argument builder.
*/
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() << "Unable to add a validation function for a \"" << ArgumentTypeHelper::toString(ArgumentType::funcName) << "\" argument, because this argument is of type \"" << ArgumentTypeHelper::toString(this->argumentType) << "\"."; \
} \
LOG_THROW(this->argumentType == ArgumentType::funcName, storm::exceptions::IllegalFunctionCallException, "Illegal validation function for argument, because it takes arguments of different type.") \
( PPCAT(this->userValidationFunction_, funcName) ).push_back(userValidationFunction); \
std::string errorMessageTarget = ""; \
if (this->hasDefaultValue && !this->validateDefaultForEach(errorMessageTarget)) { \
throw storm::exceptions::IllegalArgumentValueException() << "Unable to add a validation function for an argument that has a default value which is rejected by this validation function:\r\n" << errorMessageTarget << "."; \
} \
return *this; \
}
// Add the methods to add validation functions.
MACROaddValidationFunction(String, std::string)
MACROaddValidationFunction(Integer, int_fast64_t)
MACROaddValidationFunction(UnsignedInteger, uint_fast64_t)
@ -97,161 +117,110 @@ namespace storm {
#define MACROsetDefaultValue(funcName, funcType) ArgumentBuilder& PPCAT(setDefaultValue, funcName) (funcType const& defaultValue) { \
if (this->argumentType != ArgumentType::funcName) { \
throw storm::exceptions::IllegalFunctionCallException() << "Unable to add a default value for a \"" << ArgumentTypeHelper::toString(ArgumentType::String) << "\" argument, because the argument \"" << this->argumentName << "\" is of type \"" << ArgumentTypeHelper::toString(this->argumentType) << "\"."; \
} \
LOG_THROW(this->argumentType == ArgumentType::funcName, storm::exceptions::IllegalFunctionCallException, "Illegal default value for argument" << this->argumentName << ", because it is of different type.") \
PPCAT(this->defaultValue_, funcName) = defaultValue; \
std::string errorMessageTarget = ""; \
if (!this->validateDefaultForEach(errorMessageTarget)) { \
throw storm::exceptions::IllegalArgumentValueException() << "Unable to add a default value for the argument \"" << this->argumentName << "\", but a validation function rejected it:\r\n" << errorMessageTarget << "."; \
} \
this->hasDefaultValue = true; \
return *this; \
}
// Add the methods to set a default value.
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) {
throw storm::exceptions::IllegalFunctionCallException() << "Called build() on an instance of ArgumentBuilder that has already built an instance.";
}
this->hasBeenBuild = true;
/*!
* Builds an argument based on the information that was added to the builder object.
*
* @return The resulting argument.
*/
std::shared_ptr<ArgumentBase> build() {
LOG_THROW(!this->hasBeenBuilt, storm::exceptions::IllegalFunctionCallException, "Cannot rebuild argument with builder that was already used to build an argument.");
this->hasBeenBuilt = 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));
return std::shared_ptr<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));
return std::shared_ptr<ArgumentBase>(new Argument<std::string>(this->argumentName, this->argumentDescription, userValidationFunction_String));
}
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));
return std::shared_ptr<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));
return std::shared_ptr<ArgumentBase>(new Argument<int_fast64_t>(this->argumentName, this->argumentDescription, userValidationFunction_Integer));
}
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));
return std::shared_ptr<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));
return std::shared_ptr<ArgumentBase>(new Argument<uint_fast64_t>(this->argumentName, this->argumentDescription, userValidationFunction_UnsignedInteger));
}
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));
return std::shared_ptr<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));
return std::shared_ptr<ArgumentBase>(new Argument<double>(this->argumentName, this->argumentDescription, userValidationFunction_Double));
}
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));
return std::shared_ptr<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));
return std::shared_ptr<ArgumentBase>(new Argument<bool>(this->argumentName, this->argumentDescription, userValidationFunction_Boolean));
}
break;
default: {
throw storm::exceptions::InternalTypeErrorException() << "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 (uint_fast64_t 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 (uint_fast64_t 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 (uint_fast64_t 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 (uint_fast64_t i = 0; i < userValidationFunction_Double.size(); ++i) {
this->userValidationFunction_Double.push_back(storm::settings::Argument<double>::userValidationFunction_t(other.userValidationFunction_Double.at(i)));
}
for (uint_fast64_t i = 0; i < userValidationFunction_Boolean.size(); ++i) {
this->userValidationFunction_Boolean.push_back(storm::settings::Argument<bool>::userValidationFunction_t(other.userValidationFunction_Boolean.at(i)));
}
/*!
* Creates an argument builder for an argument with the given parameters.
*
* @param type The type of the argument.
* @param name The name of the argument.
* @param description The description of the argument.
*/
ArgumentBuilder(ArgumentType type, std::string const& name, std::string const& description) : hasBeenBuilt(false), type(type), name(name), description(description), isOptional(false), hasDefaultValue(false), defaultValue_String(), defaultValue_Integer(), defaultValue_UnsignedInteger(), defaultValue_Double(), defaultValue_Boolean(), userValidationFunctions_String(), userValidationFunctions_Integer(), userValidationFunctions_UnsignedInteger(), userValidationFunctions_Double(), userValidationFunctions_Boolean() {
// Intentionally left empty.
}
bool hasBeenBuild;
// A flag that stores whether an argument has been built using this builder.
bool hasBeenBuilt;
ArgumentType argumentType;
// The type of the argument.
ArgumentType type;
std::string argumentName;
std::string argumentDescription;
// The name of te argument.
std::string name;
/*
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;
// The description of the argument.
std::string description;
// A flag indicating whether the argument is optional.
bool isOptional;
// A flag that stores whether the argument has a default value.
bool hasDefaultValue;
// The default value of the argument separated by its type.
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: {
throw storm::exceptions::InternalTypeErrorException() << "Missing case in ArgumentBuilder.";
}
}
return result;
}
// The validation functions separated by their type.
std::vector<storm::settings::Argument<std::string>::userValidationFunction_t> userValidationFunctions_String;
std::vector<storm::settings::Argument<int_fast64_t>::userValidationFunction_t> userValidationFunctions_Integer;
std::vector<storm::settings::Argument<uint_fast64_t>::userValidationFunction_t> userValidationFunctions_UnsignedInteger;
std::vector<storm::settings::Argument<double>::userValidationFunction_t> userValidationFunctions_Double;
std::vector<storm::settings::Argument<bool>::userValidationFunction_t> userValidationFunctions_Boolean;
};
}
}

61
src/settings/ArgumentType.h

@ -1,58 +1,33 @@
#ifndef STORM_SETTINGS_ARGUMENTTYPE_H_
#define STORM_SETTINGS_ARGUMENTTYPE_H_
#include "src/exceptions/InternalTypeErrorException.h"
#include <iostream>
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
extern log4cplus::Logger logger;
#include "src/exceptions/ExceptionMacros.h"
namespace storm {
namespace settings {
/*!
* This enum captures all possible types for arguments.
*/
enum class ArgumentType {
Invalid, String, Integer, UnsignedInteger, Double, Boolean
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";
std::ostream& operator<<(std::ostream& out, ArgumentType& argumentType) {
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: {
LOG4CPLUS_ERROR(logger, "ArgumentTypeHelper::toString: Missing case in ArgumentTypeHelper.");
throw storm::exceptions::InternalTypeErrorException() << "Missing case in ArgumentTypeHelper.";
}
}
}
private:
ArgumentTypeHelper() {}
~ArgumentTypeHelper() {}
};
case ArgumentType::String: out << "string"; break;
case ArgumentType::Integer: out << "integer"; break;
case ArgumentType::UnsignedInteger: out << "unsigned integer"; break;
case ArgumentType::Double: out << "double"; break;
case ArgumentType::Boolean: out << "boolean"; break;
}
return out;
}
} // namespace settings
} // namespace storm
#endif // STORM_SETTINGS_ARGUMENTTYPE_H_

163
src/settings/ArgumentValidators.h

@ -11,110 +11,143 @@
#include <memory>
#include <string>
#include "Argument.h"
#include "src/settings/Argument.h"
namespace storm {
namespace settings {
class ArgumentValidators {
public:
// Integer - int_fast64_t
static std::function<bool (int_fast64_t const, std::string&)> integerRangeValidatorIncluding(int_fast64_t const lowerBound, int_fast64_t const upperBound) {
/*!
* Creates a validation function that checks whether an integer is in the given range (including the bounds).
*
* @param lowerBound The lower bound of the valid range.
* @param upperBound The upper bound of the valid range.
* @return The resulting validation function.
*/
static std::function<bool (int_fast64_t const&)> integerRangeValidatorIncluding(int_fast64_t const lowerBound, int_fast64_t const upperBound) {
return rangeValidatorIncluding<int_fast64_t>(lowerBound, upperBound);
}
static std::function<bool (int_fast64_t const, std::string&)> integerRangeValidatorExcluding(int_fast64_t const lowerBound, int_fast64_t const upperBound) {
/*!
* Creates a validation function that checks whether an integer is in the given range (excluding the bounds).
*
* @param lowerBound The lower bound of the valid range.
* @param upperBound The upper bound of the valid range.
* @return The resulting validation function.
*/
static std::function<bool (int_fast64_t const&)> integerRangeValidatorExcluding(int_fast64_t const lowerBound, int_fast64_t const upperBound) {
return rangeValidatorExcluding<int_fast64_t>(lowerBound, upperBound);
}
// UnsignedInteger - uint_fast64_t
static std::function<bool (uint_fast64_t const, std::string&)> unsignedIntegerRangeValidatorIncluding(uint_fast64_t const lowerBound, uint_fast64_t const upperBound) {
/*!
* Creates a validation function that checks whether an unsigned integer is in the given range (including the bounds).
*
* @param lowerBound The lower bound of the valid range.
* @param upperBound The upper bound of the valid range.
* @return The resulting validation function.
*/
static std::function<bool (uint_fast64_t const&)> unsignedIntegerRangeValidatorIncluding(uint_fast64_t const lowerBound, uint_fast64_t const upperBound) {
return rangeValidatorIncluding<uint_fast64_t>(lowerBound, upperBound);
}
static std::function<bool (uint_fast64_t const, std::string&)> unsignedIntegerRangeValidatorExcluding(uint_fast64_t const lowerBound, uint_fast64_t const upperBound) {
/*!
* Creates a validation function that checks whether an unsigned integer is in the given range (excluding the bounds).
*
* @param lowerBound The lower bound of the valid range.
* @param upperBound The upper bound of the valid range.
* @return The resulting validation function.
*/
static std::function<bool (uint_fast64_t const&)> unsignedIntegerRangeValidatorExcluding(uint_fast64_t const lowerBound, uint_fast64_t const upperBound) {
return rangeValidatorExcluding<uint_fast64_t>(lowerBound, upperBound);
}
// Double - double
static std::function<bool (double const, std::string&)> doubleRangeValidatorIncluding(double const lowerBound, double const upperBound) {
/*!
* Creates a validation function that checks whether a double is in the given range (including the bounds).
*
* @param lowerBound The lower bound of the valid range.
* @param upperBound The upper bound of the valid range.
* @return The resulting validation function.
*/
static std::function<bool (double const&)> doubleRangeValidatorIncluding(double const lowerBound, double const upperBound) {
return rangeValidatorIncluding<double>(lowerBound, upperBound);
}
static std::function<bool (double const, std::string&)> doubleRangeValidatorExcluding(double const lowerBound, double const upperBound) {
/*!
* Creates a validation function that checks whether a double is in the given range (excluding the bounds).
*
* @param lowerBound The lower bound of the valid range.
* @param upperBound The upper bound of the valid range.
* @return The resulting validation function.
*/
static std::function<bool (double const&)> doubleRangeValidatorExcluding(double const lowerBound, double const upperBound) {
return rangeValidatorExcluding<double>(lowerBound, upperBound);
}
static std::function<bool (std::string const, std::string&)> existingReadableFileValidator() {
return [] (std::string const fileName, std::string& errorMessageTarget) -> bool {
/*!
* Creates a validation function that checks whether a given string corresponds to an existing and readable
* file.
*
* @return The resulting validation function.
*/
static std::function<bool (std::string const&)> existingReadableFileValidator() {
return [] (std::string const fileName) -> bool {
std::ifstream targetFile(fileName);
bool isFileGood = targetFile.good();
if (!isFileGood) {
std::ostringstream stream;
stream << "Given file does not exist or is not readable by this process: \"" << fileName << "\"" << std::endl;
errorMessageTarget.append(stream.str());
}
LOG_THROW(isFileGood, storm::exceptions::IllegalArgumentValueException, "The file " << fileName << " does not exist or is not readable.");
return isFileGood;
};
}
static std::function<bool (std::string const, std::string&)> stringInListValidator(std::vector<std::string> list) {
return [list] (std::string const inputString, std::string& errorMessageTarget) -> bool {
std::string const lowerInputString = storm::utility::StringHelper::stringToLower(inputString);
for (auto it = list.cbegin(); it != list.cend(); ++it) {
if (storm::utility::StringHelper::stringToLower(*it).compare(lowerInputString) == 0) {
/*!
* Creates a validation function that checks whether a given string is in a provided list of strings.
*
* @param list The list of valid strings.
* @return The resulting validation function.
*/
static std::function<bool (std::string const&)> stringInListValidator(std::vector<std::string> const& list) {
return [list] (std::string const inputString) -> bool {
std::string lowerInputString = boost::algorithm::to_lower_copy(inputString);
for (auto const& validString : list) {
std::string lowerValidString = boost::algorithm::to_lower_copy(validString);
if (lowerInputString == lowerValidString) {
return true;
}
}
std::ostringstream stream;
stream << "The given Input \"" << inputString << "\" is not in the list of valid Items (";
bool first = true;
for (auto it = list.cbegin(); it != list.cend(); ++it) {
if (!first) {
stream << ", ";
}
stream << *it;
first = false;
}
stream << ")" << std::endl;
errorMessageTarget.append(stream.str());
LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Value " << inputString << " does not match any entry in the list of valid items.");
return false;
};
}
private:
/*!
* Creates a validation function that checks whether its argument is in a given range (including the bounds).
*
* @param lowerBound The lower bound of the valid range.
* @param upperBound The upper bound of the valid range.
* @return The resulting validation function.
*/
template<typename 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 smaller or equal than " << value << ".";
errorMessageTarget.append(stream.str());
}
if (!upperBoundCondition) {
std::ostringstream stream;
stream << " upper bound condition not met: " << value << " is not smaller or equal than " << upperBound << ".";
errorMessageTarget.append(stream.str());
}
return (lowerBoundCondition && upperBoundCondition);
static std::function<bool (T const)> rangeValidatorIncluding(T const lowerBound, T const upperBound) {
return std::bind([](T const& lowerBound, T const& upperBound, T const& value) -> bool {
LOG_THROW(lowerBound <= value && value <= upperBound, storm::exceptions::InvalidArgumentException, "Value " << value " is out range.");
return true;
}, lowerBound, upperBound, std::placeholders::_1, std::placeholders::_2);
}
/*!
* Creates a validation function that checks whether its argument is in a given range (excluding the bounds).
*
* @param lowerBound The lower bound of the valid range.
* @param upperBound The upper bound of the valid range.
* @return The resulting validation function.
*/
template<typename 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 smaller than " << value << ".";
errorMessageTarget.append(stream.str());
}
if (!upperBoundCondition) {
std::ostringstream stream;
stream << " upper bound condition not met: " << value << " is not smaller than < " << upperBound << ".";
errorMessageTarget.append(stream.str());
}
return (lowerBoundCondition && upperBoundCondition);
static std::function<bool (T const)> rangeValidatorExcluding(T const& lowerBound, T const& upperBound) {
return std::bind([](T const& lowerBound, T const& upperBound, T const& value) -> bool {
LOG_THROW(lowerBound < value && value < upperBound, storm::exceptions::InvalidArgumentException, "Value " << value " is out range.");
return true;
}, lowerBound, upperBound, std::placeholders::_1, std::placeholders::_2);
}
};

70
src/settings/InternalOptionMemento.h

@ -1,70 +0,0 @@
#ifndef STORM_SETTINGS_INTERNALOPTIONMEMENTO_H_
#define STORM_SETTINGS_INTERNALOPTIONMEMENTO_H_
#include "src/settings/SettingsManager.h"
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
extern log4cplus::Logger logger;
namespace storm {
namespace settings {
/*!
* @brief THIS CLASS IS FOR INTERNAL USE IN THE TESTS ONLY
*
*
* If an option is required to be set when executing a test
* the test may instantiate an Object of this class while the
* test itself is executed.
*
* This class ensures that the option has the requested value
* and resets it to its previous value as soon as its destructor
* is called.
*/
class InternalOptionMemento {
public:
/*!
* @brief The constructor.
*
* @param
*/
InternalOptionMemento(std::string const& longOptionName, bool requiredHasBeenSetState): instance(storm::settings::SettingsManager::getInstance()), optionName(longOptionName), stateRequired(requiredHasBeenSetState) {
this->stateBefore = instance->isSet(optionName);
if (stateRequired) {
instance->set(optionName);
} else {
instance->unset(optionName);
}
}
/*!
* @brief The destructor.
*
* Resets the Options state to its previous state
*/
virtual ~InternalOptionMemento() {
// Reset the state of the Option
if (stateBefore) {
instance->set(optionName);
} else {
instance->unset(optionName);
}
this->instance = nullptr;
}
private:
storm::settings::SettingsManager* instance;
std::string const optionName;
bool stateBefore;
bool stateRequired;
InternalOptionMemento(InternalOptionMemento& other) {}
};
} // namespace settings
} // namespace storm
#endif // STORM_SETTINGS_INTERNALOPTIONMEMENTO_H_

61
src/settings/InternalSettingsMemento.h

@ -0,0 +1,61 @@
#ifndef STORM_SETTINGS_INTERNALSETTINGMEMENTO_H_
#define STORM_SETTINGS_INTERNALSETTINGMEMENTO_H_
#include "src/settings/SettingsManager.h"
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
extern log4cplus::Logger logger;
namespace storm {
namespace settings {
/*!
* NOTE: THIS CLASS IS FOR INTERNAL USE IN THE TESTS ONLY.
*
* If an option is required to be set when executing a test the test may instantiate an object of this class
* while the test itself is executed. This object then ensures that the option has the requested value and
* resets it to its previous value as soon as its destructor is called.
*/
class InternalSettingMemento {
public:
/*!
* Constructs a new memento for the specified option.
*
* @param moduleName The name of the module that registered the option.
* @param longOptionName The long name of the option.
* @param requiredHasBeenSetState A flag that indicates whether the setting is to be temporarily set to
* true or false.
*/
InternalOptionMemento(std::string const& moduleName, std::string const& longOptionName, bool requiredHasBeenSetState): optionName(longOptionName), stateBefore() {
this->stateBefore = storm::settings::SettingsManager::manager().isSet(optionName);
if (requiredHasBeenSetState) {
storm::settings::SettingsManager::manager()..set(optionName);
} else {
storm::settings::SettingsManager::manager().unset(optionName);
}
}
/*!
* Destructs the memento object and resets the value of the option to its original state.
*/
virtual ~InternalOptionMemento() {
if (stateBefore) {
storm::settings::SettingsManager::manager().set(optionName);
} else {
storm::settings::SettingsManager::manager().unset(optionName);
}
}
private:
// The long name of the option that was temporarily set.
std::string const optionName;
// The state of the option before it was set.
bool stateBefore;
};
} // namespace settings
} // namespace storm
#endif // STORM_SETTINGS_INTERNALSETTINGMEMENTO_H_

302
src/settings/Option.h

@ -1,10 +1,3 @@
/*
* Option.h
*
* Created on: 11.08.2013
* Author: Philipp Berger
*/
#ifndef STORM_SETTINGS_OPTION_H_
#define STORM_SETTINGS_OPTION_H_
@ -22,233 +15,252 @@
#include "Argument.h"
#include "src/utility/StringHelper.h"
#include "src/exceptions/ExceptionMacros.h"
#include "src/exceptions/IllegalArgumentException.h"
#include "src/exceptions/OptionUnificationException.h"
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
extern log4cplus::Logger logger;
namespace storm {
namespace settings {
class SettingsManager;
/*!
* This class represents one command-line option.
*/
class Option {
public:
// (Forward-)declare settings manager class as friend.
friend class storm::settings::SettingsManager;
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 (uint_fast64_t 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 (size_t 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();
/*!
* Creates an option with the given parameters.
*
* @param moduleName The module to which this option belongs.
* @param longOptionName The long option name.
* @param optionDescription The description of the option.
* @param isOptionRequired Sets whether the option is required to appear.
* @param requireModulePrefix A flag that indicates whether this option requires to be prefixed with the
* module name.
* @param optionArguments The arguments of the option.
*/
Option(std::string const& moduleName, std::string const& longOptionName, std::string const& optionDescription, bool isOptionRequired, bool requireModulePrefix, std::vector<std::shared_ptr<ArgumentBase>> const& optionArguments = std::vector<std::shared_ptr<ArgumentBase>>()) : Option(moduleName, longOptionName, "", false, optionDescription, isOptionRequired, requireModulePrefix, optionArguments) {
// Intentionally left empty.
}
Option* clone() const {
return new Option(*this);
/*!
* Creates an option with the given parameters.
*
* @param moduleName The module to which this option belongs.
* @param longOptionName The long option name.
* @param shortOptionName The short option name.
* @param optionDescription The description of the option.
* @param isOptionRequired Sets whether the option is required to appear.
* @param requireModulePrefix A flag that indicates whether this option requires to be prefixed with the
* module name.
* @param optionArguments The arguments of the option.
*/
Option(std::string const& moduleName, std::string const& longOptionName, std::string const& shortOptionName, std::string const& optionDescription, bool isOptionRequired, bool requireModulePrefix, std::vector<std::shared_ptr<ArgumentBase>> const& optionArguments = std::vector<std::shared_ptr<ArgumentBase>>()) : Option(moduleName, longOptionName, shortOptionName, true, optionDescription, isOptionRequired, requireModulePrefix, optionArguments) {
// Intentionally left empty.
}
void unify(Option& other) {
if (this->getLongName().compare(other.getLongName()) != 0) {
LOG4CPLUS_ERROR(logger, "Option::unify: Unable to unify option \"" << getLongName() << "\" because of mismatching names (\"" << getLongName() << "\" and \"" << other.getLongName() << "\").");
throw storm::exceptions::OptionUnificationException() << "Unable to unify option \"" << getLongName() << "\" because of mismatching names (\"" << getLongName() << "\" and \"" << other.getLongName() << "\").";
}
if (this->getShortName().compare(other.getShortName()) != 0) {
LOG4CPLUS_ERROR(logger, "Option::unify: Unable to unify option \"" << getLongName() << "\" because of mismatching names (\"" << getShortName() << "\" and \"" << other.getShortName() << "\").");
throw storm::exceptions::OptionUnificationException() << "Unable to unify option \"" << getLongName() << "\" because of mismatching names (\"" << getShortName() << "\" and \"" << other.getShortName() << "\").";
}
/*!
* Checks whether the given option is compatible with the current one. If not, an exception is thrown.
*
* @param other The other option with which to check compatibility.
* @return True iff the given argument is compatible with the current one.
*/
bool isCompatibleWith(Option const& other) {
LOG_THROW(this->getArgumentCount() == other.getArgumentCount(), storm::exceptions::OptionUnificationException, "Unable to unify two options, because their argument count differs.");
if (this->getArgumentCount() != other.getArgumentCount()) {
LOG4CPLUS_ERROR(logger, "Option::unify: Unable to unify option \"" << getLongName() << "\" because of mismatching argument numbers.");
throw storm::exceptions::OptionUnificationException() << "Unable to unify option \"" << getLongName() << "\" because of mismatching argument numbers.";
}
for(size_t i = 0; i != this->arguments.size(); i++) {
ArgumentBase* A = this->arguments.at(i).get();
ArgumentBase* B = other.arguments.at(i).get();
ArgumentBase const& firstArgument = this->getArgument(i);
ArgumentBase const& secondArgument = other.getArgument(i);
if (A->getArgumentType() != B->getArgumentType()) {
LOG4CPLUS_ERROR(logger, "Option::unify: Unable to unify option \"" << getLongName() << "\" because of mismatching argument types at index " << i << ".");
throw storm::exceptions::OptionUnificationException() << "Unable to unify option \"" << getLongName() << "\" because of mismatching argument types at index " << i << ".";
}
LOG_THROW(firstArgument.getArgumentType() == secondArgument.getArgumentType(), storm::exceptions::OptionUnificationException, "Unable to unify two options, because their arguments are incompatible.");
switch (A->getArgumentType()) {
switch (firstArgument->getArgumentType()) {
case ArgumentType::String:
static_cast<storm::settings::Argument<std::string>*>(A)->unify(*static_cast<storm::settings::Argument<std::string>*>(B));
static_cast<storm::settings::Argument<std::string>&>(firstArgument).isCompatibleWith(static_cast<storm::settings::Argument<std::string>&>(secondArgument));
break;
case ArgumentType::Integer:
static_cast<storm::settings::Argument<int_fast64_t>*>(A)->unify(*static_cast<storm::settings::Argument<int_fast64_t>*>(B));
static_cast<storm::settings::Argument<int_fast64_t>&>(firstArgument).isCompatibleWith(static_cast<storm::settings::Argument<int_fast64_t>&>(secondArgument));
break;
case ArgumentType::UnsignedInteger:
static_cast<storm::settings::Argument<uint_fast64_t>*>(A)->unify(*static_cast<storm::settings::Argument<uint_fast64_t>*>(B));
static_cast<storm::settings::Argument<uint_fast64_t>&>(firstArgument).isCompatibleWith(static_cast<storm::settings::Argument<uint_fast64_t>&>(secondArgument));
break;
case ArgumentType::Double:
static_cast<storm::settings::Argument<double>*>(A)->unify(*static_cast<storm::settings::Argument<double>*>(B));
static_cast<storm::settings::Argument<double>&>(firstArgument).isCompatibleWith(static_cast<storm::settings::Argument<double>&>(secondArgument));
break;
case ArgumentType::Boolean:
static_cast<storm::settings::Argument<bool>*>(A)->unify(*static_cast<storm::settings::Argument<bool>*>(B));
static_cast<storm::settings::Argument<bool>&>(firstArgument).isCompatibleWith(static_cast<storm::settings::Argument<bool>&>(secondArgument));
break;
default:
LOG4CPLUS_ERROR(logger, "Option::unify: Missing Case in ArgumentBuilder's switch/case Code.");
throw storm::exceptions::InternalTypeErrorException() << "Missing case in Option.";
}
}
if (this->getModuleName().compare(other.getModuleName()) != 0) {
this->moduleName.append(", ").append(other.getModuleName());
}
return true;
}
/*!
* Retrieves the argument count this option expects.
*
* @return The argument count of this option.
*/
uint_fast64_t getArgumentCount() const {
return this->arguments.size();
}
ArgumentBase& getArgument(uint_fast64_t argumentIndex) const {
if (argumentIndex >= getArgumentCount()) {
LOG4CPLUS_ERROR(logger, "Option::getArgument: argumentIndex out of bounds!");
throw storm::exceptions::IllegalArgumentException() << "Option::getArgument(): index of argument is out of bounds.";
}
return *this->arguments.at(argumentIndex).get();
/*!
* Retrieves the i-th argument of this option.
*
* @param argumentIndex The index of the argument to retrieve.
* @return The i-th argument of this option.
*/
ArgumentBase const& getArgument(uint_fast64_t argumentIndex) const {
LOG_THROW(argumentIndex < this->getArgumentCount(), storm::exceptions::IllegalArgumentException, "Index of argument is out of bounds.")
return *this->arguments.at(argumentIndex);
}
/*!
* Returns a reference to the Argument with the specified longName.
* Throws an Exception of Type IllegalArgumentException if there is no such Option.
* Returns a reference to the argument with the specified long name.
*
* @param argumentName The name of the argument to retrieve.
* @return The argument with the given name.
*/
ArgumentBase const& getArgumentByName(std::string const& argumentName) const {
auto argumentIterator = this->argumentNameMap.find(storm::utility::StringHelper::stringToLower(argumentName));
if (argumentIterator == this->argumentNameMap.end()) {
LOG4CPLUS_ERROR(logger, "Option::getArgumentByName: Unable to retrieve unknown argument \"" << argumentName << "\" of option \"" << this->getLongName() << "\".");
throw storm::exceptions::IllegalArgumentException() << "Unable to retrieve unknown argument \"" << argumentName << "\" of option \"" << this->getLongName() << "\".";
}
return *argumentIterator->second.get();
LOG_THROW(argumentIterator != this->argumentNameMap.end(), storm::exceptions::IllegalArgumentException, "Unable to retrieve argument with unknown name " << argumentName << ".");
return *argumentIterator->second;
}
/*!
* Retrieves the long name of this option.
*
* @return The long name of this option.
*/
std::string const& getLongName() const {
return this->longName;
}
/*!
* Retrieves whether this option has a short name.
*
* @return True iff the option has a short name.
*/
bool getHasShortName() const {
return this->hasShortName;
}
/*!
* Retrieves the short name of this option.
*
* @return The short name of this option.
*/
std::string const& getShortName() const {
return this->shortName;
}
/*!
* Retrieves the description of the option.
*
* @return The description of the option.
*/
std::string const& getDescription() const {
return this->description;
}
/*!
* Retrieves the name of the module to which this option belongs.
*
* @return The name of the module to which this option belongs.
*/
std::string const& getModuleName() const {
return this->moduleName;
}
/*!
* Retrieves whether the option is required.
*
* @return True iff the option is required.
*/
bool getIsRequired() const {
return this->isRequired;
}
/*!
* Retrieves whether the option has been set.
*
* @return True iff the option has been set.
*/
bool getHasOptionBeenSet() const {
return this->hasBeenSet;
}
void setHasOptionBeenSet(bool newValue = true) {
this->hasBeenSet = newValue;
}
private:
// The long name of the option.
std::string longName;
// A flag that indicates whether the option has a short name.
bool hasShortName;
// The short name of the option if any is set and an empty string otherwise.
std::string shortName;
// The description of the option.
std::string description;
// The name of the module to which this option belongs.
std::string moduleName;
// A flag that indicates whether this option is required to appear.
bool isRequired;
// A flag that indicates whether this option is required to be prefixed with the module name.
bool requireModulePrefix;
// A flag that indicates whether this option has been set.
bool hasBeenSet;
// The arguments of this option (possibly empty).
std::vector<std::shared_ptr<ArgumentBase>> arguments;
// A mapping from argument names of this option to the actual arguments.
std::unordered_map<std::string, std::shared_ptr<ArgumentBase>> argumentNameMap;
void validateFields() const {
if (longName.empty()) {
LOG4CPLUS_ERROR(logger, "Option::validateFields: Unable to construct an option with empty name.");
throw storm::exceptions::IllegalArgumentException() << "Unable to construct an option with empty name.";
}
/*!
* Creates an option with the given parameters.
*
* @param moduleName The module to which this option belongs.
* @param longOptionName The long option name.
* @param shortOptionName The short option name.
* @param hasShortOptionName A flag that indicates whether this option has a short name.
* @param optionDescription The description of the option.
* @param isOptionRequired Sets whether the option is required to appear.
* @param requireModulePrefix A flag that indicates whether this option requires to be prefixed with the
* module name.
* @param optionArguments The arguments of the option.
*/
Option(std::string const& moduleName, std::string const& longOptionName, std::string const& shortOptionName, bool hasShortOptionName, std::string const& optionDescription, bool isOptionRequired, bool requireModulePrefix, std::vector<std::shared_ptr<ArgumentBase>> const& optionArguments = std::vector<std::shared_ptr<ArgumentBase>>()) : longName(longOptionName), hasShortName(hasShortOptionName), shortName(shortOptionName), description(optionDescription), moduleName(moduleName), isRequired(isOptionRequired), requireModulePrefix(requireModulePrefix), hasBeenSet(false), arguments(), argumentNameMap() {
if (moduleName.empty()) {
LOG4CPLUS_ERROR(logger, "Option::validateFields: Unable to construct an option with empty module.");
throw storm::exceptions::IllegalArgumentException() << "Unable to construct an option with empty module.";
}
// First, do some sanity checks.
LOG_THROW(!longName.empty(), storm::exceptions::IllegalArgumentException, "Unable to construct option with empty name.");
LOG_THROW(!moduleName.empty(), storm::exceptions::IllegalArgumentException, "Unable to construct option with empty module name.");
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();
LOG_THROW(!longNameContainsNonAlpha, storm::exceptions::IllegalArgumentException, "Unable to construct option with illegal name.");
if (longNameContainsNonAlpha) {
LOG4CPLUS_ERROR(logger, "Option::validateFields: Unable to construct an option with a illegal name.");
throw storm::exceptions::IllegalArgumentException() << "Unable to construct an option with a illegal name.";
}
if (shortNameContainsNonAlpha) {
LOG4CPLUS_ERROR(logger, "Option::validateFields: Unable to construct an option with a illegal name.");
throw storm::exceptions::IllegalArgumentException() << "Unable to construct an option with a illegal name.";
}
}
bool shortNameContainsNonAlpha = std::find_if(shortName.begin(), shortName.end(), [](char c) { return !std::isalpha(c); }) != shortName.end();
LOG_THROW(!shortNameContainsNonAlpha, storm::exceptions::IllegalArgumentException, "Unable to construct option with illegal name.");
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->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) {
LOG4CPLUS_ERROR(logger, "Option::isArgumentsVectorValid: The argument vector specified for option \"" << getLongName() << "\" is invalid, because it contains a non-optional argument after an optional one.");
throw storm::exceptions::IllegalArgumentException() << "The argument vector specified for option \"" << getLongName() << "\" is invalid, because it contains a non-optional argument after an optional one.";
// Then index all arguments.
for (auto const& argument : arguments) {
argumentNameMap.emplace(lowerArgumentName, std::shared_ptr<ArgumentBase>(*i));
}
std::string lowerArgumentName = storm::utility::StringHelper::stringToLower(i->get()->getArgumentName());
if (argumentNameSet.find(lowerArgumentName) != argumentNameSet.end()) {
LOG4CPLUS_ERROR(logger, "Option::isArgumentsVectorValid: The argument vector specified for option \"" << getLongName() << "\" is invalid, because it contains two arguments with the same name.");
throw storm::exceptions::IllegalArgumentException() << "The argument vector specified for option \"" << getLongName() << "\" is invalid, because it 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;
/*!
* Sets the flag that marks the option as being (un)set.
*
* @param newValue The new status of the flag.
*/
void setHasOptionBeenSet(bool newValue = true) {
this->hasBeenSet = newValue;
}
};
}

141
src/settings/OptionBuilder.h

@ -7,11 +7,13 @@
#include <vector>
#include <memory>
#include <unordered_set>
#include <boost/algorithm/string.hpp>
#include "src/settings/ArgumentType.h"
#include "src/settings/ArgumentBase.h"
#include "src/settings/Option.h"
#include "src/exceptions/ExceptionMacros.h"
#include "src/exceptions/IllegalArgumentException.h"
#include "src/exceptions/IllegalFunctionCallException.h"
@ -28,115 +30,96 @@ namespace storm {
*
* @param moduleName The name of the module to which this option belongs.
* @param longName The long name of the option.
* @param shortName The short name of the option. If empty, the option does not have a short name.
* @param
*
* @param requireModulePrefix Sets whether this option can only be set by specifying the module name as its prefix.
* @param description A description that explains the purpose of this option.
*/
OptionBuilder(std::string const& moduleName, std::string const& longName, std::string const& shortName, std::string const& description): longName(newOptionLongName), shortName(newOptionShortName), description(newOptionDescription), moduleName(newOptionModuleName), isRequired(false), isBuild(false) {}
~OptionBuilder() {}
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(std::string const& moduleName, std::string const& longName, bool requireModulePrefix, std::string const& description) : longName(longName), shortName(""), hasShortName(false), description(description), moduleName(moduleName), requireModulePrefix(requireModulePrefix), isRequired(false), isBuild(false), arguments(), argumentNameSet() {
// Intentionally left empty.
}
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;
/*!
* Sets a short name for the option.
*
* @param shortName A short name for the option.
* @return A reference to the current builder.
*/
OptionBuilder& setShortName(std::string const& shortName) {
this->shortName = shortName;
this->hasShortName = true;
return *this;
}
std::string const& getModuleName() const {
return this->moduleName;
}
OptionBuilder& setIsRequired(bool newIsRequired) {
this->isRequired = newIsRequired;
/*!
* Sets whether the option is required.
*
* @param isRequired A flag indicating whether the option is required.
* @return A reference to the current builder.
*/
OptionBuilder& setIsRequired(bool isRequired) {
this->isRequired = isRequired;
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) {
LOG4CPLUS_ERROR(logger, "OptionBuilder::addArgument: Illegal call to addArgument() on an instance of OptionBuilder that has already built an instance.");
throw storm::exceptions::IllegalFunctionCallException() << "Illegal call to addArgument() on an instance of OptionBuilder that has already built an instance.";
}
if (newArgument->getArgumentType() == ArgumentType::Invalid) {
LOG4CPLUS_ERROR(logger, "OptionBuilder::addArgument: Unable to add argument to option \"" << getLongName() << "\" because its type is invalid.");
throw storm::exceptions::InternalTypeErrorException() << "Unable to add argument to option \"" << getLongName() << "\" because its type is invalid.";
}
/*!
* Adds the given argument to the arguments of this option.
*
* @param argument The argument to be added.
* @return A reference to the current builder.
*/
OptionBuilder& addArgument(std::shared_ptr<ArgumentBase> argument) {
LOG_THROW(!this->isBuild, storm::exceptions::IllegalFunctionCallException, "Cannot add an argument to an option builder that was already used to build the option.");
LOG_THROW(this->arguments.empty() || !argument->getIsOptional() || this->arguments.back()->getIsOptional(), storm::exceptions::IllegalArgumentException, "Unable to add non-optional argument after an option that is optional.");
if (!newArgument->getIsOptional() && (this->arguments.size() > 0) && (this->arguments.at(this->arguments.size() - 1).get()->getIsOptional())) {
LOG4CPLUS_ERROR(logger, "OptionBuilder::addArgument: Unable to add a non-optional argument to option \"" << getLongName() << "\", because it already contains an optional argument.");
throw storm::exceptions::IllegalArgumentException() << "Unable to add non-optional argument to option \"" << getLongName() << "\", because it already contains an optional argument.";
}
std::string lowerArgumentName = boost::algorithm::to_lower_copy(argument->getName());
LOG_THROW(argumentNamSet.find(lowerArgumentName) == argumentNameSet.end(), storm::exceptions::IllegalArgumentException, "Unable to add argument to option, because it already has an argument with the same name.");
std::string lowerArgumentName = storm::utility::StringHelper::stringToLower(newArgument->getArgumentName());
if (argumentNameSet.find(lowerArgumentName) != argumentNameSet.end()) {
LOG4CPLUS_ERROR(logger, "OptionBuilder::addArgument: Unable to add argument with name \"" << newArgument->getArgumentName() << "\" to option \"" << getLongName() << "\", because it already contains an argument with the same name.");
throw storm::exceptions::IllegalArgumentException() << "Unable to add argument with name \"" << newArgument->getArgumentName() << "\" to option \"" << getLongName() << "\", because it already contains an argument with the same name.";
}
argumentNameSet.insert(lowerArgumentName);
this->arguments.push_back(std::shared_ptr<ArgumentBase>(argumentPtr));
this->arguments.push_back(argument);
return *this;
}
Option* build() {
if (this->isBuild) {
LOG4CPLUS_ERROR(logger, "OptionBuilder::addArgument: Illegal call to build() on an instance of OptionBuilder that has already built an instance.");
throw storm::exceptions::IllegalFunctionCallException() << "Illegal call to build() on an instance of OptionBuilder that has already built an instance.";
}
/*!
* Builds an option from the data that was added to this builder.
*
* @return The resulting option.
*/
std::shared_ptr<Option> build() {
LOG_THROW(!this->isBuild, storm::exceptions::IllegalFunctionCallException, "Cannot rebuild an option with one builder.")
this->isBuild = true;
return new storm::settings::Option(this->moduleName, this->longName, this->shortName, this->description, this->isRequired, this->arguments);
return std::shared_ptr<Option>(new Option(this->moduleName, this->longName, this->shortName, this->description, this->isRequired, this->requireModulePrefix, this->arguments));
}
private:
// The long name of the option.
std::string longName;
// A possible short name of the option or the empty string in case the option does not have a short name.
std::string shortName;
// A flag indicating whether the option has a short name.
bool hasShortName;
// The description of the option.
std::string description;
// The name of the module to which this option belongs.
std::string moduleName;
// A flag indicating whether the option has to be prefixed with the module name.
bool requireModulePrefix;
// A flag indicating whether the option is required.
bool isRequired;
// A flag indicating whether the builder has already been used to build an option.
bool isBuild;
// The arguments of the option that is being built.
std::vector<std::shared_ptr<ArgumentBase>> arguments;
// The names of the arguments of the option.
std::unordered_set<std::string> argumentNameSet;
};
}

63
src/utility/StringHelper.h

@ -1,63 +0,0 @@
/*
* 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_
Loading…
Cancel
Save