Skip to content

Commit dff10c0

Browse files
committed
Multiple positional arguments
1 parent b1dfda2 commit dff10c0

File tree

6 files changed

+498
-359
lines changed

6 files changed

+498
-359
lines changed

.clang-format

-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,4 @@ MaxEmptyLinesToKeep: 1
33
AllowShortBlocksOnASingleLine: Empty
44
AllowShortFunctionsOnASingleLine: Empty
55
SeparateDefinitionBlocks: Always
6-
BinPackArguments: false
76
ColumnLimit: 80

Argo/ArgoMetaAssigner.cc

+76-50
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,68 @@ constexpr auto tupleAssign(std::tuple<T...>& t, std::span<std::string_view> v,
5353
...);
5454
}
5555

56+
template <class PArg>
57+
struct PArgAssigner {};
58+
59+
template <class... PArg>
60+
struct PArgAssigner<std::tuple<PArg...>> {
61+
static auto assign(std::span<std::string_view> values) {
62+
return ([&values]<ArgType Arg>() {
63+
if (Arg::assigned) {
64+
return false;
65+
}
66+
if constexpr (Arg::nargs.getNargsChar() == '+') {
67+
Arg::assigned = true;
68+
for (const auto& value : values) {
69+
Arg::value.push_back(caster<typename Arg::baseType>(value));
70+
}
71+
if (Arg::validator) {
72+
Arg::validator(Arg::value, values, std::string_view(Arg::name));
73+
}
74+
if (Arg::callback) {
75+
Arg::callback(Arg::value, values);
76+
}
77+
return true;
78+
}
79+
if constexpr (Arg::nargs.getNargs() > 0) {
80+
if (Arg::nargs.getNargs() > values.size()) {
81+
throw Argo::InvalidArgument(std::format(
82+
"Positional Argument {} Invalid positional argument {}",
83+
std::string_view(Arg::name), values));
84+
}
85+
86+
if constexpr (is_array_v<typename Arg::type>) {
87+
for (int i = 0; i < Arg::nargs.getNargs(); i++) {
88+
Arg::value[i] = caster<typename Arg::baseType>(values[i]);
89+
}
90+
} else if constexpr (is_vector_v<typename Arg::type>) {
91+
for (int i = 0; i < Arg::nargs.getNargs(); i++) {
92+
Arg::value.push_back(caster<typename Arg::baseType>(values[i]));
93+
}
94+
} else if constexpr (is_tuple_v<typename Arg::type>) {
95+
tupleAssign(Arg::value, values,
96+
std::make_index_sequence<
97+
std::tuple_size_v<typename Arg::type>>());
98+
} else {
99+
static_assert(false, "Invalid Type");
100+
}
101+
102+
Arg::assigned = true;
103+
if (Arg::validator) {
104+
Arg::validator(Arg::value, values.subspan(0, Arg::nargs.getNargs()),
105+
std::string_view(Arg::name));
106+
}
107+
if (Arg::callback) {
108+
Arg::callback(Arg::value, values.subspan(0, Arg::nargs.getNargs()));
109+
}
110+
values = values.subspan(Arg::nargs.getNargs());
111+
return values.empty();
112+
}
113+
}.template operator()<PArg>() ||
114+
...);
115+
}
116+
};
117+
56118
template <class Arguments, class PArg>
57119
struct Assigner {
58120
template <ArgType Head>
@@ -64,14 +126,7 @@ struct Assigner {
64126
throw Argo::InvalidArgument(
65127
std::format("Flag {} can not take value", key));
66128
} else {
67-
if (PArg::assigned) {
68-
throw Argo::InvalidArgument(
69-
std::format("Flag {} can not take value", key));
70-
}
71-
Head::value = true;
72-
Head::assigned = true;
73-
assignOneArg<PArg>(std::string_view(PArg::name), values);
74-
return true;
129+
PArgAssigner<PArg>::assign(values);
75130
}
76131
}
77132
Head::value = true;
@@ -101,18 +156,10 @@ struct Assigner {
101156
if constexpr (std::is_same_v<PArg, std::tuple<>>) {
102157
throw Argo::InvalidArgument(
103158
std::format("Argument {} cannot take more than one value got {}",
104-
key,
105-
values.size()));
159+
key, values.size()));
106160
} else {
107-
if (PArg::assigned) {
108-
throw Argo::InvalidArgument(std::format(
109-
"Argument {} cannot take more than one value got {}",
110-
key,
111-
values.size()));
112-
}
113161
assignOneArg<Head>(key, values.subspan(0, 1));
114-
assignOneArg<PArg>(std::string_view(PArg::name), values.subspan(1));
115-
return true;
162+
return PArgAssigner<PArg>::assign(values.subspan(1));
116163
}
117164
} else if constexpr (Head::nargs.getNargsChar() == '*') {
118165
if (values.empty()) {
@@ -157,18 +204,10 @@ struct Assigner {
157204
if constexpr (std::is_same_v<PArg, std::tuple<>>) {
158205
throw Argo::InvalidArgument(
159206
std::format("Argument {} should take exactly one value but {}",
160-
key,
161-
values.size()));
207+
key, values.size()));
162208
} else {
163-
if (PArg::assigned) {
164-
throw Argo::InvalidArgument(std::format(
165-
"Argument {} should take exactly one value but {}",
166-
key,
167-
values.size()));
168-
}
169209
assignOneArg<Head>(key, values.subspan(0, 1));
170-
assignOneArg<PArg>(std::string_view(PArg::name), values.subspan(1));
171-
return true;
210+
return PArgAssigner<PArg>::assign(values.subspan(1));
172211
}
173212
}
174213
Head::value = caster<typename Head::baseType>(values[0]);
@@ -188,8 +227,7 @@ struct Assigner {
188227
caster<array_base_t<typename Head::type>>(values[idx]);
189228
}
190229
} else if constexpr (is_tuple_v<typename Head::type>) {
191-
tupleAssign(Head::value,
192-
values,
230+
tupleAssign(Head::value, values,
193231
std::make_index_sequence<
194232
std::tuple_size_v<typename Head::type>>());
195233
} else {
@@ -211,28 +249,16 @@ struct Assigner {
211249
if (values.size() < Head::nargs.getNargs()) {
212250
throw Argo::InvalidArgument(
213251
std::format("Argument {} should take exactly {} value but {}",
214-
key,
215-
Head::nargs.getNargs(),
216-
values.size()));
252+
key, Head::nargs.getNargs(), values.size()));
217253
}
218254
if constexpr (std::is_same_v<PArg, std::tuple<>>) {
219255
throw Argo::InvalidArgument(
220256
std::format("Argument {} should take exactly {} value but {}",
221-
key,
222-
Head::nargs.getNargs(),
223-
values.size()));
257+
key, Head::nargs.getNargs(), values.size()));
224258
} else {
225-
if (PArg::assigned) {
226-
throw Argo::InvalidArgument(
227-
std::format("Argument {} should take exactly {} value but {}",
228-
key,
229-
Head::nargs.getNargs(),
230-
values.size()));
231-
}
232259
assignOneArg<Head>(key, values.subspan(0, Head::nargs.getNargs()));
233-
assignOneArg<PArg>(std::string_view(PArg::name),
234-
values.subspan(Head::nargs.getNargs()));
235-
return true;
260+
return PArgAssigner<PArg>::assign(
261+
values.subspan(Head::nargs.getNargs()));
236262
}
237263
}
238264
}
@@ -252,7 +278,7 @@ struct Assigner {
252278
}
253279

