From 8474147a7c550913ad4de36338aa5be5620a69f3 Mon Sep 17 00:00:00 2001 From: Stephan van Veen Date: Wed, 8 May 2019 23:00:05 +0200 Subject: [PATCH 01/13] Use default constructor and non-static member initializers --- include/argparse.hpp | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index 731854d9..064d5816 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -87,16 +87,7 @@ T get_from_list(const std::list& aList, size_t aIndex) { class Argument { friend class ArgumentParser; public: - Argument() : - mNames({}), - mUsedName(""), - mHelp(""), - mAction([](const std::string& aValue) { return aValue; }), - mValues({}), - mRawValues({}), - mNumArgs(1), - mIsOptional(false), - mIsUsed(false) {} + Argument() = default; Argument& help(const std::string& aHelp) { mHelp = aHelp; @@ -272,12 +263,12 @@ class Argument { std::string mHelp; std::any mDefaultValue; std::any mImplicitValue; - std::function mAction; + std::function mAction = [](const std::string& aValue) { return aValue; }; std::vector mValues; std::vector mRawValues; - size_t mNumArgs; - bool mIsOptional; - bool mIsUsed; // relevant for optional arguments. True if used by user + size_t mNumArgs = 1; + bool mIsOptional = false; + bool mIsUsed = false; // relevant for optional arguments. True if used by user }; class ArgumentParser { From d9bff3dc2b7f06f1054308429253d9dcefbe801d Mon Sep 17 00:00:00 2001 From: Stephan van Veen Date: Wed, 8 May 2019 23:14:27 +0200 Subject: [PATCH 02/13] Construct Argument using template pack of names --- include/argparse.hpp | 44 +++++++++++++++----------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index 064d5816..551ef64f 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -89,6 +89,12 @@ class Argument { public: Argument() = default; + template + Argument(Args... args) + : mNames({std::move(args)...}) + , mIsOptional((is_optional(args) || ...)) + {} + Argument& help(const std::string& aHelp) { mHelp = aHelp; return *this; @@ -163,6 +169,10 @@ class Argument { } private: + // If an argument starts with "-" or "--", then it's optional + static bool is_optional(const std::string& aName) { + return (starts_with(aName, "--") || starts_with(aName, "-")); + } // Getter for template types other than std::vector and std::list template @@ -289,17 +299,9 @@ class ArgumentParser { // Parameter packing // Call add_argument with variadic number of string arguments - // TODO: enforce T to be std::string - template - Argument& add_argument(T value, Targs... Fargs) { - std::shared_ptr tArgument = std::make_shared(); - tArgument->mNames.push_back(value); - add_argument_internal(tArgument, Fargs...); - - for (auto& mName : tArgument->mNames) { - if (is_optional(mName)) - tArgument->mIsOptional = true; - } + template + Argument& add_argument(Targs... Fargs) { + std::shared_ptr tArgument = std::make_shared(Fargs...); if (!tArgument->mIsOptional) mPositionalArguments.push_back(tArgument); @@ -470,22 +472,6 @@ class ArgumentParser { } private: - Argument& add_argument_internal(std::shared_ptr aArgument) { - return *aArgument; - } - - template - Argument& add_argument_internal(std::shared_ptr aArgument, T aArgumentName, Targs... Fargs) { - aArgument->mNames.push_back(aArgumentName); - add_argument_internal(aArgument, Fargs...); - return *aArgument; - } - - // If an argument starts with "-" or "--", then it's optional - bool is_optional(const std::string& aName) { - return (starts_with(aName, "--") || starts_with(aName, "-")); - } - // If the argument was defined by the user and can be found in mArgumentMap, then it's valid bool is_valid_argument(const std::string& aName) { std::map>::iterator tIterator = mArgumentMap.find(aName); @@ -546,7 +532,7 @@ class ArgumentParser { } } else { - if (is_optional(argv[i])) { + if (Argument::is_optional(argv[i])) { // This is possibly a compound optional argument // Example: We have three optional arguments -a, -u and -x // The user provides ./main -aux ... @@ -596,7 +582,7 @@ class ArgumentParser { auto tCount = tArgument->mNumArgs - tArgument->mRawValues.size(); while (tCount > 0) { tIterator = mArgumentMap.find(argv[i]); - if (tIterator != mArgumentMap.end() || is_optional(argv[i])) { + if (tIterator != mArgumentMap.end() || Argument::is_optional(argv[i])) { i = i - 1; break; } From 328f1048da070f79d41e5fbdc978de723f01244e Mon Sep 17 00:00:00 2001 From: Stephan van Veen Date: Thu, 9 May 2019 17:42:18 +0200 Subject: [PATCH 03/13] Initialize mNames using --- include/argparse.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index 551ef64f..bdbcc878 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -90,7 +90,7 @@ class Argument { Argument() = default; template - Argument(Args... args) + explicit Argument(Args... args) : mNames({std::move(args)...}) , mIsOptional((is_optional(args) || ...)) {} @@ -301,7 +301,7 @@ class ArgumentParser { // Call add_argument with variadic number of string arguments template Argument& add_argument(Targs... Fargs) { - std::shared_ptr tArgument = std::make_shared(Fargs...); + std::shared_ptr tArgument = std::make_shared(std::move(Fargs)...); if (!tArgument->mIsOptional) mPositionalArguments.push_back(tArgument); From 89e4bb11ac4c9955968f6d99feec123faa1206c0 Mon Sep 17 00:00:00 2001 From: Stephan van Veen Date: Thu, 9 May 2019 17:54:52 +0200 Subject: [PATCH 04/13] Use auto type for iterators --- include/argparse.hpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index bdbcc878..d1aec6b1 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -52,9 +52,7 @@ struct is_specialization, Ref> : std::true_type {}; // Upsert into std::map template bool upsert(std::map& aMap, KeyType const& aKey, ElementType const& aNewValue) { - typedef typename std::map::iterator Iterator; - typedef typename std::pair Result; - Result tResult = aMap.insert(typename std::map::value_type(aKey, aNewValue)); + auto tResult = aMap.insert(typename std::map::value_type(aKey, aNewValue)); if (!tResult.second) { if (!(tResult.first->second == aNewValue)) { tResult.first->second = aNewValue; @@ -360,7 +358,7 @@ class ArgumentParser { typename std::enable_if::value == false && is_specialization::value == false, T>::type get(const char * aArgumentName) { - std::map>::iterator tIterator = mArgumentMap.find(aArgumentName); + auto tIterator = mArgumentMap.find(aArgumentName); if (tIterator != mArgumentMap.end()) { return tIterator->second->get(); } @@ -371,7 +369,7 @@ class ArgumentParser { template typename std::enable_if::value, T>::type get(const char * aArgumentName) { - std::map>::iterator tIterator = mArgumentMap.find(aArgumentName); + auto tIterator = mArgumentMap.find(aArgumentName); if (tIterator != mArgumentMap.end()) { return tIterator->second->get_vector(); } @@ -382,7 +380,7 @@ class ArgumentParser { template typename std::enable_if::value, T>::type get(const char * aArgumentName) { - std::map>::iterator tIterator = mArgumentMap.find(aArgumentName); + auto tIterator = mArgumentMap.find(aArgumentName); if (tIterator != mArgumentMap.end()) { return tIterator->second->get_list(); } @@ -392,7 +390,7 @@ class ArgumentParser { // Indexing operator. Return a reference to an Argument object // Used in conjuction with Argument.operator== e.g., parser["foo"] == true Argument& operator[](const std::string& aArgumentName) { - std::map>::iterator tIterator = mArgumentMap.find(aArgumentName); + auto tIterator = mArgumentMap.find(aArgumentName); if (tIterator != mArgumentMap.end()) { return *(tIterator->second); } @@ -474,7 +472,7 @@ class ArgumentParser { private: // If the argument was defined by the user and can be found in mArgumentMap, then it's valid bool is_valid_argument(const std::string& aName) { - std::map>::iterator tIterator = mArgumentMap.find(aName); + auto tIterator = mArgumentMap.find(aName); return (tIterator != mArgumentMap.end()); } @@ -495,8 +493,7 @@ class ArgumentParser { print_help(); exit(0); } - std::map>::iterator tIterator = - mArgumentMap.find(argv[i]); + auto tIterator = mArgumentMap.find(argv[i]); if (tIterator != mArgumentMap.end()) { // Start parsing optional argument auto tArgument = tIterator->second; From d57b191f774637837d0613b3571053c6419f33ec Mon Sep 17 00:00:00 2001 From: Stephan van Veen Date: Thu, 9 May 2019 18:00:36 +0200 Subject: [PATCH 05/13] Use range based for loop --- include/argparse.hpp | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index d1aec6b1..5d4b6ace 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -211,8 +211,8 @@ class Argument { } else { if (mRawValues.size() > 0) { - for (size_t i = 0; i < mValues.size(); i++) { - tResult.push_back(std::any_cast(mValues[i])); + for (const auto& mValue : mValues) { + tResult.push_back(std::any_cast(mValue)); } return tResult; } @@ -247,8 +247,8 @@ class Argument { } else { if (mRawValues.size() > 0) { - for (size_t i = 0; i < mValues.size(); i++) { - tResult.push_back(std::any_cast(mValues[i])); + for (const auto& mValue : mValues) { + tResult.push_back(std::any_cast(mValue)); } return tResult; } @@ -314,8 +314,7 @@ class ArgumentParser { // Base case for add_parents parameter packing void add_parents() { - for (size_t i = 0; i < mParentParsers.size(); i++) { - auto tParentParser = mParentParsers[i]; + for (const auto& tParentParser : mParentParsers) { auto tPositionalArguments = tParentParser.mPositionalArguments; for (auto& tArgument : tPositionalArguments) { mPositionalArguments.push_back(tArgument); @@ -415,9 +414,9 @@ class ArgumentParser { if (mPositionalArguments.size() > 0) stream << "Positional arguments:\n"; - for (size_t i = 0; i < mPositionalArguments.size(); i++) { + for (const auto& mPositionalArgument : mPositionalArguments) { size_t tCurrentLength = 0; - auto tNames = mPositionalArguments[i]->mNames; + auto tNames = mPositionalArgument->mNames; for (size_t j = 0; j < tNames.size() - 1; j++) { auto tCurrentName = tNames[j]; stream << tCurrentName; @@ -433,16 +432,16 @@ class ArgumentParser { else stream << std::string((tCurrentLength - tLongestArgumentLength) + 2, ' '); - stream << mPositionalArguments[i]->mHelp << "\n"; + stream << mPositionalArgument->mHelp << "\n"; } if (mOptionalArguments.size() > 0 && mPositionalArguments.size() > 0) stream << "\nOptional arguments:\n"; else if (mOptionalArguments.size() > 0) stream << "Optional arguments:\n"; - for (size_t i = 0; i < mOptionalArguments.size(); i++) { + for (const auto & mOptionalArgument : mOptionalArguments) { size_t tCurrentLength = 0; - auto tNames = mOptionalArguments[i]->mNames; + auto tNames = mOptionalArgument->mNames; std::sort(tNames.begin(), tNames.end(), [](const std::string& lhs, const std::string& rhs) { return lhs.size() == rhs.size() ? lhs < rhs : lhs.size() < rhs.size(); @@ -462,7 +461,7 @@ class ArgumentParser { else stream << std::string((tCurrentLength - tLongestArgumentLength) + 2, ' '); - stream << mOptionalArguments[i]->mHelp << "\n"; + stream << mOptionalArgument->mHelp << "\n"; } std::cout << stream.str(); @@ -607,8 +606,7 @@ class ArgumentParser { void parse_args_validate() { // Check if all positional arguments are parsed - for (size_t i = 0; i < mPositionalArguments.size(); i++) { - auto tArgument = mPositionalArguments[i]; + for (const auto& tArgument : mPositionalArguments) { if (tArgument->mValues.size() != tArgument->mNumArgs) { std::cout << "error: " << tArgument->mUsedName << ": expected " << tArgument->mNumArgs << (tArgument->mNumArgs == 1 ? " argument. " : " arguments. ") @@ -619,8 +617,7 @@ class ArgumentParser { } // Check if all user-provided optional argument values are parsed correctly - for (size_t i = 0; i < mOptionalArguments.size(); i++) { - auto tArgument = mOptionalArguments[i]; + for (const auto& tArgument : mOptionalArguments) { if (tArgument->mIsUsed && tArgument->mNumArgs > 0) { if (tArgument->mValues.size() != tArgument->mNumArgs) { // All cool if there's a default value to return @@ -643,9 +640,9 @@ class ArgumentParser { // Used by print_help. size_t get_length_of_longest_argument() { size_t tResult = 0; - for (size_t i = 0; i < mPositionalArguments.size(); i++) { + for (const auto& mPositionalArgument : mPositionalArguments) { size_t tCurrentArgumentLength = 0; - auto tNames = mPositionalArguments[i]->mNames; + auto tNames = mPositionalArgument->mNames; for (size_t j = 0; j < tNames.size() - 1; j++) { auto tNameLength = tNames[j].length(); tCurrentArgumentLength += tNameLength + 2; // +2 for ", " @@ -655,9 +652,9 @@ class ArgumentParser { tResult = tCurrentArgumentLength; } - for (size_t i = 0; i < mOptionalArguments.size(); i++) { + for (const auto& mOptionalArgument : mOptionalArguments) { size_t tCurrentArgumentLength = 0; - auto tNames = mOptionalArguments[i]->mNames; + auto tNames = mOptionalArgument->mNames; for (size_t j = 0; j < tNames.size() - 1; j++) { auto tNameLength = tNames[j].length(); tCurrentArgumentLength += tNameLength + 2; // +2 for ", " From 1eadf94438fadb554ee2a9aa163dd646faf6486c Mon Sep 17 00:00:00 2001 From: Stephan van Veen Date: Thu, 9 May 2019 18:03:56 +0200 Subject: [PATCH 06/13] Use empty() instead of size comparison --- include/argparse.hpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index 5d4b6ace..c1eb1aca 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -175,7 +175,7 @@ class Argument { // Getter for template types other than std::vector and std::list template T get() const { - if (mValues.size() == 0) { + if (mValues.empty()) { if (mDefaultValue.has_value()) { return std::any_cast(mDefaultValue); } @@ -183,7 +183,7 @@ class Argument { return T(); } else { - if (mRawValues.size() > 0) + if (!mRawValues.empty()) return std::any_cast(mValues[0]); else { if (mDefaultValue.has_value()) @@ -198,7 +198,7 @@ class Argument { template T get_vector() const { T tResult; - if (mValues.size() == 0) { + if (mValues.empty()) { if (mDefaultValue.has_value()) { T tDefaultValues = std::any_cast(mDefaultValue); for (size_t i = 0; i < tDefaultValues.size(); i++) { @@ -210,7 +210,7 @@ class Argument { return T(); } else { - if (mRawValues.size() > 0) { + if (!mRawValues.empty()) { for (const auto& mValue : mValues) { tResult.push_back(std::any_cast(mValue)); } @@ -234,7 +234,7 @@ class Argument { template T get_list() const { T tResult; - if (mValues.size() == 0) { + if (mValues.empty()) { if (mDefaultValue.has_value()) { T tDefaultValues = std::any_cast(mDefaultValue); for (size_t i = 0; i < tDefaultValues.size(); i++) { @@ -246,7 +246,7 @@ class Argument { return T(); } else { - if (mRawValues.size() > 0) { + if (!mRawValues.empty()) { for (const auto& mValue : mValues) { tResult.push_back(std::any_cast(mValue)); } @@ -412,7 +412,7 @@ class ArgumentParser { } stream << "\n\n"; - if (mPositionalArguments.size() > 0) + if (!mPositionalArguments.empty()) stream << "Positional arguments:\n"; for (const auto& mPositionalArgument : mPositionalArguments) { size_t tCurrentLength = 0; @@ -435,9 +435,9 @@ class ArgumentParser { stream << mPositionalArgument->mHelp << "\n"; } - if (mOptionalArguments.size() > 0 && mPositionalArguments.size() > 0) + if (!mOptionalArguments.empty() && !mPositionalArguments.empty()) stream << "\nOptional arguments:\n"; - else if (mOptionalArguments.size() > 0) + else if (!mOptionalArguments.empty()) stream << "Optional arguments:\n"; for (const auto & mOptionalArgument : mOptionalArguments) { size_t tCurrentLength = 0; @@ -484,7 +484,7 @@ class ArgumentParser { } void parse_args_internal(int argc, char * argv[]) { - if (mProgramName == "" && argc > 0) + if (mProgramName.empty() && argc > 0) mProgramName = argv[0]; for (int i = 1; i < argc; i++) { auto tCurrentArgument = std::string(argv[i]); @@ -553,7 +553,7 @@ class ArgumentParser { parse_args_internal(tArgumentsForRecursiveParsing); } else { - if (tArgument.size() > 0 && tArgument[0] == '-') + if (!tArgument.empty() && tArgument[0] == '-') std::cout << "warning: unrecognized optional argument " << tArgument << std::endl; else From bef90a8d4fae7800e373ef3f2f6cc4de8fbb43c5 Mon Sep 17 00:00:00 2001 From: Stephan van Veen Date: Thu, 9 May 2019 18:06:56 +0200 Subject: [PATCH 07/13] Make use of move semantics --- include/argparse.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index c1eb1aca..cb1d09f8 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -99,18 +99,18 @@ class Argument { } Argument& default_value(std::any aDefaultValue) { - mDefaultValue = aDefaultValue; + mDefaultValue = std::move(aDefaultValue); return *this; } Argument& implicit_value(std::any aImplicitValue) { - mImplicitValue = aImplicitValue; + mImplicitValue = std::move(aImplicitValue); mNumArgs = 0; return *this; } Argument& action(std::function aAction) { - mAction = aAction; + mAction = std::move(aAction); return *this; } @@ -281,8 +281,8 @@ class Argument { class ArgumentParser { public: - ArgumentParser(const std::string& aProgramName = "") : - mProgramName(aProgramName), + explicit ArgumentParser(std::string aProgramName = "") : + mProgramName(std::move(aProgramName)), mNextPositionalArgument(0) { std::shared_ptr tArgument = std::make_shared(); tArgument->mNames = { "-h", "--help" }; From df21d07bd680d26ef51b72e0843935305815cfbe Mon Sep 17 00:00:00 2001 From: Stephan van Veen Date: Thu, 9 May 2019 18:24:16 +0200 Subject: [PATCH 08/13] Prefer emplace_back over push_back --- include/argparse.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index cb1d09f8..bdd7b4a0 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -478,8 +478,8 @@ class ArgumentParser { void parse_args_internal(const std::vector& aArguments) { std::vector argv; for (const auto& arg : aArguments) - argv.push_back(const_cast(arg.data())); - argv.push_back(nullptr); + argv.emplace_back(const_cast(arg.data())); + argv.emplace_back(nullptr); return parse_args_internal(int(argv.size()) - 1, argv.data()); } @@ -507,21 +507,21 @@ class ArgumentParser { if (tCount == 0) { // Use implicit value for this optional argument tArgument->mValues.push_back(tArgument->mImplicitValue); - tArgument->mRawValues.push_back(""); + tArgument->mRawValues.emplace_back(); tCount = 0; } while (tCount > 0) { i = i + 1; if (i < argc) { tArgument->mUsedName = tCurrentArgument; - tArgument->mRawValues.push_back(argv[i]); + tArgument->mRawValues.emplace_back(argv[i]); if (tArgument->mAction != nullptr) tArgument->mValues.push_back(tArgument->mAction(argv[i])); else { if (tArgument->mDefaultValue.has_value()) tArgument->mValues.push_back(tArgument->mDefaultValue); else - tArgument->mValues.push_back(std::string(argv[i])); + tArgument->mValues.emplace_back(std::string(argv[i])); } } tCount -= 1; @@ -546,7 +546,7 @@ class ArgumentParser { while (tNumArgs > 0 && i < argc) { i += 1; if (i < argc) { - tArgumentsForRecursiveParsing.push_back(argv[i]); + tArgumentsForRecursiveParsing.emplace_back(argv[i]); tNumArgs -= 1; } } @@ -584,14 +584,14 @@ class ArgumentParser { } if (i < argc) { tArgument->mUsedName = tCurrentArgument; - tArgument->mRawValues.push_back(argv[i]); + tArgument->mRawValues.emplace_back(argv[i]); if (tArgument->mAction != nullptr) tArgument->mValues.push_back(tArgument->mAction(argv[i])); else { if (tArgument->mDefaultValue.has_value()) tArgument->mValues.push_back(tArgument->mDefaultValue); else - tArgument->mValues.push_back(std::string(argv[i])); + tArgument->mValues.emplace_back(std::string(argv[i])); } } tCount -= 1; From 2dc9121acffc3448f5caa65f1d84126f17814b22 Mon Sep 17 00:00:00 2001 From: Stephan van Veen Date: Thu, 9 May 2019 18:24:30 +0200 Subject: [PATCH 09/13] Simplify type traits --- include/argparse.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index bdd7b4a0..5567a23f 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -126,8 +126,8 @@ class Argument { // Entry point for template types other than std::vector and std::list template - typename std::enable_if::value == false && - is_specialization::value == false, bool>::type + typename std::enable_if::value && + !is_specialization::value, bool>::type operator==(const T& aRhs) const { return get() == aRhs; } @@ -354,8 +354,8 @@ class ArgumentParser { // Getter enabled for all template types other than std::vector and std::list template - typename std::enable_if::value == false && - is_specialization::value == false, T>::type + typename std::enable_if::value && + !is_specialization::value, T>::type get(const char * aArgumentName) { auto tIterator = mArgumentMap.find(aArgumentName); if (tIterator != mArgumentMap.end()) { From 91cd2477dea4446ab9ee96750b1eee817af44390 Mon Sep 17 00:00:00 2001 From: Stephan van Veen Date: Thu, 9 May 2019 20:28:10 +0200 Subject: [PATCH 10/13] Fix broken indentation --- include/argparse.hpp | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index 5567a23f..2b56ff56 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -69,7 +69,7 @@ bool upsert(std::map& aMap, KeyType const& aKey, ElementTy bool starts_with(const std::string& haystack, const std::string& needle) { return needle.length() <= haystack.length() && std::equal(needle.begin(), needle.end(), haystack.begin()); -}; +} // Get value at index from std::list template @@ -496,7 +496,7 @@ class ArgumentParser { if (tIterator != mArgumentMap.end()) { // Start parsing optional argument auto tArgument = tIterator->second; - tArgument->mUsedName = tCurrentArgument; + tArgument->mUsedName = tCurrentArgument; tArgument->mIsUsed = true; auto tCount = tArgument->mNumArgs; @@ -513,7 +513,7 @@ class ArgumentParser { while (tCount > 0) { i = i + 1; if (i < argc) { - tArgument->mUsedName = tCurrentArgument; + tArgument->mUsedName = tCurrentArgument; tArgument->mRawValues.emplace_back(argv[i]); if (tArgument->mAction != nullptr) tArgument->mValues.push_back(tArgument->mAction(argv[i])); @@ -542,24 +542,24 @@ class ArgumentParser { if (tIterator != mArgumentMap.end()) { auto tArgumentObject = tIterator->second; tNumArgs = tArgumentObject->mNumArgs; - std::vector tArgumentsForRecursiveParsing = { "", "-" + tArgument }; - while (tNumArgs > 0 && i < argc) { - i += 1; - if (i < argc) { - tArgumentsForRecursiveParsing.emplace_back(argv[i]); - tNumArgs -= 1; - } - } - parse_args_internal(tArgumentsForRecursiveParsing); + std::vector tArgumentsForRecursiveParsing = {"", "-" + tArgument}; + while (tNumArgs > 0 && i < argc) { + i += 1; + if (i < argc) { + tArgumentsForRecursiveParsing.emplace_back(argv[i]); + tNumArgs -= 1; + } + } + parse_args_internal(tArgumentsForRecursiveParsing); + } + else { + if (!tArgument.empty() && tArgument[0] == '-') + std::cout << "warning: unrecognized optional argument " << tArgument + << std::endl; + else + std::cout << "warning: unrecognized optional argument -" << tArgument + << std::endl; } - else { - if (!tArgument.empty() && tArgument[0] == '-') - std::cout << "warning: unrecognized optional argument " << tArgument - << std::endl; - else - std::cout << "warning: unrecognized optional argument -" << tArgument - << std::endl; - } } } else { @@ -583,7 +583,7 @@ class ArgumentParser { break; } if (i < argc) { - tArgument->mUsedName = tCurrentArgument; + tArgument->mUsedName = tCurrentArgument; tArgument->mRawValues.emplace_back(argv[i]); if (tArgument->mAction != nullptr) tArgument->mValues.push_back(tArgument->mAction(argv[i])); From 10fab589699127e02fed9fca18d115dc96f8e8c0 Mon Sep 17 00:00:00 2001 From: Stephan van Veen Date: Fri, 10 May 2019 17:06:28 +0200 Subject: [PATCH 11/13] Replace upsert method by std::map::insert_or_assign --- include/argparse.hpp | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index 2b56ff56..2877f9de 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -49,22 +49,6 @@ struct is_specialization : std::false_type {}; template class Ref, typename... Args> struct is_specialization, Ref> : std::true_type {}; -// Upsert into std::map -template -bool upsert(std::map& aMap, KeyType const& aKey, ElementType const& aNewValue) { - auto tResult = aMap.insert(typename std::map::value_type(aKey, aNewValue)); - if (!tResult.second) { - if (!(tResult.first->second == aNewValue)) { - tResult.first->second = aNewValue; - return true; - } - else - return false; // it was the same - } - else - return true; // changed cause not existing -} - // Check if string (haystack) starts with a substring (needle) bool starts_with(const std::string& haystack, const std::string& needle) { return needle.length() <= haystack.length() @@ -291,8 +275,8 @@ class ArgumentParser { tArgument->mDefaultValue = false; tArgument->mImplicitValue = true; mOptionalArguments.push_back(tArgument); - upsert(mArgumentMap, std::string("-h"), tArgument); - upsert(mArgumentMap, std::string("--help"), tArgument); + mArgumentMap.insert_or_assign(std::string("-h"), tArgument); + mArgumentMap.insert_or_assign(std::string("--help"), tArgument); } // Parameter packing @@ -307,7 +291,7 @@ class ArgumentParser { mOptionalArguments.push_back(tArgument); for (auto& mName : tArgument->mNames) { - upsert(mArgumentMap, mName, tArgument); + mArgumentMap.insert_or_assign(mName, tArgument); } return *tArgument; } @@ -325,7 +309,7 @@ class ArgumentParser { } auto tArgumentMap = tParentParser.mArgumentMap; for (auto&[tKey, tValue] : tArgumentMap) { - upsert(mArgumentMap, tKey, tValue); + mArgumentMap.insert_or_assign(tKey, tValue); } } } From 6d3be1927ce7048295f7a8653bde3e9751f20fc1 Mon Sep 17 00:00:00 2001 From: Stephan van Veen Date: Fri, 10 May 2019 17:20:12 +0200 Subject: [PATCH 12/13] Use new constructor of Argument in constructor of ArgumentParser --- include/argparse.hpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index 2877f9de..23f40a86 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -265,11 +265,10 @@ class Argument { class ArgumentParser { public: - explicit ArgumentParser(std::string aProgramName = "") : - mProgramName(std::move(aProgramName)), - mNextPositionalArgument(0) { - std::shared_ptr tArgument = std::make_shared(); - tArgument->mNames = { "-h", "--help" }; + explicit ArgumentParser(std::string aProgramName = {}) : + mProgramName(std::move(aProgramName)) + { + std::shared_ptr tArgument = std::make_shared("-h", "--help"); tArgument->mHelp = "show this help message and exit"; tArgument->mNumArgs = 0; tArgument->mDefaultValue = false; @@ -654,7 +653,7 @@ class ArgumentParser { std::vector mParentParsers; std::vector> mPositionalArguments; std::vector> mOptionalArguments; - size_t mNextPositionalArgument; + size_t mNextPositionalArgument = 0; std::map> mArgumentMap; }; From b1c566b434ea23fdc574599b11fe873decb3ed37 Mon Sep 17 00:00:00 2001 From: Stephan van Veen Date: Fri, 10 May 2019 19:11:43 +0200 Subject: [PATCH 13/13] Prefer emplace_back over push_back --- include/argparse.hpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index 23f40a86..aef3c38c 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -186,7 +186,7 @@ class Argument { if (mDefaultValue.has_value()) { T tDefaultValues = std::any_cast(mDefaultValue); for (size_t i = 0; i < tDefaultValues.size(); i++) { - tResult.push_back(std::any_cast(tDefaultValues[i])); + tResult.emplace_back(std::any_cast(tDefaultValues[i])); } return tResult; } @@ -196,7 +196,7 @@ class Argument { else { if (!mRawValues.empty()) { for (const auto& mValue : mValues) { - tResult.push_back(std::any_cast(mValue)); + tResult.emplace_back(std::any_cast(mValue)); } return tResult; } @@ -204,7 +204,7 @@ class Argument { if (mDefaultValue.has_value()) { std::vector tDefaultValues = std::any_cast>(mDefaultValue); for (size_t i = 0; i < tDefaultValues.size(); i++) { - tResult.push_back(std::any_cast(tDefaultValues[i])); + tResult.emplace_back(std::any_cast(tDefaultValues[i])); } return tResult; } @@ -222,7 +222,7 @@ class Argument { if (mDefaultValue.has_value()) { T tDefaultValues = std::any_cast(mDefaultValue); for (size_t i = 0; i < tDefaultValues.size(); i++) { - tResult.push_back(std::any_cast(get_from_list(tDefaultValues, i))); + tResult.emplace_back(std::any_cast(get_from_list(tDefaultValues, i))); } return tResult; } @@ -232,7 +232,7 @@ class Argument { else { if (!mRawValues.empty()) { for (const auto& mValue : mValues) { - tResult.push_back(std::any_cast(mValue)); + tResult.emplace_back(std::any_cast(mValue)); } return tResult; } @@ -240,7 +240,7 @@ class Argument { if (mDefaultValue.has_value()) { std::list tDefaultValues = std::any_cast>(mDefaultValue); for (size_t i = 0; i < tDefaultValues.size(); i++) { - tResult.push_back(std::any_cast(get_from_list(tDefaultValues, i))); + tResult.emplace_back(std::any_cast(get_from_list(tDefaultValues, i))); } return tResult; } @@ -273,7 +273,7 @@ class ArgumentParser { tArgument->mNumArgs = 0; tArgument->mDefaultValue = false; tArgument->mImplicitValue = true; - mOptionalArguments.push_back(tArgument); + mOptionalArguments.emplace_back(tArgument); mArgumentMap.insert_or_assign(std::string("-h"), tArgument); mArgumentMap.insert_or_assign(std::string("--help"), tArgument); } @@ -285,9 +285,9 @@ class ArgumentParser { std::shared_ptr tArgument = std::make_shared(std::move(Fargs)...); if (!tArgument->mIsOptional) - mPositionalArguments.push_back(tArgument); + mPositionalArguments.emplace_back(tArgument); else - mOptionalArguments.push_back(tArgument); + mOptionalArguments.emplace_back(tArgument); for (auto& mName : tArgument->mNames) { mArgumentMap.insert_or_assign(mName, tArgument); @@ -300,11 +300,11 @@ class ArgumentParser { for (const auto& tParentParser : mParentParsers) { auto tPositionalArguments = tParentParser.mPositionalArguments; for (auto& tArgument : tPositionalArguments) { - mPositionalArguments.push_back(tArgument); + mPositionalArguments.emplace_back(tArgument); } auto tOptionalArguments = tParentParser.mOptionalArguments; for (auto& tArgument : tOptionalArguments) { - mOptionalArguments.push_back(tArgument); + mOptionalArguments.emplace_back(tArgument); } auto tArgumentMap = tParentParser.mArgumentMap; for (auto&[tKey, tValue] : tArgumentMap) { @@ -317,7 +317,7 @@ class ArgumentParser { // Accepts a variadic number of ArgumentParser objects template void add_parents(T aArgumentParser, Targs... Fargs) { - mParentParsers.push_back(aArgumentParser); + mParentParsers.emplace_back(aArgumentParser); add_parents(Fargs...); } @@ -489,7 +489,7 @@ class ArgumentParser { // (2) User has provided an implicit value, which also sets nargs to 0 if (tCount == 0) { // Use implicit value for this optional argument - tArgument->mValues.push_back(tArgument->mImplicitValue); + tArgument->mValues.emplace_back(tArgument->mImplicitValue); tArgument->mRawValues.emplace_back(); tCount = 0; } @@ -499,10 +499,10 @@ class ArgumentParser { tArgument->mUsedName = tCurrentArgument; tArgument->mRawValues.emplace_back(argv[i]); if (tArgument->mAction != nullptr) - tArgument->mValues.push_back(tArgument->mAction(argv[i])); + tArgument->mValues.emplace_back(tArgument->mAction(argv[i])); else { if (tArgument->mDefaultValue.has_value()) - tArgument->mValues.push_back(tArgument->mDefaultValue); + tArgument->mValues.emplace_back(tArgument->mDefaultValue); else tArgument->mValues.emplace_back(std::string(argv[i])); } @@ -569,10 +569,10 @@ class ArgumentParser { tArgument->mUsedName = tCurrentArgument; tArgument->mRawValues.emplace_back(argv[i]); if (tArgument->mAction != nullptr) - tArgument->mValues.push_back(tArgument->mAction(argv[i])); + tArgument->mValues.emplace_back(tArgument->mAction(argv[i])); else { if (tArgument->mDefaultValue.has_value()) - tArgument->mValues.push_back(tArgument->mDefaultValue); + tArgument->mValues.emplace_back(tArgument->mDefaultValue); else tArgument->mValues.emplace_back(std::string(argv[i])); }