aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTaylor C. Richberger <Taywee@gmx.com>2016-07-11 14:30:37 -0600
committerTaylor C. Richberger <Taywee@gmx.com>2016-07-11 14:30:37 -0600
commitd8645e87109d76b868f0d9b3cba72e2d9392df3a (patch)
tree8869b1c1cadfd4e402ac730a736c4f917a05f0b4
parentswitch pages to a submodule (diff)
downloadargs.hxx-6.0.0.tar.xz
bump version, change template use6.0.0
-rw-r--r--CHANGELOG10
-rw-r--r--Doxyfile2
-rw-r--r--README.md14
-rw-r--r--args.hxx204
-rw-r--r--test.cxx30
5 files changed, 164 insertions, 96 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 0dd68bc..ad62d44 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -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:
diff --git a/Doxyfile b/Doxyfile
index 1ba8d5e..8c76055 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -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
diff --git a/README.md b/README.md
index 966eabd..b08f9f2 100644
--- a/README.md
+++ b/README.md
@@ -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)
{
diff --git a/args.hxx b/args.hxx
index f2a45b9..fa38aab 100644
--- a/args.hxx
+++ b/args.hxx
@@ -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;
}
diff --git a/test.cxx b/test.cxx
index b4cc9fc..8d77bf4 100644
--- a/test.cxx
+++ b/test.cxx
@@ -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]")
{