From 6ef173d47030b0c89d947eb2876ec9b1650e2955 Mon Sep 17 00:00:00 2001 From: Mathieu Westphal Date: Sat, 31 Aug 2024 12:04:04 +0200 Subject: [PATCH] options: Add all type support for vector parsing (#1597) options: Add int and string vector parsing support --- library/private/options_tools.h.in | 60 ++++++++++++++++++------------ library/public/options.h.in | 4 +- library/src/options.cxx | 7 +++- library/testing/TestSDKOptions.cxx | 14 ++++++- 4 files changed, 57 insertions(+), 28 deletions(-) diff --git a/library/private/options_tools.h.in b/library/private/options_tools.h.in index aa10b0c529..c4e04150f9 100644 --- a/library/private/options_tools.h.in +++ b/library/private/options_tools.h.in @@ -10,14 +10,45 @@ namespace f3d { namespace options_tools { -// TODO expose parse methods in options API ? //---------------------------------------------------------------------------- /** - * Not implemented generic templated parse method + * A std::string_view trim function */ +std::string trim(std::string_view strv) +{ + constexpr std::string_view spaces = " \t\r\v\n"; + strv.remove_prefix(std::min(strv.find_first_not_of(spaces), strv.size())); + strv.remove_suffix(std::min(strv.size() - strv.find_last_not_of(spaces) - 1, strv.size())); + return std::string(strv); +} + +//---------------------------------------------------------------------------- +/** + * Vector specific templated parse method + */ +template +struct is_vector : std::false_type +{ +}; +template +struct is_vector> : std::true_type +{ +}; template -T parse(const std::string& str) = delete; +T parse(const std::string& str) +{ + static_assert(is_vector::value, "non-vector types parsing must be specialized"); + + // TODO implement more parsing possibilities, eg different types of tokens + T vec; + std::istringstream split(str); + for (std::string each; std::getline(split, each, ',');) + { + vec.emplace_back(options_tools::parse(each)); + } + return vec; +} //---------------------------------------------------------------------------- /** @@ -100,31 +131,12 @@ ratio_t parse(const std::string& str) //---------------------------------------------------------------------------- /** - * Return provided string + * Return provided string stripped of leading and trailing spaces. */ template<> std::string parse(const std::string& str) { - return str; -} - -//---------------------------------------------------------------------------- -/** - * Parse provided string into a double vector - * Split the string using ',', then rely on double version for parsing each token - * Can throw options::parsing_exception in case of failure to parse - */ -template<> -std::vector parse(const std::string& str) -{ - // TODO implement more parsing possibilities, eg different types of tokens - std::vector vec; - std::istringstream split(str); - for (std::string each; std::getline(split, each, ',');) - { - vec.emplace_back(options_tools::parse(each)); - } - return vec; + return options_tools::trim(str); } // TODO Improve string generation diff --git a/library/public/options.h.in b/library/public/options.h.in index 6468d26bea..22efa63c45 100644 --- a/library/public/options.h.in +++ b/library/public/options.h.in @@ -108,7 +108,9 @@ public: /** * Templated parsing method used internally to parse strings. - * Implemented only for: bool, int, double, ratio_t, string and double vector. + * Implemented only for types: bool, int, double, ratio_t, + * as well as vector for each of these types. + * See parsing documentation for more info. TODO. * Throw an options::parsing_exception if parsing failed. */ template diff --git a/library/src/options.cxx b/library/src/options.cxx index 0cb2293f09..cb07fe7c81 100644 --- a/library/src/options.cxx +++ b/library/src/options.cxx @@ -113,13 +113,16 @@ T options::parse(const std::string& str) } //---------------------------------------------------------------------------- -#define F3D_DECL_TYPE(TYPE) template F3D_EXPORT TYPE options::parse(const std::string& str) +#define F3D_DECL_TYPE_INTERNAL(TYPE) \ + template F3D_EXPORT TYPE options::parse(const std::string& str) +#define F3D_DECL_TYPE(TYPE) \ + F3D_DECL_TYPE_INTERNAL(TYPE); \ + F3D_DECL_TYPE_INTERNAL(std::vector) F3D_DECL_TYPE(bool); F3D_DECL_TYPE(int); F3D_DECL_TYPE(double); F3D_DECL_TYPE(f3d::ratio_t); F3D_DECL_TYPE(std::string); -F3D_DECL_TYPE(std::vector); //---------------------------------------------------------------------------- options::parsing_exception::parsing_exception(const std::string& what) diff --git a/library/testing/TestSDKOptions.cxx b/library/testing/TestSDKOptions.cxx index 91e3b7a949..fd309b576d 100644 --- a/library/testing/TestSDKOptions.cxx +++ b/library/testing/TestSDKOptions.cxx @@ -312,17 +312,29 @@ int TestSDKOptions(int argc, char* argv[]) std::cerr << "Options parse method not behaving as expected with ratio_t." << std::endl; return EXIT_FAILURE; } - if (f3d::options::parse(std::string("foobar")) != "foobar") + if (f3d::options::parse(std::string(" foobar ")) != "foobar") { std::cerr << "Options parse method not behaving as expected with string." << std::endl; return EXIT_FAILURE; } + if (f3d::options::parse>(std::string("1, 2, 3")) != + std::vector({ 1, 2, 3 })) + { + std::cerr << "Options parse method not behaving as expected with int vector." << std::endl; + return EXIT_FAILURE; + } if (f3d::options::parse>(std::string("0.1, 0.2, 0.3")) != std::vector({ 0.1, 0.2, 0.3 })) { std::cerr << "Options parse method not behaving as expected with double vector." << std::endl; return EXIT_FAILURE; } + if (f3d::options::parse>(std::string("foo, bar, baz")) != + std::vector({ "foo", "bar", "baz" })) + { + std::cerr << "Options parse method not behaving as expected with string vector." << std::endl; + return EXIT_FAILURE; + } return EXIT_SUCCESS; }