229 lines
10 KiB

#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 "src/settings/ArgumentType.h"
#include "src/settings/ArgumentBase.h"
#include "src/settings/Argument.h"
#include "src/settings/ArgumentValidators.h"
#include "src/utility/macros.h"
#include "src/exceptions/IllegalFunctionCallException.h"
#include "src/exceptions/IllegalArgumentTypeException.h"
namespace storm {
namespace settings {
/*!
* This class serves as an API for creating arguments.
*/
class ArgumentBuilder {
public:
/*!
* 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& name, std::string const& description) {
ArgumentBuilder ab(ArgumentType::String, name, description);
return ab;
}
/*!
* 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;
}
/*!
* 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;
}
/*!
* 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;
}
/*!
* 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;
}
/*!
* 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;
STORM_LOG_THROW(this->hasDefaultValue, storm::exceptions::IllegalFunctionCallException, "Unable to make argument '" << this->name << "' optional without default value.");
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) { \
STORM_LOG_THROW(this->type == ArgumentType::funcName, storm::exceptions::IllegalFunctionCallException, "Illegal validation function for argument, because it takes arguments of different type."); \
( PPCAT(this->userValidationFunctions_, funcName) ).push_back(userValidationFunction); \
return *this; \
}
// Add the methods to add validation functions.
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) { \
STORM_LOG_THROW(this->type == ArgumentType::funcName, storm::exceptions::IllegalFunctionCallException, "Illegal default value for argument" << this->name << ", because it is of different type."); \
PPCAT(this->defaultValue_, funcName) = defaultValue; \
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)
/*!
* Builds an argument based on the information that was added to the builder object.
*
* @return The resulting argument.
*/
std::shared_ptr<ArgumentBase> build() {
STORM_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->type) {
case ArgumentType::String: {
if (this->hasDefaultValue) {
return std::shared_ptr<ArgumentBase>(new Argument<std::string>(this->name, this->description, this->userValidationFunctions_String, this->isOptional, this->defaultValue_String));
} else {
return std::shared_ptr<ArgumentBase>(new Argument<std::string>(this->name, this->description, this->userValidationFunctions_String));
}
break;
}
case ArgumentType::Integer:
if (this->hasDefaultValue) {
return std::shared_ptr<ArgumentBase>(new Argument<int_fast64_t>(this->name, this->description, this->userValidationFunctions_Integer, this->isOptional, this->defaultValue_Integer));
} else {
return std::shared_ptr<ArgumentBase>(new Argument<int_fast64_t>(this->name, this->description, this->userValidationFunctions_Integer));
}
break;
case ArgumentType::UnsignedInteger:
if (this->hasDefaultValue) {
return std::shared_ptr<ArgumentBase>(new Argument<uint_fast64_t>(this->name, this->description, this->userValidationFunctions_UnsignedInteger, this->isOptional, this->defaultValue_UnsignedInteger));
} else {
return std::shared_ptr<ArgumentBase>(new Argument<uint_fast64_t>(this->name, this->description, this->userValidationFunctions_UnsignedInteger));
}
break;
case ArgumentType::Double:
if (this->hasDefaultValue) {
return std::shared_ptr<ArgumentBase>(new Argument<double>(this->name, this->description, this->userValidationFunctions_Double, this->isOptional, this->defaultValue_Double));
} else {
return std::shared_ptr<ArgumentBase>(new Argument<double>(this->name, this->description, this->userValidationFunctions_Double));
}
break;
case ArgumentType::Boolean:
if (this->hasDefaultValue) {
return std::shared_ptr<ArgumentBase>(new Argument<bool>(this->name, this->description, this->userValidationFunctions_Boolean, this->isOptional, this->defaultValue_Boolean));
} else {
return std::shared_ptr<ArgumentBase>(new Argument<bool>(this->name, this->description, this->userValidationFunctions_Boolean));
}
break;
}
STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentTypeException, "Argument has illegal type.");
}
private:
/*!
* 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.
}
// A flag that stores whether an argument has been built using this builder.
bool hasBeenBuilt;
// The type of the argument.
ArgumentType type;
// The name of te argument.
std::string name;
// 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;
// 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;
};
}
}
#endif // STORM_SETTINGS_ARGUMENTBUILDER_H_