1
0
Fork 0

Codechange: Use StringBuilder to create encoded strings.

pull/13983/head
frosch 2025-04-04 20:08:25 +02:00 committed by frosch
parent 128e0fcde2
commit dd073eb38d
4 changed files with 44 additions and 48 deletions

View File

@ -29,6 +29,7 @@
#include "../window_func.h" #include "../window_func.h"
#include "../strings_func.h" #include "../strings_func.h"
#include "../core/endian_func.hpp" #include "../core/endian_func.hpp"
#include "../core/string_builder.hpp"
#include "../vehicle_base.h" #include "../vehicle_base.h"
#include "../company_func.h" #include "../company_func.h"
#include "../timer/timer_game_economy.h" #include "../timer/timer_game_economy.h"
@ -928,7 +929,7 @@ void FixSCCEncoded(std::string &str, bool fix_code)
* `:"<STRING>"` becomes `<RS><SCC_ENCODED_STRING><STRING>` * `:"<STRING>"` becomes `<RS><SCC_ENCODED_STRING><STRING>`
*/ */
std::string result; std::string result;
auto output = std::back_inserter(result); StringBuilder builder(result);
bool is_encoded = false; // Set if we determine by the presence of SCC_ENCODED that the string is an encoded string. bool is_encoded = false; // Set if we determine by the presence of SCC_ENCODED that the string is an encoded string.
bool in_string = false; // Set if we in a string, between double-quotes. bool in_string = false; // Set if we in a string, between double-quotes.
@ -940,11 +941,11 @@ void FixSCCEncoded(std::string &str, bool fix_code)
char32_t c; char32_t c;
Utf8Decode(&c, &*it); Utf8Decode(&c, &*it);
it += len;
if (c == SCC_ENCODED || (fix_code && (c == 0xE028 || c == 0xE02A))) { if (c == SCC_ENCODED || (fix_code && (c == 0xE028 || c == 0xE02A))) {
Utf8Encode(output, SCC_ENCODED); builder.PutUtf8(SCC_ENCODED);
need_type = false; need_type = false;
is_encoded = true; is_encoded = true;
it += len;
continue; continue;
} }
@ -955,27 +956,24 @@ void FixSCCEncoded(std::string &str, bool fix_code)
in_string = !in_string; in_string = !in_string;
if (in_string && need_type) { if (in_string && need_type) {
/* Started a new string parameter. */ /* Started a new string parameter. */
Utf8Encode(output, SCC_ENCODED_STRING); builder.PutUtf8(SCC_ENCODED_STRING);
need_type = false; need_type = false;
} }
it += len;
continue; continue;
} }
if (!in_string && c == ':') { if (!in_string && c == ':') {
*output = SCC_RECORD_SEPARATOR; builder.PutUtf8(SCC_RECORD_SEPARATOR);
need_type = true; need_type = true;
it += len;
continue; continue;
} }
if (need_type) { if (need_type) {
/* Started a new numeric parameter. */ /* Started a new numeric parameter. */
Utf8Encode(output, SCC_ENCODED_NUMERIC); builder.PutUtf8(SCC_ENCODED_NUMERIC);
need_type = false; need_type = false;
} }
Utf8Encode(output, c); builder.PutUtf8(c);
it += len;
} }
str = std::move(result); str = std::move(result);

View File

