diff --git a/src/openrct2/localisation/Formatting.cpp b/src/openrct2/localisation/Formatting.cpp index ec18d92577..695ecbf9ce 100644 --- a/src/openrct2/localisation/Formatting.cpp +++ b/src/openrct2/localisation/Formatting.cpp @@ -204,4 +204,47 @@ namespace OpenRCT2 template void FormatArgument(std::stringstream&, uint32_t, int32_t); template void FormatArgument(std::stringstream&, uint32_t, const char*); + + void FormatArgumentAny(std::stringstream& ss, FormatToken token, const std::any& value) + { + if (value.type() == typeid(int32_t)) + { + FormatArgument(ss, token, std::any_cast(value)); + } + else if (value.type() == typeid(const char*)) + { + FormatArgument(ss, token, std::any_cast(value)); + } + else + { + throw std::runtime_error("No support for format argument type."); + } + } + + std::string FormatStringAny(std::string_view fmt, const std::vector& args) + { + thread_local std::stringstream ss; + // Reset the buffer (reported as most efficient way) + std::stringstream().swap(ss); + + size_t argIndex = 0; + auto fmtc = fmt; + while (!fmtc.empty()) + { + auto [part, token] = FormatNextPart(fmtc); + if (CanFormatToken(token)) + { + if (argIndex < args.size()) + { + FormatArgumentAny(ss, token, args[argIndex]); + } + argIndex++; + } + else + { + ss << part; + } + } + return ss.str(); + } } // namespace OpenRCT2 diff --git a/src/openrct2/localisation/Formatting.h b/src/openrct2/localisation/Formatting.h index 6233af63bf..b9dca7a7fc 100644 --- a/src/openrct2/localisation/Formatting.h +++ b/src/openrct2/localisation/Formatting.h @@ -12,10 +12,12 @@ #include "../common.h" #include "Language.h" +#include #include #include #include #include +#include namespace OpenRCT2 { @@ -99,4 +101,6 @@ namespace OpenRCT2 auto fmtc = language_convert_string_to_tokens(lang); return FormatString(fmtc, argN...); } + + std::string FormatStringAny(std::string_view fmt, const std::vector& args); } // namespace OpenRCT2 diff --git a/test/tests/FormattingTests.cpp b/test/tests/FormattingTests.cpp index a6339d6d3f..90651027c2 100644 --- a/test/tests/FormattingTests.cpp +++ b/test/tests/FormattingTests.cpp @@ -116,3 +116,10 @@ TEST_F(FormattingTests, velocity_mps) auto actual = FormatString("Train is going at {VELOCITY}.", 1024); ASSERT_EQ("Train is going at 457.7 m/s.", actual); } + +TEST_F(FormattingTests, any_string_int_string) +{ + auto actual = FormatStringAny( + "{RED}{STRING} {INT32} has broken down due to '{STRING}'.", { "Twist", 2, "Mechanical failure" }); + ASSERT_EQ("{RED}Twist 2 has broken down due to 'Mechanical failure'.", actual); +}