diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index e57e7cd710..c0242709d8 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -1793,7 +1793,9 @@ std::string Game_Interpreter::CommandString(lcf::rpg::EventCommand const& com) { #endif return ToString(com.string); } - return PendingMessage::ApplyTextInsertingCommands(ToString(com.string), Player::escape_char, Game_Message::CommandCodeInserter); + std::string command_string = ToString(com.string); + PendingMessage::ApplyTextInsertingCommands(command_string, Player::escape_char, Game_Message::CommandCodeInserter); + return command_string; } diff --git a/src/game_message.cpp b/src/game_message.cpp index b6eb498ea2..2f986d23c6 100644 --- a/src/game_message.cpp +++ b/src/game_message.cpp @@ -164,7 +164,8 @@ static std::optional CommandCodeInserterNoRecurse(char ch, const ch std::string str = ToString(Main_Data::game_strings->Get(value)); // \t[] is evaluated but command codes inside it are not evaluated again - return PendingMessage::ApplyTextInsertingCommands(str, escape_char, PendingMessage::DefaultCommandInserter); + PendingMessage::ApplyTextInsertingCommands(str, escape_char, PendingMessage::DefaultCommandInserter); + return str; } return PendingMessage::DefaultCommandInserter(ch, iter, end, escape_char); @@ -179,7 +180,8 @@ std::optional Game_Message::CommandCodeInserter(char ch, const char std::string str = ToString(Main_Data::game_strings->Get(value)); // Command codes in \t[] are evaluated once. - return PendingMessage::ApplyTextInsertingCommands(str, escape_char, CommandCodeInserterNoRecurse); + PendingMessage::ApplyTextInsertingCommands(str, escape_char, CommandCodeInserterNoRecurse); + return str; } return PendingMessage::DefaultCommandInserter(ch, iter, end, escape_char); diff --git a/src/game_strings.cpp b/src/game_strings.cpp index 1258a854ea..5876ab8d01 100644 --- a/src/game_strings.cpp +++ b/src/game_strings.cpp @@ -322,7 +322,9 @@ std::string Game_Strings::Extract(StringView string, bool as_hex) { cmd_fn = ManiacsCommandInserter; } - return PendingMessage::ApplyTextInsertingCommands(ToString(string), Player::escape_char, cmd_fn); + std::string str = ToString(string); + PendingMessage::ApplyTextInsertingCommands(str, Player::escape_char, cmd_fn); + return str; } std::optional Game_Strings::ManiacsCommandInserter(char ch, const char** iter, const char* end, uint32_t escape_char) { diff --git a/src/pending_message.cpp b/src/pending_message.cpp index 7b8daede92..cde353f480 100644 --- a/src/pending_message.cpp +++ b/src/pending_message.cpp @@ -44,7 +44,7 @@ PendingMessage::PendingMessage(PendingMessage::CommandInserter cmd_fn) : int PendingMessage::PushLineImpl(std::string msg) { RemoveControlChars(msg); - msg = ApplyTextInsertingCommands(std::move(msg), Player::escape_char, command_inserter); + ApplyTextInsertingCommands(msg, Player::escape_char, command_inserter); texts.push_back(std::move(msg)); return texts.size(); } @@ -94,17 +94,15 @@ void PendingMessage::SetChoiceResetColors(bool value) { choice_reset_color = value; } -std::string PendingMessage::ApplyTextInsertingCommands(std::string input, uint32_t escape_char, const CommandInserter& cmd_fn) { +void PendingMessage::ApplyTextInsertingCommands(std::string& input, uint32_t escape_char, const CommandInserter& cmd_fn) { if (input.empty()) { - return input; + return; } - std::string output; - const char* iter = input.data(); - const auto end = input.data() + input.size(); + auto end = input.data() + input.size(); - const char* start_copy = iter; + const char* start_replace = nullptr; while (iter != end) { auto ret = Utils::UTF8Next(iter, end); if (ret.ch != escape_char) { @@ -117,8 +115,7 @@ std::string PendingMessage::ApplyTextInsertingCommands(std::string input, uint32 break; } - output.append(start_copy, iter - start_copy); - start_copy = iter; + start_replace = iter; iter = ret.next; if (iter == end) { @@ -130,19 +127,17 @@ std::string PendingMessage::ApplyTextInsertingCommands(std::string input, uint32 auto fn_res = cmd_fn(ch, &iter, end, escape_char); if (fn_res) { - output.append(*fn_res); - start_copy = iter; - } - } + size_t repl_pos = start_replace - input.data(); + size_t repl_len = iter - start_replace; + size_t insert_len = fn_res->size(); - if (start_copy == input.data()) { - // Fast path - no substitutions occured, so just move the input into the return value. - output = std::move(input); - } else { - output.append(start_copy, end - start_copy); - } + input.replace(repl_pos, repl_len, fn_res->data(), insert_len); - return output; + iter = input.data() + repl_pos + insert_len; + end = input.data() + input.size(); + start_replace = nullptr; + } + } } std::optional PendingMessage::DefaultCommandInserter(char ch, const char** iter, const char* end, uint32_t escape_char) { diff --git a/src/pending_message.h b/src/pending_message.h index 793d47e498..3e61542810 100644 --- a/src/pending_message.h +++ b/src/pending_message.h @@ -68,7 +68,7 @@ class PendingMessage { void SetIsEventMessage(bool value) { is_event_message = value; } bool IsEventMessage() const { return is_event_message; } - static std::string ApplyTextInsertingCommands(std::string input, uint32_t escape_char, const CommandInserter& cmd_fn); + static void ApplyTextInsertingCommands(std::string& input, uint32_t escape_char, const CommandInserter& cmd_fn); private: int PushLineImpl(std::string msg);