Implement multi-level formatting for any implementation

This commit is contained in:
Ted John 2020-10-11 14:03:12 +01:00
parent 43842bb668
commit 6c23da4965
4 changed files with 52 additions and 54 deletions

View File

@ -478,48 +478,18 @@ namespace OpenRCT2
}
}
std::pair<std::string_view, uint32_t> FormatNextPart(std::string_view& fmt)
{
if (fmt.size() > 0)
{
for (size_t i = 0; i < fmt.size() - 1; i++)
{
if (fmt[i] == '{' && fmt[i + 1] != '}')
{
if (i == 0)
{
// Find end brace
for (size_t j = i + 1; j < fmt.size(); j++)
{
if (fmt[j] == '}')
{
auto result = fmt.substr(0, j + 1);
fmt = fmt.substr(j + 1);
return { result, format_get_code(result.substr(1, result.size() - 2)) };
}
}
}
else
{
auto result = fmt.substr(0, i);
fmt = fmt.substr(i);
return { result, 0 };
}
}
}
}
{
auto result = fmt;
fmt = {};
return { result, 0 };
}
}
bool CanFormatToken(FormatToken t)
{
return t == FORMAT_COMMA1DP16 || (t >= FORMAT_COMMA32 && t <= FORMAT_LENGTH);
}
FmtString GetFmtStringById(rct_string_id id)
{
auto lang = language_get_string(id);
auto fmtc = language_convert_string_to_tokens(lang);
return FmtString(std::move(fmtc));
}
template void FormatArgument(std::stringstream&, uint32_t, int32_t);
template void FormatArgument(std::stringstream&, uint32_t, const char*);
@ -539,16 +509,28 @@ namespace OpenRCT2
}
}
std::string FormatStringAny(const FmtString& fmt, const std::vector<std::any>& args)
static void FormatStringAny(
std::stringstream& ss, const FmtString& fmt, const std::vector<std::any>& args, size_t& argIndex)
{
thread_local std::stringstream ss;
// Reset the buffer (reported as most efficient way)
std::stringstream().swap(ss);
size_t argIndex = 0;
for (const auto& token : fmt)
{
if (CanFormatToken(token.kind))
if (token.kind == FORMAT_STRINGID || token.kind == FORMAT_STRINGID2)
{
if (argIndex < args.size())
{
auto arg = args[argIndex++];
if (arg.type() == typeid(rct_string_id))
{
auto subfmt = GetFmtStringById(std::any_cast<rct_string_id>(arg));
FormatStringAny(ss, subfmt, args, argIndex);
}
}
else
{
argIndex++;
}
}
else if (CanFormatToken(token.kind))
{
if (argIndex < args.size())
{
@ -561,6 +543,15 @@ namespace OpenRCT2
ss << token.text;
}
}
}
std::string FormatStringAny(const FmtString& fmt, const std::vector<std::any>& args)
{
thread_local std::stringstream ss;
// Reset the buffer (reported as most efficient way)
std::stringstream().swap(ss);
size_t argIndex = 0;
FormatStringAny(ss, fmt, args, argIndex);
return ss.str();
}
} // namespace OpenRCT2

View File

@ -72,8 +72,8 @@ namespace OpenRCT2
template<typename T> void FormatArgument(std::stringstream& ss, FormatToken token, T arg);
std::pair<std::string_view, uint32_t> FormatNextPart(std::string_view& fmt);
bool CanFormatToken(FormatToken t);
FmtString GetFmtStringById(rct_string_id id);
inline void FormatString(std::stringstream& ss, FmtString::iterator& it)
{
@ -122,18 +122,16 @@ namespace OpenRCT2
return ss.str();
}
template<typename... TArgs> static void FormatStringId(std::stringstream& ss, rct_string_id fmt, TArgs&&... argN)
template<typename... TArgs> static void FormatStringId(std::stringstream& ss, rct_string_id id, TArgs&&... argN)
{
auto lang = language_get_string(fmt);
auto fmtsz = language_convert_string_to_tokens(lang);
FormatString(ss, FmtString(fmtsz), argN...);
auto fmt = GetFmtStringById(id);
FormatString(ss, fmt, argN...);
}
template<typename... TArgs> std::string FormatStringId(rct_string_id fmt, TArgs&&... argN)
template<typename... TArgs> std::string FormatStringId(rct_string_id id, TArgs&&... argN)
{
auto lang = language_get_string(fmt);
auto fmtc = language_convert_string_to_tokens(lang);
return FormatString(fmtc, argN...);
auto fmt = GetFmtStringById(id);
return FormatString(fmt, argN...);
}
std::string FormatStringAny(const FmtString& fmt, const std::vector<std::any>& args);

View File

@ -18,7 +18,7 @@ constexpr const rct_string_id STR_VIEWPORT = 0xFFFE;
enum
{
STR_EMPTY = 0,
// STR_0001 :{STRINGID} {COMMA16}
STR_RIDE_NAME_DEFAULT = 1,
STR_RIDE_NAME_SPIRAL_ROLLER_COASTER = 2,
STR_RIDE_NAME_STAND_UP_ROLLER_COASTER = 3,
STR_RIDE_NAME_SUSPENDED_SWINGING_COASTER = 4,

View File

@ -14,6 +14,7 @@
#include <openrct2/OpenRCT2.h>
#include <openrct2/config/Config.h>
#include <openrct2/core/String.hpp>
#include <openrct2/localisation/StringIds.h>
using namespace OpenRCT2;
@ -263,3 +264,11 @@ TEST_F(FormattingTests, any_string_int_string)
"{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);
}
TEST_F(FormattingTests, any_two_level_format)
{
constexpr rct_string_id strDefault = STR_RIDE_NAME_DEFAULT;
constexpr rct_string_id strBoatHire = STR_RIDE_NAME_BOAT_HIRE;
auto actual = FormatStringAny("Queuing for {STRINGID}", { strDefault, strBoatHire, 2 });
ASSERT_EQ("Queuing for Boat Hire 2", actual);
}