Implemented constraint for forced types

This commit is contained in:
Leonetienne 2021-06-02 19:20:50 +02:00
parent a2de37264a
commit 9fd183e0cd
7 changed files with 164 additions and 11 deletions

View File

@ -4,6 +4,7 @@
#include "FloatValue.h"
#include "StringValue.h"
#include "ListValue.h"
#include "HazelnuppException.h"
#include "StringTools.h"
Hazelnupp::Hazelnupp()
@ -70,7 +71,10 @@ std::size_t Hazelnupp::ParseNextParameter(const std::size_t parIndex, Parameter*
break;
}
Value* parsedVal = ParseValue(values);
// Fetch constraint info
const ParamConstraint* pcn = GetConstraintForKey(key);
Value* parsedVal = ParseValue(values, pcn);
if (parsedVal != nullptr)
{
out_Par = new Parameter(key, parsedVal);
@ -116,21 +120,38 @@ bool Hazelnupp::HasParam(const std::string& key) const
return parameters.find(key) != parameters.end();
}
Value* Hazelnupp::ParseValue(const std::vector<std::string>& values)
Value* Hazelnupp::ParseValue(const std::vector<std::string>& values, const ParamConstraint* constraint)
{
// Constraint values
const bool constrainType = (constraint != nullptr) && (constraint->constrainType);
// Void-type
if (values.size() == 0)
{
return new VoidValue;
}
// Force void type by constraint
if ((constrainType) &&
(constraint->wantedType == DATA_TYPE::VOID))
{
return new VoidValue;
}
// List-type
else if (values.size() > 1)
{
// Should the type be something other than list?
if ((constrainType) &&
(constraint->wantedType != DATA_TYPE::LIST))
{
throw HazelnutConstraintMissmatch();
}
ListValue* newList = new ListValue();
for (const std::string& val : values)
{
Value* tmp = ParseValue(std::vector<std::string>({ val }));
Value* tmp = ParseValue({ val });
newList->AddValue(tmp);
delete tmp;
}
@ -142,6 +163,34 @@ Value* Hazelnupp::ParseValue(const std::vector<std::string>& values)
// String
if (!StringTools::IsNumeric(val, true))
{
// Is the type not supposed to be a string?
// void and list are already sorted out
if ((constrainType) &&
(constraint->wantedType != DATA_TYPE::STRING))
{
// We can only force a list-value from here
if (constraint->wantedType == DATA_TYPE::LIST)
{
ListValue* list = new ListValue();
Value* tmp = ParseValue({ val });
list->AddValue(tmp);
delete tmp;
tmp = nullptr;
return list;
}
// Else it not possible to convert to a numeric
else
throw HazelnutConstraintMissmatch();
}
return new StringValue(val);
}
// In this case we have a numeric value.
// We should still produce a string if requested
if ((constrainType) &&
(constraint->wantedType == DATA_TYPE::STRING))
return new StringValue(val);
// Numeric
@ -149,6 +198,30 @@ Value* Hazelnupp::ParseValue(const std::vector<std::string>& values)
long double num;
if (StringTools::ParseNumber(val, isInt, num))
{
// Is the type constrained?
// (only int and float left)
if (constrainType)
{
// Must it be an integer?
if (constraint->wantedType == DATA_TYPE::INT)
return new IntValue((long long int)num);
// Must it be a floating point?
else if (constraint->wantedType == DATA_TYPE::FLOAT)
return new FloatValue(num);
// Else it must be a List
else
{
ListValue* list = new ListValue();
Value* tmp = ParseValue({ val });
list->AddValue(tmp);
delete tmp;
tmp = nullptr;
return list;
}
}
// Type is not constrained
else
{
// Integer
if (isInt)
@ -157,6 +230,7 @@ Value* Hazelnupp::ParseValue(const std::vector<std::string>& values)
// Double
return new FloatValue(num);
}
}
// Failed
return nullptr;
@ -187,3 +261,22 @@ bool Hazelnupp::HasAbbreviation(const std::string& abbrev) const
{
return abbreviations.find(abbrev) != abbreviations.end();
}
void Hazelnupp::AddConstraints(const std::vector<ParamConstraint>& constraints)
{
for (const ParamConstraint& pc : constraints)
this->constraints.insert(std::pair<std::string, ParamConstraint>(
pc.key,
pc
));
}
const ParamConstraint* Hazelnupp::GetConstraintForKey(const std::string& key) const
{
const auto constraint = constraints.find(key);
if (constraint == constraints.end())
return nullptr;
return &constraint->second;
}

View File

@ -1,5 +1,6 @@
#pragma once
#include "Parameter.h"
#include "ParamConstraint.h"
#include <unordered_map>
#include <vector>
@ -33,6 +34,8 @@ public:
//! Will check wether or not an abbreviation is registered
bool HasAbbreviation(const std::string& abbrev) const;
void AddConstraints(const std::vector<ParamConstraint>& constraints);
private:
//! Will translate the c-like args to an std::vector
void PopulateRawArgs(const int argc, const char* const* argv);
@ -44,7 +47,13 @@ private:
std::size_t ParseNextParameter(const std::size_t parIndex, Parameter*& out_Par);
//! Will convert a vector of string-values to an actual Value
Value* ParseValue(const std::vector<std::string>& values);
Value* ParseValue(const std::vector<std::string>& values, const ParamConstraint* constraint = nullptr);
//! Will apply the loaded constraints on the loaded values.
void ApplyConstraints();
//! Will return a pointer to a paramConstraint given a key. If there is no, it returns nullptr
const ParamConstraint* GetConstraintForKey(const std::string& key) const;
std::string executableName; //! The path of the executable. Always argv[0]
std::unordered_map<std::string, Parameter*> parameters;
@ -52,5 +61,8 @@ private:
// These are abbreviations. Like, -f for --force.
std::unordered_map<std::string, std::string> abbreviations;
// Parameter constraints, mapped to keys
std::unordered_map<std::string, ParamConstraint> constraints;
std::vector<std::string> rawArgs;
};

View File

@ -153,8 +153,10 @@
<ItemGroup>
<ClInclude Include="FloatValue.h" />
<ClInclude Include="Hazelnupp.h" />
<ClInclude Include="HazelnuppException.h" />
<ClInclude Include="IntValue.h" />
<ClInclude Include="ListValue.h" />
<ClInclude Include="ParamConstraint.h" />
<ClInclude Include="Parameter.h" />
<ClInclude Include="DataType.h" />
<ClInclude Include="StringTools.h" />

View File

@ -77,5 +77,11 @@
<ClInclude Include="StringTools.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="ParamConstraint.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="HazelnuppException.h">
<Filter>Headerdateien</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,5 @@
#pragma once
#include <stdexcept>
class HazelnutException : public std::exception {};
class HazelnutConstraintMissmatch : public HazelnutException {};

View File

@ -0,0 +1,25 @@
#pragma once
#include "DataType.h"
#include <string>
struct ParamConstraint
{
public:
//! The key of the parameter to constrain
std::string key;
//! Should this parameter be forced to be of a certain type?
//! Remember to set `constrainTo` to the wanted type
bool constrainType = false;
//! Constrain the parameter to this value. Requires `constrainType` to be set to true.
DATA_TYPE wantedType;
//! The default value for this parameter.
//! Gets applied if this parameter was not given.
std::string defaultValue;
//! If set to true, and no default value set,
//! an error will be produced if this parameter is not supplied by the user.
bool required = false;
};

View File

@ -9,7 +9,7 @@ int main(int argc, char** argv)
std::vector<const char*> testArgv = {
"meinpfad",
"-w",
"123",
"-99",
"--alfred",
"apfel",
"banane",
@ -24,6 +24,16 @@ int main(int argc, char** argv)
Hazelnupp args;
ParamConstraint pc;
pc.key = "--word";
pc.constrainType = true;
pc.wantedType = DATA_TYPE::INT;
pc.required = true;
args.AddConstraints({
pc
});
args.RegisterAbbreviation("-w", "--word");
args.Parse(testArgv.size(), testArgv.data());
@ -31,7 +41,7 @@ int main(int argc, char** argv)
if (args.HasParam("--word"))
{
std::cout << args["--word"]->GetString() << std::endl;
std::cout << *args["--word"] << std::endl;
}
else
{