mirror of
https://github.com/OpenRCT2/OpenRCT2.git
synced 2025-01-23 19:02:04 -05:00
Implement multi-level formatting for template FormatString
This commit is contained in:
parent
6c23da4965
commit
6294188e93
3 changed files with 53 additions and 21 deletions
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Add table
Reference in a new issue