Revive remaining method

I reimplemented remaining() method for backward compatibility.

It consumes "all" remaining args.

So, I added mAcceptsOptionalLikeValue flag and handle it by using this
flag.

Currently, remaining() behavior is slightly different from the original when no
args are provided and get<Container<T>>() method is called.
Originally it raises an exception. But current implementation returns
an empty container instead of exception.

It is possible to implement complete backward compatibility by
referencing mAcceptsOptionalLikeValue flag and raises an exception in get() method,
but I did not do this.
I think that is too much.
This commit is contained in:
Yoshihiro Hokazono 2021-09-12 03:36:05 +09:00
parent c6c3be04d3
commit 3d559d3a23

View File

@ -490,6 +490,11 @@ public:
return *this; return *this;
} }
Argument &remaining() {
mAcceptsOptionalLikeValue = true;
return nargs(NArgsPattern::ANY);
}
template <typename Iterator> template <typename Iterator>
Iterator consume(Iterator start, Iterator end, Iterator consume(Iterator start, Iterator end,
std::string_view usedName = {}) { std::string_view usedName = {}) {
@ -501,25 +506,21 @@ public:
const auto numArgsMax = mNumArgsRange.get_max(); const auto numArgsMax = mNumArgsRange.get_max();
const auto numArgsMin = mNumArgsRange.get_min(); const auto numArgsMin = mNumArgsRange.get_min();
std::size_t dist = 0;
if (numArgsMax == 0) { if (numArgsMax == 0) {
mValues.emplace_back(mImplicitValue); mValues.emplace_back(mImplicitValue);
return start; return start;
} else if (static_cast<std::size_t>(std::distance(start, end)) >= numArgsMin) { } else if ((dist = static_cast<std::size_t>(std::distance(start, end))) >= numArgsMin) {
if (numArgsMax < dist) {
auto it = start; end = std::next(start, numArgsMax);
for (std::size_t i = 0; it != end; ++it, ++i) {
if (Argument::is_optional(*it)) {
break;
} }
if (i >= numArgsMax) { if (!mAcceptsOptionalLikeValue) {
break; end = std::find_if(start, end, Argument::is_optional);
} dist = static_cast<std::size_t>(std::distance(start, end));
}
auto dist = static_cast<std::size_t>(std::distance(start, it));
if (dist < numArgsMin) { if (dist < numArgsMin) {
throw std::runtime_error("Too few arguments"); throw std::runtime_error("Too few arguments");
} }
end = it; }
struct action_apply { struct action_apply {
void operator()(valued_action &f) { void operator()(valued_action &f) {
@ -529,6 +530,7 @@ public:
void operator()(void_action &f) { void operator()(void_action &f) {
std::for_each(start, end, f); std::for_each(start, end, f);
if (!self.mDefaultValue.has_value()) { if (!self.mDefaultValue.has_value()) {
if (!self.mAcceptsOptionalLikeValue)
self.mValues.resize(std::distance(start, end)); self.mValues.resize(std::distance(start, end));
} }
} }
@ -882,6 +884,7 @@ private:
[](const std::string &aValue) { return aValue; }}; [](const std::string &aValue) { return aValue; }};
std::vector<std::any> mValues; std::vector<std::any> mValues;
SizeRange mNumArgsRange {1, 1}; SizeRange mNumArgsRange {1, 1};
bool mAcceptsOptionalLikeValue = false;
bool mIsOptional : true; bool mIsOptional : true;
bool mIsRequired : true; bool mIsRequired : true;
bool mIsRepeatable : true; bool mIsRepeatable : true;