@ -163,9 +163,9 @@ EncodedString ScriptText::GetEncodedText()
ParamList params; ParamList params;
int param_count = 0; int param_count = 0;
std::string result; std::string result;
auto output = std::back_inserter(result); StringBuilder builder(result);
this->_FillParamList(params, seen_texts); this->_FillParamList(params, seen_texts);
this->_GetEncodedText(output, param_count, params, true); this->_GetEncodedText(builder, param_count, params, true);
if (param_count > SCRIPT_TEXT_MAX_PARAMETERS) throw Script_FatalError(fmt::format("{}: Too many parameters", GetGameStringName(this->string))); if (param_count > SCRIPT_TEXT_MAX_PARAMETERS) throw Script_FatalError(fmt::format("{}: Too many parameters", GetGameStringName(this->string)));
return ::EncodedString{std::move(result)}; return ::EncodedString{std::move(result)};
} }
@ -193,46 +193,46 @@ void ScriptText::_FillParamList(ParamList &params, ScriptTextList &seen_texts)
} }
} }
void ScriptText::ParamCheck::Encode(std::back_insert_iterator<std::string> &output, std::string_view cmd) void ScriptText::ParamCheck::Encode(StringBuilder &builder, std::string_view cmd)
{ {
if (this->cmd.empty()) this->cmd = cmd; if (this->cmd.empty()) this->cmd = cmd;
if (this->used) return; if (this->used) return;
struct visitor { struct visitor {
std::back_insert_iterator<std::string> &output; StringBuilder &builder;
void operator()(std::string value) void operator()(std::string value)
{ {
Utf8Encode(this->output, SCC_ENCODED_STRING); this->builder.PutUtf8(SCC_ENCODED_STRING);
StrMakeValidInPlace(value, {StringValidationSetting::ReplaceWithQuestionMark, StringValidationSetting::AllowNewline, StringValidationSetting::ReplaceTabCrNlWithSpace}); StrMakeValidInPlace(value, {StringValidationSetting::ReplaceWithQuestionMark, StringValidationSetting::AllowNewline, StringValidationSetting::ReplaceTabCrNlWithSpace});
fmt::format_to(this->output, "{}", value); this->builder.Put(value);
} }
void operator()(const SQInteger &value) void operator()(const SQInteger &value)
{ {
Utf8Encode(this->output, SCC_ENCODED_NUMERIC); this->builder.PutUtf8(SCC_ENCODED_NUMERIC);
fmt::format_to(this->output, "{:X}", value); this->builder.PutIntegerBase(value, 16);
} }
void operator()(const ScriptTextRef &value) void operator()(const ScriptTextRef &value)
{ {
Utf8Encode(this->output, SCC_ENCODED); this->builder.PutUtf8(SCC_ENCODED);
fmt::format_to(this->output, "{:X}", value->string); this->builder.PutIntegerBase(value->string.base(), 16);
} }
}; };
*output = SCC_RECORD_SEPARATOR; builder.PutUtf8(SCC_RECORD_SEPARATOR);
std::visit(visitor{output}, *this->param); std::visit(visitor{builder}, *this->param);
this->used = true; this->used = true;
} }
void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output, int &param_count, ParamSpan args, bool first) void ScriptText::_GetEncodedText(StringBuilder &builder, int &param_count, ParamSpan args, bool first)
{ {
const std::string &name = GetGameStringName(this->string); const std::string &name = GetGameStringName(this->string);
if (first) { if (first) {
Utf8Encode(output, SCC_ENCODED); builder.PutUtf8(SCC_ENCODED);
fmt::format_to(output, "{:X}", this->string); builder.PutIntegerBase(this->string.base(), 16);
} }
const StringParams &params = GetGameStringParams(this->string); const StringParams &params = GetGameStringParams(this->string);
@ -256,7 +256,7 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output,
case StringParam::RAW_STRING: case StringParam::RAW_STRING:
{ {
ParamCheck &p = *get_next_arg(); ParamCheck &p = *get_next_arg();
p.Encode(output, cur_param.cmd); p.Encode(builder, cur_param.cmd);
if (p.cmd != cur_param.cmd) throw 1; if (p.cmd != cur_param.cmd) throw 1;
if (!std::holds_alternative<std::string>(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a raw string", name, param_count + 1, cur_param.cmd)); if (!std::holds_alternative<std::string>(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a raw string", name, param_count + 1, cur_param.cmd));
break; break;
@ -265,7 +265,7 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output,
case StringParam::STRING: case StringParam::STRING:
{ {
ParamCheck &p = *get_next_arg(); ParamCheck &p = *get_next_arg();
p.Encode(output, cur_param.cmd); p.Encode(builder, cur_param.cmd);
if (p.cmd != cur_param.cmd) throw 1; if (p.cmd != cur_param.cmd) throw 1;
if (!std::holds_alternative<ScriptTextRef>(*p.param)) { if (!std::holds_alternative<ScriptTextRef>(*p.param)) {
ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a GSText", name, param_count + 1, cur_param.cmd)); ScriptLog::Error(fmt::format("{}({}): {{{}}} expects a GSText", name, param_count + 1, cur_param.cmd));
@ -274,12 +274,12 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output,
} }
int count = 0; int count = 0;
ScriptTextRef &ref = std::get<ScriptTextRef>(*p.param); ScriptTextRef &ref = std::get<ScriptTextRef>(*p.param);
ref->_GetEncodedText(output, count, args.subspan(idx), false); ref->_GetEncodedText(builder, count, args.subspan(idx), false);
if (++count != cur_param.consumes) { if (++count != cur_param.consumes) {
ScriptLog::Warning(fmt::format("{}({}): {{{}}} expects {} to be consumed, but {} consumes {}", name, param_count + 1, cur_param.cmd, cur_param.consumes - 1, GetGameStringName(ref->string), count - 1)); ScriptLog::Warning(fmt::format("{}({}): {{{}}} expects {} to be consumed, but {} consumes {}", name, param_count + 1, cur_param.cmd, cur_param.consumes - 1, GetGameStringName(ref->string), count - 1));
/* Fill missing params if needed. */ /* Fill missing params if needed. */
for (int i = count; i < cur_param.consumes; i++) { for (int i = count; i < cur_param.consumes; i++) {
Utf8Encode(output, SCC_RECORD_SEPARATOR); builder.PutUtf8(SCC_RECORD_SEPARATOR);
} }
} }
skip_args(cur_param.consumes - 1); skip_args(cur_param.consumes - 1);
@ -289,7 +289,7 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator<std::string> &output,
default: default:
for (int i = 0; i < cur_param.consumes; i++) { for (int i = 0; i < cur_param.consumes; i++) {
ParamCheck &p = *get_next_arg(); ParamCheck &p = *get_next_arg();
p.Encode(output, i == 0 ? cur_param.cmd : ""); p.Encode(builder, i == 0 ? cur_param.cmd : "");
if (i == 0 && p.cmd != cur_param.cmd) throw 1; if (i == 0 && p.cmd != cur_param.cmd) throw 1;
if (!std::holds_alternative<SQInteger>(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects an integer", name, param_count + i + 1, cur_param.cmd)); if (!std::holds_alternative<SQInteger>(*p.param)) ScriptLog::Error(fmt::format("{}({}): {{{}}} expects an integer", name, param_count + i + 1, cur_param.cmd));
} }

View File

@ -12,6 +12,7 @@
#include "script_object.hpp" #include "script_object.hpp"
#include "../../strings_func.h" #include "../../strings_func.h"
#include "../../core/string_builder.hpp"
#include <variant> #include <variant>
@ -141,7 +142,7 @@ private:
ParamCheck(StringIndexInTab owner, int idx, Param *param) : owner(owner), idx(idx), param(param) {} ParamCheck(StringIndexInTab owner, int idx, Param *param) : owner(owner), idx(idx), param(param) {}
void Encode(std::back_insert_iterator<std::string> &output, std::string_view cmd); void Encode(StringBuilder &output, std::string_view cmd);
}; };
using ParamList = std::vector<ParamCheck>; using ParamList = std::vector<ParamCheck>;
@ -168,7 +169,7 @@ private:
* @param args The parameters to be consumed. * @param args The parameters to be consumed.
* @param first Whether it's the first call in the recursion. * @param first Whether it's the first call in the recursion.
*/ */
void _GetEncodedText(std::back_insert_iterator<std::string> &output, int &param_count, ParamSpan args, bool first); void _GetEncodedText(StringBuilder &output, int &param_count, ParamSpan args, bool first);
/** /**
* Set a parameter, where the value is the first item on the stack. * Set a parameter, where the value is the first item on the stack.

View File

@ -103,41 +103,38 @@ EncodedString GetEncodedString(StringID str)
EncodedString GetEncodedStringWithArgs(StringID str, std::span<const StringParameter> params) EncodedString GetEncodedStringWithArgs(StringID str, std::span<const StringParameter> params)
{ {
std::string result; std::string result;
auto output = std::back_inserter(result); StringBuilder builder(result);
Utf8Encode(output, SCC_ENCODED_INTERNAL); builder.PutUtf8(SCC_ENCODED_INTERNAL);
fmt::format_to(output, "{:X}", str); builder.PutIntegerBase(str, 16);
struct visitor { struct visitor {
std::back_insert_iterator<std::string> &output; StringBuilder &builder;
void operator()(const std::monostate &) {} void operator()(const std::monostate &) {}
void operator()(const uint64_t &arg) void operator()(const uint64_t &arg)
{ {
Utf8Encode(output, SCC_ENCODED_NUMERIC); this->builder.PutUtf8(SCC_ENCODED_NUMERIC);
fmt::format_to(this->output, "{:X}", arg); this->builder.PutIntegerBase(arg, 16);
} }
void operator()(const std::string &value) void operator()(const std::string &value)
{ {
#ifdef WITH_ASSERT #ifdef WITH_ASSERT
/* Don't allow an encoded string to contain another encoded string. */ /* Don't allow an encoded string to contain another encoded string. */
if (!value.empty()) { {
char32_t c; auto [len, c] = DecodeUtf8(value);
const char *p = value.data(); assert(len == 0 || (c != SCC_ENCODED && c != SCC_ENCODED_INTERNAL && c != SCC_RECORD_SEPARATOR));
if (Utf8Decode(&c, p)) {
assert(c != SCC_ENCODED && c != SCC_ENCODED_INTERNAL && c != SCC_RECORD_SEPARATOR);
}
} }
#endif /* WITH_ASSERT */ #endif /* WITH_ASSERT */
Utf8Encode(output, SCC_ENCODED_STRING); this->builder.PutUtf8(SCC_ENCODED_STRING);
fmt::format_to(this->output, "{}", value); this->builder += value;
} }
}; };
visitor v{output}; visitor v{builder};
for (const auto &param : params) { for (const auto &param : params) {
*output = SCC_RECORD_SEPARATOR; builder.PutUtf8(SCC_RECORD_SEPARATOR);
std::visit(v, param.data); std::visit(v, param.data);
} }