From cb04248cfaea241afcf77a55688a1f521cdd965e Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Sat, 17 Aug 2019 17:01:04 -0500 Subject: [PATCH] Updated formatting --- include/argparse.hpp | 715 +++++++++++++++++++++---------------------- 1 file changed, 355 insertions(+), 360 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index 74904cc..e689b6f 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -28,46 +28,45 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include +#include +#include +#include namespace argparse { -namespace { // anonymous namespace for helper methods - not visible outside this header file +namespace { // anonymous namespace for helper methods - not visible outside this + // header file -template -struct is_container_helper {}; +template struct is_container_helper {}; -template +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()) - >, void>> : public std::true_type { -}; +template +struct is_container< + T, + std::conditional_t().begin()), + decltype(std::declval().end()), + decltype(std::declval().size())>, + void>> : public std::true_type {}; -template +template static constexpr bool is_container_v = is_container::value; template @@ -75,50 +74,50 @@ using enable_if_container = std::enable_if_t, T>; template using enable_if_not_container = std::enable_if_t, T>; -} +} // namespace class Argument { friend class ArgumentParser; + public: Argument() = default; - template + template explicit Argument(Args... args) - : mNames({std::move(args)...}) - , mIsOptional((is_optional(args) || ...)) - { - std::sort(mNames.begin(), mNames.end(), [](const auto& lhs, const auto& rhs) { - return lhs.size() == rhs.size() ? lhs < rhs : lhs.size() < rhs.size(); - }); + : mNames({std::move(args)...}), mIsOptional((is_optional(args) || ...)) { + std::sort( + mNames.begin(), mNames.end(), [](const auto &lhs, const auto &rhs) { + return lhs.size() == rhs.size() ? lhs < rhs : lhs.size() < rhs.size(); + }); } - Argument& help(std::string aHelp) { + Argument &help(std::string aHelp) { mHelp = std::move(aHelp); return *this; } - Argument& default_value(std::any aDefaultValue) { + Argument &default_value(std::any aDefaultValue) { mDefaultValue = std::move(aDefaultValue); return *this; } - Argument& required() { - mIsRequired = true; - return *this; + Argument &required() { + mIsRequired = true; + return *this; } - Argument& implicit_value(std::any aImplicitValue) { + Argument &implicit_value(std::any aImplicitValue) { mImplicitValue = std::move(aImplicitValue); mNumArgs = 0; return *this; } - Argument& action(std::function aAction) { + Argument &action(std::function aAction) { mAction = std::move(aAction); return *this; } - Argument& nargs(size_t aNumArgs) { + Argument &nargs(size_t aNumArgs) { mNumArgs = aNumArgs; return *this; } @@ -133,19 +132,16 @@ public: if (mNumArgs == 0) { mValues.emplace_back(mImplicitValue); return start; - } - else if (mNumArgs <= static_cast(std::distance(start, end))) { + } else if (mNumArgs <= static_cast(std::distance(start, end))) { end = std::next(start, mNumArgs); if (std::any_of(start, end, Argument::is_optional)) { - throw std::runtime_error("optional argument in parameter sequence"); + throw std::runtime_error("optional argument in parameter sequence"); } std::transform(start, end, std::back_inserter(mValues), mAction); return end; - } - else if (mDefaultValue.has_value()) { + } else if (mDefaultValue.has_value()) { return start; - } - else { + } else { throw std::runtime_error("Too few arguments"); } } @@ -157,53 +153,53 @@ public: if (mIsOptional) { if (mIsUsed && mValues.size() != mNumArgs && !mDefaultValue.has_value()) { std::stringstream stream; - stream << "error: " << mUsedName << ": expected " << mNumArgs << " argument(s). " - << mValues.size() << " provided."; + stream << "error: " << mUsedName << ": expected " << mNumArgs + << " argument(s). " << mValues.size() << " provided."; throw std::runtime_error(stream.str()); - } - else { + } else { // TODO: check if an implicit value was programmed for this argument - if (!mIsUsed && !mDefaultValue.has_value() && mIsRequired) { - std::stringstream stream; - stream << "error: " << mNames[0] << ": required."; - throw std::runtime_error(stream.str()); - } - if (mIsUsed && mIsRequired && mValues.size() == 0) { - std::stringstream stream; - stream << "error: " << mUsedName << ": no value provided."; - throw std::runtime_error(stream.str()); + if (!mIsUsed && !mDefaultValue.has_value() && mIsRequired) { + std::stringstream stream; + stream << "error: " << mNames[0] << ": required."; + throw std::runtime_error(stream.str()); + } + if (mIsUsed && mIsRequired && mValues.size() == 0) { + std::stringstream stream; + stream << "error: " << mUsedName << ": no value provided."; + throw std::runtime_error(stream.str()); } } - } - else { + } else { if (mValues.size() != mNumArgs && !mDefaultValue.has_value()) { std::stringstream stream; - stream << "error: " << mUsedName << ": expected " << mNumArgs << " argument(s). " - << mValues.size() << " provided."; + stream << "error: " << mUsedName << ": expected " << mNumArgs + << " argument(s). " << mValues.size() << " provided."; throw std::runtime_error(stream.str()); } } } size_t get_arguments_length() const { - return std::accumulate(std::begin(mNames), std::end(mNames), size_t(0), [](const auto& sum, const auto& s) { - return sum + s.size() + 1; // +1 for space between names - }); + return std::accumulate(std::begin(mNames), std::end(mNames), size_t(0), + [](const auto &sum, const auto &s) { + return sum + s.size() + + 1; // +1 for space between names + }); } - friend std::ostream& operator<<(std::ostream& stream, const Argument& 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.mIsRequired) - stream << "[Required]"; - stream << "\n"; + std::copy(std::begin(argument.mNames), std::end(argument.mNames), + std::ostream_iterator(nameStream, " ")); + stream << nameStream.str() << "\t" << argument.mHelp; + if (argument.mIsRequired) + stream << "[Required]"; + stream << "\n"; return stream; } - - template - bool operator!=(const T& aRhs) const { + template bool operator!=(const T &aRhs) const { return !(*this == aRhs); } @@ -212,8 +208,7 @@ public: * @throws std::logic_error in case of incompatible types */ template - std::enable_if_t , bool> - operator==(const T& aRhs) const { + std::enable_if_t, bool> operator==(const T &aRhs) const { return get() == aRhs; } @@ -222,324 +217,324 @@ public: * @throws std::logic_error in case of incompatible types */ template - std::enable_if_t , bool> - operator==(const T& aRhs) const { + std::enable_if_t, bool> operator==(const T &aRhs) const { using ValueType = typename T::value_type; auto tLhs = get(); if (tLhs.size() != aRhs.size()) return false; else { - return std::equal(std::begin(tLhs), std::end(tLhs), std::begin(aRhs), [](const auto& lhs, const auto& rhs) { - return std::any_cast(lhs) == rhs; - }); + return std::equal(std::begin(tLhs), std::end(tLhs), std::begin(aRhs), + [](const auto &lhs, const auto &rhs) { + return std::any_cast(lhs) == rhs; + }); } } - private: +private: + static bool is_integer(const std::string &aValue) { + if (aValue.empty() || + ((!isdigit(aValue[0])) && (aValue[0] != '-') && (aValue[0] != '+'))) + return false; + char *tPtr; + strtol(aValue.c_str(), &tPtr, 10); + return (*tPtr == 0); + } - static bool is_integer(const std::string& aValue) { - if(aValue.empty() || - ((!isdigit(aValue[0])) && (aValue[0] != '-') && (aValue[0] != '+'))) - return false; - char * tPtr; - strtol(aValue.c_str(), &tPtr, 10); - return (*tPtr == 0); + static bool is_float(const std::string &aValue) { + std::istringstream tStream(aValue); + float tFloat; + // noskipws considers leading whitespace invalid + tStream >> std::noskipws >> tFloat; + // Check the entire string was consumed + // and if either failbit or badbit is set + return tStream.eof() && !tStream.fail(); + } + + // If an argument starts with "-" or "--", then it's optional + static bool is_optional(const std::string &aName) { + return (!aName.empty() && aName[0] == '-' && !is_integer(aName) && + !is_float(aName)); + } + + static bool is_positional(const std::string &aName) { + return !is_optional(aName); + } + + /* + * Getter for template non-container types + * @throws std::logic_error in case of incompatible types + */ + template enable_if_not_container get() const { + if (!mValues.empty()) { + return std::any_cast(mValues.front()); } - - static bool is_float(const std::string& aValue) { - std::istringstream tStream(aValue); - float tFloat; - // noskipws considers leading whitespace invalid - tStream >> std::noskipws >> tFloat; - // Check the entire string was consumed - // and if either failbit or badbit is set - return tStream.eof() && !tStream.fail(); + if (mDefaultValue.has_value()) { + return std::any_cast(mDefaultValue); } - - // If an argument starts with "-" or "--", then it's optional - static bool is_optional(const std::string& aName) { - return (!aName.empty() && aName[0] == '-' && - !is_integer(aName) && !is_float(aName)); + throw std::logic_error("No value provided"); + } + + /* + * Getter for container types + * @throws std::logic_error in case of incompatible types + */ + template enable_if_container get() const { + using ValueType = typename CONTAINER::value_type; + CONTAINER tResult; + if (!mValues.empty()) { + std::transform( + std::begin(mValues), std::end(mValues), std::back_inserter(tResult), + [](const auto &value) { return std::any_cast(value); }); + return tResult; } - - static bool is_positional(const std::string& aName) { - return !is_optional(aName); + if (mDefaultValue.has_value()) { + const auto &tDefaultValues = + std::any_cast(mDefaultValue); + std::transform(std::begin(tDefaultValues), std::end(tDefaultValues), + std::back_inserter(tResult), [](const auto &value) { + return std::any_cast(value); + }); + return tResult; } + throw std::logic_error("No value provided"); + } - /* - * Getter for template non-container types - * @throws std::logic_error in case of incompatible types - */ - template - enable_if_not_container - get() const { - if (!mValues.empty()) { - return std::any_cast(mValues.front()); - } - if (mDefaultValue.has_value()) { - return std::any_cast(mDefaultValue); - } - throw std::logic_error("No value provided"); - } + std::vector mNames; + std::string mUsedName; + std::string mHelp; + std::any mDefaultValue; + std::any mImplicitValue; + std::function mAction = + [](const std::string &aValue) { return aValue; }; + std::vector mValues; + std::vector mRawValues; + size_t mNumArgs = 1; + bool mIsOptional = false; + bool mIsRequired = false; + bool mIsUsed = false; // relevant for optional arguments. True if used by user - /* - * Getter for container types - * @throws std::logic_error in case of incompatible types - */ - template - enable_if_container - get() const { - using ValueType = typename CONTAINER::value_type; - CONTAINER tResult; - if (!mValues.empty()) { - std::transform(std::begin(mValues), std::end(mValues), std::back_inserter(tResult), [](const auto & value) { - return std::any_cast(value); - }); - return tResult; - } - if (mDefaultValue.has_value()) { - const auto& tDefaultValues = std::any_cast(mDefaultValue); - std::transform(std::begin(tDefaultValues), std::end(tDefaultValues), std::back_inserter(tResult), [](const auto & value) { - return std::any_cast(value); - }); - return tResult; - } - throw std::logic_error("No value provided"); - } - - std::vector mNames; - std::string mUsedName; - std::string mHelp; - std::any mDefaultValue; - std::any mImplicitValue; - std::function mAction = [](const std::string& aValue) { return aValue; }; - std::vector mValues; - std::vector mRawValues; - size_t mNumArgs = 1; - bool mIsOptional = false; - bool mIsRequired = false; - bool mIsUsed = false; // relevant for optional arguments. True if used by user - - public: - static constexpr auto mHelpOption = "-h"; - static constexpr auto mHelpOptionLong = "--help"; +public: + static constexpr auto mHelpOption = "-h"; + static constexpr auto mHelpOptionLong = "--help"; }; class ArgumentParser { - public: - explicit ArgumentParser(std::string aProgramName = {}) : - mProgramName(std::move(aProgramName)) - { - add_argument(Argument::mHelpOption, Argument::mHelpOptionLong) +public: + explicit ArgumentParser(std::string aProgramName = {}) + : mProgramName(std::move(aProgramName)) { + add_argument(Argument::mHelpOption, Argument::mHelpOptionLong) .help("show this help message and exit") .nargs(0) .default_value(false) .implicit_value(true); + } + + // Parameter packing + // Call add_argument with variadic number of string arguments + template Argument &add_argument(Targs... Fargs) { + std::shared_ptr tArgument = + std::make_shared(std::move(Fargs)...); + + if (tArgument->mIsOptional) + mOptionalArguments.emplace_back(tArgument); + else + mPositionalArguments.emplace_back(tArgument); + + for (const auto &mName : tArgument->mNames) { + mArgumentMap.insert_or_assign(mName, tArgument); } + return *tArgument; + } - // Parameter packing - // Call add_argument with variadic number of string arguments - template - Argument& add_argument(Targs... Fargs) { - std::shared_ptr tArgument = std::make_shared(std::move(Fargs)...); + // Parameter packed add_parents method + // Accepts a variadic number of ArgumentParser objects + template void add_parents(Targs... Fargs) { + const auto tNewParentParsers = {Fargs...}; + for (const auto &tParentParser : tNewParentParsers) { + const auto &tPositionalArguments = tParentParser.mPositionalArguments; + std::copy(std::begin(tPositionalArguments), + std::end(tPositionalArguments), + std::back_inserter(mPositionalArguments)); - if (tArgument->mIsOptional) - mOptionalArguments.emplace_back(tArgument); - else - mPositionalArguments.emplace_back(tArgument); + const auto &tOptionalArguments = tParentParser.mOptionalArguments; + std::copy(std::begin(tOptionalArguments), std::end(tOptionalArguments), + std::back_inserter(mOptionalArguments)); - for (const auto& mName : tArgument->mNames) { - mArgumentMap.insert_or_assign(mName, tArgument); + const auto &tArgumentMap = tParentParser.mArgumentMap; + for (const auto &[tKey, tValue] : tArgumentMap) { + mArgumentMap.insert_or_assign(tKey, tValue); } - return *tArgument; + } + std::move(std::begin(tNewParentParsers), std::end(tNewParentParsers), + std::back_inserter(mParentParsers)); + } + + /* Call parse_args_internal - which does all the work + * Then, validate the parsed arguments + * 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); + parse_args_validate(); + } + + /* Main entry point for parsing command-line arguments using this + * ArgumentParser + * @throws std::runtime_error in case of any invalid argument + */ + void parse_args(int argc, const char *const argv[]) { + std::vector arguments; + std::copy(argv, argv + argc, std::back_inserter(arguments)); + parse_args(arguments); + } + + /* Getter enabled for all template types other than std::vector and std::list + * @throws std::logic_error in case of an invalid argument name + * @throws std::logic_error in case of incompatible types + */ + template T get(const std::string &aArgumentName) { + auto tIterator = mArgumentMap.find(aArgumentName); + if (tIterator != mArgumentMap.end()) { + return tIterator->second->get(); + } + throw std::logic_error("No such argument"); + } + + /* 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[](const std::string &aArgumentName) { + auto tIterator = mArgumentMap.find(aArgumentName); + if (tIterator != mArgumentMap.end()) { + return *(tIterator->second); + } + throw std::logic_error("No such argument"); + } + + // Printing the one and only help message + // I've stuck with a simple message format, nothing fancy. + // TODO: support user-defined help and usage messages for the ArgumentParser + std::string print_help() { + std::stringstream stream; + stream << std::left; + stream << "Usage: " << mProgramName << " [options] "; + size_t tLongestArgumentLength = get_length_of_longest_argument(); + + for (const auto &argument : mPositionalArguments) { + stream << argument->mNames.front() << " "; + } + stream << "\n\n"; + + if (!mPositionalArguments.empty()) + stream << "Positional arguments:\n"; + + for (const auto &mPositionalArgument : mPositionalArguments) { + stream.width(tLongestArgumentLength); + stream << *mPositionalArgument; } - // Parameter packed add_parents method - // Accepts a variadic number of ArgumentParser objects - template - void add_parents(Targs... Fargs) { - const auto tNewParentParsers = {Fargs...}; - for (const auto& tParentParser : tNewParentParsers) { - const auto& tPositionalArguments = tParentParser.mPositionalArguments; - std::copy(std::begin(tPositionalArguments), std::end(tPositionalArguments), std::back_inserter(mPositionalArguments)); + if (!mOptionalArguments.empty()) + stream << (mPositionalArguments.empty() ? "" : "\n") + << "Optional arguments:\n"; - const auto& tOptionalArguments = tParentParser.mOptionalArguments; - std::copy(std::begin(tOptionalArguments), std::end(tOptionalArguments), std::back_inserter(mOptionalArguments)); + for (const auto &mOptionalArgument : mOptionalArguments) { + stream.width(tLongestArgumentLength); + stream << *mOptionalArgument; + } - const auto& tArgumentMap = tParentParser.mArgumentMap; - for (const auto&[tKey, tValue] : tArgumentMap) { - mArgumentMap.insert_or_assign(tKey, tValue); + std::cout << stream.str(); + return stream.str(); + } + +private: + /* + * @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 (tCurrentArgument == Argument::mHelpOption || + tCurrentArgument == Argument::mHelpOptionLong) { + throw std::runtime_error("help called"); + } + if (Argument::is_positional(tCurrentArgument)) { + if (positionalArgumentIt == std::end(mPositionalArguments)) { + throw std::runtime_error( + "Maximum number of positional arguments exceeded"); } - } - std::move(std::begin(tNewParentParsers), std::end(tNewParentParsers), std::back_inserter(mParentParsers)); - } - - /* Call parse_args_internal - which does all the work - * Then, validate the parsed arguments - * 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); - parse_args_validate(); - } - - /* Main entry point for parsing command-line arguments using this ArgumentParser - * @throws std::runtime_error in case of any invalid argument - */ - void parse_args(int argc, const char * const argv[]) { - std::vector arguments; - std::copy(argv, argv + argc, std::back_inserter(arguments)); - parse_args(arguments); - } - - /* Getter enabled for all template types other than std::vector and std::list - * @throws std::logic_error in case of an invalid argument name - * @throws std::logic_error in case of incompatible types - */ - template - T get(const std::string& aArgumentName) { - auto tIterator = mArgumentMap.find(aArgumentName); - if (tIterator != mArgumentMap.end()) { - return tIterator->second->get(); - } - throw std::logic_error("No such argument"); - } - - /* 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[](const std::string& aArgumentName) { - auto tIterator = mArgumentMap.find(aArgumentName); - if (tIterator != mArgumentMap.end()) { - return *(tIterator->second); - } - throw std::logic_error("No such argument"); - } - - // Printing the one and only help message - // I've stuck with a simple message format, nothing fancy. - // TODO: support user-defined help and usage messages for the ArgumentParser - std::string print_help() { - std::stringstream stream; - stream << std::left; - stream << "Usage: " << mProgramName << " [options] "; - size_t tLongestArgumentLength = get_length_of_longest_argument(); - - for (const auto& argument : mPositionalArguments) { - stream << argument->mNames.front() << " "; - } - stream << "\n\n"; - - if (!mPositionalArguments.empty()) - stream << "Positional arguments:\n"; - - for (const auto& mPositionalArgument : mPositionalArguments) { - stream.width(tLongestArgumentLength); - stream << *mPositionalArgument; - } - - if (!mOptionalArguments.empty()) - stream << (mPositionalArguments.empty() ? "" : "\n") << "Optional arguments:\n"; - - for (const auto & mOptionalArgument : mOptionalArguments) { - stream.width(tLongestArgumentLength); - stream << *mOptionalArgument; - } - - std::cout << stream.str(); - return stream.str(); - } - - private: - /* - * @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 (tCurrentArgument == Argument::mHelpOption || tCurrentArgument == Argument::mHelpOptionLong) { - throw std::runtime_error("help called"); - } - if (Argument::is_positional(tCurrentArgument)) { - if (positionalArgumentIt == std::end(mPositionalArguments)) { - throw std::runtime_error("Maximum number of positional arguments exceeded"); - } - auto tArgument = *(positionalArgumentIt++); - it = tArgument->consume(it, end); - } - else if (auto tIterator = mArgumentMap.find(tCurrentArgument); tIterator != mArgumentMap.end()) { - auto tArgument = tIterator->second; - it = tArgument->consume(std::next(it), end, tCurrentArgument); - } - else if (const auto& tCompoundArgument = tCurrentArgument; - tCompoundArgument.size() > 1 && - tCompoundArgument[0] == '-' && + auto tArgument = *(positionalArgumentIt++); + it = tArgument->consume(it, end); + } else if (auto tIterator = mArgumentMap.find(tCurrentArgument); + tIterator != mArgumentMap.end()) { + auto tArgument = tIterator->second; + it = tArgument->consume(std::next(it), end, tCurrentArgument); + } else if (const auto &tCompoundArgument = tCurrentArgument; + tCompoundArgument.size() > 1 && tCompoundArgument[0] == '-' && tCompoundArgument[1] != '-') { - ++it; - for (size_t j = 1; j < tCompoundArgument.size(); j++) { - auto tCurrentArgument = std::string{'-', tCompoundArgument[j]}; - if (auto tIterator = mArgumentMap.find(tCurrentArgument); tIterator != mArgumentMap.end()) { - auto tArgument = tIterator->second; - it = tArgument->consume(it, end, tCurrentArgument); - } - else { - throw std::runtime_error("Unknown argument"); - } + ++it; + for (size_t j = 1; j < tCompoundArgument.size(); j++) { + auto tCurrentArgument = std::string{'-', tCompoundArgument[j]}; + if (auto tIterator = mArgumentMap.find(tCurrentArgument); + tIterator != mArgumentMap.end()) { + auto tArgument = tIterator->second; + it = tArgument->consume(it, end, tCurrentArgument); + } else { + throw std::runtime_error("Unknown argument"); } } - else { - throw std::runtime_error("Unknown argument"); - } + } else { + throw std::runtime_error("Unknown argument"); } } + } - /* - * @throws std::runtime_error in case of any invalid argument - */ - 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(); - }); - } + /* + * @throws std::runtime_error in case of any invalid argument + */ + 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(); + }); + } - // Used by print_help. - size_t get_length_of_longest_argument() { - if (mArgumentMap.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(); - }); - return *std::max_element(std::begin(argumentLengths), - std::end(argumentLengths)); - } + // Used by print_help. + size_t get_length_of_longest_argument() { + if (mArgumentMap.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(); + }); + return *std::max_element(std::begin(argumentLengths), + std::end(argumentLengths)); + } - std::string mProgramName; - std::vector mParentParsers; - std::vector> mPositionalArguments; - std::vector> mOptionalArguments; - std::map> mArgumentMap; + std::string mProgramName; + std::vector mParentParsers; + std::vector> mPositionalArguments; + std::vector> mOptionalArguments; + std::map> mArgumentMap; }; -#define PARSE_ARGS(parser, argc, argv) \ -try { \ - parser.parse_args(argc, argv); \ -} catch (const std::runtime_error& err) { \ - std::cout << err.what() << std::endl; \ - parser.print_help(); \ - exit(0); \ -} +#define PARSE_ARGS(parser, argc, argv) \ + try { \ + parser.parse_args(argc, argv); \ + } catch (const std::runtime_error &err) { \ + std::cout << err.what() << std::endl; \ + parser.print_help(); \ + exit(0); \ + } -} +} // namespace argparse