From c8a9fd51d59c9632eda7654b31b601822fc8e9ad Mon Sep 17 00:00:00 2001 From: Andrew Bell Date: Wed, 12 Oct 2016 12:36:55 -0500 Subject: [PATCH] Default values for vector args. --- include/pdal/util/Bounds.hpp | 6 +- include/pdal/util/ProgramArgs.hpp | 138 ++++++++++++++++++++++++++++-- src/util/Bounds.cpp | 9 ++ test/unit/ProgramArgsTest.cpp | 21 ++++- 4 files changed, 164 insertions(+), 10 deletions(-) diff --git a/include/pdal/util/Bounds.hpp b/include/pdal/util/Bounds.hpp index fc8c2d80ea..7a9ddaad54 100644 --- a/include/pdal/util/Bounds.hpp +++ b/include/pdal/util/Bounds.hpp @@ -560,7 +560,10 @@ class PDAL_DLL Bounds BOX2D to2d() const; bool is3d() const; - friend PDAL_DLL std::istream& operator >> (std::istream& in, Bounds& bounds); + friend PDAL_DLL std::istream& operator >> (std::istream& in, + Bounds& bounds); + friend PDAL_DLL std::ostream& operator << (std::ostream& out, + const Bounds& bounds); private: BOX3D m_box; @@ -635,5 +638,6 @@ extern PDAL_DLL std::istream& operator>>(std::istream& istr, BOX2D& bounds); extern PDAL_DLL std::istream& operator>>(std::istream& istr, BOX3D& bounds); PDAL_DLL std::istream& operator >> (std::istream& in, Bounds& bounds); +PDAL_DLL std::ostream& operator << (std::ostream& in, Bounds& bounds); } // namespace pdal diff --git a/include/pdal/util/ProgramArgs.hpp b/include/pdal/util/ProgramArgs.hpp index 4d5f35df0e..317ac4f32d 100644 --- a/include/pdal/util/ProgramArgs.hpp +++ b/include/pdal/util/ProgramArgs.hpp @@ -66,6 +66,9 @@ class ArgValList { if (s.empty()) return; + + // Turn a short arg list into a set of short args: -afv -> -a -f -v + // so that each argval represents a single arg. if (s.size() > 1 && s[0] == '-' && s[1] != '-') for (size_t i = 1; i < s.size(); i++) m_vals.push_back({std::string("-") + s[i]}); @@ -638,7 +641,8 @@ class BaseVArg : public Arg \param description Argument description. */ BaseVArg(const std::string& longname, const std::string& shortname, - const std::string& description) : Arg(longname, shortname, description) + const std::string& description) : Arg(longname, shortname, description), + m_defaultProvided(false) {} /** @@ -681,6 +685,17 @@ class BaseVArg : public Arg throw arg_error(oss.str()); } } + + /** + Return whether a default value was provided for the argument. + + \return Whether a default was provided. + */ + virtual bool defaultProvided() const + { return m_defaultProvided; } + +protected: + bool m_defaultProvided; }; /** @@ -692,7 +707,28 @@ class VArg : public BaseVArg { public: /** - Constructor. + Constructor for arguments with default value. + + \param longname Name of argument specified on command line with "--" + prefix. + \param shortname Optional name of argument specified on command + line with "-" prefix. + \param description Argument description. + \param variable Variable to which the argument value(s) should be bound. + \param def Default value. + */ + VArg(const std::string& longname, const std::string& shortname, + const std::string& description, std::vector& variable, + std::vector def) : + BaseVArg(longname, shortname, description), m_var(variable), + m_defaultVal(def) + { + m_var = def; + m_defaultProvided = true; + } + + /** + Constructor for arguments without default value. \param longname Name of argument specified on command line with "--" prefix. @@ -735,6 +771,8 @@ class VArg : public BaseVArg oss << "Invalid value for argument '" << m_longname << "'."; throw arg_error(oss.str()); } + if (!m_set) + m_var.clear(); m_var.push_back(var); m_set = true; } @@ -748,13 +786,33 @@ class VArg : public BaseVArg */ virtual void reset() { - m_var.clear(); + m_var = m_defaultVal; m_set = false; m_hidden = false; } + /** + Return a string representation of an Arg's default value, or an + empty string if none exists. + + \return Default value as a string. + */ + virtual std::string defaultVal() const + { + std::string s; + + for (size_t i = 0; i < m_defaultVal.size(); ++i) + { + if (i > 0) + s += ", "; + s += Utils::toString(m_defaultVal[i]); + } + return s; + } + private: std::vector& m_var; + std::vector m_defaultVal; }; /** @@ -765,7 +823,28 @@ class VArg : public BaseVArg { public: /** - Constructor. + Constructor for arguments wit default value. + + \param longname Name of argument specified on command line with "--" + prefix. + \param shortname Optional name of argument specified on command + line with "-" prefix. + \param description Argument description. + \param variable Variable to which the argument value(s) should be bound. + \param def Default value. + */ + VArg(const std::string& longname, const std::string& shortname, + const std::string& description, std::vector& variable, + std::vector def) : + BaseVArg(longname, shortname, description), m_var(variable), + m_defaultVal(def) + { + m_var = def; + m_defaultProvided = true; + } + + /** + Constructor for arguments without default value. \param longname Name of argument specified on command line with "--" prefix. @@ -802,6 +881,8 @@ class VArg : public BaseVArg throw arg_error(oss.str()); } m_rawVal = s; + if (!m_set) + m_var.clear(); m_var.reserve(m_var.size() + slist.size()); m_var.insert(m_var.end(), slist.begin(), slist.end()); m_set = true; @@ -816,13 +897,33 @@ class VArg : public BaseVArg */ virtual void reset() { - m_var.clear(); + m_var = m_defaultVal; m_set = false; m_hidden = false; } + /** + Return a string representation of an Arg's default value, or an + empty string if none exists. + + \return Default value as a string. + */ + virtual std::string defaultVal() const + { + std::string s; + + for (size_t i = 0; i < m_defaultVal.size(); ++i) + { + if (i > 0) + s += ", "; + s += m_defaultVal[i]; + } + return s; + } + private: std::vector& m_var; + std::vector m_defaultVal; }; /** @@ -904,6 +1005,30 @@ class ProgramArgs return *arg; } + /** + Add a list-based (vector) argument with a default. + + \param name Name of argument. Argument names are specified as + "longname[,shortname]", where shortname is an optional one-character + abbreviation. + \param description Description of the argument. + \param var Reference to variable to bind to argument. + \return Reference to the new argument. + */ + template + Arg& add(const std::string& name, const std::string& description, + std::vector& var, std::vector def) + { + std::string longname, shortname; + splitName(name, longname, shortname); + + Arg *arg = new VArg(longname, shortname, description, var, def); + addLongArg(longname, arg); + addShortArg(shortname, arg); + m_args.push_back(std::unique_ptr(arg)); + return *arg; + } + /** Add an argument to the list of arguments with a default. @@ -912,8 +1037,7 @@ class ProgramArgs abbreviation. \param description Description of the argument. \param var Reference to variable to bind to argument. - \param def Default value of argument. If not specified, a - default-constructed value is used. + \param def Default value of argument. \return Reference to the new argument. */ template diff --git a/src/util/Bounds.cpp b/src/util/Bounds.cpp index 9cc74de833..1b62cbe640 100644 --- a/src/util/Bounds.cpp +++ b/src/util/Bounds.cpp @@ -313,4 +313,13 @@ std::istream& operator>>(std::istream& in, Bounds& bounds) return in; } +std::ostream& operator<<(std::ostream& out, const Bounds& bounds) +{ + if (bounds.is3d()) + out << bounds.to3d(); + else + out << bounds.to2d(); + return out; +} + } // namespace pdal diff --git a/test/unit/ProgramArgsTest.cpp b/test/unit/ProgramArgsTest.cpp index 55631ca1a1..f0acec5df6 100644 --- a/test/unit/ProgramArgsTest.cpp +++ b/test/unit/ProgramArgsTest.cpp @@ -268,13 +268,13 @@ TEST(ProgramArgsTest, vector) std::string m_foo; std::vector m_bar; + std::vector m_flub; bool m_baz; args.add("foo,f", "Foo description", m_foo, "foo").setPositional(); args.add("bar", "Foo description", m_bar).setOptionalPositional(); args.add("baz,z", "Foo description", m_baz); - - // Go through exceptions procedurally. + args.add("flub", "Flub description", m_flub, {1, 3, 5}); StringList s = toStringList("--bar 23 --bar 45 Foo -z"); args.parse(s); @@ -283,6 +283,10 @@ TEST(ProgramArgsTest, vector) EXPECT_EQ(m_baz, true); EXPECT_EQ(m_bar[0], 23); EXPECT_EQ(m_bar[1], 45); + EXPECT_EQ(m_flub.size(), 3u); + EXPECT_EQ(m_flub[0], 1); + EXPECT_EQ(m_flub[1], 3); + EXPECT_EQ(m_flub[2], 5); args.reset(); s = toStringList("Foo"); @@ -290,6 +294,7 @@ TEST(ProgramArgsTest, vector) EXPECT_EQ(m_bar.size(), 0u); EXPECT_EQ(m_foo, "Foo"); EXPECT_EQ(m_baz, false); + EXPECT_EQ(m_flub.size(), 3u); args.reset(); s = toStringList("Fool 44 55 66"); @@ -300,6 +305,18 @@ TEST(ProgramArgsTest, vector) EXPECT_EQ(m_bar[1], 55); EXPECT_EQ(m_bar[2], 66); EXPECT_EQ(m_baz, false); + EXPECT_EQ(m_flub.size(), 3u); + + args.reset(); + s = toStringList("--bar 23 --flub 2 Foo -z --flub 4"); + args.parse(s); + EXPECT_EQ(m_foo, "Foo"); + EXPECT_EQ(m_bar.size(), 1u); + EXPECT_EQ(m_baz, true); + EXPECT_EQ(m_bar[0], 23); + EXPECT_EQ(m_flub.size(), 2u); + EXPECT_EQ(m_flub[0], 2); + EXPECT_EQ(m_flub[1], 4); } TEST(ProgramArgsTest, stringvector)