Implement multi-level formatting for template FormatString

This commit is contained in:
Ted John 2020-10-11 15:09:38 +01:00
parent 6c23da4965
commit 6294188e93
3 changed files with 53 additions and 21 deletions

View file

@ -478,6 +478,11 @@ namespace OpenRCT2
}
}
template void FormatArgument(std::stringstream&, uint32_t, uint16_t);
template void FormatArgument(std::stringstream&, uint32_t, int16_t);
template void FormatArgument(std::stringstream&, uint32_t, int32_t);
template void FormatArgument(std::stringstream&, uint32_t, const char*);
bool CanFormatToken(FormatToken t)
{
return t == FORMAT_COMMA1DP16 || (t >= FORMAT_COMMA32 && t <= FORMAT_LENGTH);
@ -490,9 +495,6 @@ namespace OpenRCT2
return FmtString(std::move(fmtc));
}
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))

View file

@ -10,10 +10,12 @@
#pragma once
#include "../common.h"
#include "FormatCodes.h"
#include "Language.h"
#include <any>
#include <sstream>
#include <stack>
#include <string>
#include <string_view>
#include <utility>
@ -75,42 +77,62 @@ namespace OpenRCT2
bool CanFormatToken(FormatToken t);
FmtString GetFmtStringById(rct_string_id id);
inline void FormatString(std::stringstream& ss, FmtString::iterator& it)
inline void FormatString(std::stringstream& ss, std::stack<FmtString::iterator*> stack)
{
while (!it.eol())
while (!stack.empty())
{
const auto& token = *it++;
if (!CanFormatToken(token.kind))
auto& it = *stack.top();
while (!it.eol())
{
ss << token.text;
FormatString(ss, it);
const auto& token = *it++;
if (!CanFormatToken(token.kind))
{
ss << token.text;
}
}
stack.pop();
}
}
template<typename TArg0, typename... TArgs>
static void FormatString(std::stringstream& ss, FmtString::iterator& it, TArg0 arg0, TArgs&&... argN)
static void FormatString(std::stringstream& ss, std::stack<FmtString::iterator*> stack, TArg0 arg0, TArgs&&... argN)
{
while (!it.eol())
while (!stack.empty())
{
const auto& token = *it++;
if (CanFormatToken(token.kind))
auto& it = *stack.top();
while (!it.eol())
{
FormatArgument(ss, token.kind, arg0);
return FormatString(ss, it, argN...);
}
else
{
ss << token.text;
return FormatString(ss, it, arg0, argN...);
const auto& token = *it++;
if (token.kind == FORMAT_STRINGID || token.kind == FORMAT_STRINGID2)
{
if constexpr (std::is_integral<TArg0>())
{
auto subfmt = GetFmtStringById(static_cast<rct_string_id>(arg0));
auto subit = subfmt.begin();
stack.push(&subit);
FormatString(ss, stack, argN...);
}
}
else if (CanFormatToken(token.kind))
{
FormatArgument(ss, token.kind, arg0);
return FormatString(ss, stack, argN...);
}
else
{
ss << token.text;
}
}
stack.pop();
}
}
template<typename... TArgs> static void FormatString(std::stringstream& ss, const FmtString& fmt, TArgs&&... argN)
{
auto it = fmt.begin();
FormatString(ss, it, argN...);
std::stack<FmtString::iterator*> stack;
stack.push(&it);
FormatString(ss, stack, argN...);
}
template<typename... TArgs> std::string FormatString(const FmtString& fmt, TArgs&&... argN)

View file

@ -258,6 +258,14 @@ TEST_F(FormattingTests, monthyear)
ASSERT_EQ("Date: April, Year 2", FormatString("Date: {MONTHYEAR}", 9));
}
TEST_F(FormattingTests, two_level_format)
{
constexpr rct_string_id strDefault = STR_RIDE_NAME_DEFAULT;
constexpr rct_string_id strBoatHire = STR_RIDE_NAME_BOAT_HIRE;
auto actual = FormatString("Queuing for {STRINGID}", strDefault, strBoatHire, 2);
ASSERT_EQ("Queuing for Boat Hire 2", actual);
}
TEST_F(FormattingTests, any_string_int_string)
{
auto actual = FormatStringAny(