From efcab7bbd409d62255e7e5b73d2693782dbb8c93 Mon Sep 17 00:00:00 2001 From: Yyf2333 <2514537033@qq.com> Date: Fri, 4 Oct 2024 00:08:50 +0800 Subject: [PATCH 1/4] Optimize update_node_tooltip and StringBuilder Co-authored-by: Tomek --- core/string/string_builder.cpp | 22 +++++++++++++--------- core/string/string_builder.h | 11 +++++++---- editor/gui/scene_tree_editor.cpp | 26 ++++++++++++++++++++------ 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/core/string/string_builder.cpp b/core/string/string_builder.cpp index 4f74a2e42dc7..b025f49bbe1d 100644 --- a/core/string/string_builder.cpp +++ b/core/string/string_builder.cpp @@ -56,24 +56,32 @@ StringBuilder &StringBuilder::append(const char *p_cstring) { return *this; } +void StringBuilder::clear() { + string_length = 0; + strings.clear(); + c_strings.clear(); + appended_strings.clear(); + buffer_persist.clear(); +} + String StringBuilder::as_string() const { if (string_length == 0) { return ""; } - char32_t *buffer = memnew_arr(char32_t, string_length); + buffer_persist.resize(string_length); int current_position = 0; int godot_string_elem = 0; int c_string_elem = 0; - for (int i = 0; i < appended_strings.size(); i++) { + for (uint32_t i = 0; i < appended_strings.size(); i++) { if (appended_strings[i] == -1) { // Godot string const String &s = strings[godot_string_elem]; - memcpy(buffer + current_position, s.ptr(), s.length() * sizeof(char32_t)); + memcpy(buffer_persist.ptr() + current_position, s.ptr(), s.length() * sizeof(char32_t)); current_position += s.length(); @@ -82,7 +90,7 @@ String StringBuilder::as_string() const { const char *s = c_strings[c_string_elem]; for (int32_t j = 0; j < appended_strings[i]; j++) { - buffer[current_position + j] = s[j]; + buffer_persist[current_position + j] = s[j]; } current_position += appended_strings[i]; @@ -91,9 +99,5 @@ String StringBuilder::as_string() const { } } - String final_string = String(buffer, string_length); - - memdelete_arr(buffer); - - return final_string; + return String(buffer_persist.ptr(), string_length); } diff --git a/core/string/string_builder.h b/core/string/string_builder.h index 1a989e8422cf..0fb367dbf421 100644 --- a/core/string/string_builder.h +++ b/core/string/string_builder.h @@ -32,21 +32,24 @@ #define STRING_BUILDER_H #include "core/string/ustring.h" -#include "core/templates/vector.h" +#include "core/templates/local_vector.h" class StringBuilder { uint32_t string_length = 0; - Vector strings; - Vector c_strings; + LocalVector strings; + LocalVector c_strings; // -1 means it's a Godot String // a natural number means C string. - Vector appended_strings; + LocalVector appended_strings; + + mutable LocalVector buffer_persist; public: StringBuilder &append(const String &p_string); StringBuilder &append(const char *p_cstring); + void clear(); _FORCE_INLINE_ StringBuilder &operator+(const String &p_string) { return append(p_string); diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp index e89912d5bc68..4adab1c43c6e 100644 --- a/editor/gui/scene_tree_editor.cpp +++ b/editor/gui/scene_tree_editor.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/object/script_language.h" +#include "core/string/string_builder.h" #include "editor/editor_dock_manager.h" #include "editor/editor_file_system.h" #include "editor/editor_node.h" @@ -511,24 +512,36 @@ void SceneTreeEditor::_queue_update_node_tooltip(Node *p_node, TreeItem *p_item) } void SceneTreeEditor::_update_node_tooltip(Node *p_node, TreeItem *p_item) { + // Use static StringBuilder to reuse inner buffer, avoiding memory allocation. + static StringBuilder tooltip; + tooltip.clear(); // Display the node name in all tooltips so that long node names can be previewed // without having to rename them. - String tooltip = p_node->get_name(); + tooltip += p_node->get_name(); if (p_node == get_scene_node() && p_node->get_scene_inherited_state().is_valid()) { if (p_item->get_button_by_id(0, BUTTON_SUBSCENE) == -1) { p_item->add_button(0, get_editor_theme_icon(SNAME("InstanceOptions")), BUTTON_SUBSCENE, false, TTR("Open in Editor")); } - tooltip += String("\n" + TTR("Inherits:") + " " + p_node->get_scene_inherited_state()->get_path()); + tooltip += "\n"; + tooltip += TTR("Inherits:"); + tooltip += " "; + tooltip += p_node->get_scene_inherited_state()->get_path(); } else if (p_node != get_scene_node() && !p_node->get_scene_file_path().is_empty() && can_open_instance) { if (p_item->get_button_by_id(0, BUTTON_SUBSCENE) == -1) { p_item->add_button(0, get_editor_theme_icon(SNAME("InstanceOptions")), BUTTON_SUBSCENE, false, TTR("Open in Editor")); } - tooltip += String("\n" + TTR("Instance:") + " " + p_node->get_scene_file_path()); + tooltip += "\n"; + tooltip += TTR("Instance:"); + tooltip += " "; + tooltip += p_node->get_scene_file_path(); } StringName custom_type = EditorNode::get_singleton()->get_object_custom_type_name(p_node); - tooltip += "\n" + TTR("Type:") + " " + (custom_type != StringName() ? String(custom_type) : p_node->get_class()); + tooltip += "\n"; + tooltip += TTR("Type:"); + tooltip += " "; + tooltip += custom_type != StringName() ? String(custom_type) : p_node->get_class(); if (!p_node->get_editor_description().is_empty()) { const PackedInt32Array boundaries = TS->string_get_word_breaks(p_node->get_editor_description(), "", 80); @@ -537,11 +550,12 @@ void SceneTreeEditor::_update_node_tooltip(Node *p_node, TreeItem *p_item) { for (int i = 0; i < boundaries.size(); i += 2) { const int start = boundaries[i]; const int end = boundaries[i + 1]; - tooltip += "\n" + p_node->get_editor_description().substr(start, end - start + 1).rstrip("\n"); + tooltip += "\n"; + tooltip += p_node->get_editor_description().substr(start, end - start + 1).rstrip("\n"); } } - p_item->set_tooltip_text(0, tooltip); + p_item->set_tooltip_text(0, tooltip.as_string()); } void SceneTreeEditor::_node_visibility_changed(Node *p_node) { From 4fbaceb3cf8769f3d14f41a39ecd12a62d946c3a Mon Sep 17 00:00:00 2001 From: Yufeng Ying Date: Wed, 27 Nov 2024 17:01:27 +0800 Subject: [PATCH 2/4] Directly construct String --- core/string/string_builder.cpp | 12 +++++++----- core/string/string_builder.h | 2 -- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/string/string_builder.cpp b/core/string/string_builder.cpp index b025f49bbe1d..e5ae6c9dabca 100644 --- a/core/string/string_builder.cpp +++ b/core/string/string_builder.cpp @@ -61,7 +61,6 @@ void StringBuilder::clear() { strings.clear(); c_strings.clear(); appended_strings.clear(); - buffer_persist.clear(); } String StringBuilder::as_string() const { @@ -69,7 +68,8 @@ String StringBuilder::as_string() const { return ""; } - buffer_persist.resize(string_length); + String buffer = String(); + buffer.resize(string_length + 1); int current_position = 0; @@ -81,7 +81,7 @@ String StringBuilder::as_string() const { // Godot string const String &s = strings[godot_string_elem]; - memcpy(buffer_persist.ptr() + current_position, s.ptr(), s.length() * sizeof(char32_t)); + memcpy(buffer.ptrw() + current_position, s.ptr(), s.length() * sizeof(char32_t)); current_position += s.length(); @@ -90,7 +90,7 @@ String StringBuilder::as_string() const { const char *s = c_strings[c_string_elem]; for (int32_t j = 0; j < appended_strings[i]; j++) { - buffer_persist[current_position + j] = s[j]; + buffer[current_position + j] = s[j]; } current_position += appended_strings[i]; @@ -99,5 +99,7 @@ String StringBuilder::as_string() const { } } - return String(buffer_persist.ptr(), string_length); + buffer[current_position] = 0; + + return buffer; } diff --git a/core/string/string_builder.h b/core/string/string_builder.h index 0fb367dbf421..5b50ead81df4 100644 --- a/core/string/string_builder.h +++ b/core/string/string_builder.h @@ -44,8 +44,6 @@ class StringBuilder { // a natural number means C string. LocalVector appended_strings; - mutable LocalVector buffer_persist; - public: StringBuilder &append(const String &p_string); StringBuilder &append(const char *p_cstring); From a4f1f1d580705c7c4f13f8ce3533b93b7ac80ea3 Mon Sep 17 00:00:00 2001 From: YYF2333 <67693830+YYF233333@users.noreply.github.com> Date: Wed, 27 Nov 2024 18:58:58 +0800 Subject: [PATCH 3/4] Update core/string/string_builder.cpp Co-authored-by: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> --- core/string/string_builder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/string/string_builder.cpp b/core/string/string_builder.cpp index e5ae6c9dabca..ba93e3744a49 100644 --- a/core/string/string_builder.cpp +++ b/core/string/string_builder.cpp @@ -68,7 +68,7 @@ String StringBuilder::as_string() const { return ""; } - String buffer = String(); + String buffer; buffer.resize(string_length + 1); int current_position = 0; From dfb0b4e1e1cd637dbdbe362798c49d6aa7f96dcf Mon Sep 17 00:00:00 2001 From: Yufeng Ying Date: Thu, 28 Nov 2024 18:05:11 +0800 Subject: [PATCH 4/4] fix ptr --- core/string/string_builder.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/string/string_builder.cpp b/core/string/string_builder.cpp index ba93e3744a49..d08bcdb9d481 100644 --- a/core/string/string_builder.cpp +++ b/core/string/string_builder.cpp @@ -70,6 +70,7 @@ String StringBuilder::as_string() const { String buffer; buffer.resize(string_length + 1); + char32_t *buffer_ptr = buffer.ptrw(); int current_position = 0; @@ -81,7 +82,7 @@ String StringBuilder::as_string() const { // Godot string const String &s = strings[godot_string_elem]; - memcpy(buffer.ptrw() + current_position, s.ptr(), s.length() * sizeof(char32_t)); + memcpy(buffer_ptr + current_position, s.ptr(), s.length() * sizeof(char32_t)); current_position += s.length(); @@ -90,7 +91,7 @@ String StringBuilder::as_string() const { const char *s = c_strings[c_string_elem]; for (int32_t j = 0; j < appended_strings[i]; j++) { - buffer[current_position + j] = s[j]; + buffer_ptr[current_position + j] = s[j]; } current_position += appended_strings[i]; @@ -99,7 +100,7 @@ String StringBuilder::as_string() const { } } - buffer[current_position] = 0; + buffer_ptr[current_position] = 0; return buffer; }