Hyperiso 1.0.3
Modular flavour-physics calculations, Wilson coefficients and statistical inference
Loading...
Searching...
No Matches
ArgsParser.cpp
Go to the documentation of this file.
1#include "ArgsParser.h"
2
3static bool looksLikeNumber(const std::string& s) {
4 if (s.empty()) return false;
5 char* end = nullptr;
6 std::strtod(s.c_str(), &end);
7 return end && *end == '\0';
8}
9
10Argument::Argument(const std::string& longName, const std::string& shortName, const std::string& helpText,
11 ArgType type, bool isRequired, bool allowsMultiple,
12 std::optional<std::string> defaultValue, bool isPositional)
13 : longName(longName), shortName(shortName), helpText(helpText), type(type),
14 isRequired(isRequired), allowsMultiple(allowsMultiple),
15 defaultValue(defaultValue), isPositional(isPositional) {}
16
17void Argument::addValidator(std::shared_ptr<IValidator> validator) {
18 validators.push_back(validator);
19}
20
22 return type;
23}
24
25bool Argument::validate(const std::string& value) const {
26 for (const auto& validator : validators) {
27 if (!validator->validate(value)) {
28 throw std::invalid_argument(validator->errorMessage());
29 }
30 }
31 return true;
32}
33
34std::string Argument::getLongName() const {
35 return longName;
36}
37
38std::string Argument::getShortName() const {
39 return shortName;
40}
41
42std::string Argument::getHelpText() const {
43 return helpText;
44}
45
47 return isRequired;
48}
49
51 return allowsMultiple;
52}
53
55 return isPositional;
56}
57
58std::optional<std::string> Argument::getDefaultValue() const {
59 return defaultValue;
60}
61
63 type = argType;
64 return *this;
65}
66
68 longName = name;
69 return *this;
70}
71
73 shortName = name;
74 return *this;
75}
76
78 helpText = text;
79 return *this;
80}
81
83 isRequired = required;
84 return *this;
85}
86
88 defaultValue = value;
89 return *this;
90}
91
93 allowsMultiple = multiple;
94 return *this;
95}
96
97ArgumentBuilder& ArgumentBuilder::addValidator(std::shared_ptr<IValidator> validator) {
98 validators.push_back(validator);
99 return *this;
100}
101
103 isPositional = positional;
104 return *this;
105}
106
108 Argument arg = Argument(longName, shortName, helpText, type, isRequired, allowsMultiple, defaultValue, isPositional);
109 if (!validators.empty()){
110 for (auto &validator : validators) {
111 arg.addValidator(validator);
112 }
113 }
114 return arg;
115}
116
117const Argument* ArgParser::findArgumentByLongName(const std::string& name) const {
118 auto it = std::find_if(arguments.begin(), arguments.end(),
119 [&](const Argument& a){ return a.getLongName() == name; });
120 return (it == arguments.end()) ? nullptr : &(*it);
121}
122
123bool ArgParser::exists(const std::string& name) const {
124 return parsedValues.find(name) != parsedValues.end();
125}
126
128 if (arg.isPositionalArg()) {
129 positional_arguments.push_back(arg);
130 }
131 arguments.push_back(arg);
132}
133
134void ArgParser::parse(int argc, char* argv[]) {
135 size_t positionalIndex = 0;
136 positionalValues.clear();
137 for (int i = 1; i < argc; ++i) {
138 std::string arg = argv[i];
139 if (arg.rfind("--", 0) == 0 || arg.rfind("-", 0) == 0) {
140 std::string key = arg.substr(arg[1] == '-' ? 2 : 1);
141 auto it = std::find_if(arguments.begin(), arguments.end(), [&](const Argument& a) {
142 return a.getLongName() == key || a.getShortName() == key;
143 });
144
145 if (it == arguments.end()) {
146 throw std::invalid_argument("Unknown option: " + arg);
147 }
148
149 Argument& option = *it;
150 if (option.allowsMultipleValues()) {
151 std::vector<std::string> values;
152 while (i + 1 < argc && ((argv[i + 1][0] != '-') || looksLikeNumber(argv[i + 1]))) {
153 std::string value = argv[++i];
154 option.validate(value);
155 values.push_back(value);
156 }
157 if (!values.size()) {
158 throw std::invalid_argument("Please put at least one argument for : " + arg);
159 }
160 parsedValues[option.getLongName()] = values;
161 } else {
162 if (option.getLongName() == "help") {
163 parsedValues[option.getLongName()] = {"true"};
164 continue;
165 }
166 if (i + 1 < argc && ((argv[i + 1][0] != '-') || looksLikeNumber(argv[i + 1]))) {
167 std::string value = argv[++i];
168 option.validate(value);
169 parsedValues[option.getLongName()] = {value};
170 } else {
171 throw std::invalid_argument("Missing value for option: " + key);
172 }
173 }
174 } else {
175 if (positionalIndex >= positional_arguments.size()) {
176 throw std::invalid_argument("Unexpected positional argument: " + arg);
177 }
178 Argument& positionalArg = positional_arguments[positionalIndex++];
179 positionalArg.validate(arg);
180 positionalValues.push_back(arg);
181 }
182 }
183
184 for (const auto& arg : positional_arguments) {
185 if (arg.isRequiredArg() && positionalValues.size() < positional_arguments.size()) {
186 throw std::invalid_argument("Missing required positional argument: " + arg.getLongName());
187 }
188 }
189
190 for (const auto& arg : arguments) {
191 if (parsedValues.find(arg.getLongName()) == parsedValues.end() && arg.getDefaultValue()) {
192 parsedValues[arg.getLongName()] = {*arg.getDefaultValue()};
193 }
194}
195}
196
197std::string ArgParser::getValue(const std::string& name) const {
198 auto it = parsedValues.find(name);
199 if (it != parsedValues.end() && !it->second.empty()) {
200 return it->second[0];
201 }
202 for (const auto& arg : arguments) {
203 if (arg.getLongName() == name && arg.getDefaultValue()) {
204 return *arg.getDefaultValue();
205 }
206 }
207 throw std::invalid_argument("Value for argument " + name + " not provided.");
208}
209
210std::vector<std::string> ArgParser::getValues(const std::string& name) const {
211 auto it = parsedValues.find(name);
212 if (it != parsedValues.end()) {
213 return it->second;
214 }
215 throw std::invalid_argument("Values for argument " + name + " not provided.");
216}
217
218std::vector<std::string> ArgParser::getPositionalValues() const {
219 return positionalValues;
220}
221
223 for (const auto& arg : arguments) {
224 if (arg.isPositionalArg()) {
225 std::cout << arg.getLongName() << ": " << arg.getHelpText() << " (Positional)\n";
226 } else {
227 std::cout << "--" << arg.getLongName() << ", -" << arg.getShortName()
228 << ": " << arg.getHelpText();
229 if (arg.getDefaultValue()) {
230 std::cout << " (default: " << *arg.getDefaultValue() << ")";
231 }
232 std::cout << "\n";
233 }
234 }
235}
ArgType
Definition ArgsParser.h:14
void parse(int argc, char *argv[])
std::vector< std::string > getValues(const std::string &name) const
std::vector< std::string > getPositionalValues() const
std::string getValue(const std::string &name) const
void addArgument(const Argument &arg)
void displayHelp() const
bool exists(const std::string &name) const
ArgumentBuilder & setAllowsMultiple(bool multiple)
ArgumentBuilder & setType(ArgType argType)
ArgumentBuilder & setLongName(const std::string &name)
ArgumentBuilder & setDefaultValue(const std::string &value)
Argument build()
ArgumentBuilder & setHelpText(const std::string &text)
ArgumentBuilder & setPositional(bool positional)
ArgumentBuilder & setRequired(bool required)
ArgumentBuilder & setShortName(const std::string &name)
ArgumentBuilder & addValidator(std::shared_ptr< IValidator > validator)
bool allowsMultipleValues() const
bool isRequiredArg() const
std::string getLongName() const
bool validate(const std::string &value) const
Argument(const std::string &longName, const std::string &shortName, const std::string &helpText, ArgType type, bool isRequired, bool allowsMultiple, std::optional< std::string > defaultValue, bool isPositional)
bool isPositionalArg() const
std::optional< std::string > getDefaultValue() const
ArgType getType() const
std::string getShortName() const
void addValidator(std::shared_ptr< IValidator > validator)
std::string getHelpText() const