From 95a0886f93cfb6fab6cfb8fc904527bc0b6d4599 Mon Sep 17 00:00:00 2001 From: Karroffel Date: Fri, 1 Sep 2017 15:43:23 +0200 Subject: [PATCH] added StringBuilder class When doing large string concatenations the default push_back on the String class can slow down things quite a bit. This is because it has to constantly reallocate the memory and copy the contents. This StringBuilder class delays the concatenation until the size of the resulting string is known. --- core/string_builder.cpp | 94 +++++++++++++++++++++++++++++++++++++++++ core/string_builder.h | 79 ++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 core/string_builder.cpp create mode 100644 core/string_builder.h diff --git a/core/string_builder.cpp b/core/string_builder.cpp new file mode 100644 index 00000000000..18c710ed2df --- /dev/null +++ b/core/string_builder.cpp @@ -0,0 +1,94 @@ +/*************************************************************************/ +/* string_builder.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "string_builder.h" + +#include + +StringBuilder &StringBuilder::append(const String &p_string) { + + strings.push_back(p_string); + appended_strings.push_back(-1); + + string_length += p_string.length(); + + return *this; +} + +StringBuilder &StringBuilder::append(const char *p_cstring) { + + int32_t len = strlen(p_cstring); + + c_strings.push_back(p_cstring); + appended_strings.push_back(len); + + string_length += len; + + return *this; +} + +String StringBuilder::as_string() const { + + CharType *buffer = memnew_arr(CharType, 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++) { + if (appended_strings[i] == -1) { + // Godot string + const String &s = strings[godot_string_elem]; + + memcpy(buffer + current_position, s.ptr(), s.length() * sizeof(CharType)); + + current_position += s.length(); + + godot_string_elem++; + } else { + + const char *s = c_strings[c_string_elem]; + + for (int32_t j = 0; j < appended_strings[i]; j++) { + buffer[current_position + j] = s[j]; + } + + current_position += appended_strings[i]; + + c_string_elem++; + } + } + + String final_string = String(buffer, string_length); + + memdelete_arr(buffer); + + return final_string; +} diff --git a/core/string_builder.h b/core/string_builder.h new file mode 100644 index 00000000000..7cf2f07872d --- /dev/null +++ b/core/string_builder.h @@ -0,0 +1,79 @@ +/*************************************************************************/ +/* string_builder.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef STRING_BUILDER_H +#define STRING_BUILDER_H + +#include "core/ustring.h" + +#include "core/vector.h" + +class StringBuilder { + + uint32_t string_length = 0; + + Vector strings; + Vector c_strings; + + // -1 means it's a Godot String + // a natural number means C string. + Vector appended_strings; + +public: + StringBuilder &append(const String &p_string); + StringBuilder &append(const char *p_cstring); + + _FORCE_INLINE_ StringBuilder &operator+(const String &p_string) { + return append(p_string); + } + + _FORCE_INLINE_ StringBuilder &operator+(const char *p_cstring) { + return append(p_cstring); + } + + _FORCE_INLINE_ void operator+=(const String &p_string) { + append(p_string); + } + + _FORCE_INLINE_ void operator+=(const char *p_cstring) { + append(p_cstring); + } + + _FORCE_INLINE_ int num_strings_appended() const { + return appended_strings.size(); + } + + String as_string() const; + + _FORCE_INLINE_ operator String() const { + return as_string(); + } +}; + +#endif // STRING_BUILDER_H