254280
template <class T>
255-
static auto assignFlagImpl(std::string_view key) {
281+
static auto assignFlagImpl(std::string_view key) -> void {
256282
[&key]<std::size_t... Is>(std::index_sequence<Is...>) {
257283
if (!(... || [&key]<ArgType Head>() {
258284
if constexpr (std::derived_from<Head, FlagArgTag>) {
@@ -270,13 +296,13 @@ struct Assigner {
270296
}(std::make_index_sequence<std::tuple_size_v<T>>());
271297
}
272298

273-
static auto assign(std::string_view key, std::span<std::string_view> values) {
299+
static auto assign(std::string_view key,
300+
std::span<std::string_view> values) -> void {
274301
if (key.empty()) {
275302
if constexpr (!std::is_same_v<PArg, std::tuple<>>) {
276-
if (PArg::assigned) {
303+
if (!PArgAssigner<PArg>::assign(values)) {
277304
throw InvalidArgument(std::format("Duplicated positional argument"));
278305
}
279-
assignOneArg<PArg>(std::string_view(PArg::name), values);
280306
return;
281307
} else {
282308
throw Argo::InvalidArgument(

Argo/ArgoParser.cc

+40-32
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class Parser {
8888
: info_(std::move(info)), subParsers(tuple){};
8989

9090
template <class Type, ArgName Name, auto arg1 = Unspecified(),
91-
auto arg2 = Unspecified(), class... T>
91+
auto arg2 = Unspecified(), bool ISPArg, class... T>
9292
auto createArg(T... args) {
9393
static_assert(!Name.containsInvalidChar(), "Name has invalid char");
9494
static_assert(Name.hasValidNameLength(),
@@ -135,13 +135,16 @@ class Parser {
135135
if constexpr (is_tuple_v<Type>) {
136136
return NArgs{static_cast<int>(std::tuple_size_v<Type>)};
137137
}
138+
if constexpr (ISPArg) {
139+
return NArgs(1);
140+
}
138141
return NArgs('?');
139142
}
140143
}();
141144

142-
static_assert(!(is_array_v<Type> and nargs.nargs == 1),
145+
static_assert(!(is_array_v<Type> and nargs.getNargs() == 1),
143146
"Array size must be more than one");
144-
static_assert(!(is_tuple_v<Type> and nargs.nargs == 1),
147+
static_assert(!(is_tuple_v<Type> and nargs.getNargs() == 1),
145148
"Tuple size must be more than one");
146149

147150
static constexpr auto required = []() {
@@ -156,8 +159,7 @@ class Parser {
156159
}
157160
}();
158161
if constexpr (!std::is_same_v<PArg, std::tuple<>>) {
159-
static_assert(!(std::string_view(Name) == std::string_view(PArg::name)),
160-
"Duplicated name");
162+
static_assert(SearchIndex<PArg, Name>::value == -1, "Duplicated name");
161163
}
162164
static_assert(
163165
(Name.shortName == '\0') ||
@@ -166,11 +168,11 @@ class Parser {
166168
static_assert( //
167169
Argo::SearchIndex<Args, Name>::value == -1, //
168170
"Duplicated name");
169-
static_assert( //
170-
(nargs.nargs > 0 //
171-
|| nargs.nargs_char == '?' //
172-
|| nargs.nargs_char == '+' //
173-
|| nargs.nargs_char == '*'), //
171+
static_assert( //
172+
(nargs.getNargs() > 0 //
173+
|| nargs.getNargsChar() == '?' //
174+
|| nargs.getNargsChar() == '+' //
175+
|| nargs.getNargsChar() == '*'), //
174176
"nargs must be '?', '+', '*' or int");
175177

176178
ArgInitializer<Type, Name, nargs, required, ID>::init(
@@ -179,39 +181,47 @@ class Parser {
179181
}
180182

181183
/*!
182-
* Type: type of argument
183184
* Name: name of argument
184-
* arg1: ShortName or NArgs or Unspecified
185-
* arg2: NArgs or Unspecified
185+
* Type: type of argument
186+
* arg1: Required(bool) or NArgs or Unspecified
187+
* arg2: Required(bool) or NArgs or Unspecified
186188
*/
187189
template <ArgName Name, class Type, auto arg1 = Unspecified(),
188190
auto arg2 = Unspecified(), class... T>
189191
auto addArg(T... args) {
190-
auto arg = createArg<Type, Name, arg1, arg2>(std::forward<T>(args)...);
191-
return Parser<ID,
192-
tuple_append_t<Args, typename decltype(arg)::type>,
193-
PArg,
194-
HArg,
195-
SubParsers>(std::move(this->info_), subParsers);
192+
auto arg =
193+
createArg<Type, Name, arg1, arg2, false>(std::forward<T>(args)...);
194+
return Parser<ID, tuple_append_t<Args, typename decltype(arg)::type>, PArg,
195+
HArg, SubParsers>(std::move(this->info_), subParsers);
196196
}
197197

198+
/*!
199+
* Name: name of argument
200+
* Type: type of argument
201+
* arg1: Required(bool) or NArgs or Unspecified
202+
* arg2: Required(bool) or NArgs or Unspecified
203+
*/
198204
template <ArgName Name, class Type, auto arg1 = Unspecified(),
199205
auto arg2 = Unspecified(), class... T>
200206
auto addPositionalArg(T... args) {
201-
static_assert(std::is_same_v<PArg, std::tuple<>>,
202-
"Positional argument cannot set more than one");
203207
static_assert(Name.shortName == '\0',
204208
"Positional argment cannot have short name");
205-
auto arg = createArg<Type, Name, arg1, arg2>(std::forward<T>(args)...);
206-
return Parser<ID, Args, typename decltype(arg)::type, HArg, SubParsers>(
207-
std::move(this->info_), subParsers);
209+
auto arg =
210+
createArg<Type, Name, arg1, arg2, true>(std::forward<T>(args)...);
211+
212+
static_assert(decltype(arg)::type::nargs.getNargsChar() != '?',
213+
"Cannot assign narg: ? to the positional argument");
214+
static_assert(decltype(arg)::type::nargs.getNargsChar() != '*',
215+
"Cannot assign narg: * to the positional argument");
216+
217+
return Parser<ID, Args, tuple_append_t<PArg, typename decltype(arg)::type>,
218+
HArg, SubParsers>(std::move(this->info_), subParsers);
208219
}
209220

210221
template <ArgName Name, class... T>
211222
auto addFlag(T... args) {
212223
if constexpr (!std::is_same_v<PArg, std::tuple<>>) {
213-
static_assert(!(std::string_view(Name) == std::string_view(PArg::name)),
214-
"Duplicated name");
224+
static_assert(SearchIndex<PArg, Name>::value == -1, "Duplicated name");
215225
}
216226
static_assert(
217227
(Name.shortName == '\0') ||
@@ -220,10 +230,7 @@ class Parser {
220230
static_assert(Argo::SearchIndex<Args, Name>::value == -1,
221231
"Duplicated name");
222232
FlagArgInitializer<Name, ID>::init(std::forward<T>(args)...);
223-
return Parser<ID,
224-
tuple_append_t<Args, FlagArg<Name, ID>>,
225-
PArg,
226-
HArg,
233+
return Parser<ID, tuple_append_t<Args, FlagArg<Name, ID>>, PArg, HArg,
227234
SubParsers>(std::move(this->info_), subParsers);
228235
}
229236

@@ -257,8 +264,9 @@ class Parser {
257264
throw ParseError("Parser did not parse argument, call parse first");
258265
}
259266
if constexpr (!std::is_same_v<PArg, std::tuple<>>) {
260-
if constexpr (std::string_view(Name) == std::string_view(PArg::name)) {
261-
return PArg::value;
267+
if constexpr (SearchIndex<PArg, Name>::value != -1) {
268+
return std::tuple_element_t<SearchIndex<PArg, Name>::value,
269+
PArg>::value;
262270
} else {
263271
static_assert(SearchIndex<Args, Name>::value != -1,
264272
"Argument does not exist");

0 commit comments

Comments
 (0)