Skip to content

Commit

Permalink
options: Add options::format template method (#1857)
Browse files Browse the repository at this point in the history
Co-authored-by: Michael Migliore <[email protected]>
  • Loading branch information
mwestphal and Meakk authored Jan 3, 2025
1 parent 8b78094 commit 89df7ec
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 26 deletions.
37 changes: 15 additions & 22 deletions library/private/options_tools.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -194,35 +194,31 @@ std::string parse(const std::string& str)
// TODO Improve string generation
//----------------------------------------------------------------------------
/**
* Generic templated string generation from provided value
* rely on std::to_string
* Format provided var into a string from provided boolean
* using boolalpha formatting, eg: "true" or "false"
*/
template<typename T>
std::string format(const T& var)
std::string format(bool var)
{
return std::to_string(var);
std::stringstream stream;
stream << std::boolalpha << var;
return stream.str();
}

//----------------------------------------------------------------------------
/**
* Format provided var into a string from provided boolean
* using boolalpha formatting, eg: "true" or "false"
* Format provided var into a string from provided int
*/
template<>
std::string format(const bool& var)
std::string format(int var)
{
std::stringstream stream;
stream << std::boolalpha << var;
return stream.str();
return std::to_string(var);
}

//----------------------------------------------------------------------------
/**
* Format provided var into a string from provided double
* using ostringstream with std::noshowpoint
*/
template<>
std::string format(const double& var)
std::string format(double var)
{
std::ostringstream stream;
stream << std::noshowpoint << var;
Expand All @@ -234,19 +230,16 @@ std::string format(const double& var)
* Format provided var into a string from provided ratio_t
* rely on format(double&)
*/
template<>
std::string format(const ratio_t& var)
std::string format(ratio_t var)
{
// TODO generate a proper ratio string
double val = var;
return options_tools::format(val);
return options_tools::format(static_cast<double>(var));
}

//----------------------------------------------------------------------------
/**
* Generate (returns) a string from provided string
*/
template<>
std::string format(const std::string& var)
{
return var;
Expand All @@ -257,12 +250,12 @@ std::string format(const std::string& var)
* Format provided var into a string from provided double vector
* rely on format(double&) and add `, ` between the double values
*/
template<>
std::string format(const std::vector<double>& var)
template<typename T>
std::string format(const std::vector<T>& var)
{
std::ostringstream stream;
unsigned int i = 0;
for (auto& elem : var)
for (const T& elem : var)
{
stream << ((i > 0) ? "," : "") << options_tools::format(elem);
i++;
Expand Down
8 changes: 8 additions & 0 deletions library/public/options.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,14 @@ public:
template<typename T>
[[nodiscard]] static T parse(const std::string& str);

/**
* Templated parsing method used internally to format var into strings.
* Implemented for the different supported types,
* see PARSING.md for more info.
*/
template<typename T>
[[nodiscard]] static std::string format(const T& var);

/**
* An exception that can be thrown by the options
* when parsing of a string into an option value fails
Expand Down
10 changes: 9 additions & 1 deletion library/src/options.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,17 @@ T options::parse(const std::string& str)
return options_tools::parse<T>(str);
}

//----------------------------------------------------------------------------
template<typename T>
std::string options::format(const T& var)
{
return options_tools::format(var);
}

//----------------------------------------------------------------------------
#define F3D_DECL_TYPE_INTERNAL(TYPE) \
template F3D_EXPORT TYPE options::parse<TYPE>(const std::string& str)
template F3D_EXPORT TYPE options::parse<TYPE>(const std::string& str); \
template F3D_EXPORT std::string options::format<TYPE>(const TYPE& val)
#define F3D_DECL_TYPE(TYPE) \
F3D_DECL_TYPE_INTERNAL(TYPE); \
F3D_DECL_TYPE_INTERNAL(std::vector<TYPE>)
Expand Down
36 changes: 33 additions & 3 deletions library/testing/TestSDKOptionsIO.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class ParsingTest : public PseudoUnitTest
template<typename T>
void parse(const std::string& label, const std::string& input, const T& expected)
{
PseudoUnitTest::operator()(label + " `" + input + "`", [&]() {
PseudoUnitTest::operator()("parse: " + label + " `" + input + "`", [&]() {
const T actual = f3d::options::parse<T>(input);
if (actual != expected)
{
Expand All @@ -23,8 +23,20 @@ class ParsingTest : public PseudoUnitTest
template<typename T, typename E>
void parse_expect(const std::string& label, const std::string& input)
{
PseudoUnitTest::expect<E>(
label + " `" + input + "`", [&]() { std::ignore = f3d::options::parse<T>(input); });
PseudoUnitTest::expect<E>("parse exception: " + label + " `" + input + "`",
[&]() { std::ignore = f3d::options::parse<T>(input); });
}

template<typename T>
void format(const std::string& label, const T& input, const std::string& expected)
{
PseudoUnitTest::operator()("format: " + label + " `" + expected + "`", [&]() {
const std::string actual = f3d::options::format<T>(input);
if (actual != expected)
{
throw this->comparisonMessage(actual, expected, "!=");
}
});
}
};

Expand All @@ -42,22 +54,31 @@ int TestSDKOptionsIO(int argc, char* argv[])
test.parse<bool>("bool", "0", false);
test.parse_expect<bool, parsing_exception>("invalid bool", "foo");

test.format<bool>("bool", true, "true");
test.format<bool>("bool", false, "false");

test.parse<int>("int", "123", 123);
test.parse<int>("int", "-123", -123);
test.parse<int>("int", "+123", +123);
test.parse_expect<int, parsing_exception>("invalid int", "1.2");
test.parse_expect<int, parsing_exception>("invalid int", "abc");
test.parse_expect<int, parsing_exception>("invalid int",
"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
test.format<int>("int", 123, "123");
test.format<int>("int", -123, "-123");

test.parse<double>("double", "123", 123.0);
test.parse<double>("double", "-123.45", -123.45);
test.parse<double>("double", "+1e-3", 0.001);
test.parse_expect<double, parsing_exception>("invalid double", "1.2.3");
test.parse_expect<double, parsing_exception>("invalid double", "abc");
test.format<double>("double", 0.001, "0.001");
test.format<double>("double", -123.45, "-123.45");

test.parse<std::string>("std::string", "foobar", "foobar");
test.parse<std::string>("std::string", " foobar ", "foobar");
test.format<std::string>("std::string", "foobar", "foobar");
test.format<std::string>("std::string", " foobar ", " foobar ");

test.parse<f3d::ratio_t>("ratio_t", "0.1234", 0.1234);
test.parse<f3d::ratio_t>("ratio_t", "12.34%", 0.1234);
Expand All @@ -66,13 +87,22 @@ int TestSDKOptionsIO(int argc, char* argv[])
test.parse_expect<f3d::ratio_t, parsing_exception>("invalid ratio_t", "12.34&");
test.parse<f3d::ratio_t>("ratio_t", "-2/-3.5", 2.0 / 3.5);
test.parse_expect<f3d::ratio_t, parsing_exception>("invalid ratio_t", "1/2/3");
test.format<f3d::ratio_t>("ratio_t", .1234, "0.1234");

test.parse<std::vector<int>>("std::vector<int>", "1, 2, 3", { 1, 2, 3 });
test.parse<std::vector<int>>("std::vector<int>", "1,2,3", { 1, 2, 3 });
test.format<std::vector<int>>("std::vector<int>", { 1, 2, 3 }, "1,2,3");

test.parse<std::vector<double>>("std::vector<double>", "0.1,0.2,0.3", { 0.1, 0.2, 0.3 });
test.parse<std::vector<double>>("std::vector<double>", " 0.1, 0.2 , 0.3 ", { 0.1, 0.2, 0.3 });
test.format<std::vector<double>>("std::vector<double>", { 0.1, 0.2, 0.3 }, "0.1,0.2,0.3");

test.parse<std::vector<std::string>>(
"std::vector<std::string>", "foo,bar,baz", { "foo", "bar", "baz" });
test.parse<std::vector<std::string>>(
"std::vector<std::string>", " foo, bar , baz ", { "foo", "bar", "baz" });
test.format<std::vector<std::string>>(
"std::vector<std::string>", { "foo", "bar", "baz" }, "foo,bar,baz");

return test.result();
}

0 comments on commit 89df7ec

Please sign in to comment.