From 158b8a0d2f9f62377010a5d35157a9abb5b6565f Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Mon, 7 Feb 2022 13:10:03 -0700 Subject: [PATCH 01/18] Enable clang-tidy readability-braces-around-statements check All tests still pass. Signed-off-by: Sean Robinson --- .clang-tidy | 1 - include/argparse/argparse.hpp | 178 +++++++++++++++++++++------------- 2 files changed, 108 insertions(+), 71 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 56d7f643..e156a4a2 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,7 +1,6 @@ Checks: -*, readability-*, - -readability-braces-around-statements, -readability-container-size-empty, -readability-else-after-return, -readability-implicit-bool-conversion, diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index 2aa06fd5..2c31cd96 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -101,13 +101,15 @@ template std::string repr(T const &val) { std::next(val.begin()), std::next(val.begin(), std::min(size, repr_max_container_size) - 1), [&out](const auto &v) { out << " " << repr(v); }); - if (size <= repr_max_container_size) + if (size <= repr_max_container_size) { out << " "; - else + } else { out << "..."; + } } - if (size > 0) + if (size > 0) { out << repr(*std::prev(val.end())); + } out << "}"; return out.str(); } else if constexpr (is_streamable_v) { @@ -197,10 +199,11 @@ inline auto do_from_chars(std::string_view s) -> T { auto [first, last] = pointer_range(s); auto [ptr, ec] = std::from_chars(first, last, x, Param); if (ec == std::errc()) { - if (ptr == last) + if (ptr == last) { return x; - else + } else { throw std::invalid_argument{"pattern does not match to the end"}; + } } else if (ec == std::errc::invalid_argument) { throw std::invalid_argument{"pattern not found"}; } else if (ec == std::errc::result_out_of_range) { @@ -218,21 +221,23 @@ template struct parse_number { template struct parse_number { auto operator()(std::string_view s) -> T { - if (auto [ok, rest] = consume_hex_prefix(s); ok) + if (auto [ok, rest] = consume_hex_prefix(s); ok) { return do_from_chars(rest); - else + } else { throw std::invalid_argument{"pattern not found"}; + } } }; template struct parse_number { auto operator()(std::string_view s) -> T { - if (auto [ok, rest] = consume_hex_prefix(s); ok) + if (auto [ok, rest] = consume_hex_prefix(s); ok) { return do_from_chars(rest); - else if (starts_with("0"sv, s)) + } else if (starts_with("0"sv, s)) { return do_from_chars(rest); - else + } else { return do_from_chars(rest); + } } }; @@ -246,18 +251,20 @@ template <> constexpr auto generic_strtod = strtold; } // namespace template inline auto do_strtod(std::string const &s) -> T { - if (isspace(static_cast(s[0])) || s[0] == '+') + if (isspace(static_cast(s[0])) || s[0] == '+') { throw std::invalid_argument{"pattern not found"}; + } auto [first, last] = pointer_range(s); char *ptr; errno = 0; if (auto x = generic_strtod(first, &ptr); errno == 0) { - if (ptr == last) + if (ptr == last) { return x; - else + } else { throw std::invalid_argument{"pattern does not match to the end"}; + } } else if (errno == ERANGE) { throw std::range_error{"not representable"}; } else { @@ -267,9 +274,10 @@ template inline auto do_strtod(std::string const &s) -> T { template struct parse_number { auto operator()(std::string const &s) -> T { - if (auto r = consume_hex_prefix(s); r.is_hexadecimal) + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { throw std::invalid_argument{ "chars_format::general does not parse hexfloat"}; + } return do_strtod(s); } @@ -277,8 +285,9 @@ template struct parse_number { template struct parse_number { auto operator()(std::string const &s) -> T { - if (auto r = consume_hex_prefix(s); !r.is_hexadecimal) + if (auto r = consume_hex_prefix(s); !r.is_hexadecimal) { throw std::invalid_argument{"chars_format::hex parses hexfloat"}; + } return do_strtod(s); } @@ -286,12 +295,14 @@ template struct parse_number { template struct parse_number { auto operator()(std::string const &s) -> T { - if (auto r = consume_hex_prefix(s); r.is_hexadecimal) + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { throw std::invalid_argument{ "chars_format::scientific does not parse hexfloat"}; - if (s.find_first_of("eE") == s.npos) + } + if (s.find_first_of("eE") == s.npos) { throw std::invalid_argument{ "chars_format::scientific requires exponent part"}; + } return do_strtod(s); } @@ -299,12 +310,14 @@ template struct parse_number { template struct parse_number { auto operator()(std::string const &s) -> T { - if (auto r = consume_hex_prefix(s); r.is_hexadecimal) + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { throw std::invalid_argument{ "chars_format::fixed does not parse hexfloat"}; - if (s.find_first_of("eE") != s.npos) + } + if (s.find_first_of("eE") != s.npos) { throw std::invalid_argument{ "chars_format::fixed does not parse exponent part"}; + } return do_strtod(s); } @@ -375,15 +388,16 @@ class Argument { using action_type = std::conditional_t< std::is_void_v>, void_action, valued_action>; - if constexpr (sizeof...(Args) == 0) + if constexpr (sizeof...(Args) == 0) { mAction.emplace(std::forward(aAction)); - else + } else { mAction.emplace( [f = std::forward(aAction), tup = std::make_tuple(std::forward(aBound)...)]( std::string const &opt) mutable { return details::apply_plus_one(f, tup, opt); }); + } return *this; } @@ -400,40 +414,42 @@ class Argument { return ((c == x) || ...); }; - if constexpr (is_one_of(Shape, 'd') && details::standard_integer) + if constexpr (is_one_of(Shape, 'd') && details::standard_integer) { action(details::parse_number()); - else if constexpr (is_one_of(Shape, 'i') && details::standard_integer) + } else if constexpr (is_one_of(Shape, 'i') && details::standard_integer) { action(details::parse_number()); - else if constexpr (is_one_of(Shape, 'u') && - details::standard_unsigned_integer) + } else if constexpr (is_one_of(Shape, 'u') && + details::standard_unsigned_integer) { action(details::parse_number()); - else if constexpr (is_one_of(Shape, 'o') && - details::standard_unsigned_integer) + } else if constexpr (is_one_of(Shape, 'o') && + details::standard_unsigned_integer) { action(details::parse_number()); - else if constexpr (is_one_of(Shape, 'x', 'X') && - details::standard_unsigned_integer) + } else if constexpr (is_one_of(Shape, 'x', 'X') && + details::standard_unsigned_integer) { action(details::parse_number()); - else if constexpr (is_one_of(Shape, 'a', 'A') && - std::is_floating_point_v) + } else if constexpr (is_one_of(Shape, 'a', 'A') && + std::is_floating_point_v) { action(details::parse_number()); - else if constexpr (is_one_of(Shape, 'e', 'E') && - std::is_floating_point_v) + } else if constexpr (is_one_of(Shape, 'e', 'E') && + std::is_floating_point_v) { action(details::parse_number()); - else if constexpr (is_one_of(Shape, 'f', 'F') && - std::is_floating_point_v) + } else if constexpr (is_one_of(Shape, 'f', 'F') && + std::is_floating_point_v) { action(details::parse_number()); - else if constexpr (is_one_of(Shape, 'g', 'G') && - std::is_floating_point_v) + } else if constexpr (is_one_of(Shape, 'g', 'G') && + std::is_floating_point_v) { action(details::parse_number()); - else + } else { static_assert(alignof(T) == 0, "No scan specification for T"); + } return *this; } Argument &nargs(int aNumArgs) { - if (aNumArgs < 0) + if (aNumArgs < 0) { throw std::logic_error("Number of arguments must be non-negative"); + } mNumArgs = aNumArgs; return *this; } @@ -471,8 +487,9 @@ class Argument { void operator()(void_action &f) { std::for_each(first, last, f); if (!self.mDefaultValue.has_value()) { - if (auto expected = self.maybe_nargs()) + if (auto expected = self.maybe_nargs()) { self.mValues.resize(*expected); + } } } @@ -517,8 +534,9 @@ class Argument { } else { if (mValues.size() != expected && !mDefaultValue.has_value()) { std::stringstream stream; - if (!mUsedName.empty()) + if (!mUsedName.empty()) { stream << mUsedName << ": "; + } stream << *expected << " argument(s) expected. " << mValues.size() << " provided."; throw std::runtime_error(stream.str()); @@ -528,10 +546,11 @@ class Argument { } auto maybe_nargs() const -> std::optional { - if (mNumArgs < 0) + if (mNumArgs < 0) { return std::nullopt; - else + } else { return static_cast(mNumArgs); + } } std::size_t get_arguments_length() const { @@ -549,12 +568,14 @@ class Argument { std::ostream_iterator(nameStream, " ")); stream << nameStream.str() << "\t" << argument.mHelp; if (argument.mDefaultValue.has_value()) { - if (!argument.mHelp.empty()) + if (!argument.mHelp.empty()) { stream << " "; + } stream << "[default: " << argument.mDefaultValueRepr << "]"; } else if (argument.mIsRequired) { - if (!argument.mHelp.empty()) + if (!argument.mHelp.empty()) { stream << " "; + } stream << "[required]"; } stream << "\n"; @@ -586,10 +607,11 @@ class Argument { static constexpr int eof = std::char_traits::eof(); static auto lookahead(std::string_view s) -> int { - if (s.empty()) + if (s.empty()) { return eof; - else + } else { return static_cast(static_cast(s[0])); + } } /* @@ -648,10 +670,11 @@ class Argument { switch (lookahead(s)) { case '0': { s.remove_prefix(1); - if (s.empty()) + if (s.empty()) { return true; - else + } else { goto integer_part; + } } case '1': case '2': @@ -663,10 +686,11 @@ class Argument { case '8': case '9': { s = consume_digits(s); - if (s.empty()) + if (s.empty()) { return true; - else + } else { goto integer_part_consumed; + } } case '.': { s.remove_prefix(1); @@ -682,10 +706,11 @@ class Argument { switch (lookahead(s)) { case '.': { s.remove_prefix(1); - if (is_digit(lookahead(s))) + if (is_digit(lookahead(s))) { goto post_decimal_point; - else + } else { goto exponent_part_opt; + } } case 'e': case 'E': { @@ -748,10 +773,11 @@ class Argument { return true; case '-': { aName.remove_prefix(1); - if (aName.empty()) + if (aName.empty()) { return true; - else + } else { return is_decimal_literal(aName); + } } default: return true; @@ -764,10 +790,11 @@ class Argument { */ template T get() const { if (!mValues.empty()) { - if constexpr (details::is_container_v) + if constexpr (details::is_container_v) { return any_cast_container(mValues); - else + } else { return std::any_cast(mValues.front()); + } } if (mDefaultValue.has_value()) { return std::any_cast(mDefaultValue); @@ -781,15 +808,17 @@ class Argument { * @returns The stored value if any, std::nullopt otherwise. */ template auto present() const -> std::optional { - if (mDefaultValue.has_value()) + if (mDefaultValue.has_value()) { throw std::logic_error("Argument with default value always presents"); + } - if (mValues.empty()) + if (mValues.empty()) { return std::nullopt; - else if constexpr (details::is_container_v) + } else if constexpr (details::is_container_v) { return any_cast_container(mValues); - else + } else { return std::any_cast(mValues.front()); + } } template @@ -864,11 +893,13 @@ class ArgumentParser { mPositionalArguments(other.mPositionalArguments), mOptionalArguments(other.mOptionalArguments) { for (auto it = std::begin(mPositionalArguments); it != std::end(mPositionalArguments); - ++it) + ++it) { index_argument(it); + } for (auto it = std::begin(mOptionalArguments); it != std::end(mOptionalArguments); - ++it) + ++it) { index_argument(it); + } } ArgumentParser &operator=(const ArgumentParser &other) { @@ -884,9 +915,10 @@ class ArgumentParser { auto tArgument = mOptionalArguments.emplace(cend(mOptionalArguments), array_of_sv{Fargs...}); - if (!tArgument->mIsOptional) + if (!tArgument->mIsOptional) { mPositionalArguments.splice(cend(mPositionalArguments), mOptionalArguments, tArgument); + } index_argument(tArgument); return *tArgument; @@ -1011,28 +1043,32 @@ class ArgumentParser { } stream << "\n\n"; - if (!parser.mDescription.empty()) + if (!parser.mDescription.empty()) { stream << parser.mDescription << "\n\n"; + } - if (!parser.mPositionalArguments.empty()) + if (!parser.mPositionalArguments.empty()) { stream << "Positional arguments:\n"; + } for (const auto &mPositionalArgument : parser.mPositionalArguments) { stream.width(tLongestArgumentLength); stream << mPositionalArgument; } - if (!parser.mOptionalArguments.empty()) + if (!parser.mOptionalArguments.empty()) { stream << (parser.mPositionalArguments.empty() ? "" : "\n") << "Optional arguments:\n"; + } for (const auto &mOptionalArgument : parser.mOptionalArguments) { stream.width(tLongestArgumentLength); stream << mOptionalArgument; } - if (!parser.mEpilog.empty()) + if (!parser.mEpilog.empty()) { stream << parser.mEpilog << "\n\n"; + } return stream; } @@ -1114,8 +1150,9 @@ class ArgumentParser { // Used by print_help. std::size_t get_length_of_longest_argument() const { - if (mArgumentMap.empty()) + if (mArgumentMap.empty()) { return 0; + } std::vector argumentLengths(mArgumentMap.size()); std::transform(std::begin(mArgumentMap), std::end(mArgumentMap), std::begin(argumentLengths), [](const auto &argPair) { @@ -1129,8 +1166,9 @@ class ArgumentParser { using list_iterator = std::list::iterator; void index_argument(list_iterator argIt) { - for (auto &mName : std::as_const(argIt->mNames)) + for (auto &mName : std::as_const(argIt->mNames)) { mArgumentMap.insert_or_assign(mName, argIt); + } } std::string mProgramName; From 6a8b1318ec485b188cc84d3aa93ed767848256c2 Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Mon, 7 Feb 2022 14:27:06 -0700 Subject: [PATCH 02/18] Enable clang-tidy readability-container-size-empty check Signed-off-by: Sean Robinson --- .clang-tidy | 1 - include/argparse/argparse.hpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index e156a4a2..f48b448d 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,7 +1,6 @@ Checks: -*, readability-*, - -readability-container-size-empty, -readability-else-after-return, -readability-implicit-bool-conversion, -readability-function-cognitive-complexity, diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index 2c31cd96..f5bb2329 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -525,7 +525,7 @@ class Argument { stream << mNames[0] << ": required."; throw std::runtime_error(stream.str()); } - if (mIsUsed && mIsRequired && mValues.size() == 0) { + if (mIsUsed && mIsRequired && mValues.empty()) { std::stringstream stream; stream << mUsedName << ": no value provided."; throw std::runtime_error(stream.str()); From 7cbc66f65b6b46ca196e7ab4e4944315905953b3 Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Mon, 7 Feb 2022 14:27:06 -0700 Subject: [PATCH 03/18] Return default_arguments from operator& of two default_arguments operator& should return combined values of the same type, not a new type (i.e. bool). This is much more verbose, but easier to reason about without implied conversion. Signed-off-by: Sean Robinson --- include/argparse/argparse.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index f5bb2329..317ed2b0 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -332,8 +332,11 @@ enum class default_arguments : unsigned int { all = help | version, }; -inline bool operator& (const default_arguments &a, const default_arguments &b) { - return static_cast(a) & static_cast(b); +inline default_arguments operator& (const default_arguments &a, + const default_arguments &b) { + return static_cast( + static_cast::type>(a) & + static_cast::type>(b)); } class ArgumentParser; @@ -857,7 +860,7 @@ class ArgumentParser { std::string aVersion = "1.0", default_arguments aArgs = default_arguments::all) : mProgramName(std::move(aProgramName)), mVersion(std::move(aVersion)) { - if (aArgs & default_arguments::help) { + if ((aArgs & default_arguments::help) == default_arguments::help) { add_argument("-h", "--help") .action([&](const auto &) { std::cout << help().str(); @@ -868,7 +871,7 @@ class ArgumentParser { .implicit_value(true) .nargs(0); } - if (aArgs & default_arguments::version) { + if ((aArgs & default_arguments::version) == default_arguments::version) { add_argument("-v", "--version") .action([&](const auto &) { std::cout << mVersion; From b918763adf032daa1ef8df27873c8c9511438886 Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Mon, 7 Feb 2022 14:27:06 -0700 Subject: [PATCH 04/18] Enable clang-tidy readability-implicit-bool-conversion check Enabling this check caught the implicit bool conversion with default_arguments::operator& fixed in the previous commit. Signed-off-by: Sean Robinson --- .clang-tidy | 1 - 1 file changed, 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index f48b448d..e099fa85 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -2,7 +2,6 @@ Checks: -*, readability-*, -readability-else-after-return, - -readability-implicit-bool-conversion, -readability-function-cognitive-complexity, -readability-magic-numbers, -readability-named-parameter, From 9eb1fe5cefa7b87e7f9d1c371e5eaf763d7955a3 Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Mon, 7 Feb 2022 14:29:25 -0700 Subject: [PATCH 05/18] Enable clang-tidy readability-magic-numbers check Adds names for integer bases used with details::parse_number. Signed-off-by: Sean Robinson --- .clang-tidy | 1 - include/argparse/argparse.hpp | 22 +++++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index e099fa85..812baacd 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -3,7 +3,6 @@ Checks: readability-*, -readability-else-after-return, -readability-function-cognitive-complexity, - -readability-magic-numbers, -readability-named-parameter, -readability-qualified-auto, -readability-static-accessed-through-instance, diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index 317ed2b0..ec27b9d6 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -140,6 +140,10 @@ constexpr bool standard_unsigned_integer = true; } // namespace +constexpr int radix_8 = 8; +constexpr int radix_10 = 10; +constexpr int radix_16 = 16; + template constexpr bool standard_integer = standard_signed_integer || standard_unsigned_integer; @@ -219,10 +223,10 @@ template struct parse_number { } }; -template struct parse_number { +template struct parse_number { auto operator()(std::string_view s) -> T { if (auto [ok, rest] = consume_hex_prefix(s); ok) { - return do_from_chars(rest); + return do_from_chars(rest); } else { throw std::invalid_argument{"pattern not found"}; } @@ -232,11 +236,11 @@ template struct parse_number { template struct parse_number { auto operator()(std::string_view s) -> T { if (auto [ok, rest] = consume_hex_prefix(s); ok) { - return do_from_chars(rest); + return do_from_chars(rest); } else if (starts_with("0"sv, s)) { - return do_from_chars(rest); + return do_from_chars(rest); } else { - return do_from_chars(rest); + return do_from_chars(rest); } } }; @@ -418,18 +422,18 @@ class Argument { }; if constexpr (is_one_of(Shape, 'd') && details::standard_integer) { - action(details::parse_number()); + action(details::parse_number()); } else if constexpr (is_one_of(Shape, 'i') && details::standard_integer) { action(details::parse_number()); } else if constexpr (is_one_of(Shape, 'u') && details::standard_unsigned_integer) { - action(details::parse_number()); + action(details::parse_number()); } else if constexpr (is_one_of(Shape, 'o') && details::standard_unsigned_integer) { - action(details::parse_number()); + action(details::parse_number()); } else if constexpr (is_one_of(Shape, 'x', 'X') && details::standard_unsigned_integer) { - action(details::parse_number()); + action(details::parse_number()); } else if constexpr (is_one_of(Shape, 'a', 'A') && std::is_floating_point_v) { action(details::parse_number()); From b5fb663bc8e6aad92c84588cde750815258cbcab Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Mon, 7 Feb 2022 14:29:32 -0700 Subject: [PATCH 06/18] Enable clang-tidy readability-named-parameter check Adds names recommended by clang-tidy (e.g. "unused"). Note that clang-tidy v12 appears to detect unnamed parameters in lambdas, while clang-tidy v13 does not. Signed-off-by: Sean Robinson --- .clang-tidy | 1 - include/argparse/argparse.hpp | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 812baacd..107ed936 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -3,7 +3,6 @@ Checks: readability-*, -readability-else-after-return, -readability-function-cognitive-complexity, - -readability-named-parameter, -readability-qualified-auto, -readability-static-accessed-through-instance, diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index ec27b9d6..8bce3ab5 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -150,7 +150,7 @@ constexpr bool standard_integer = template constexpr decltype(auto) apply_plus_one_impl(F &&f, Tuple &&t, Extra &&x, - std::index_sequence) { + std::index_sequence unused) { return std::invoke(std::forward(f), std::get(std::forward(t))..., std::forward(x)); } @@ -347,11 +347,11 @@ class ArgumentParser; class Argument { friend class ArgumentParser; - friend auto operator<<(std::ostream &, ArgumentParser const &) + friend auto operator<<(std::ostream &stream, const ArgumentParser &parser) -> std::ostream &; template - explicit Argument(std::string_view(&&a)[N], std::index_sequence) + explicit Argument(std::string_view(&&a)[N], std::index_sequence unused) : mIsOptional((is_optional(a[I]) || ...)), mIsRequired(false), mIsRepeatable(false), mIsUsed(false) { ((void)mNames.emplace_back(a[I]), ...); @@ -866,7 +866,7 @@ class ArgumentParser { : mProgramName(std::move(aProgramName)), mVersion(std::move(aVersion)) { if ((aArgs & default_arguments::help) == default_arguments::help) { add_argument("-h", "--help") - .action([&](const auto &) { + .action([&](const auto &unused) { std::cout << help().str(); std::exit(0); }) @@ -877,7 +877,7 @@ class ArgumentParser { } if ((aArgs & default_arguments::version) == default_arguments::version) { add_argument("-v", "--version") - .action([&](const auto &) { + .action([&](const auto &unused) { std::cout << mVersion; std::exit(0); }) From bd4837f2404f20c0516d6e3579b7a0173df37d39 Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Wed, 9 Feb 2022 15:27:16 -0700 Subject: [PATCH 07/18] Enable clang-tidy's readability-qualified-auto check Following the clang-tidy suggested fix in consume_digits causes compile failures with MSVC 19.29 in our CI. Signed-off-by: Sean Robinson --- .clang-tidy | 1 - include/argparse/argparse.hpp | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 107ed936..419f5eed 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -3,7 +3,6 @@ Checks: readability-*, -readability-else-after-return, -readability-function-cognitive-complexity, - -readability-qualified-auto, -readability-static-accessed-through-instance, CheckOptions: diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index 8bce3ab5..ddade055 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -670,6 +670,7 @@ class Argument { // precondition: we have consumed or will consume at least one digit auto consume_digits = [=](std::string_view s) { + // NOLINTNEXTLINE(readability-qualified-auto) auto it = std::find_if_not(std::begin(s), std::end(s), is_digit); return s.substr(it - std::begin(s)); }; @@ -936,12 +937,12 @@ class ArgumentParser { template ArgumentParser &add_parents(const Targs &... Fargs) { for (const ArgumentParser &tParentParser : {std::ref(Fargs)...}) { - for (auto &tArgument : tParentParser.mPositionalArguments) { + for (const auto &tArgument : tParentParser.mPositionalArguments) { auto it = mPositionalArguments.insert(cend(mPositionalArguments), tArgument); index_argument(it); } - for (auto &tArgument : tParentParser.mOptionalArguments) { + for (const auto &tArgument : tParentParser.mOptionalArguments) { auto it = mOptionalArguments.insert(cend(mOptionalArguments), tArgument); index_argument(it); @@ -1173,7 +1174,7 @@ class ArgumentParser { using list_iterator = std::list::iterator; void index_argument(list_iterator argIt) { - for (auto &mName : std::as_const(argIt->mNames)) { + for (const auto &mName : std::as_const(argIt->mNames)) { mArgumentMap.insert_or_assign(mName, argIt); } } From c25a959597671a38395f0947f96efd9d188fe77d Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Mon, 7 Feb 2022 14:29:32 -0700 Subject: [PATCH 08/18] Enable clang-tidy readability-static-accessed-through-instance check Signed-off-by: Sean Robinson --- .clang-tidy | 1 - include/argparse/argparse.hpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 419f5eed..c1dd3006 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -3,7 +3,6 @@ Checks: readability-*, -readability-else-after-return, -readability-function-cognitive-complexity, - -readability-static-accessed-through-instance, CheckOptions: - { key: readability-identifier-naming.ClassCase, value: CamelCase } diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index ddade055..112dbb01 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -303,7 +303,7 @@ template struct parse_number { throw std::invalid_argument{ "chars_format::scientific does not parse hexfloat"}; } - if (s.find_first_of("eE") == s.npos) { + if (s.find_first_of("eE") == std::string::npos) { throw std::invalid_argument{ "chars_format::scientific requires exponent part"}; } @@ -318,7 +318,7 @@ template struct parse_number { throw std::invalid_argument{ "chars_format::fixed does not parse hexfloat"}; } - if (s.find_first_of("eE") != s.npos) { + if (s.find_first_of("eE") != std::string::npos) { throw std::invalid_argument{ "chars_format::fixed does not parse exponent part"}; } From 0b74da54d43f021325e2a1cbfb78a7adc6fda9a9 Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Mon, 7 Feb 2022 14:29:32 -0700 Subject: [PATCH 09/18] Enable clang-tidy cppcoreguidelines-special-member-functions check Also adds a default destructor, as recommended by the check. Signed-off-by: Sean Robinson --- .clang-tidy | 1 + include/argparse/argparse.hpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.clang-tidy b/.clang-tidy index c1dd3006..6dd99da2 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,5 +1,6 @@ Checks: -*, + cppcoreguidelines-special-member-functions, readability-*, -readability-else-after-return, -readability-function-cognitive-complexity, diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index 112dbb01..9b08ea04 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -910,6 +910,8 @@ class ArgumentParser { } } + ~ArgumentParser() = default; + ArgumentParser &operator=(const ArgumentParser &other) { auto tmp = other; std::swap(*this, tmp); From 3c317ddd2d9537133bba0e04f59159098d5f43d0 Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Mon, 7 Feb 2022 14:29:32 -0700 Subject: [PATCH 10/18] Enable clang-tidy clang-analyzer default checks Surprisingly, no fixes are required in argparse when turning on this suite of checks. Signed-off-by: Sean Robinson --- .clang-tidy | 1 + 1 file changed, 1 insertion(+) diff --git a/.clang-tidy b/.clang-tidy index 6dd99da2..8977e685 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,5 +1,6 @@ Checks: -*, + clang-analyzer-*, cppcoreguidelines-special-member-functions, readability-*, -readability-else-after-return, From d0a492ccbaf01ef924e473a87ed6c33c2fed9797 Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Mon, 7 Feb 2022 14:29:32 -0700 Subject: [PATCH 11/18] Enable clang-tidy readability-else-after-return check A common pattern in the previous code was goto/return/throw if a condition is true, else goto/return/throw something different. The new pattern uses the fact that the second goto/return/throw is only reachable when the first goto/return/throw is not called. Signed-off-by: Sean Robinson --- .clang-tidy | 1 - include/argparse/argparse.hpp | 113 +++++++++++++++------------------- 2 files changed, 51 insertions(+), 63 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 8977e685..62c77f15 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -3,7 +3,6 @@ Checks: clang-analyzer-*, cppcoreguidelines-special-member-functions, readability-*, - -readability-else-after-return, -readability-function-cognitive-complexity, CheckOptions: diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index 9b08ea04..483efb97 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -192,9 +192,8 @@ constexpr auto consume_hex_prefix(std::string_view s) if (starts_with("0x"sv, s) || starts_with("0X"sv, s)) { s.remove_prefix(2); return {true, s}; - } else { - return {false, s}; } + return {false, s}; } template @@ -205,16 +204,16 @@ inline auto do_from_chars(std::string_view s) -> T { if (ec == std::errc()) { if (ptr == last) { return x; - } else { - throw std::invalid_argument{"pattern does not match to the end"}; } - } else if (ec == std::errc::invalid_argument) { + throw std::invalid_argument{"pattern does not match to the end"}; + } + if (ec == std::errc::invalid_argument) { throw std::invalid_argument{"pattern not found"}; - } else if (ec == std::errc::result_out_of_range) { + } + if (ec == std::errc::result_out_of_range) { throw std::range_error{"not representable"}; - } else { - return x; // unreachable } + return x; // unreachable } template struct parse_number { @@ -227,21 +226,21 @@ template struct parse_number { auto operator()(std::string_view s) -> T { if (auto [ok, rest] = consume_hex_prefix(s); ok) { return do_from_chars(rest); - } else { - throw std::invalid_argument{"pattern not found"}; } + throw std::invalid_argument{"pattern not found"}; } }; template struct parse_number { auto operator()(std::string_view s) -> T { - if (auto [ok, rest] = consume_hex_prefix(s); ok) { + auto [ok, rest] = consume_hex_prefix(s); + if (ok) { return do_from_chars(rest); - } else if (starts_with("0"sv, s)) { + } + if (starts_with("0"sv, s)) { return do_from_chars(rest); - } else { - return do_from_chars(rest); } + return do_from_chars(rest); } }; @@ -263,17 +262,17 @@ template inline auto do_strtod(std::string const &s) -> T { char *ptr; errno = 0; - if (auto x = generic_strtod(first, &ptr); errno == 0) { + auto x = generic_strtod(first, &ptr); + if (errno == 0) { if (ptr == last) { return x; - } else { - throw std::invalid_argument{"pattern does not match to the end"}; } - } else if (errno == ERANGE) { + throw std::invalid_argument{"pattern does not match to the end"}; + } + if (errno == ERANGE) { throw std::range_error{"not representable"}; - } else { - return x; // unreachable } + return x; // unreachable } template struct parse_number { @@ -478,7 +477,8 @@ class Argument { mValues.emplace_back(mImplicitValue); std::visit([](const auto &aAction) { aAction({}); }, mAction); return start; - } else if (mNumArgs <= std::distance(start, end)) { + } + if (mNumArgs <= std::distance(start, end)) { if (auto expected = maybe_nargs()) { end = std::next(start, *expected); if (std::any_of(start, end, Argument::is_optional)) { @@ -505,12 +505,12 @@ class Argument { }; std::visit(action_apply{start, end, *this}, mAction); return end; - } else if (mDefaultValue.has_value()) { + } + if (mDefaultValue.has_value()) { return start; - } else { - throw std::runtime_error("Too few arguments for '" + - std::string(mUsedName) + "'."); } + throw std::runtime_error("Too few arguments for '" + + std::string(mUsedName) + "'."); } /* @@ -525,29 +525,26 @@ class Argument { stream << mUsedName << ": expected " << *expected << " argument(s). " << mValues.size() << " provided."; throw std::runtime_error(stream.str()); - } else { - // TODO: check if an implicit value was programmed for this argument - if (!mIsUsed && !mDefaultValue.has_value() && mIsRequired) { - std::stringstream stream; - stream << mNames[0] << ": required."; - throw std::runtime_error(stream.str()); - } - if (mIsUsed && mIsRequired && mValues.empty()) { - std::stringstream stream; - stream << mUsedName << ": no value provided."; - throw std::runtime_error(stream.str()); - } } - } else { - if (mValues.size() != expected && !mDefaultValue.has_value()) { + // TODO: check if an implicit value was programmed for this argument + if (!mIsUsed && !mDefaultValue.has_value() && mIsRequired) { std::stringstream stream; - if (!mUsedName.empty()) { - stream << mUsedName << ": "; - } - stream << *expected << " argument(s) expected. " << mValues.size() - << " provided."; + stream << mNames[0] << ": required."; + throw std::runtime_error(stream.str()); + } + if (mIsUsed && mIsRequired && mValues.empty()) { + std::stringstream stream; + stream << mUsedName << ": no value provided."; throw std::runtime_error(stream.str()); } + } else if (mValues.size() != expected && !mDefaultValue.has_value()) { + std::stringstream stream; + if (!mUsedName.empty()) { + stream << mUsedName << ": "; + } + stream << *expected << " argument(s) expected. " << mValues.size() + << " provided."; + throw std::runtime_error(stream.str()); } } } @@ -555,9 +552,8 @@ class Argument { auto maybe_nargs() const -> std::optional { if (mNumArgs < 0) { return std::nullopt; - } else { - return static_cast(mNumArgs); } + return static_cast(mNumArgs); } std::size_t get_arguments_length() const { @@ -616,9 +612,8 @@ class Argument { static auto lookahead(std::string_view s) -> int { if (s.empty()) { return eof; - } else { - return static_cast(static_cast(s[0])); } + return static_cast(static_cast(s[0])); } /* @@ -680,9 +675,8 @@ class Argument { s.remove_prefix(1); if (s.empty()) { return true; - } else { - goto integer_part; } + goto integer_part; } case '1': case '2': @@ -696,9 +690,8 @@ class Argument { s = consume_digits(s); if (s.empty()) { return true; - } else { - goto integer_part_consumed; } + goto integer_part_consumed; } case '.': { s.remove_prefix(1); @@ -733,9 +726,8 @@ class Argument { if (is_digit(lookahead(s))) { s = consume_digits(s); goto exponent_part_opt; - } else { - return false; } + return false; exponent_part_opt: switch (lookahead(s)) { @@ -759,9 +751,8 @@ class Argument { if (is_digit(lookahead(s))) { s = consume_digits(s); return s.empty(); - } else { - return false; } + return false; } static bool is_optional(std::string_view aName) { @@ -783,9 +774,8 @@ class Argument { aName.remove_prefix(1); if (aName.empty()) { return true; - } else { - return is_decimal_literal(aName); } + return is_decimal_literal(aName); } default: return true; @@ -819,14 +809,13 @@ class Argument { if (mDefaultValue.has_value()) { throw std::logic_error("Argument with default value always presents"); } - if (mValues.empty()) { return std::nullopt; - } else if constexpr (details::is_container_v) { + } + if constexpr (details::is_container_v) { return any_cast_container(mValues); - } else { - return std::any_cast(mValues.front()); } + return std::any_cast(mValues.front()); } template From 65648399715efa449746bd016d9b047c260ed648 Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Mon, 7 Feb 2022 14:29:32 -0700 Subject: [PATCH 12/18] Enable clang-tidy readability-function-cognitive-complexity check The two functions previously flagged by this check, Argument::is_decimal_literal and Argument::validate, fell below the default Cognitive Complexity threshold as a result of the branch simplification for the readability-else-after-return check. Signed-off-by: Sean Robinson --- .clang-tidy | 1 - 1 file changed, 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index 62c77f15..1920dcf7 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -3,7 +3,6 @@ Checks: clang-analyzer-*, cppcoreguidelines-special-member-functions, readability-*, - -readability-function-cognitive-complexity, CheckOptions: - { key: readability-identifier-naming.ClassCase, value: CamelCase } From a915728da09b7a93f5f96182712ee4d66bca6919 Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Mon, 7 Feb 2022 14:29:32 -0700 Subject: [PATCH 13/18] Enable clang-tidy cppcoreguidelines-avoid-c-arrays check Also converts most C-style arrays to a std::array onjects. The check is disabled for ArgumentParser::parse_args(int, const char *const[]) as this is a helper function to convert away from a common input format. Signed-off-by: Sean Robinson --- .clang-tidy | 1 + include/argparse/argparse.hpp | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 1920dcf7..fad0e715 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,6 +1,7 @@ Checks: -*, clang-analyzer-*, + cppcoreguidelines-avoid-c-arrays, cppcoreguidelines-special-member-functions, readability-*, diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index 483efb97..9f8cde27 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -31,6 +31,7 @@ SOFTWARE. #pragma once #include #include +#include #include #include #include @@ -350,7 +351,8 @@ class Argument { -> std::ostream &; template - explicit Argument(std::string_view(&&a)[N], std::index_sequence unused) + explicit Argument(std::array &&a, + std::index_sequence unused) : mIsOptional((is_optional(a[I]) || ...)), mIsRequired(false), mIsRepeatable(false), mIsUsed(false) { ((void)mNames.emplace_back(a[I]), ...); @@ -362,7 +364,7 @@ class Argument { public: template - explicit Argument(std::string_view(&&a)[N]) + explicit Argument(std::array &&a) : Argument(std::move(a), std::make_index_sequence{}) {} Argument &help(std::string aHelp) { @@ -910,7 +912,7 @@ class ArgumentParser { // Parameter packing // Call add_argument with variadic number of string arguments template Argument &add_argument(Targs... Fargs) { - using array_of_sv = std::string_view[sizeof...(Targs)]; + using array_of_sv = std::array; auto tArgument = mOptionalArguments.emplace(cend(mOptionalArguments), array_of_sv{Fargs...}); @@ -966,6 +968,7 @@ class ArgumentParser { * ArgumentParser * @throws std::runtime_error in case of any invalid argument */ + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) void parse_args(int argc, const char *const argv[]) { std::vector arguments; std::copy(argv, argv + argc, std::back_inserter(arguments)); From 486bfdaf8d308c891c05dd717805a10eb1589a97 Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Mon, 7 Feb 2022 14:29:32 -0700 Subject: [PATCH 14/18] Update clang-format configuration standard to C++17 The "Cpp11" alias is deprecated for Latest (a rolling standard). For now, stick to C++17. Includes end-of-line whitespace removal. Signed-off-by: Sean Robinson --- .clang-format | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.clang-format b/.clang-format index 35cdf3cd..2cfd8b19 100644 --- a/.clang-format +++ b/.clang-format @@ -20,7 +20,7 @@ AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: false BinPackArguments: true BinPackParameters: true -BraceWrapping: +BraceWrapping: AfterClass: false AfterControlStatement: false AfterEnum: false @@ -55,12 +55,12 @@ DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true -ForEachMacros: +ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH IncludeBlocks: Preserve -IncludeCategories: +IncludeCategories: - Regex: '^"(llvm|llvm-c|clang|clang-c)/' Priority: 2 - Regex: '^(<|"(gtest|gmock|isl|json)/)' @@ -110,7 +110,7 @@ SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false -Standard: Cpp11 +Standard: c++17 TabWidth: 8 UseTab: Never ... From cb2777db6e868fec0f1ea8bece12dc6323bb1f78 Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Mon, 7 Feb 2022 14:33:16 -0700 Subject: [PATCH 15/18] Update header source format with clang-format Most changes are to better fit within "ColumnLimit: 80". The change from "T &&... var" to "T &&...var" is caused by "PointerAlignment: Right". Member functions chained from add_argument() use ContinuationIndentWidth, which is set to 4. Setting ContinuationIndentWidth to 2 causes many other continuation lines to change. So, this commit uses the original value (i.e. 4) as the preferred size. Signed-off-by: Sean Robinson --- include/argparse/argparse.hpp | 69 +++++++++++++++++------------------ 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index 9f8cde27..af20f0bb 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -55,17 +55,15 @@ namespace argparse { namespace details { // namespace for helper methods -template -struct is_container : std::false_type {}; +template struct is_container : std::false_type {}; template <> struct is_container : std::false_type {}; template -struct is_container().begin()), - decltype(std::declval().end()), - decltype(std::declval().size())>> - : std::true_type {}; +struct is_container< + T, std::void_t().begin()), + decltype(std::declval().end()), + decltype(std::declval().size())>> : std::true_type {}; template static constexpr bool is_container_v = is_container::value; @@ -74,9 +72,9 @@ template struct is_streamable : std::false_type {}; template -struct is_streamable< - T, std::void_t() << std::declval())>> - : std::true_type {}; +struct is_streamable() + << std::declval())>> + : std::true_type {}; template static constexpr bool is_streamable_v = is_streamable::value; @@ -100,7 +98,8 @@ template std::string repr(T const &val) { out << repr(*val.begin()); std::for_each( std::next(val.begin()), - std::next(val.begin(), std::min(size, repr_max_container_size) - 1), + std::next(val.begin(), + std::min(size, repr_max_container_size) - 1), [&out](const auto &v) { out << " " << repr(v); }); if (size <= repr_max_container_size) { out << " "; @@ -336,8 +335,8 @@ enum class default_arguments : unsigned int { all = help | version, }; -inline default_arguments operator& (const default_arguments &a, - const default_arguments &b) { +inline default_arguments operator&(const default_arguments &a, + const default_arguments &b) { return static_cast( static_cast::type>(a) & static_cast::type>(b)); @@ -390,7 +389,7 @@ class Argument { } template - auto action(F &&aAction, Args &&... aBound) + auto action(F &&aAction, Args &&...aBound) -> std::enable_if_t, Argument &> { using action_type = std::conditional_t< @@ -858,25 +857,25 @@ class ArgumentParser { : mProgramName(std::move(aProgramName)), mVersion(std::move(aVersion)) { if ((aArgs & default_arguments::help) == default_arguments::help) { add_argument("-h", "--help") - .action([&](const auto &unused) { - std::cout << help().str(); - std::exit(0); - }) - .default_value(false) - .help("shows help message and exits") - .implicit_value(true) - .nargs(0); + .action([&](const auto &unused) { + std::cout << help().str(); + std::exit(0); + }) + .default_value(false) + .help("shows help message and exits") + .implicit_value(true) + .nargs(0); } if ((aArgs & default_arguments::version) == default_arguments::version) { add_argument("-v", "--version") - .action([&](const auto &unused) { - std::cout << mVersion; - std::exit(0); - }) - .default_value(false) - .help("prints version information and exits") - .implicit_value(true) - .nargs(0); + .action([&](const auto &unused) { + std::cout << mVersion; + std::exit(0); + }) + .default_value(false) + .help("prints version information and exits") + .implicit_value(true) + .nargs(0); } } @@ -891,12 +890,12 @@ class ArgumentParser { mIsParsed(other.mIsParsed), mPositionalArguments(other.mPositionalArguments), mOptionalArguments(other.mOptionalArguments) { - for (auto it = std::begin(mPositionalArguments); it != std::end(mPositionalArguments); - ++it) { + for (auto it = std::begin(mPositionalArguments); + it != std::end(mPositionalArguments); ++it) { index_argument(it); } - for (auto it = std::begin(mOptionalArguments); it != std::end(mOptionalArguments); - ++it) { + for (auto it = std::begin(mOptionalArguments); + it != std::end(mOptionalArguments); ++it) { index_argument(it); } } @@ -928,7 +927,7 @@ class ArgumentParser { // Parameter packed add_parents method // Accepts a variadic number of ArgumentParser objects template - ArgumentParser &add_parents(const Targs &... Fargs) { + ArgumentParser &add_parents(const Targs &...Fargs) { for (const ArgumentParser &tParentParser : {std::ref(Fargs)...}) { for (const auto &tArgument : tParentParser.mPositionalArguments) { auto it = From c50346c1dff00af89db9a9a19533a3a34caaa190 Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Mon, 7 Feb 2022 14:33:24 -0700 Subject: [PATCH 16/18] Remove is_representable_v trait This trait is unused and removing it does not cause any tests to fail. Signed-off-by: Sean Robinson --- include/argparse/argparse.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index af20f0bb..e64beeba 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -79,10 +79,6 @@ struct is_streamable() template static constexpr bool is_streamable_v = is_streamable::value; -template -static constexpr bool is_representable_v = - is_streamable_v || is_container_v; - constexpr std::size_t repr_max_container_size = 5; template std::string repr(T const &val) { From 985ea8666d973202e2644ecbe5a4dd13120c37c2 Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Mon, 7 Feb 2022 14:33:24 -0700 Subject: [PATCH 17/18] Update identifier names for structs The new naming pattern is CamelCase for structs, except parse_number as a primarily callable interface. Trait structs are named Has*Traits and constexpr variables to the struct template are named Is*. Signed-off-by: Sean Robinson --- .clang-tidy | 4 +++- include/argparse/argparse.hpp | 36 ++++++++++++++++++----------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index fad0e715..88642ae0 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -8,11 +8,13 @@ Checks: CheckOptions: - { key: readability-identifier-naming.ClassCase, value: CamelCase } - { key: readability-identifier-naming.ConstexprVariableCase, value: lower_case } + - { key: readability-identifier-naming.ConstexprVariableIgnoredRegexp, value: "^Is.+" } - { key: readability-identifier-naming.FunctionCase, value: lower_case } - { key: readability-identifier-naming.LocalVariableIgnoredRegexp, value: "^[a-z][a-z_]+" } - { key: readability-identifier-naming.NamespaceCase, value: lower_case } - { key: readability-identifier-naming.PrivateMemberPrefix, value: m } - - { key: readability-identifier-naming.StructCase, value: lower_case } + - { key: readability-identifier-naming.StructCase, value: CamelCase } + - { key: readability-identifier-naming.StructIgnoredRegexp, value: "parse_number" } - { key: readability-identifier-naming.VariableCase, value: camelBack } HeaderFilterRegex: '.*' diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index e64beeba..21a2c11e 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -55,29 +55,31 @@ namespace argparse { namespace details { // namespace for helper methods -template struct is_container : std::false_type {}; +template +struct HasContainerTraits : std::false_type {}; -template <> struct is_container : std::false_type {}; +template <> struct HasContainerTraits : std::false_type {}; template -struct is_container< +struct HasContainerTraits< T, std::void_t().begin()), decltype(std::declval().end()), decltype(std::declval().size())>> : std::true_type {}; template -static constexpr bool is_container_v = is_container::value; +static constexpr bool IsContainer = HasContainerTraits::value; template -struct is_streamable : std::false_type {}; +struct HasStreamableTraits : std::false_type {}; template -struct is_streamable() - << std::declval())>> +struct HasStreamableTraits< + T, + std::void_t() << std::declval())>> : std::true_type {}; template -static constexpr bool is_streamable_v = is_streamable::value; +static constexpr bool IsStreamable = HasStreamableTraits::value; constexpr std::size_t repr_max_container_size = 5; @@ -86,7 +88,7 @@ template std::string repr(T const &val) { return val ? "true" : "false"; } else if constexpr (std::is_convertible_v) { return '"' + std::string{std::string_view{val}} + '"'; - } else if constexpr (is_container_v) { + } else if constexpr (IsContainer) { std::stringstream out; out << "{"; const auto size = val.size(); @@ -108,7 +110,7 @@ template std::string repr(T const &val) { } out << "}"; return out.str(); - } else if constexpr (is_streamable_v) { + } else if constexpr (IsStreamable) { std::stringstream out; out << val; return out.str(); @@ -176,7 +178,7 @@ enum class chars_format { general = fixed | scientific }; -struct consume_hex_prefix_result { +struct ConsumeHexPrefixResult { bool is_hexadecimal; std::string_view rest; }; @@ -184,7 +186,7 @@ struct consume_hex_prefix_result { using namespace std::literals; constexpr auto consume_hex_prefix(std::string_view s) - -> consume_hex_prefix_result { + -> ConsumeHexPrefixResult { if (starts_with("0x"sv, s) || starts_with("0X"sv, s)) { s.remove_prefix(2); return {true, s}; @@ -483,7 +485,7 @@ class Argument { } } - struct action_apply { + struct ActionApply { void operator()(valued_action &f) { std::transform(first, last, std::back_inserter(self.mValues), f); } @@ -500,7 +502,7 @@ class Argument { Iterator first, last; Argument &self; }; - std::visit(action_apply{start, end, *this}, mAction); + std::visit(ActionApply{start, end, *this}, mAction); return end; } if (mDefaultValue.has_value()) { @@ -591,7 +593,7 @@ class Argument { * @throws std::logic_error in case of incompatible types */ template bool operator==(const T &aRhs) const { - if constexpr (!details::is_container_v) { + if constexpr (!details::IsContainer) { return get() == aRhs; } else { using ValueType = typename T::value_type; @@ -785,7 +787,7 @@ class Argument { */ template T get() const { if (!mValues.empty()) { - if constexpr (details::is_container_v) { + if constexpr (details::IsContainer) { return any_cast_container(mValues); } else { return std::any_cast(mValues.front()); @@ -809,7 +811,7 @@ class Argument { if (mValues.empty()) { return std::nullopt; } - if constexpr (details::is_container_v) { + if constexpr (details::IsContainer) { return any_cast_container(mValues); } return std::any_cast(mValues.front()); From ce3c43eb9b3d8eb93030ca04608f732314e23719 Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Thu, 10 Feb 2022 09:41:20 -0700 Subject: [PATCH 18/18] Rename identifiers There are no functional changes in this commit. Signed-off-by: Sean Robinson --- .clang-tidy | 7 +- include/argparse/argparse.hpp | 475 +++++++++++++++++----------------- 2 files changed, 241 insertions(+), 241 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 88642ae0..d0b28f4f 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -10,11 +10,12 @@ CheckOptions: - { key: readability-identifier-naming.ConstexprVariableCase, value: lower_case } - { key: readability-identifier-naming.ConstexprVariableIgnoredRegexp, value: "^Is.+" } - { key: readability-identifier-naming.FunctionCase, value: lower_case } - - { key: readability-identifier-naming.LocalVariableIgnoredRegexp, value: "^[a-z][a-z_]+" } - { key: readability-identifier-naming.NamespaceCase, value: lower_case } - - { key: readability-identifier-naming.PrivateMemberPrefix, value: m } + - { key: readability-identifier-naming.ParameterCase, value: lower_case } + - { key: readability-identifier-naming.PrivateMemberCase, value: lower_case } + - { key: readability-identifier-naming.PrivateMemberPrefix, value: m_ } - { key: readability-identifier-naming.StructCase, value: CamelCase } - { key: readability-identifier-naming.StructIgnoredRegexp, value: "parse_number" } - - { key: readability-identifier-naming.VariableCase, value: camelBack } + - { key: readability-identifier-naming.VariableCase, value: lower_case } HeaderFilterRegex: '.*' diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index 21a2c11e..4cb17b80 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -350,11 +350,11 @@ class Argument { template explicit Argument(std::array &&a, std::index_sequence unused) - : mIsOptional((is_optional(a[I]) || ...)), mIsRequired(false), - mIsRepeatable(false), mIsUsed(false) { - ((void)mNames.emplace_back(a[I]), ...); + : m_is_optional((is_optional(a[I]) || ...)), m_is_required(false), + m_is_repeatable(false), m_is_used(false) { + ((void)m_names.emplace_back(a[I]), ...); std::sort( - mNames.begin(), mNames.end(), [](const auto &lhs, const auto &rhs) { + m_names.begin(), m_names.end(), [](const auto &lhs, const auto &rhs) { return lhs.size() == rhs.size() ? lhs < rhs : lhs.size() < rhs.size(); }); } @@ -364,41 +364,41 @@ class Argument { explicit Argument(std::array &&a) : Argument(std::move(a), std::make_index_sequence{}) {} - Argument &help(std::string aHelp) { - mHelp = std::move(aHelp); + Argument &help(std::string help_text) { + m_help = std::move(help_text); return *this; } - template Argument &default_value(T &&aDefaultValue) { - mDefaultValueRepr = details::repr(aDefaultValue); - mDefaultValue = std::forward(aDefaultValue); + template Argument &default_value(T &&value) { + m_default_value_repr = details::repr(value); + m_default_value = std::forward(value); return *this; } Argument &required() { - mIsRequired = true; + m_is_required = true; return *this; } - Argument &implicit_value(std::any aImplicitValue) { - mImplicitValue = std::move(aImplicitValue); - mNumArgs = 0; + Argument &implicit_value(std::any value) { + m_implicit_value = std::move(value); + m_num_args = 0; return *this; } template - auto action(F &&aAction, Args &&...aBound) + auto action(F &&callable, Args &&...bound_args) -> std::enable_if_t, Argument &> { using action_type = std::conditional_t< std::is_void_v>, void_action, valued_action>; if constexpr (sizeof...(Args) == 0) { - mAction.emplace(std::forward(aAction)); + m_action.emplace(std::forward(callable)); } else { - mAction.emplace( - [f = std::forward(aAction), - tup = std::make_tuple(std::forward(aBound)...)]( + m_action.emplace( + [f = std::forward(callable), + tup = std::make_tuple(std::forward(bound_args)...)]( std::string const &opt) mutable { return details::apply_plus_one(f, tup, opt); }); @@ -407,7 +407,7 @@ class Argument { } auto &append() { - mIsRepeatable = true; + m_is_repeatable = true; return *this; } @@ -451,33 +451,33 @@ class Argument { return *this; } - Argument &nargs(int aNumArgs) { - if (aNumArgs < 0) { + Argument &nargs(int num_args) { + if (num_args < 0) { throw std::logic_error("Number of arguments must be non-negative"); } - mNumArgs = aNumArgs; + m_num_args = num_args; return *this; } Argument &remaining() { - mNumArgs = -1; + m_num_args = -1; return *this; } template Iterator consume(Iterator start, Iterator end, - std::string_view usedName = {}) { - if (!mIsRepeatable && mIsUsed) { + std::string_view used_name = {}) { + if (!m_is_repeatable && m_is_used) { throw std::runtime_error("Duplicate argument"); } - mIsUsed = true; - mUsedName = usedName; - if (mNumArgs == 0) { - mValues.emplace_back(mImplicitValue); - std::visit([](const auto &aAction) { aAction({}); }, mAction); + m_is_used = true; + m_used_name = used_name; + if (m_num_args == 0) { + m_values.emplace_back(m_implicit_value); + std::visit([](const auto &f) { f({}); }, m_action); return start; } - if (mNumArgs <= std::distance(start, end)) { + if (m_num_args <= std::distance(start, end)) { if (auto expected = maybe_nargs()) { end = std::next(start, *expected); if (std::any_of(start, end, Argument::is_optional)) { @@ -487,14 +487,14 @@ class Argument { struct ActionApply { void operator()(valued_action &f) { - std::transform(first, last, std::back_inserter(self.mValues), f); + std::transform(first, last, std::back_inserter(self.m_values), f); } void operator()(void_action &f) { std::for_each(first, last, f); - if (!self.mDefaultValue.has_value()) { + if (!self.m_default_value.has_value()) { if (auto expected = self.maybe_nargs()) { - self.mValues.resize(*expected); + self.m_values.resize(*expected); } } } @@ -502,14 +502,14 @@ class Argument { Iterator first, last; Argument &self; }; - std::visit(ActionApply{start, end, *this}, mAction); + std::visit(ActionApply{start, end, *this}, m_action); return end; } - if (mDefaultValue.has_value()) { + if (m_default_value.has_value()) { return start; } throw std::runtime_error("Too few arguments for '" + - std::string(mUsedName) + "'."); + std::string(m_used_name) + "'."); } /* @@ -517,31 +517,31 @@ class Argument { */ void validate() const { if (auto expected = maybe_nargs()) { - if (mIsOptional) { - if (mIsUsed && mValues.size() != *expected && !mIsRepeatable && - !mDefaultValue.has_value()) { + if (m_is_optional) { + if (m_is_used && m_values.size() != *expected && !m_is_repeatable && + !m_default_value.has_value()) { std::stringstream stream; - stream << mUsedName << ": expected " << *expected << " argument(s). " - << mValues.size() << " provided."; + stream << m_used_name << ": expected " << *expected + << " argument(s). " << m_values.size() << " provided."; throw std::runtime_error(stream.str()); } // TODO: check if an implicit value was programmed for this argument - if (!mIsUsed && !mDefaultValue.has_value() && mIsRequired) { + if (!m_is_used && !m_default_value.has_value() && m_is_required) { std::stringstream stream; - stream << mNames[0] << ": required."; + stream << m_names[0] << ": required."; throw std::runtime_error(stream.str()); } - if (mIsUsed && mIsRequired && mValues.empty()) { + if (m_is_used && m_is_required && m_values.empty()) { std::stringstream stream; - stream << mUsedName << ": no value provided."; + stream << m_used_name << ": no value provided."; throw std::runtime_error(stream.str()); } - } else if (mValues.size() != expected && !mDefaultValue.has_value()) { + } else if (m_values.size() != expected && !m_default_value.has_value()) { std::stringstream stream; - if (!mUsedName.empty()) { - stream << mUsedName << ": "; + if (!m_used_name.empty()) { + stream << m_used_name << ": "; } - stream << *expected << " argument(s) expected. " << mValues.size() + stream << *expected << " argument(s) expected. " << m_values.size() << " provided."; throw std::runtime_error(stream.str()); } @@ -549,15 +549,15 @@ class Argument { } auto maybe_nargs() const -> std::optional { - if (mNumArgs < 0) { + if (m_num_args < 0) { return std::nullopt; } - return static_cast(mNumArgs); + return static_cast(m_num_args); } std::size_t get_arguments_length() const { - return std::accumulate(std::begin(mNames), std::end(mNames), std::size_t(0), - [](const auto &sum, const auto &s) { + return std::accumulate(std::begin(m_names), std::end(m_names), + std::size_t(0), [](const auto &sum, const auto &s) { return sum + s.size() + 1; // +1 for space between names }); @@ -565,17 +565,17 @@ class Argument { friend std::ostream &operator<<(std::ostream &stream, const Argument &argument) { - std::stringstream nameStream; - std::copy(std::begin(argument.mNames), std::end(argument.mNames), - std::ostream_iterator(nameStream, " ")); - stream << nameStream.str() << "\t" << argument.mHelp; - if (argument.mDefaultValue.has_value()) { - if (!argument.mHelp.empty()) { + std::stringstream name_stream; + std::copy(std::begin(argument.m_names), std::end(argument.m_names), + std::ostream_iterator(name_stream, " ")); + stream << name_stream.str() << "\t" << argument.m_help; + if (argument.m_default_value.has_value()) { + if (!argument.m_help.empty()) { stream << " "; } - stream << "[default: " << argument.mDefaultValueRepr << "]"; - } else if (argument.mIsRequired) { - if (!argument.mHelp.empty()) { + stream << "[default: " << argument.m_default_value_repr << "]"; + } else if (argument.m_is_required) { + if (!argument.m_help.empty()) { stream << " "; } stream << "[required]"; @@ -584,22 +584,22 @@ class Argument { return stream; } - template bool operator!=(const T &aRhs) const { - return !(*this == aRhs); + template bool operator!=(const T &rhs) const { + return !(*this == rhs); } /* * Compare to an argument value of known type * @throws std::logic_error in case of incompatible types */ - template bool operator==(const T &aRhs) const { + template bool operator==(const T &rhs) const { if constexpr (!details::IsContainer) { - return get() == aRhs; + return get() == rhs; } else { using ValueType = typename T::value_type; - auto tLhs = get(); - return std::equal(std::begin(tLhs), std::end(tLhs), std::begin(aRhs), - std::end(aRhs), [](const auto &lhs, const auto &rhs) { + auto lhs = get(); + return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs), + std::end(rhs), [](const auto &lhs, const auto &rhs) { return std::any_cast(lhs) == rhs; }); } @@ -754,8 +754,8 @@ class Argument { return false; } - static bool is_optional(std::string_view aName) { - return !is_positional(aName); + static bool is_optional(std::string_view name) { + return !is_positional(name); } /* @@ -765,16 +765,16 @@ class Argument { * '-' decimal-literal * !'-' anything */ - static bool is_positional(std::string_view aName) { - switch (lookahead(aName)) { + static bool is_positional(std::string_view name) { + switch (lookahead(name)) { case eof: return true; case '-': { - aName.remove_prefix(1); - if (aName.empty()) { + name.remove_prefix(1); + if (name.empty()) { return true; } - return is_decimal_literal(aName); + return is_decimal_literal(name); } default: return true; @@ -786,17 +786,17 @@ class Argument { * @throws std::logic_error in case of incompatible types */ template T get() const { - if (!mValues.empty()) { + if (!m_values.empty()) { if constexpr (details::IsContainer) { - return any_cast_container(mValues); + return any_cast_container(m_values); } else { - return std::any_cast(mValues.front()); + return std::any_cast(m_values.front()); } } - if (mDefaultValue.has_value()) { - return std::any_cast(mDefaultValue); + if (m_default_value.has_value()) { + return std::any_cast(m_default_value); } - throw std::logic_error("No value provided for '" + mNames.back() + "'."); + throw std::logic_error("No value provided for '" + m_names.back() + "'."); } /* @@ -805,55 +805,55 @@ class Argument { * @returns The stored value if any, std::nullopt otherwise. */ template auto present() const -> std::optional { - if (mDefaultValue.has_value()) { + if (m_default_value.has_value()) { throw std::logic_error("Argument with default value always presents"); } - if (mValues.empty()) { + if (m_values.empty()) { return std::nullopt; } if constexpr (details::IsContainer) { - return any_cast_container(mValues); + return any_cast_container(m_values); } - return std::any_cast(mValues.front()); + return std::any_cast(m_values.front()); } template - static auto any_cast_container(const std::vector &aOperand) -> T { + static auto any_cast_container(const std::vector &operand) -> T { using ValueType = typename T::value_type; - T tResult; + T result; std::transform( - std::begin(aOperand), std::end(aOperand), std::back_inserter(tResult), + std::begin(operand), std::end(operand), std::back_inserter(result), [](const auto &value) { return std::any_cast(value); }); - return tResult; + return result; } - std::vector mNames; - std::string_view mUsedName; - std::string mHelp; - std::any mDefaultValue; - std::string mDefaultValueRepr; - std::any mImplicitValue; + std::vector m_names; + std::string_view m_used_name; + std::string m_help; + std::any m_default_value; + std::string m_default_value_repr; + std::any m_implicit_value; using valued_action = std::function; using void_action = std::function; - std::variant mAction{ + std::variant m_action{ std::in_place_type, - [](const std::string &aValue) { return aValue; }}; - std::vector mValues; - int mNumArgs = 1; - bool mIsOptional : true; - bool mIsRequired : true; - bool mIsRepeatable : true; - bool mIsUsed : true; // True if the optional argument is used by user + [](const std::string &value) { return value; }}; + std::vector m_values; + int m_num_args = 1; + bool m_is_optional : true; + bool m_is_required : true; + bool m_is_repeatable : true; + bool m_is_used : true; // True if the optional argument is used by user }; class ArgumentParser { public: - explicit ArgumentParser(std::string aProgramName = {}, - std::string aVersion = "1.0", - default_arguments aArgs = default_arguments::all) - : mProgramName(std::move(aProgramName)), mVersion(std::move(aVersion)) { - if ((aArgs & default_arguments::help) == default_arguments::help) { + explicit ArgumentParser(std::string program_name = {}, + std::string version = "1.0", + default_arguments add_args = default_arguments::all) + : m_program_name(std::move(program_name)), m_version(std::move(version)) { + if ((add_args & default_arguments::help) == default_arguments::help) { add_argument("-h", "--help") .action([&](const auto &unused) { std::cout << help().str(); @@ -864,10 +864,10 @@ class ArgumentParser { .implicit_value(true) .nargs(0); } - if ((aArgs & default_arguments::version) == default_arguments::version) { + if ((add_args & default_arguments::version) == default_arguments::version) { add_argument("-v", "--version") .action([&](const auto &unused) { - std::cout << mVersion; + std::cout << m_version; std::exit(0); }) .default_value(false) @@ -881,19 +881,19 @@ class ArgumentParser { ArgumentParser &operator=(ArgumentParser &&) = default; ArgumentParser(const ArgumentParser &other) - : mProgramName(other.mProgramName), - mVersion(other.mVersion), - mDescription(other.mDescription), - mEpilog(other.mEpilog), - mIsParsed(other.mIsParsed), - mPositionalArguments(other.mPositionalArguments), - mOptionalArguments(other.mOptionalArguments) { - for (auto it = std::begin(mPositionalArguments); - it != std::end(mPositionalArguments); ++it) { + : m_program_name(other.m_program_name), + m_version(other.m_version), + m_description(other.m_description), + m_epilog(other.m_epilog), + m_is_parsed(other.m_is_parsed), + m_positional_arguments(other.m_positional_arguments), + m_optional_arguments(other.m_optional_arguments) { + for (auto it = std::begin(m_positional_arguments); + it != std::end(m_positional_arguments); ++it) { index_argument(it); } - for (auto it = std::begin(mOptionalArguments); - it != std::end(mOptionalArguments); ++it) { + for (auto it = std::begin(m_optional_arguments); + it != std::end(m_optional_arguments); ++it) { index_argument(it); } } @@ -908,46 +908,46 @@ class ArgumentParser { // Parameter packing // Call add_argument with variadic number of string arguments - template Argument &add_argument(Targs... Fargs) { + template Argument &add_argument(Targs... f_args) { using array_of_sv = std::array; - auto tArgument = mOptionalArguments.emplace(cend(mOptionalArguments), - array_of_sv{Fargs...}); + auto argument = m_optional_arguments.emplace(cend(m_optional_arguments), + array_of_sv{f_args...}); - if (!tArgument->mIsOptional) { - mPositionalArguments.splice(cend(mPositionalArguments), - mOptionalArguments, tArgument); + if (!argument->m_is_optional) { + m_positional_arguments.splice(cend(m_positional_arguments), + m_optional_arguments, argument); } - index_argument(tArgument); - return *tArgument; + index_argument(argument); + return *argument; } // Parameter packed add_parents method // Accepts a variadic number of ArgumentParser objects template - ArgumentParser &add_parents(const Targs &...Fargs) { - for (const ArgumentParser &tParentParser : {std::ref(Fargs)...}) { - for (const auto &tArgument : tParentParser.mPositionalArguments) { - auto it = - mPositionalArguments.insert(cend(mPositionalArguments), tArgument); + ArgumentParser &add_parents(const Targs &...f_args) { + for (const ArgumentParser &parent_parser : {std::ref(f_args)...}) { + for (const auto &argument : parent_parser.m_positional_arguments) { + auto it = m_positional_arguments.insert(cend(m_positional_arguments), + argument); index_argument(it); } - for (const auto &tArgument : tParentParser.mOptionalArguments) { + for (const auto &argument : parent_parser.m_optional_arguments) { auto it = - mOptionalArguments.insert(cend(mOptionalArguments), tArgument); + m_optional_arguments.insert(cend(m_optional_arguments), argument); index_argument(it); } } return *this; } - ArgumentParser &add_description(std::string aDescription) { - mDescription = std::move(aDescription); + ArgumentParser &add_description(std::string description) { + m_description = std::move(description); return *this; } - ArgumentParser &add_epilog(std::string aEpilog) { - mEpilog = std::move(aEpilog); + ArgumentParser &add_epilog(std::string epilog) { + m_epilog = std::move(epilog); return *this; } @@ -956,8 +956,8 @@ class ArgumentParser { * This variant is used mainly for testing * @throws std::runtime_error in case of any invalid argument */ - void parse_args(const std::vector &aArguments) { - parse_args_internal(aArguments); + void parse_args(const std::vector &arguments) { + parse_args_internal(arguments); parse_args_validate(); } @@ -978,12 +978,11 @@ class ArgumentParser { * @throws std::logic_error if the option has no value * @throws std::bad_any_cast if the option is not of type T */ - template - T get(std::string_view aArgumentName) const { - if (!mIsParsed) { + template T get(std::string_view arg_name) const { + if (!m_is_parsed) { throw std::logic_error("Nothing parsed, no arguments are available."); } - return (*this)[aArgumentName].get(); + return (*this)[arg_name].get(); } /* Getter for options without default values. @@ -992,81 +991,81 @@ class ArgumentParser { * @throws std::bad_any_cast if the option is not of type T */ template - auto present(std::string_view aArgumentName) const -> std::optional { - return (*this)[aArgumentName].present(); + auto present(std::string_view arg_name) const -> std::optional { + return (*this)[arg_name].present(); } /* Getter that returns true for user-supplied options. Returns false if not * user-supplied, even with a default value. */ - auto is_used(std::string_view aArgumentName) const { - return (*this)[aArgumentName].mIsUsed; + auto is_used(std::string_view arg_name) const { + return (*this)[arg_name].m_is_used; } /* Indexing operator. Return a reference to an Argument object * Used in conjuction with Argument.operator== e.g., parser["foo"] == true * @throws std::logic_error in case of an invalid argument name */ - Argument &operator[](std::string_view aArgumentName) const { - auto tIterator = mArgumentMap.find(aArgumentName); - if (tIterator != mArgumentMap.end()) { - return *(tIterator->second); - } - if (aArgumentName.front() != '-') { - std::string nameStr(aArgumentName); - // "-" + aArgumentName - nameStr = "-" + nameStr; - tIterator = mArgumentMap.find(nameStr); - if (tIterator != mArgumentMap.end()) { - return *(tIterator->second); + Argument &operator[](std::string_view arg_name) const { + auto it = m_argument_map.find(arg_name); + if (it != m_argument_map.end()) { + return *(it->second); + } + if (arg_name.front() != '-') { + std::string name(arg_name); + // "-" + arg_name + name = "-" + name; + it = m_argument_map.find(name); + if (it != m_argument_map.end()) { + return *(it->second); } - // "--" + aArgumentName - nameStr = "-" + nameStr; - tIterator = mArgumentMap.find(nameStr); - if (tIterator != mArgumentMap.end()) { - return *(tIterator->second); + // "--" + arg_name + name = "-" + name; + it = m_argument_map.find(name); + if (it != m_argument_map.end()) { + return *(it->second); } } - throw std::logic_error("No such argument: " + std::string(aArgumentName)); + throw std::logic_error("No such argument: " + std::string(arg_name)); } // Print help message friend auto operator<<(std::ostream &stream, const ArgumentParser &parser) -> std::ostream & { stream.setf(std::ios_base::left); - stream << "Usage: " << parser.mProgramName << " [options] "; - std::size_t tLongestArgumentLength = parser.get_length_of_longest_argument(); + stream << "Usage: " << parser.m_program_name << " [options] "; + std::size_t longest_arg_length = parser.get_length_of_longest_argument(); - for (const auto &argument : parser.mPositionalArguments) { - stream << argument.mNames.front() << " "; + for (const auto &argument : parser.m_positional_arguments) { + stream << argument.m_names.front() << " "; } stream << "\n\n"; - if (!parser.mDescription.empty()) { - stream << parser.mDescription << "\n\n"; + if (!parser.m_description.empty()) { + stream << parser.m_description << "\n\n"; } - if (!parser.mPositionalArguments.empty()) { + if (!parser.m_positional_arguments.empty()) { stream << "Positional arguments:\n"; } - for (const auto &mPositionalArgument : parser.mPositionalArguments) { - stream.width(tLongestArgumentLength); - stream << mPositionalArgument; + for (const auto &argument : parser.m_positional_arguments) { + stream.width(longest_arg_length); + stream << argument; } - if (!parser.mOptionalArguments.empty()) { - stream << (parser.mPositionalArguments.empty() ? "" : "\n") + if (!parser.m_optional_arguments.empty()) { + stream << (parser.m_positional_arguments.empty() ? "" : "\n") << "Optional arguments:\n"; } - for (const auto &mOptionalArgument : parser.mOptionalArguments) { - stream.width(tLongestArgumentLength); - stream << mOptionalArgument; + for (const auto &argument : parser.m_optional_arguments) { + stream.width(longest_arg_length); + stream << argument; } - if (!parser.mEpilog.empty()) { - stream << parser.mEpilog << "\n\n"; + if (!parser.m_epilog.empty()) { + stream << parser.m_epilog << "\n\n"; } return stream; @@ -1092,47 +1091,47 @@ class ArgumentParser { /* * @throws std::runtime_error in case of any invalid argument */ - void parse_args_internal(const std::vector &aArguments) { - if (mProgramName.empty() && !aArguments.empty()) { - mProgramName = aArguments.front(); - } - auto end = std::end(aArguments); - auto positionalArgumentIt = std::begin(mPositionalArguments); - for (auto it = std::next(std::begin(aArguments)); it != end;) { - const auto &tCurrentArgument = *it; - if (Argument::is_positional(tCurrentArgument)) { - if (positionalArgumentIt == std::end(mPositionalArguments)) { + void parse_args_internal(const std::vector &arguments) { + if (m_program_name.empty() && !arguments.empty()) { + m_program_name = arguments.front(); + } + auto end = std::end(arguments); + auto positional_argument_it = std::begin(m_positional_arguments); + for (auto it = std::next(std::begin(arguments)); it != end;) { + const auto ¤t_argument = *it; + if (Argument::is_positional(current_argument)) { + if (positional_argument_it == std::end(m_positional_arguments)) { throw std::runtime_error( "Maximum number of positional arguments exceeded"); } - auto tArgument = positionalArgumentIt++; - it = tArgument->consume(it, end); + auto argument = positional_argument_it++; + it = argument->consume(it, end); continue; } - auto tIterator = mArgumentMap.find(tCurrentArgument); - if (tIterator != mArgumentMap.end()) { - auto tArgument = tIterator->second; - it = tArgument->consume(std::next(it), end, tIterator->first); - } else if (const auto &tCompoundArgument = tCurrentArgument; - tCompoundArgument.size() > 1 && tCompoundArgument[0] == '-' && - tCompoundArgument[1] != '-') { + auto arg_map_it = m_argument_map.find(current_argument); + if (arg_map_it != m_argument_map.end()) { + auto argument = arg_map_it->second; + it = argument->consume(std::next(it), end, arg_map_it->first); + } else if (const auto &compound_arg = current_argument; + compound_arg.size() > 1 && compound_arg[0] == '-' && + compound_arg[1] != '-') { ++it; - for (std::size_t j = 1; j < tCompoundArgument.size(); j++) { - auto tHypotheticalArgument = std::string{'-', tCompoundArgument[j]}; - auto tIterator2 = mArgumentMap.find(tHypotheticalArgument); - if (tIterator2 != mArgumentMap.end()) { - auto tArgument = tIterator2->second; - it = tArgument->consume(it, end, tIterator2->first); + for (std::size_t j = 1; j < compound_arg.size(); j++) { + auto hypothetical_arg = std::string{'-', compound_arg[j]}; + auto arg_map_it2 = m_argument_map.find(hypothetical_arg); + if (arg_map_it2 != m_argument_map.end()) { + auto argument = arg_map_it2->second; + it = argument->consume(it, end, arg_map_it2->first); } else { - throw std::runtime_error("Unknown argument: " + tCurrentArgument); + throw std::runtime_error("Unknown argument: " + current_argument); } } } else { - throw std::runtime_error("Unknown argument: " + tCurrentArgument); + throw std::runtime_error("Unknown argument: " + current_argument); } } - mIsParsed = true; + m_is_parsed = true; } /* @@ -1140,44 +1139,44 @@ class ArgumentParser { */ void parse_args_validate() { // Check if all arguments are parsed - std::for_each(std::begin(mArgumentMap), std::end(mArgumentMap), - [](const auto &argPair) { - const auto &tArgument = argPair.second; - tArgument->validate(); + std::for_each(std::begin(m_argument_map), std::end(m_argument_map), + [](const auto &pair) { + const auto &argument = pair.second; + argument->validate(); }); } // Used by print_help. std::size_t get_length_of_longest_argument() const { - if (mArgumentMap.empty()) { + if (m_argument_map.empty()) { return 0; } - std::vector argumentLengths(mArgumentMap.size()); - std::transform(std::begin(mArgumentMap), std::end(mArgumentMap), - std::begin(argumentLengths), [](const auto &argPair) { - const auto &tArgument = argPair.second; - return tArgument->get_arguments_length(); + std::vector argument_lengths(m_argument_map.size()); + std::transform(std::begin(m_argument_map), std::end(m_argument_map), + std::begin(argument_lengths), [](const auto &pair) { + const auto &argument = pair.second; + return argument->get_arguments_length(); }); - return *std::max_element(std::begin(argumentLengths), - std::end(argumentLengths)); + return *std::max_element(std::begin(argument_lengths), + std::end(argument_lengths)); } using list_iterator = std::list::iterator; - void index_argument(list_iterator argIt) { - for (const auto &mName : std::as_const(argIt->mNames)) { - mArgumentMap.insert_or_assign(mName, argIt); + void index_argument(list_iterator it) { + for (const auto &name : std::as_const(it->m_names)) { + m_argument_map.insert_or_assign(name, it); } } - std::string mProgramName; - std::string mVersion; - std::string mDescription; - std::string mEpilog; - bool mIsParsed = false; - std::list mPositionalArguments; - std::list mOptionalArguments; - std::map> mArgumentMap; + std::string m_program_name; + std::string m_version; + std::string m_description; + std::string m_epilog; + bool m_is_parsed = false; + std::list m_positional_arguments; + std::list m_optional_arguments; + std::map> m_argument_map; }; } // namespace argparse