You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
259 lines
9.8 KiB
259 lines
9.8 KiB
/*
|
|
* 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 Settings;
|
|
|
|
class Option {
|
|
public:
|
|
|
|
friend class storm::settings::Settings;
|
|
/*
|
|
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->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_
|