Merge pull request #12 from svanveen/feature/modernize

Modernize code
This commit is contained in:
Pranav Srinivas Kumar 2019-05-10 17:59:55 -04:00 committed by GitHub
commit 16ef9d84e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -49,29 +49,11 @@ struct is_specialization : std::false_type {};
template<template<typename...> class Ref, typename... Args> template<template<typename...> class Ref, typename... Args>
struct is_specialization<Ref<Args...>, Ref> : std::true_type {}; struct is_specialization<Ref<Args...>, Ref> : std::true_type {};
// Upsert into std::map
template <class KeyType, class ElementType>
bool upsert(std::map<KeyType, ElementType>& aMap, KeyType const& aKey, ElementType const& aNewValue) {
typedef typename std::map<KeyType, ElementType>::iterator Iterator;
typedef typename std::pair<Iterator, bool> Result;
Result tResult = aMap.insert(typename std::map<KeyType, ElementType>::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) // Check if string (haystack) starts with a substring (needle)
bool starts_with(const std::string& haystack, const std::string& needle) { bool starts_with(const std::string& haystack, const std::string& needle) {
return needle.length() <= haystack.length() return needle.length() <= haystack.length()
&& std::equal(needle.begin(), needle.end(), haystack.begin()); && std::equal(needle.begin(), needle.end(), haystack.begin());
}; }
// Get value at index from std::list // Get value at index from std::list
template <typename T> template <typename T>
@ -87,16 +69,13 @@ T get_from_list(const std::list<T>& aList, size_t aIndex) {
class Argument { class Argument {
friend class ArgumentParser; friend class ArgumentParser;
public: public:
Argument() : Argument() = default;
mNames({}),
mUsedName(""), template <typename ...Args>
mHelp(""), explicit Argument(Args... args)
mAction([](const std::string& aValue) { return aValue; }), : mNames({std::move(args)...})
mValues({}), , mIsOptional((is_optional(args) || ...))
mRawValues({}), {}
mNumArgs(1),
mIsOptional(false),
mIsUsed(false) {}
Argument& help(const std::string& aHelp) { Argument& help(const std::string& aHelp) {
mHelp = aHelp; mHelp = aHelp;
@ -104,18 +83,18 @@ public:
} }
Argument& default_value(std::any aDefaultValue) { Argument& default_value(std::any aDefaultValue) {
mDefaultValue = aDefaultValue; mDefaultValue = std::move(aDefaultValue);
return *this; return *this;
} }
Argument& implicit_value(std::any aImplicitValue) { Argument& implicit_value(std::any aImplicitValue) {
mImplicitValue = aImplicitValue; mImplicitValue = std::move(aImplicitValue);
mNumArgs = 0; mNumArgs = 0;
return *this; return *this;
} }
Argument& action(std::function<std::any(const std::string&)> aAction) { Argument& action(std::function<std::any(const std::string&)> aAction) {
mAction = aAction; mAction = std::move(aAction);
return *this; return *this;
} }
@ -131,8 +110,8 @@ public:
// Entry point for template types other than std::vector and std::list // Entry point for template types other than std::vector and std::list
template <typename T> template <typename T>
typename std::enable_if<is_specialization<T, std::vector>::value == false && typename std::enable_if<!is_specialization<T, std::vector>::value &&
is_specialization<T, std::list>::value == false, bool>::type !is_specialization<T, std::list>::value, bool>::type
operator==(const T& aRhs) const { operator==(const T& aRhs) const {
return get<T>() == aRhs; return get<T>() == aRhs;
} }
@ -172,11 +151,15 @@ public:
} }
private: 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 // Getter for template types other than std::vector and std::list
template <typename T> template <typename T>
T get() const { T get() const {
if (mValues.size() == 0) { if (mValues.empty()) {
if (mDefaultValue.has_value()) { if (mDefaultValue.has_value()) {
return std::any_cast<T>(mDefaultValue); return std::any_cast<T>(mDefaultValue);
} }
@ -184,7 +167,7 @@ public:
return T(); return T();
} }
else { else {
if (mRawValues.size() > 0) if (!mRawValues.empty())
return std::any_cast<T>(mValues[0]); return std::any_cast<T>(mValues[0]);
else { else {
if (mDefaultValue.has_value()) if (mDefaultValue.has_value())
@ -199,11 +182,11 @@ public:
template <typename T> template <typename T>
T get_vector() const { T get_vector() const {
T tResult; T tResult;
if (mValues.size() == 0) { if (mValues.empty()) {
if (mDefaultValue.has_value()) { if (mDefaultValue.has_value()) {
T tDefaultValues = std::any_cast<T>(mDefaultValue); T tDefaultValues = std::any_cast<T>(mDefaultValue);
for (size_t i = 0; i < tDefaultValues.size(); i++) { for (size_t i = 0; i < tDefaultValues.size(); i++) {
tResult.push_back(std::any_cast<typename T::value_type>(tDefaultValues[i])); tResult.emplace_back(std::any_cast<typename T::value_type>(tDefaultValues[i]));
} }
return tResult; return tResult;
} }
@ -211,9 +194,9 @@ public:
return T(); return T();
} }
else { else {
if (mRawValues.size() > 0) { if (!mRawValues.empty()) {
for (size_t i = 0; i < mValues.size(); i++) { for (const auto& mValue : mValues) {
tResult.push_back(std::any_cast<typename T::value_type>(mValues[i])); tResult.emplace_back(std::any_cast<typename T::value_type>(mValue));
} }
return tResult; return tResult;
} }
@ -221,7 +204,7 @@ public:
if (mDefaultValue.has_value()) { if (mDefaultValue.has_value()) {
std::vector<T> tDefaultValues = std::any_cast<std::vector<T>>(mDefaultValue); std::vector<T> tDefaultValues = std::any_cast<std::vector<T>>(mDefaultValue);
for (size_t i = 0; i < tDefaultValues.size(); i++) { for (size_t i = 0; i < tDefaultValues.size(); i++) {
tResult.push_back(std::any_cast<typename T::value_type>(tDefaultValues[i])); tResult.emplace_back(std::any_cast<typename T::value_type>(tDefaultValues[i]));
} }
return tResult; return tResult;
} }
@ -235,11 +218,11 @@ public:
template <typename T> template <typename T>
T get_list() const { T get_list() const {
T tResult; T tResult;
if (mValues.size() == 0) { if (mValues.empty()) {
if (mDefaultValue.has_value()) { if (mDefaultValue.has_value()) {
T tDefaultValues = std::any_cast<T>(mDefaultValue); T tDefaultValues = std::any_cast<T>(mDefaultValue);
for (size_t i = 0; i < tDefaultValues.size(); i++) { for (size_t i = 0; i < tDefaultValues.size(); i++) {
tResult.push_back(std::any_cast<typename T::value_type>(get_from_list(tDefaultValues, i))); tResult.emplace_back(std::any_cast<typename T::value_type>(get_from_list(tDefaultValues, i)));
} }
return tResult; return tResult;
} }
@ -247,9 +230,9 @@ public:
return T(); return T();
} }
else { else {
if (mRawValues.size() > 0) { if (!mRawValues.empty()) {
for (size_t i = 0; i < mValues.size(); i++) { for (const auto& mValue : mValues) {
tResult.push_back(std::any_cast<typename T::value_type>(mValues[i])); tResult.emplace_back(std::any_cast<typename T::value_type>(mValue));
} }
return tResult; return tResult;
} }
@ -257,7 +240,7 @@ public:
if (mDefaultValue.has_value()) { if (mDefaultValue.has_value()) {
std::list<T> tDefaultValues = std::any_cast<std::list<T>>(mDefaultValue); std::list<T> tDefaultValues = std::any_cast<std::list<T>>(mDefaultValue);
for (size_t i = 0; i < tDefaultValues.size(); i++) { for (size_t i = 0; i < tDefaultValues.size(); i++) {
tResult.push_back(std::any_cast<typename T::value_type>(get_from_list(tDefaultValues, i))); tResult.emplace_back(std::any_cast<typename T::value_type>(get_from_list(tDefaultValues, i)));
} }
return tResult; return tResult;
} }
@ -272,70 +255,60 @@ public:
std::string mHelp; std::string mHelp;
std::any mDefaultValue; std::any mDefaultValue;
std::any mImplicitValue; std::any mImplicitValue;
std::function<std::any(const std::string&)> mAction; std::function<std::any(const std::string&)> mAction = [](const std::string& aValue) { return aValue; };
std::vector<std::any> mValues; std::vector<std::any> mValues;
std::vector<std::string> mRawValues; std::vector<std::string> mRawValues;
size_t mNumArgs; size_t mNumArgs = 1;
bool mIsOptional; bool mIsOptional = false;
bool mIsUsed; // relevant for optional arguments. True if used by user bool mIsUsed = false; // relevant for optional arguments. True if used by user
}; };
class ArgumentParser { class ArgumentParser {
public: public:
ArgumentParser(const std::string& aProgramName = "") : explicit ArgumentParser(std::string aProgramName = {}) :
mProgramName(aProgramName), mProgramName(std::move(aProgramName))
mNextPositionalArgument(0) { {
std::shared_ptr<Argument> tArgument = std::make_shared<Argument>(); std::shared_ptr<Argument> tArgument = std::make_shared<Argument>("-h", "--help");
tArgument->mNames = { "-h", "--help" };
tArgument->mHelp = "show this help message and exit"; tArgument->mHelp = "show this help message and exit";
tArgument->mNumArgs = 0; tArgument->mNumArgs = 0;
tArgument->mDefaultValue = false; tArgument->mDefaultValue = false;
tArgument->mImplicitValue = true; tArgument->mImplicitValue = true;
mOptionalArguments.push_back(tArgument); mOptionalArguments.emplace_back(tArgument);
upsert(mArgumentMap, std::string("-h"), tArgument); mArgumentMap.insert_or_assign(std::string("-h"), tArgument);
upsert(mArgumentMap, std::string("--help"), tArgument); mArgumentMap.insert_or_assign(std::string("--help"), tArgument);
} }
// Parameter packing // Parameter packing
// Call add_argument with variadic number of string arguments // Call add_argument with variadic number of string arguments
// TODO: enforce T to be std::string template<typename... Targs>
template<typename T, typename... Targs> Argument& add_argument(Targs... Fargs) {
Argument& add_argument(T value, Targs... Fargs) { std::shared_ptr<Argument> tArgument = std::make_shared<Argument>(std::move(Fargs)...);
std::shared_ptr<Argument> tArgument = std::make_shared<Argument>();
tArgument->mNames.push_back(value);
add_argument_internal(tArgument, Fargs...);
for (auto& mName : tArgument->mNames) {
if (is_optional(mName))
tArgument->mIsOptional = true;
}
if (!tArgument->mIsOptional) if (!tArgument->mIsOptional)
mPositionalArguments.push_back(tArgument); mPositionalArguments.emplace_back(tArgument);
else else
mOptionalArguments.push_back(tArgument); mOptionalArguments.emplace_back(tArgument);
for (auto& mName : tArgument->mNames) { for (auto& mName : tArgument->mNames) {
upsert(mArgumentMap, mName, tArgument); mArgumentMap.insert_or_assign(mName, tArgument);
} }
return *tArgument; return *tArgument;
} }
// Base case for add_parents parameter packing // Base case for add_parents parameter packing
void add_parents() { void add_parents() {
for (size_t i = 0; i < mParentParsers.size(); i++) { for (const auto& tParentParser : mParentParsers) {
auto tParentParser = mParentParsers[i];
auto tPositionalArguments = tParentParser.mPositionalArguments; auto tPositionalArguments = tParentParser.mPositionalArguments;
for (auto& tArgument : tPositionalArguments) { for (auto& tArgument : tPositionalArguments) {
mPositionalArguments.push_back(tArgument); mPositionalArguments.emplace_back(tArgument);
} }
auto tOptionalArguments = tParentParser.mOptionalArguments; auto tOptionalArguments = tParentParser.mOptionalArguments;
for (auto& tArgument : tOptionalArguments) { for (auto& tArgument : tOptionalArguments) {
mOptionalArguments.push_back(tArgument); mOptionalArguments.emplace_back(tArgument);
} }
auto tArgumentMap = tParentParser.mArgumentMap; auto tArgumentMap = tParentParser.mArgumentMap;
for (auto&[tKey, tValue] : tArgumentMap) { for (auto&[tKey, tValue] : tArgumentMap) {
upsert(mArgumentMap, tKey, tValue); mArgumentMap.insert_or_assign(tKey, tValue);
} }
} }
} }
@ -344,7 +317,7 @@ class ArgumentParser {
// Accepts a variadic number of ArgumentParser objects // Accepts a variadic number of ArgumentParser objects
template<typename T, typename... Targs> template<typename T, typename... Targs>
void add_parents(T aArgumentParser, Targs... Fargs) { void add_parents(T aArgumentParser, Targs... Fargs) {
mParentParsers.push_back(aArgumentParser); mParentParsers.emplace_back(aArgumentParser);
add_parents(Fargs...); add_parents(Fargs...);
} }
@ -364,10 +337,10 @@ class ArgumentParser {
// Getter enabled for all template types other than std::vector and std::list // Getter enabled for all template types other than std::vector and std::list
template <typename T = std::string> template <typename T = std::string>
typename std::enable_if<is_specialization<T, std::vector>::value == false && typename std::enable_if<!is_specialization<T, std::vector>::value &&
is_specialization<T, std::list>::value == false, T>::type !is_specialization<T, std::list>::value, T>::type
get(const char * aArgumentName) { get(const char * aArgumentName) {
std::map<std::string, std::shared_ptr<Argument>>::iterator tIterator = mArgumentMap.find(aArgumentName); auto tIterator = mArgumentMap.find(aArgumentName);
if (tIterator != mArgumentMap.end()) { if (tIterator != mArgumentMap.end()) {
return tIterator->second->get<T>(); return tIterator->second->get<T>();
} }
@ -378,7 +351,7 @@ class ArgumentParser {
template <typename T> template <typename T>
typename std::enable_if<is_specialization<T, std::vector>::value, T>::type typename std::enable_if<is_specialization<T, std::vector>::value, T>::type
get(const char * aArgumentName) { get(const char * aArgumentName) {
std::map<std::string, std::shared_ptr<Argument>>::iterator tIterator = mArgumentMap.find(aArgumentName); auto tIterator = mArgumentMap.find(aArgumentName);
if (tIterator != mArgumentMap.end()) { if (tIterator != mArgumentMap.end()) {
return tIterator->second->get_vector<T>(); return tIterator->second->get_vector<T>();
} }
@ -389,7 +362,7 @@ class ArgumentParser {
template <typename T> template <typename T>
typename std::enable_if<is_specialization<T, std::list>::value, T>::type typename std::enable_if<is_specialization<T, std::list>::value, T>::type
get(const char * aArgumentName) { get(const char * aArgumentName) {
std::map<std::string, std::shared_ptr<Argument>>::iterator tIterator = mArgumentMap.find(aArgumentName); auto tIterator = mArgumentMap.find(aArgumentName);
if (tIterator != mArgumentMap.end()) { if (tIterator != mArgumentMap.end()) {
return tIterator->second->get_list<T>(); return tIterator->second->get_list<T>();
} }
@ -399,7 +372,7 @@ class ArgumentParser {
// Indexing operator. Return a reference to an Argument object // Indexing operator. Return a reference to an Argument object
// Used in conjuction with Argument.operator== e.g., parser["foo"] == true // Used in conjuction with Argument.operator== e.g., parser["foo"] == true
Argument& operator[](const std::string& aArgumentName) { Argument& operator[](const std::string& aArgumentName) {
std::map<std::string, std::shared_ptr<Argument>>::iterator tIterator = mArgumentMap.find(aArgumentName); auto tIterator = mArgumentMap.find(aArgumentName);
if (tIterator != mArgumentMap.end()) { if (tIterator != mArgumentMap.end()) {
return *(tIterator->second); return *(tIterator->second);
} }
@ -422,11 +395,11 @@ class ArgumentParser {
} }
stream << "\n\n"; stream << "\n\n";
if (mPositionalArguments.size() > 0) if (!mPositionalArguments.empty())
stream << "Positional arguments:\n"; stream << "Positional arguments:\n";
for (size_t i = 0; i < mPositionalArguments.size(); i++) { for (const auto& mPositionalArgument : mPositionalArguments) {
size_t tCurrentLength = 0; size_t tCurrentLength = 0;
auto tNames = mPositionalArguments[i]->mNames; auto tNames = mPositionalArgument->mNames;
for (size_t j = 0; j < tNames.size() - 1; j++) { for (size_t j = 0; j < tNames.size() - 1; j++) {
auto tCurrentName = tNames[j]; auto tCurrentName = tNames[j];
stream << tCurrentName; stream << tCurrentName;
@ -442,16 +415,16 @@ class ArgumentParser {
else else
stream << std::string((tCurrentLength - tLongestArgumentLength) + 2, ' '); stream << std::string((tCurrentLength - tLongestArgumentLength) + 2, ' ');
stream << mPositionalArguments[i]->mHelp << "\n"; stream << mPositionalArgument->mHelp << "\n";
} }
if (mOptionalArguments.size() > 0 && mPositionalArguments.size() > 0) if (!mOptionalArguments.empty() && !mPositionalArguments.empty())
stream << "\nOptional arguments:\n"; stream << "\nOptional arguments:\n";
else if (mOptionalArguments.size() > 0) else if (!mOptionalArguments.empty())
stream << "Optional arguments:\n"; stream << "Optional arguments:\n";
for (size_t i = 0; i < mOptionalArguments.size(); i++) { for (const auto & mOptionalArgument : mOptionalArguments) {
size_t tCurrentLength = 0; size_t tCurrentLength = 0;
auto tNames = mOptionalArguments[i]->mNames; auto tNames = mOptionalArgument->mNames;
std::sort(tNames.begin(), tNames.end(), std::sort(tNames.begin(), tNames.end(),
[](const std::string& lhs, const std::string& rhs) { [](const std::string& lhs, const std::string& rhs) {
return lhs.size() == rhs.size() ? lhs < rhs : lhs.size() < rhs.size(); return lhs.size() == rhs.size() ? lhs < rhs : lhs.size() < rhs.size();
@ -471,7 +444,7 @@ class ArgumentParser {
else else
stream << std::string((tCurrentLength - tLongestArgumentLength) + 2, ' '); stream << std::string((tCurrentLength - tLongestArgumentLength) + 2, ' ');
stream << mOptionalArguments[i]->mHelp << "\n"; stream << mOptionalArgument->mHelp << "\n";
} }
std::cout << stream.str(); std::cout << stream.str();
@ -479,38 +452,22 @@ class ArgumentParser {
} }
private: private:
Argument& add_argument_internal(std::shared_ptr<Argument> aArgument) {
return *aArgument;
}
template<typename T, typename... Targs>
Argument& add_argument_internal(std::shared_ptr<Argument> 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 // 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) { bool is_valid_argument(const std::string& aName) {
std::map<std::string, std::shared_ptr<Argument>>::iterator tIterator = mArgumentMap.find(aName); auto tIterator = mArgumentMap.find(aName);
return (tIterator != mArgumentMap.end()); return (tIterator != mArgumentMap.end());
} }
void parse_args_internal(const std::vector<std::string>& aArguments) { void parse_args_internal(const std::vector<std::string>& aArguments) {
std::vector<char*> argv; std::vector<char*> argv;
for (const auto& arg : aArguments) for (const auto& arg : aArguments)
argv.push_back(const_cast<char*>(arg.data())); argv.emplace_back(const_cast<char*>(arg.data()));
argv.push_back(nullptr); argv.emplace_back(nullptr);
return parse_args_internal(int(argv.size()) - 1, argv.data()); return parse_args_internal(int(argv.size()) - 1, argv.data());
} }
void parse_args_internal(int argc, char * argv[]) { void parse_args_internal(int argc, char * argv[]) {
if (mProgramName == "" && argc > 0) if (mProgramName.empty() && argc > 0)
mProgramName = argv[0]; mProgramName = argv[0];
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; i++) {
auto tCurrentArgument = std::string(argv[i]); auto tCurrentArgument = std::string(argv[i]);
@ -518,8 +475,7 @@ class ArgumentParser {
print_help(); print_help();
exit(0); exit(0);
} }
std::map<std::string, std::shared_ptr<Argument>>::iterator tIterator = auto tIterator = mArgumentMap.find(argv[i]);
mArgumentMap.find(argv[i]);
if (tIterator != mArgumentMap.end()) { if (tIterator != mArgumentMap.end()) {
// Start parsing optional argument // Start parsing optional argument
auto tArgument = tIterator->second; auto tArgument = tIterator->second;
@ -533,29 +489,29 @@ class ArgumentParser {
// (2) User has provided an implicit value, which also sets nargs to 0 // (2) User has provided an implicit value, which also sets nargs to 0
if (tCount == 0) { if (tCount == 0) {
// Use implicit value for this optional argument // Use implicit value for this optional argument
tArgument->mValues.push_back(tArgument->mImplicitValue); tArgument->mValues.emplace_back(tArgument->mImplicitValue);
tArgument->mRawValues.push_back(""); tArgument->mRawValues.emplace_back();
tCount = 0; tCount = 0;
} }
while (tCount > 0) { while (tCount > 0) {
i = i + 1; i = i + 1;
if (i < argc) { if (i < argc) {
tArgument->mUsedName = tCurrentArgument; tArgument->mUsedName = tCurrentArgument;
tArgument->mRawValues.push_back(argv[i]); tArgument->mRawValues.emplace_back(argv[i]);
if (tArgument->mAction != nullptr) if (tArgument->mAction != nullptr)
tArgument->mValues.push_back(tArgument->mAction(argv[i])); tArgument->mValues.emplace_back(tArgument->mAction(argv[i]));
else { else {
if (tArgument->mDefaultValue.has_value()) if (tArgument->mDefaultValue.has_value())
tArgument->mValues.push_back(tArgument->mDefaultValue); tArgument->mValues.emplace_back(tArgument->mDefaultValue);
else else
tArgument->mValues.push_back(std::string(argv[i])); tArgument->mValues.emplace_back(std::string(argv[i]));
} }
} }
tCount -= 1; tCount -= 1;
} }
} }
else { else {
if (is_optional(argv[i])) { if (Argument::is_optional(argv[i])) {
// This is possibly a compound optional argument // This is possibly a compound optional argument
// Example: We have three optional arguments -a, -u and -x // Example: We have three optional arguments -a, -u and -x
// The user provides ./main -aux ... // The user provides ./main -aux ...
@ -573,14 +529,14 @@ class ArgumentParser {
while (tNumArgs > 0 && i < argc) { while (tNumArgs > 0 && i < argc) {
i += 1; i += 1;
if (i < argc) { if (i < argc) {
tArgumentsForRecursiveParsing.push_back(argv[i]); tArgumentsForRecursiveParsing.emplace_back(argv[i]);
tNumArgs -= 1; tNumArgs -= 1;
} }
} }
parse_args_internal(tArgumentsForRecursiveParsing); parse_args_internal(tArgumentsForRecursiveParsing);
} }
else { else {
if (tArgument.size() > 0 && tArgument[0] == '-') if (!tArgument.empty() && tArgument[0] == '-')
std::cout << "warning: unrecognized optional argument " << tArgument std::cout << "warning: unrecognized optional argument " << tArgument
<< std::endl; << std::endl;
else else
@ -605,20 +561,20 @@ class ArgumentParser {
auto tCount = tArgument->mNumArgs - tArgument->mRawValues.size(); auto tCount = tArgument->mNumArgs - tArgument->mRawValues.size();
while (tCount > 0) { while (tCount > 0) {
tIterator = mArgumentMap.find(argv[i]); 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; i = i - 1;
break; break;
} }
if (i < argc) { if (i < argc) {
tArgument->mUsedName = tCurrentArgument; tArgument->mUsedName = tCurrentArgument;
tArgument->mRawValues.push_back(argv[i]); tArgument->mRawValues.emplace_back(argv[i]);
if (tArgument->mAction != nullptr) if (tArgument->mAction != nullptr)
tArgument->mValues.push_back(tArgument->mAction(argv[i])); tArgument->mValues.emplace_back(tArgument->mAction(argv[i]));
else { else {
if (tArgument->mDefaultValue.has_value()) if (tArgument->mDefaultValue.has_value())
tArgument->mValues.push_back(tArgument->mDefaultValue); tArgument->mValues.emplace_back(tArgument->mDefaultValue);
else else
tArgument->mValues.push_back(std::string(argv[i])); tArgument->mValues.emplace_back(std::string(argv[i]));
} }
} }
tCount -= 1; tCount -= 1;
@ -633,8 +589,7 @@ class ArgumentParser {
void parse_args_validate() { void parse_args_validate() {
// Check if all positional arguments are parsed // Check if all positional arguments are parsed
for (size_t i = 0; i < mPositionalArguments.size(); i++) { for (const auto& tArgument : mPositionalArguments) {
auto tArgument = mPositionalArguments[i];
if (tArgument->mValues.size() != tArgument->mNumArgs) { if (tArgument->mValues.size() != tArgument->mNumArgs) {
std::cout << "error: " << tArgument->mUsedName << ": expected " std::cout << "error: " << tArgument->mUsedName << ": expected "
<< tArgument->mNumArgs << (tArgument->mNumArgs == 1 ? " argument. " : " arguments. ") << tArgument->mNumArgs << (tArgument->mNumArgs == 1 ? " argument. " : " arguments. ")
@ -645,8 +600,7 @@ class ArgumentParser {
} }
// Check if all user-provided optional argument values are parsed correctly // Check if all user-provided optional argument values are parsed correctly
for (size_t i = 0; i < mOptionalArguments.size(); i++) { for (const auto& tArgument : mOptionalArguments) {
auto tArgument = mOptionalArguments[i];
if (tArgument->mIsUsed && tArgument->mNumArgs > 0) { if (tArgument->mIsUsed && tArgument->mNumArgs > 0) {
if (tArgument->mValues.size() != tArgument->mNumArgs) { if (tArgument->mValues.size() != tArgument->mNumArgs) {
// All cool if there's a default value to return // All cool if there's a default value to return
@ -669,9 +623,9 @@ class ArgumentParser {
// Used by print_help. // Used by print_help.
size_t get_length_of_longest_argument() { size_t get_length_of_longest_argument() {
size_t tResult = 0; size_t tResult = 0;
for (size_t i = 0; i < mPositionalArguments.size(); i++) { for (const auto& mPositionalArgument : mPositionalArguments) {
size_t tCurrentArgumentLength = 0; size_t tCurrentArgumentLength = 0;
auto tNames = mPositionalArguments[i]->mNames; auto tNames = mPositionalArgument->mNames;
for (size_t j = 0; j < tNames.size() - 1; j++) { for (size_t j = 0; j < tNames.size() - 1; j++) {
auto tNameLength = tNames[j].length(); auto tNameLength = tNames[j].length();
tCurrentArgumentLength += tNameLength + 2; // +2 for ", " tCurrentArgumentLength += tNameLength + 2; // +2 for ", "
@ -681,9 +635,9 @@ class ArgumentParser {
tResult = tCurrentArgumentLength; tResult = tCurrentArgumentLength;
} }
for (size_t i = 0; i < mOptionalArguments.size(); i++) { for (const auto& mOptionalArgument : mOptionalArguments) {
size_t tCurrentArgumentLength = 0; size_t tCurrentArgumentLength = 0;
auto tNames = mOptionalArguments[i]->mNames; auto tNames = mOptionalArgument->mNames;
for (size_t j = 0; j < tNames.size() - 1; j++) { for (size_t j = 0; j < tNames.size() - 1; j++) {
auto tNameLength = tNames[j].length(); auto tNameLength = tNames[j].length();
tCurrentArgumentLength += tNameLength + 2; // +2 for ", " tCurrentArgumentLength += tNameLength + 2; // +2 for ", "
@ -699,7 +653,7 @@ class ArgumentParser {
std::vector<ArgumentParser> mParentParsers; std::vector<ArgumentParser> mParentParsers;
std::vector<std::shared_ptr<Argument>> mPositionalArguments; std::vector<std::shared_ptr<Argument>> mPositionalArguments;
std::vector<std::shared_ptr<Argument>> mOptionalArguments; std::vector<std::shared_ptr<Argument>> mOptionalArguments;
size_t mNextPositionalArgument; size_t mNextPositionalArgument = 0;
std::map<std::string, std::shared_ptr<Argument>> mArgumentMap; std::map<std::string, std::shared_ptr<Argument>> mArgumentMap;
}; };