diff --git a/flags.cpp b/flags.cpp index 508e458..bffbbc3 100644 --- a/flags.cpp +++ b/flags.cpp @@ -1,5 +1,6 @@ #include "flags.h" #include +#include namespace Flags { @@ -14,7 +15,110 @@ std::vector split(const std::string &input, const char separator) { } bool starts_with(const std::string &input, const std::string &start) { - return (input.length() >= start.length() && input.substr(0, 2) == start); + return (input.size() >= start.size() && input.substr(0, 2) == start); +} + +PARSER(StringFlag, std::string, { + set_found(true); + set_parsed(true); + value = arg; +}) + +PARSER(IntFlag, int, { + set_found(true); + try { + value = std::stoi(arg); + set_parsed(true); + } catch (std::exception &) { + } +}) + +PARSER(LongIntFlag, long int, { + set_found(true); + try { + value = std::stol(arg); + set_parsed(true); + } catch (std::exception &) { + } +}) + +PARSER(LongLongIntFlag, long long int, { + set_found(true); + try { + value = std::stoll(arg); + set_parsed(true); + } catch (std::exception &) { + } +}) + +PARSER(UnsignedLongIntFlag, unsigned long int, { + set_found(true); + try { + value = std::stoul(arg); + set_parsed(true); + } catch (std::exception &) { + } +}) + +PARSER(UnsignedLongLongIntFlag, unsigned long long int, { + set_found(true); + try { + value = std::stoull(arg); + set_parsed(true); + } catch (std::exception &) { + } +}) + +PARSER(FloatFlag, float, { + set_found(true); + try { + value = std::stof(arg); + set_parsed(true); + } catch (std::exception &) { + } +}) + +PARSER(DoubleFlag, double, { + set_found(true); + try { + value = stod(arg); + set_parsed(true); + } catch (std::exception &) { + } +}) + +PARSER(LongDoubleFlag, long double, { + set_found(true); + try { + value = stold(arg); + set_parsed(true); + } catch (std::exception &) { + } +}) + +PARSER(BoolFlag, bool, { + std::string copy(arg); + std::transform(copy.begin(), copy.end(), copy.begin(), + [](const char c) { return std::tolower(c); }); + if (copy == "false") + value = false; + else + value = true; +}) + +Parser::Parser(const std::string &prefix, const std::string &help_text) + : prefix(prefix), help_text(help_text) { + set_parser(flag_constructor_t(StringFlag::make)); + set_parser(flag_constructor_t(IntFlag::make)); + set_parser(flag_constructor_t(LongIntFlag::make)); + set_parser(flag_constructor_t(LongLongIntFlag::make)); + set_parser(flag_constructor_t(UnsignedLongIntFlag::make)); + set_parser( + flag_constructor_t(UnsignedLongLongIntFlag::make)); + set_parser(flag_constructor_t(FloatFlag::make)); + set_parser(flag_constructor_t(DoubleFlag::make)); + set_parser(flag_constructor_t(LongDoubleFlag::make)); + set_parser(flag_constructor_t(BoolFlag::make)); } bool Parser::parse(int argc, char **argv) { @@ -22,7 +126,7 @@ bool Parser::parse(int argc, char **argv) { std::vector args; for (int i = 0; i < argc; i++) { std::string arg(argv[i]); - if (starts_with(arg, prefix) && arg.length() > prefix.length()) { + if (starts_with(arg, prefix) && arg.size() > prefix.size()) { std::vector parts = split(arg, '='); args.insert(args.end(), parts.begin(), parts.end()); } else { @@ -33,27 +137,27 @@ bool Parser::parse(int argc, char **argv) { // search for flags for (size_t i = 1; i < args.size() - 1; i++) { const std::string &arg = args[i]; - if (starts_with(arg, prefix) && arg.length() > prefix.length()) { - flags[arg.substr(prefix.length())]->parse(args[i + 1]); + if (starts_with(arg, prefix) && arg.size() > prefix.size()) { + flags[arg.substr(prefix.size())]->parse(args[i + 1]); } } // check for the last argument if (starts_with(args[args.size() - 1], prefix) && - args[args.size() - 1].length() > prefix.length()) { - flags[args[args.size() - 1].substr(prefix.length())]->parse(""); + args[args.size() - 1].size() > prefix.size()) { + flags[args[args.size() - 1].substr(prefix.size())]->parse(""); } return get_found() == flags.size(); } -const unsigned Parser::get_parsed() const { +unsigned Parser::get_parsed() const { return std::count_if( flags.begin(), flags.end(), [](std::pair f) { return f.second->get_parsed(); }); } -const unsigned Parser::get_found() const { +unsigned Parser::get_found() const { return std::count_if( flags.begin(), flags.end(), [](std::pair f) { return f.second->get_found(); }); diff --git a/flags.h b/flags.h index 535b59c..a667a8a 100644 --- a/flags.h +++ b/flags.h @@ -1,9 +1,7 @@ #ifndef FLAGS_H #define FLAGS_H -#include #include -#include #include #include #include @@ -31,41 +29,44 @@ public: Flag(const std::string &description, const bool required) : description(description), found(!required), parsed(false) {} - virtual ~Flag() {}; + virtual ~Flag(){}; const std::string &get_description() const { return description; } - const bool get_found() const { return found; } - const bool get_parsed() const { return parsed; } + bool get_found() const { return found; } + bool get_parsed() const { return parsed; } - virtual void parse(const std::string &arg) {} + virtual void parse(const std::string &arg) = 0; }; // type of flag based parser classes' factory functions typedef std::function flag_constructor_t; -class StringFlag : public Flag { - std::string value; +// use this class to create your own parser +template class FlagTemplate : public Flag { +protected: + T value; public: - StringFlag(const void *default_value, const std::string &description, - const bool required) - : Flag(description, required), value(*(std::string *)default_value) {} - - static Flag *make(const void *default_value, const std::string &description, - const bool required) { - return new StringFlag(default_value, description, required); - } + explicit FlagTemplate(const void *default_value, + const std::string &description, const bool required) + : Flag(description, required), value(*(T *)default_value) {} const void *get_value_ptr() const override { return &value; }; - - void parse(const std::string &arg) override { - set_found(true); - set_parsed(true); - value = arg; - } }; +#define PARSER(name, type, func) \ + class name : public FlagTemplate { \ + using FlagTemplate::FlagTemplate; \ + \ + public: \ + static Flag *make(const void *default_value, \ + const std::string &description, const bool required) { \ + return new name(default_value, description, required); \ + } \ + void parse(const std::string &arg) override func \ + }; // namespace Flags + // flag holder, parsing orchestrator class Parser { private: @@ -76,10 +77,7 @@ private: std::map constructors; public: - Parser(const std::string &prefix, const std::string &help_text) - : prefix(prefix), help_text(help_text) { - set_parser(flag_constructor_t(StringFlag::make)); - } + Parser(const std::string &prefix, const std::string &help_text); Parser() : Parser("--", "Help:") {} @@ -89,7 +87,8 @@ public: } } - template void set_parser(flag_constructor_t constructor_function) { + template + void set_parser(flag_constructor_t constructor_function) { constructors[typeid(T)] = constructor_function; } @@ -101,9 +100,9 @@ public: return (T *)flags[name]->get_value_ptr(); } - const unsigned get_found() const; + unsigned get_found() const; - const unsigned get_parsed() const; + unsigned get_parsed() const; bool parse(int argc, char **argv);