diff options
author | Taylor C. Richberger <Taywee@gmx.com> | 2016-07-11 14:30:37 -0600 |
---|---|---|
committer | Taylor C. Richberger <Taywee@gmx.com> | 2016-07-11 14:30:37 -0600 |
commit | d8645e87109d76b868f0d9b3cba72e2d9392df3a (patch) | |
tree | 8869b1c1cadfd4e402ac730a736c4f917a05f0b4 | |
parent | switch pages to a submodule (diff) | |
download | args.hxx-d8645e87109d76b868f0d9b3cba72e2d9392df3a.tar.xz |
bump version, change template use6.0.0
-rw-r--r-- | CHANGELOG | 10 | ||||
-rw-r--r-- | Doxyfile | 2 | ||||
-rw-r--r-- | README.md | 14 | ||||
-rw-r--r-- | args.hxx | 204 | ||||
-rw-r--r-- | test.cxx | 30 |
5 files changed, 164 insertions, 96 deletions
@@ -1,3 +1,13 @@ +* 6.0.0 +Change Reader to functor type, breaking change. +Change Reader functor to allow any return type, but specifically need bool-testable return for NOEXCEPT use. +Change List and Map templates into template templates to enforce proper type use and to clean up user template invocations (i.e. `args::ValueFlagList<std::string, std::unordered_set<std::string>>` becomes `args::ValueFlagList<std::string, std::unordered_set>`, also breaking change. + +* 5.0.0 +Implemented proper subparsers. +Added better C++11 style. +Improved documentation. + * 4.0.0 Changed all wording: @@ -38,7 +38,7 @@ PROJECT_NAME = "args" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 5.1.0 +PROJECT_NUMBER = 6.0.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -391,13 +391,15 @@ std::istream& operator>>(std::istream& is, std::tuple<int, int>& ints) #include <args.hxx> -bool DoublesReader(const std::string &name, const std::string &value, std::tuple<double, double> &destination) +struct DoublesReader { - size_t commapos = 0; - std::get<0>(destination) = std::stod(value, &commapos); - std::get<1>(destination) = std::stod(std::string(value, commapos + 1)); - return true; -} + void operator()(const std::string &name, const std::string &value, std::tuple<double, double> &destination) + { + size_t commapos = 0; + std::get<0>(destination) = std::stod(value, &commapos); + std::get<1>(destination) = std::stod(std::string(value, commapos + 1)); + } +}; int main(int argc, char **argv) { @@ -1510,29 +1510,32 @@ namespace args } }; - /** A default Reader function for argument classes + /** A default Reader class for argument classes * * Simply uses a std::istringstream to read into the destination type, and * raises a ParseError if there are any characters left. */ template <typename T> - bool ValueReader(const std::string &name, const std::string &value, T &destination) + struct ValueReader { - std::istringstream ss(value); - ss >> destination; - - if (ss.rdbuf()->in_avail() > 0) + bool operator ()(const std::string &name, const std::string &value, T &destination) { + std::istringstream ss(value); + ss >> destination; + + if (ss.rdbuf()->in_avail() > 0) + { #ifdef ARGS_NOEXCEPT - return false; + return false; #else - std::ostringstream problem; - problem << "Argument '" << name << "' received invalid value type '" << value << "'"; - throw ParseError(problem.str()); + std::ostringstream problem; + problem << "Argument '" << name << "' received invalid value type '" << value << "'"; + throw ParseError(problem.str()); #endif + } + return true; } - return true; - } + }; /** std::string specialization for ValueReader * @@ -1540,22 +1543,28 @@ namespace args * it is more efficient to ust copy a string into the destination. */ template <> - bool ValueReader<std::string>(const std::string &name, const std::string &value, std::string &destination) + struct ValueReader<std::string> { - destination.assign(value); - return true; - } + bool operator()(const std::string &name, const std::string &value, std::string &destination) + { + destination.assign(value); + return true; + } + }; /** An argument-accepting flag class * * \tparam T the type to extract the argument as - * \tparam Reader The function used to read the argument, taking the name, value, and destination reference + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) */ - template <typename T, bool (*Reader)(const std::string &, const std::string &, T&) = ValueReader<T>> + template < + typename T, + typename Reader = ValueReader<T>> class ValueFlag : public ValueFlagBase { private: T value; + Reader reader; public: @@ -1568,12 +1577,14 @@ namespace args virtual void ParseValue(const std::string &value) override { - if (!Reader(name, value, this->value)) - { #ifdef ARGS_NOEXCEPT + if (!reader(name, value, this->value)) + { error = Error::Parse; -#endif } +#else + reader(name, value, this->value); +#endif } /** Get the value @@ -1588,20 +1599,21 @@ namespace args * * \tparam T the type to extract the argument as * \tparam List the list type that houses the values - * \tparam Reader The function used to read the argument, taking the name, value, and destination reference + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) */ template < typename T, - typename List = std::vector<T>, - bool (*Reader)(const std::string &, const std::string &, T&) = ValueReader<T>> + template <typename...> class List = std::vector, + typename Reader = ValueReader<T>> class ValueFlagList : public ValueFlagBase { private: - List values; + List<T> values; + Reader reader; public: - ValueFlagList(Group &group, const std::string &name, const std::string &help, Matcher &&matcher, const List &defaultValues = List()): ValueFlagBase(name, help, std::move(matcher)), values(defaultValues) + ValueFlagList(Group &group, const std::string &name, const std::string &help, Matcher &&matcher, const List<T> &defaultValues = List<T>()): ValueFlagBase(name, help, std::move(matcher)), values(defaultValues) { group.Add(*this); } @@ -1611,18 +1623,20 @@ namespace args virtual void ParseValue(const std::string &value) override { T v; - if (!Reader(name, value, v)) - { #ifdef ARGS_NOEXCEPT + if (!reader(name, value, v)) + { error = Error::Parse; -#endif } +#else + reader(name, value, v); +#endif values.insert(std::end(values), v); } /** Get the values */ - List &Get() noexcept + List<T> &Get() noexcept { return values; } @@ -1637,19 +1651,24 @@ namespace args * * \tparam K the type to extract the argument as * \tparam T the type to store the result as - * \tparam Reader The function used to read the argument into the key type, taking the name, value, and destination reference + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) * \tparam Map The Map type. Should operate like std::map or std::unordered_map */ - template <typename K, typename T, bool (*Reader)(const std::string &, const std::string &, K&) = ValueReader<K>, typename Map = std::unordered_map<K, T>> + template < + typename K, + typename T, + typename Reader = ValueReader<K>, + template <typename...> class Map = std::unordered_map> class MapFlag : public ValueFlagBase { private: - const Map map; + const Map<K, T> map; T value; + Reader reader; public: - MapFlag(Group &group, const std::string &name, const std::string &help, Matcher &&matcher, const Map &map, const T &defaultValue = T(), const bool extraError = false): ValueFlagBase(name, help, std::move(matcher), extraError), map(map), value(defaultValue) + MapFlag(Group &group, const std::string &name, const std::string &help, Matcher &&matcher, const Map<K, T> &map, const T &defaultValue = T(), const bool extraError = false): ValueFlagBase(name, help, std::move(matcher), extraError), map(map), value(defaultValue) { group.Add(*this); } @@ -1659,12 +1678,14 @@ namespace args virtual void ParseValue(const std::string &value) override { K key; - if (!Reader(name, value, key)) - { #ifdef ARGS_NOEXCEPT + if (!reader(name, value, key)) + { error = Error::Parse; -#endif } +#else + reader(name, value, key); +#endif auto it = map.find(key); if (it == std::end(map)) { @@ -1694,19 +1715,25 @@ namespace args * \tparam K the type to extract the argument as * \tparam T the type to store the result as * \tparam List the list type that houses the values - * \tparam Reader The function used to read the argument into the key type, taking the name, value, and destination reference + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) * \tparam Map The Map type. Should operate like std::map or std::unordered_map */ - template <typename K, typename T, typename List = std::vector<T>, bool (*Reader)(const std::string &, const std::string &, K&) = ValueReader<K>, typename Map = std::unordered_map<K, T>> + template < + typename K, + typename T, + template <typename...> class List = std::vector, + typename Reader = ValueReader<K>, + template <typename...> class Map = std::unordered_map> class MapFlagList : public ValueFlagBase { private: - const Map map; - List values; + const Map<K, T> map; + List<T> values; + Reader reader; public: - MapFlagList(Group &group, const std::string &name, const std::string &help, Matcher &&matcher, const Map &map, const List &defaultValues = List()): ValueFlagBase(name, help, std::move(matcher)), map(map), values(defaultValues) + MapFlagList(Group &group, const std::string &name, const std::string &help, Matcher &&matcher, const Map<K, T> &map, const List<T> &defaultValues = List<T>()): ValueFlagBase(name, help, std::move(matcher)), map(map), values(defaultValues) { group.Add(*this); } @@ -1716,12 +1743,14 @@ namespace args virtual void ParseValue(const std::string &value) override { K key; - if (!Reader(name, value, key)) - { #ifdef ARGS_NOEXCEPT + if (!reader(name, value, key)) + { error = Error::Parse; -#endif } +#else + reader(name, value, key); +#endif auto it = map.find(key); if (it == std::end(map)) { @@ -1740,7 +1769,7 @@ namespace args /** Get the value */ - List &Get() noexcept + List<T> &Get() noexcept { return values; } @@ -1754,13 +1783,16 @@ namespace args /** A positional argument class * * \tparam T the type to extract the argument as - * \tparam Reader The function used to read the argument, taking the name, value, and destination reference + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) */ - template <typename T, bool (*Reader)(const std::string &, const std::string &, T&) = ValueReader<T>> + template < + typename T, + typename Reader = ValueReader<T>> class Positional : public PositionalBase { private: T value; + Reader reader; public: Positional(Group &group, const std::string &name, const std::string &help, const T &defaultValue = T()): PositionalBase(name, help), value(defaultValue) { @@ -1771,12 +1803,14 @@ namespace args virtual void ParseValue(const std::string &value) override { - if (!Reader(name, value, this->value)) - { #ifdef ARGS_NOEXCEPT + if (!reader(name, value, this->value)) + { error = Error::Parse; -#endif } +#else + reader(name, value, this->value); +#endif ready = false; matched = true; } @@ -1793,19 +1827,20 @@ namespace args * * \tparam T the type to extract the argument as * \tparam List the list type that houses the values - * \tparam Reader The function used to read the argument, taking the name, value, and destination reference + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) */ template < typename T, - typename List = std::vector<T>, - bool (*Reader)(const std::string &, const std::string &, T&) = ValueReader<T>> + template <typename...> class List = std::vector, + typename Reader = ValueReader<T>> class PositionalList : public PositionalBase { private: - List values; + List<T> values; + Reader reader; public: - PositionalList(Group &group, const std::string &name, const std::string &help, const List &defaultValues = List()): PositionalBase(name, help), values(defaultValues) + PositionalList(Group &group, const std::string &name, const std::string &help, const List<T> &defaultValues = List<T>()): PositionalBase(name, help), values(defaultValues) { group.Add(*this); } @@ -1815,12 +1850,14 @@ namespace args virtual void ParseValue(const std::string &value) override { T v; - if (!Reader(name, value, v)) - { #ifdef ARGS_NOEXCEPT + if (!reader(name, value, v)) + { error = Error::Parse; -#endif } +#else + reader(name, value, v); +#endif values.insert(std::end(values), v); matched = true; } @@ -1832,7 +1869,7 @@ namespace args /** Get the values */ - List &Get() noexcept + List<T> &Get() noexcept { return values; } @@ -1842,19 +1879,24 @@ namespace args * * \tparam K the type to extract the argument as * \tparam T the type to store the result as - * \tparam Reader The function used to read the argument into the key type, taking the name, value, and destination reference + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) * \tparam Map The Map type. Should operate like std::map or std::unordered_map */ - template <typename K, typename T, bool (*Reader)(const std::string &, const std::string &, K&) = ValueReader<K>, typename Map = std::unordered_map<K, T>> + template < + typename K, + typename T, + typename Reader = ValueReader<K>, + template <typename...> class Map = std::unordered_map> class MapPositional : public PositionalBase { private: - const Map map; + const Map<K, T> map; T value; + Reader reader; public: - MapPositional(Group &group, const std::string &name, const std::string &help, const Map &map, const T &defaultValue = T()): PositionalBase(name, help), map(map), value(defaultValue) + MapPositional(Group &group, const std::string &name, const std::string &help, const Map<K, T> &map, const T &defaultValue = T()): PositionalBase(name, help), map(map), value(defaultValue) { group.Add(*this); } @@ -1864,12 +1906,14 @@ namespace args virtual void ParseValue(const std::string &value) override { K key; - if (!Reader(name, value, key)) - { #ifdef ARGS_NOEXCEPT + if (!reader(name, value, key)) + { error = Error::Parse; -#endif } +#else + reader(name, value, key); +#endif auto it = map.find(key); if (it == std::end(map)) { @@ -1901,19 +1945,25 @@ namespace args * \tparam K the type to extract the argument as * \tparam T the type to store the result as * \tparam List the list type that houses the values - * \tparam Reader The function used to read the argument into the key type, taking the name, value, and destination reference + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) * \tparam Map The Map type. Should operate like std::map or std::unordered_map */ - template <typename K, typename T, typename List = std::vector<T>, bool (*Reader)(const std::string &, const std::string &, K&) = ValueReader<K>, typename Map = std::unordered_map<K, T>> + template < + typename K, + typename T, + template <typename...> class List = std::vector, + typename Reader = ValueReader<K>, + template <typename...> class Map = std::unordered_map> class MapPositionalList : public PositionalBase { private: - const Map map; - List values; + const Map<K, T> map; + List<T> values; + Reader reader; public: - MapPositionalList(Group &group, const std::string &name, const std::string &help, const Map &map, const List &defaultValues = List()): PositionalBase(name, help), map(map), values(defaultValues) + MapPositionalList(Group &group, const std::string &name, const std::string &help, const Map<K, T> &map, const List<T> &defaultValues = List<T>()): PositionalBase(name, help), map(map), values(defaultValues) { group.Add(*this); } @@ -1923,12 +1973,14 @@ namespace args virtual void ParseValue(const std::string &value) override { K key; - if (!Reader(name, value, key)) - { #ifdef ARGS_NOEXCEPT + if (!reader(name, value, key)) + { error = Error::Parse; -#endif } +#else + reader(name, value, key); +#endif auto it = map.find(key); if (it == std::end(map)) { @@ -1948,7 +2000,7 @@ namespace args /** Get the value */ - List &Get() noexcept + List<T> &Get() noexcept { return values; } @@ -142,7 +142,7 @@ TEST_CASE("Argument flag lists work as expected", "[args]") TEST_CASE("Argument flag lists work with sets", "[args]") { args::ArgumentParser parser("This is a test program.", "This goes after the options."); - args::ValueFlagList<std::string, std::unordered_set<std::string>> foo(parser, "FOO", "test flag", {'f', "foo"}); + args::ValueFlagList<std::string, std::unordered_set> foo(parser, "FOO", "test flag", {'f', "foo"}); parser.ParseArgs(std::vector<std::string>{"--foo=7", "-fblah", "-f", "9", "--foo", "blah"}); REQUIRE((args::get(foo) == std::unordered_set<std::string>{"7", "9", "blah"})); } @@ -165,7 +165,7 @@ TEST_CASE("Positional arguments and positional argument lists work as expected", TEST_CASE("Positional lists work with sets", "[args]") { args::ArgumentParser parser("This is a test program.", "This goes after the options."); - args::PositionalList<std::string, std::unordered_set<std::string>> foo(parser, "FOO", "test positional"); + args::PositionalList<std::string, std::unordered_set> foo(parser, "FOO", "test positional"); parser.ParseArgs(std::vector<std::string>{"foo", "FoO", "bar", "baz", "foo", "9", "baz"}); REQUIRE((args::get(foo) == std::unordered_set<std::string>{"foo", "FoO", "bar", "baz", "9"})); } @@ -251,13 +251,15 @@ TEST_CASE("Argument groups should nest", "[args]") REQUIRE_THROWS_AS(parser.ParseArgs(std::vector<std::string>{"-a", "-dg"}), args::ValidationError); } -bool DoublesReader(const std::string &name, const std::string &value, std::tuple<double, double> &destination) +struct DoublesReader { - size_t commapos = 0; - std::get<0>(destination) = std::stod(value, &commapos); - std::get<1>(destination) = std::stod(std::string(value, commapos + 1)); - return true; -} + void operator()(const std::string &name, const std::string &value, std::tuple<double, double> &destination) + { + size_t commapos = 0; + std::get<0>(destination) = std::stod(value, &commapos); + std::get<1>(destination) = std::stod(std::string(value, commapos + 1)); + } +}; TEST_CASE("Custom types work", "[args]") { @@ -376,12 +378,14 @@ enum class MappingEnum #include <algorithm> #include <string> -bool ToLowerReader(const std::string &name, const std::string &value, std::string &destination) +struct ToLowerReader { - destination = value; - std::transform(destination.begin(), destination.end(), destination.begin(), ::tolower); - return true; -} + void operator()(const std::string &name, const std::string &value, std::string &destination) + { + destination = value; + std::transform(destination.begin(), destination.end(), destination.begin(), ::tolower); + } +}; TEST_CASE("Mapping types work as needed", "[args]") { |