Browse Source

Added my initial implementation of Settings

Former-commit-id: 5da4b7604f
tempestpy_adaptions
PBerger 12 years ago
parent
commit
bde10b750e
  1. 2
      CMakeLists.txt
  2. 23
      src/exceptions/ArgumentUnificationException.h
  3. 18
      src/exceptions/IllegalArgumentException.h
  4. 23
      src/exceptions/IllegalArgumentTypeException.h
  5. 23
      src/exceptions/IllegalArgumentValueException.h
  6. 25
      src/exceptions/IllegalFunctionCallException.h
  7. 26
      src/exceptions/InternalTypeErrorException.h
  8. 23
      src/exceptions/OptionParserException.h
  9. 23
      src/exceptions/OptionUnificationException.h
  10. 259
      src/settings/Argument.h
  11. 110
      src/settings/ArgumentBase.h
  12. 292
      src/settings/ArgumentBuilder.h
  13. 52
      src/settings/ArgumentType.h
  14. 152
      src/settings/ArgumentTypeInferationHelper.h
  15. 256
      src/settings/Option.h
  16. 142
      src/settings/OptionBuilder.h
  17. 48
      src/settings/OptionsAccumulator.cpp
  18. 120
      src/settings/OptionsAccumulator.h
  19. 195
      src/settings/Settings.cpp
  20. 210
      src/settings/Settings.h
  21. 4
      src/storm.cpp
  22. 234
      src/utility/Settings.cpp
  23. 266
      src/utility/Settings.h
  24. 63
      src/utility/StringHelper.h

2
CMakeLists.txt

@ -148,6 +148,7 @@ file(GLOB_RECURSE STORM_MODELCHECKER_FILES ${PROJECT_SOURCE_DIR}/src/modelchecke
file(GLOB_RECURSE STORM_MODELS_FILES ${PROJECT_SOURCE_DIR}/src/models/*.h ${PROJECT_SOURCE_DIR}/src/models/*.cpp)
file(GLOB STORM_PARSER_FILES ${PROJECT_SOURCE_DIR}/src/parser/*.h ${PROJECT_SOURCE_DIR}/src/parser/*.cpp)
file(GLOB_RECURSE STORM_PARSER_PRISMPARSER_FILES ${PROJECT_SOURCE_DIR}/src/parser/prismparser/*.h ${PROJECT_SOURCE_DIR}/src/parser/prismparser/*.cpp)
file(GLOB_RECURSE STORM_SETTINGS_FILES ${PROJECT_SOURCE_DIR}/src/settings/*.h ${PROJECT_SOURCE_DIR}/src/settings/*.cpp)
file(GLOB_RECURSE STORM_STORAGE_FILES ${PROJECT_SOURCE_DIR}/src/storage/*.h ${PROJECT_SOURCE_DIR}/src/storage/*.cpp)
file(GLOB_RECURSE STORM_UTILITY_FILES ${PROJECT_SOURCE_DIR}/src/utility/*.h ${PROJECT_SOURCE_DIR}/src/utility/*.cpp)
file(GLOB STORM_IR_FILES ${PROJECT_SOURCE_DIR}/src/ir/*.h ${PROJECT_SOURCE_DIR}/src/ir/*.cpp)
@ -171,6 +172,7 @@ source_group(modelchecker FILES ${STORM_MODELCHECKER_FILES})
source_group(models FILES ${STORM_MODELS_FILES})
source_group(parser FILES ${STORM_PARSER_FILES})
source_group(parser\\prismparser FILES ${STORM_PARSER_PRISMPARSER_FILES})
source_group(settings FILES ${STORM_SETTINGS_FILES})
source_group(storage FILES ${STORM_STORAGE_FILES})
source_group(utility FILES ${STORM_UTILITY_FILES})
source_group(ir FILES ${STORM_IR_FILES})

23
src/exceptions/ArgumentUnificationException.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_ */

18
src/exceptions/IllegalArgumentException.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_

23
src/exceptions/IllegalArgumentTypeException.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_ */

23
src/exceptions/IllegalArgumentValueException.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_ */

25
src/exceptions/IllegalFunctionCallException.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_

26
src/exceptions/InternalTypeErrorException.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_ */

23
src/exceptions/OptionParserException.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_ */

23
src/exceptions/OptionUnificationException.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_ */

259
src/settings/Argument.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_

110
src/settings/ArgumentBase.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_

292
src/settings/ArgumentBuilder.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_

52
src/settings/ArgumentType.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_

152
src/settings/ArgumentTypeInferationHelper.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_

256
src/settings/Option.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_

142
src/settings/OptionBuilder.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_

48
src/settings/OptionsAccumulator.cpp

@ -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());
}
}

120
src/settings/OptionsAccumulator.h

@ -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_

195
src/settings/Settings.cpp

@ -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);
}

210
src/settings/Settings.h

@ -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 //

4
src/storm.cpp

@ -28,7 +28,7 @@
#include "src/solver/GmmxxNondeterministicLinearEquationSolver.h"
#include "src/parser/AutoParser.h"
#include "src/parser/PrctlParser.h"
#include "src/utility/Settings.h"
#include "src/settings/Settings.h"
#include "src/utility/ErrorHandling.h"
#include "src/formula/Prctl.h"
@ -110,7 +110,7 @@ void initializeLogger() {
* Sets up the logging to file.
*/
void setUpFileLogging() {
storm::settings::Settings* s = storm::settings::instance();
storm::settings::Settings* s = storm::settings::Settings::getInstance();
log4cplus::SharedAppenderPtr fileLogAppender(new log4cplus::FileAppender(s->getString("logfile")));
fileLogAppender->setName("mainFileAppender");
fileLogAppender->setLayout(std::auto_ptr<log4cplus::Layout>(new log4cplus::PatternLayout("%-5p - %D{%H:%M:%S} (%r ms) - %F:%L: %m%n")));

234
src/utility/Settings.cpp

@ -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

266
src/utility/Settings.h

@ -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_

63
src/utility/StringHelper.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_
Loading…
Cancel
Save