mirror of
https://github.com/KeqingMoe/argparse.git
synced 2025-07-04 15:14:39 +00:00
Merge pull request #52 from lichray/cleanup
Cleanup & allow creating and accessing arguments with string_view
This commit is contained in:
commit
d3127eb737
@ -64,7 +64,7 @@ struct is_container<
|
|||||||
decltype(std::declval<T>().begin()),
|
decltype(std::declval<T>().begin()),
|
||||||
decltype(std::declval<T>().end()),
|
decltype(std::declval<T>().end()),
|
||||||
decltype(std::declval<T>().size())>,
|
decltype(std::declval<T>().size())>,
|
||||||
void>> : public std::true_type {};
|
void>> : std::true_type {};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr bool is_container_v = is_container<T>::value;
|
static constexpr bool is_container_v = is_container<T>::value;
|
||||||
@ -99,18 +99,28 @@ class Argument {
|
|||||||
friend auto operator<<(std::ostream &, ArgumentParser const &)
|
friend auto operator<<(std::ostream &, ArgumentParser const &)
|
||||||
-> std::ostream &;
|
-> std::ostream &;
|
||||||
|
|
||||||
public:
|
template <size_t N, size_t... I>
|
||||||
Argument() = default;
|
explicit Argument(std::string(&&a)[N], std::index_sequence<I...>)
|
||||||
|
: mIsOptional((is_optional(a[I]) || ...)), mIsRequired(false),
|
||||||
template <typename... Args>
|
mIsUsed(false) {
|
||||||
explicit Argument(Args... args)
|
((void)mNames.push_back(std::move(a[I])), ...);
|
||||||
: mNames({std::move(args)...}), mIsOptional((is_optional(args) || ...)) {
|
|
||||||
std::sort(
|
std::sort(
|
||||||
mNames.begin(), mNames.end(), [](const auto &lhs, const auto &rhs) {
|
mNames.begin(), mNames.end(), [](const auto &lhs, const auto &rhs) {
|
||||||
return lhs.size() == rhs.size() ? lhs < rhs : lhs.size() < rhs.size();
|
return lhs.size() == rhs.size() ? lhs < rhs : lhs.size() < rhs.size();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Argument() = default;
|
||||||
|
|
||||||
|
template <typename... Args,
|
||||||
|
std::enable_if_t<
|
||||||
|
std::conjunction_v<std::is_constructible<std::string, Args>...>,
|
||||||
|
int> = 0>
|
||||||
|
explicit Argument(Args &&... args)
|
||||||
|
: Argument({std::string(std::forward<Args>(args))...},
|
||||||
|
std::make_index_sequence<sizeof...(Args)>{}) {}
|
||||||
|
|
||||||
Argument &help(std::string aHelp) {
|
Argument &help(std::string aHelp) {
|
||||||
mHelp = std::move(aHelp);
|
mHelp = std::move(aHelp);
|
||||||
return *this;
|
return *this;
|
||||||
@ -201,8 +211,8 @@ public:
|
|||||||
if (mIsOptional) {
|
if (mIsOptional) {
|
||||||
if (mIsUsed && mValues.size() != mNumArgs && !mDefaultValue.has_value()) {
|
if (mIsUsed && mValues.size() != mNumArgs && !mDefaultValue.has_value()) {
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
stream << mUsedName << ": expected " << mNumArgs
|
stream << mUsedName << ": expected " << mNumArgs << " argument(s). "
|
||||||
<< " argument(s). " << mValues.size() << " provided.";
|
<< mValues.size() << " provided.";
|
||||||
throw std::runtime_error(stream.str());
|
throw std::runtime_error(stream.str());
|
||||||
} else {
|
} else {
|
||||||
// TODO: check if an implicit value was programmed for this argument
|
// TODO: check if an implicit value was programmed for this argument
|
||||||
@ -220,8 +230,8 @@ public:
|
|||||||
} else {
|
} else {
|
||||||
if (mValues.size() != mNumArgs && !mDefaultValue.has_value()) {
|
if (mValues.size() != mNumArgs && !mDefaultValue.has_value()) {
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
stream << mUsedName << ": expected " << mNumArgs
|
stream << mUsedName << ": expected " << mNumArgs << " argument(s). "
|
||||||
<< " argument(s). " << mValues.size() << " provided.";
|
<< mValues.size() << " provided.";
|
||||||
throw std::runtime_error(stream.str());
|
throw std::runtime_error(stream.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,7 +266,8 @@ public:
|
|||||||
* @throws std::logic_error in case of incompatible types
|
* @throws std::logic_error in case of incompatible types
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::enable_if_t<!details::is_container_v<T>, bool> operator==(const T &aRhs) const {
|
std::enable_if_t<!details::is_container_v<T>, bool>
|
||||||
|
operator==(const T &aRhs) const {
|
||||||
return get<T>() == aRhs;
|
return get<T>() == aRhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,18 +276,15 @@ public:
|
|||||||
* @throws std::logic_error in case of incompatible types
|
* @throws std::logic_error in case of incompatible types
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::enable_if_t<details::is_container_v<T>, bool> operator==(const T &aRhs) const {
|
std::enable_if_t<details::is_container_v<T>, bool>
|
||||||
|
operator==(const T &aRhs) const {
|
||||||
using ValueType = typename T::value_type;
|
using ValueType = typename T::value_type;
|
||||||
auto tLhs = get<T>();
|
auto tLhs = get<T>();
|
||||||
if (tLhs.size() != aRhs.size())
|
|
||||||
return false;
|
|
||||||
else {
|
|
||||||
return std::equal(std::begin(tLhs), std::end(tLhs), std::begin(aRhs),
|
return std::equal(std::begin(tLhs), std::end(tLhs), std::begin(aRhs),
|
||||||
[](const auto &lhs, const auto &rhs) {
|
std::end(aRhs), [](const auto &lhs, const auto &rhs) {
|
||||||
return std::any_cast<const ValueType &>(lhs) == rhs;
|
return std::any_cast<const ValueType &>(lhs) == rhs;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool is_integer(const std::string &aValue) {
|
static bool is_integer(const std::string &aValue) {
|
||||||
@ -326,7 +334,8 @@ private:
|
|||||||
* Getter for container types
|
* Getter for container types
|
||||||
* @throws std::logic_error in case of incompatible types
|
* @throws std::logic_error in case of incompatible types
|
||||||
*/
|
*/
|
||||||
template <typename CONTAINER> details::enable_if_container<CONTAINER> get() const {
|
template <typename CONTAINER>
|
||||||
|
details::enable_if_container<CONTAINER> get() const {
|
||||||
using ValueType = typename CONTAINER::value_type;
|
using ValueType = typename CONTAINER::value_type;
|
||||||
CONTAINER tResult;
|
CONTAINER tResult;
|
||||||
if (!mValues.empty()) {
|
if (!mValues.empty()) {
|
||||||
@ -358,13 +367,11 @@ private:
|
|||||||
std::in_place_type<valued_action>,
|
std::in_place_type<valued_action>,
|
||||||
[](const std::string &aValue) { return aValue; }};
|
[](const std::string &aValue) { return aValue; }};
|
||||||
std::vector<std::any> mValues;
|
std::vector<std::any> mValues;
|
||||||
std::vector<std::string> mRawValues;
|
|
||||||
size_t mNumArgs = 1;
|
size_t mNumArgs = 1;
|
||||||
bool mIsOptional = false;
|
bool mIsOptional : 1;
|
||||||
bool mIsRequired = false;
|
bool mIsRequired : 1;
|
||||||
bool mIsUsed = false; // relevant for optional arguments. True if used by user
|
bool mIsUsed : 1; // True if the optional argument is used by user
|
||||||
|
|
||||||
public:
|
|
||||||
static constexpr auto mHelpOption = "-h";
|
static constexpr auto mHelpOption = "-h";
|
||||||
static constexpr auto mHelpOptionLong = "--help";
|
static constexpr auto mHelpOptionLong = "--help";
|
||||||
};
|
};
|
||||||
@ -418,7 +425,7 @@ public:
|
|||||||
// Parameter packed add_parents method
|
// Parameter packed add_parents method
|
||||||
// Accepts a variadic number of ArgumentParser objects
|
// Accepts a variadic number of ArgumentParser objects
|
||||||
template <typename... Targs> void add_parents(const Targs &... Fargs) {
|
template <typename... Targs> void add_parents(const Targs &... Fargs) {
|
||||||
for (auto &tParentParser : {Fargs...}) {
|
for (const ArgumentParser &tParentParser : {std::ref(Fargs)...}) {
|
||||||
for (auto &tArgument : tParentParser.mPositionalArguments) {
|
for (auto &tArgument : tParentParser.mPositionalArguments) {
|
||||||
auto it =
|
auto it =
|
||||||
mPositionalArguments.insert(cend(mPositionalArguments), tArgument);
|
mPositionalArguments.insert(cend(mPositionalArguments), tArgument);
|
||||||
@ -456,19 +463,15 @@ public:
|
|||||||
* @throws std::logic_error in case of an invalid argument name
|
* @throws std::logic_error in case of an invalid argument name
|
||||||
* @throws std::logic_error in case of incompatible types
|
* @throws std::logic_error in case of incompatible types
|
||||||
*/
|
*/
|
||||||
template <typename T = std::string> T get(const std::string &aArgumentName) {
|
template <typename T = std::string> T get(std::string_view aArgumentName) {
|
||||||
auto tIterator = mArgumentMap.find(aArgumentName);
|
return (*this)[aArgumentName].get<T>();
|
||||||
if (tIterator != mArgumentMap.end()) {
|
|
||||||
return tIterator->second->get<T>();
|
|
||||||
}
|
|
||||||
throw std::logic_error("No such argument");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Indexing operator. Return a reference to an Argument object
|
/* Indexing operator. Return a reference to an Argument object
|
||||||
* Used in conjuction with Argument.operator== e.g., parser["foo"] == true
|
* Used in conjuction with Argument.operator== e.g., parser["foo"] == true
|
||||||
* @throws std::logic_error in case of an invalid argument name
|
* @throws std::logic_error in case of an invalid argument name
|
||||||
*/
|
*/
|
||||||
Argument &operator[](const std::string &aArgumentName) {
|
Argument &operator[](std::string_view aArgumentName) {
|
||||||
auto tIterator = mArgumentMap.find(aArgumentName);
|
auto tIterator = mArgumentMap.find(aArgumentName);
|
||||||
if (tIterator != mArgumentMap.end()) {
|
if (tIterator != mArgumentMap.end()) {
|
||||||
return *(tIterator->second);
|
return *(tIterator->second);
|
||||||
|
@ -44,3 +44,22 @@ TEST_CASE("Parse multiple toggle arguments with implicit values", "[optional_arg
|
|||||||
REQUIRE(program.get<bool>("-u") == false);
|
REQUIRE(program.get<bool>("-u") == false);
|
||||||
REQUIRE(program.get<bool>("-x") == true);
|
REQUIRE(program.get<bool>("-x") == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Parse arguments of different types", "[optional_arguments]") {
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
argparse::ArgumentParser program("test");
|
||||||
|
program.add_argument("--this-argument-is-longer-than-any-sso-buffer-that-"
|
||||||
|
"makes-sense-unless-your-cache-line-is-this-long"s);
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(program.parse_args({"test"}));
|
||||||
|
|
||||||
|
program.add_argument("-string"s, "-string-view"sv, "-builtin")
|
||||||
|
.default_value(false)
|
||||||
|
.implicit_value(true);
|
||||||
|
|
||||||
|
program.parse_args({"test", "-string-view"});
|
||||||
|
REQUIRE(program["-string"sv] == true);
|
||||||
|
REQUIRE(program["-string-view"] == true);
|
||||||
|
REQUIRE(program["-builtin"s] == true);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user