From e211d08c9274c1ce5ad2d836a2a88087236e93bd Mon Sep 17 00:00:00 2001 From: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Date: Thu, 30 May 2024 16:52:30 +0200 Subject: [PATCH] [Core] Optimize `String::join` Avoid reallocation by pre-computing size --- core/string/ustring.cpp | 42 +++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index 3d37e17ef83..b15ed7b732a 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -1639,13 +1639,43 @@ Vector String::split_ints_mk(const Vector &p_splitters, bool p_allo } String String::join(const Vector &parts) const { - String ret; - for (int i = 0; i < parts.size(); ++i) { - if (i > 0) { - ret += *this; - } - ret += parts[i]; + if (parts.is_empty()) { + return String(); + } else if (parts.size() == 1) { + return parts[0]; } + + const int this_length = length(); + + int new_size = (parts.size() - 1) * this_length; + for (const String &part : parts) { + new_size += part.length(); + } + new_size += 1; + + String ret; + ret.resize(new_size); + char32_t *ret_ptrw = ret.ptrw(); + const char32_t *this_ptr = ptr(); + + bool first = true; + for (const String &part : parts) { + if (first) { + first = false; + } else if (this_length) { + memcpy(ret_ptrw, this_ptr, this_length * sizeof(char32_t)); + ret_ptrw += this_length; + } + + const int part_length = part.length(); + if (part_length) { + memcpy(ret_ptrw, part.ptr(), part_length * sizeof(char32_t)); + ret_ptrw += part_length; + } + } + + *ret_ptrw = 0; + return ret; }