From be066984fed556fe1837f931532061890029a2ed Mon Sep 17 00:00:00 2001 From: Lukas Tenbrink Date: Fri, 29 Nov 2024 16:47:35 +0100 Subject: [PATCH] Soft-deprecate String constructors and assignment operators that implicitly parse the given string to find its end. Add known-length constructors and explicit from_c_str static methods. --- core/string/ustring.cpp | 211 ++++++------------------------- core/string/ustring.h | 225 +++++++++++++++++++++++++++++----- modules/openxr/openxr_api.cpp | 2 +- 3 files changed, 230 insertions(+), 208 deletions(-) diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index 9e99fc3b2f57..d2ed11d14d86 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -304,95 +304,43 @@ Error String::parse_url(String &r_scheme, String &r_host, int &r_port, String &r return OK; } -void String::copy_from(const char *p_cstr) { - // copy Latin-1 encoded c-string directly - if (!p_cstr) { - resize(0); - return; - } - - const size_t len = strlen(p_cstr); - - if (len == 0) { +void String::copy_from(const StrRange &p_cstr) { + if (p_cstr.len == 0) { resize(0); return; } - resize(len + 1); // include 0 + resize(p_cstr.len + 1); // include 0 + const char *src = p_cstr.c_str; + const char *end = src + p_cstr.len; char32_t *dst = ptrw(); - for (size_t i = 0; i <= len; i++) { -#if CHAR_MIN == 0 - uint8_t c = p_cstr[i]; -#else - uint8_t c = p_cstr[i] >= 0 ? p_cstr[i] : uint8_t(256 + p_cstr[i]); -#endif - if (c == 0 && i < len) { - print_unicode_error("NUL character", true); - dst[i] = _replacement_char; - } else { - dst[i] = c; - } + for (; src < end; ++src, ++dst) { + // If char is int8_t, a set sign bit will be reinterpreted as 256 - val implicitly. + *dst = static_cast(*src); } + *dst = 0; } -void String::copy_from(const char *p_cstr, const int p_clip_to) { - // copy Latin-1 encoded c-string directly - if (!p_cstr) { - resize(0); - return; - } - - int len = 0; - const char *ptr = p_cstr; - while ((p_clip_to < 0 || len < p_clip_to) && *(ptr++) != 0) { - len++; - } - - if (len == 0) { - resize(0); - return; - } - - resize(len + 1); // include 0 - - char32_t *dst = ptrw(); - - for (int i = 0; i < len; i++) { -#if CHAR_MIN == 0 - uint8_t c = p_cstr[i]; -#else - uint8_t c = p_cstr[i] >= 0 ? p_cstr[i] : uint8_t(256 + p_cstr[i]); -#endif - if (c == 0) { - print_unicode_error("NUL character", true); - dst[i] = _replacement_char; - } else { - dst[i] = c; - } - } - dst[len] = 0; -} - -void String::copy_from(const wchar_t *p_cstr) { +void String::copy_from(const StrRange &p_cstr) { #ifdef WINDOWS_ENABLED // wchar_t is 16-bit, parse as UTF-16 - parse_utf16((const char16_t *)p_cstr); + // TODO parse_utf16 does not currently support passing in a known length to save time. + parse_utf16((const char16_t *)p_cstr.c_str); #else // wchar_t is 32-bit, copy directly - copy_from((const char32_t *)p_cstr); + copy_from((StrRange &)p_cstr); #endif } -void String::copy_from(const wchar_t *p_cstr, const int p_clip_to) { -#ifdef WINDOWS_ENABLED - // wchar_t is 16-bit, parse as UTF-16 - parse_utf16((const char16_t *)p_cstr, p_clip_to); -#else - // wchar_t is 32-bit, copy directly - copy_from((const char32_t *)p_cstr, p_clip_to); -#endif +void String::copy_from(const StrRange &p_cstr) { + if (p_cstr.len == 0) { + resize(0); + return; + } + + copy_from_unchecked(p_cstr.c_str, p_cstr.len); } void String::copy_from(const char32_t &p_char) { @@ -418,84 +366,42 @@ void String::copy_from(const char32_t &p_char) { dst[1] = 0; } -void String::copy_from(const char32_t *p_cstr) { - if (!p_cstr) { - resize(0); - return; - } - - int len = 0; - const char32_t *ptr = p_cstr; - while (*(ptr++) != 0) { - len++; - } - - if (len == 0) { - resize(0); - return; - } - - copy_from_unchecked(p_cstr, len); -} - -void String::copy_from(const char32_t *p_cstr, const int p_clip_to) { - if (!p_cstr) { - resize(0); - return; - } - - int len = 0; - const char32_t *ptr = p_cstr; - while ((p_clip_to < 0 || len < p_clip_to) && *(ptr++) != 0) { - len++; - } - - if (len == 0) { - resize(0); - return; - } - - copy_from_unchecked(p_cstr, len); -} - // assumes the following have already been validated: // p_char != nullptr // p_length > 0 // p_length <= p_char strlen void String::copy_from_unchecked(const char32_t *p_char, const int p_length) { resize(p_length + 1); + + const char32_t *end = p_char + p_length; char32_t *dst = ptrw(); - dst[p_length] = 0; - for (int i = 0; i < p_length; i++) { - if (p_char[i] == 0) { - print_unicode_error("NUL character", true); - dst[i] = _replacement_char; + for (; p_char < end; ++p_char, ++dst) { + const char32_t chr = *p_char; + if ((chr & 0xfffff800) == 0xd800) { + print_unicode_error(vformat("Unpaired surrogate (%x)", (uint32_t)chr)); + *dst = _replacement_char; continue; } - if ((p_char[i] & 0xfffff800) == 0xd800) { - print_unicode_error(vformat("Unpaired surrogate (%x)", (uint32_t)p_char[i])); - dst[i] = _replacement_char; + if (chr > 0x10ffff) { + print_unicode_error(vformat("Invalid unicode codepoint (%x)", (uint32_t)chr)); + *dst = _replacement_char; continue; } - if (p_char[i] > 0x10ffff) { - print_unicode_error(vformat("Invalid unicode codepoint (%x)", (uint32_t)p_char[i])); - dst[i] = _replacement_char; - continue; - } - dst[i] = p_char[i]; + *dst = chr; } + *dst = 0; } -void String::operator=(const char *p_str) { +void String::operator=(const StrRange &p_str) { copy_from(p_str); } -void String::operator=(const char32_t *p_str) { +void String::operator=(const StrRange &p_str) { copy_from(p_str); } -void String::operator=(const wchar_t *p_str) { +void String::operator=(const StrRange &p_str) { copy_from(p_str); } @@ -629,12 +535,7 @@ String &String::operator+=(char32_t p_char) { bool String::operator==(const char *p_str) const { // compare Latin-1 encoded c-string - int len = 0; - const char *aux = p_str; - - while (*(aux++) != 0) { - len++; - } + int len = strlen(p_str); if (length() != len) { return false; @@ -668,12 +569,7 @@ bool String::operator==(const wchar_t *p_str) const { } bool String::operator==(const char32_t *p_str) const { - int len = 0; - const char32_t *aux = p_str; - - while (*(aux++) != 0) { - len++; - } + const int len = strlen(p_str); if (length() != len) { return false; @@ -719,7 +615,7 @@ bool String::operator==(const String &p_str) const { return true; } -bool String::operator==(const StrRange &p_str_range) const { +bool String::operator==(const StrRange &p_str_range) const { int len = p_str_range.len; if (length() != len) { @@ -2525,37 +2421,6 @@ Char16String String::utf16() const { return utf16s; } -String::String(const char *p_str) { - copy_from(p_str); -} - -String::String(const wchar_t *p_str) { - copy_from(p_str); -} - -String::String(const char32_t *p_str) { - copy_from(p_str); -} - -String::String(const char *p_str, int p_clip_to_len) { - copy_from(p_str, p_clip_to_len); -} - -String::String(const wchar_t *p_str, int p_clip_to_len) { - copy_from(p_str, p_clip_to_len); -} - -String::String(const char32_t *p_str, int p_clip_to_len) { - copy_from(p_str, p_clip_to_len); -} - -String::String(const StrRange &p_range) { - if (!p_range.c_str) { - return; - } - copy_from(p_range.c_str, p_range.len); -} - int64_t String::hex_to_int() const { int len = length(); if (len == 0) { diff --git a/core/string/ustring.h b/core/string/ustring.h index d6e563223a90..d48c11f8345b 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -39,6 +39,95 @@ #include "core/typedefs.h" #include "core/variant/array.h" +#ifdef GODOT_SHOW_STR_DEPRECATIONS +#define GODOT_STR_CONSTRUCTOR_DEPRECATED [[deprecated("Use a known-length constructor or String::from_c_str(x).")]] +#define GODOT_STR_CONVERSION_DEPRECATED [[deprecated("Implicit conversion deprecated, use StrRange conversions or .get_data().")]] +#else +#define GODOT_STR_CONSTRUCTOR_DEPRECATED +#define GODOT_STR_CONVERSION_DEPRECATED +#endif + +/*************************************************************************/ +/* Utility Functions */ +/*************************************************************************/ + +// Not defined by std. +// strlen equivalent function for char32_t * arguments. +constexpr size_t strlen(const char16_t *p_str) { + const char16_t *ptr = p_str; + while (*ptr != 0) { + ++ptr; + } + return ptr - p_str; +} + +constexpr size_t strlen(const char32_t *p_str) { + const char32_t *ptr = p_str; + while (*ptr != 0) { + ++ptr; + } + return ptr - p_str; +} + +constexpr size_t _strlen_clipped(const char *p_str, int p_clip_to_len) { + if (p_clip_to_len < 0) { + return strlen(p_str); + } + + int len = 0; + while (len < p_clip_to_len && *(p_str++) != 0) { + len++; + } + return len; +} + +constexpr size_t _strlen_clipped(const char32_t *p_str, int p_clip_to_len) { + if (p_clip_to_len < 0) { + return strlen(p_str); + } + + int len = 0; + while (len < p_clip_to_len && *(p_str++) != 0) { + len++; + } + return len; +} + +constexpr size_t strlen(const wchar_t *str) { + // Use static_cast twice because reinterpret_cast is not allowed in constexpr +#ifdef WINDOWS_ENABLED + // wchar_t is 16-bit + return strlen(static_cast(static_cast(str))); +#else + // wchar_t is 32-bit + return strlen(static_cast(static_cast(str))); +#endif +} + +/*************************************************************************/ +/* StrRange */ +/*************************************************************************/ + +template +struct StrRange { + const Element *c_str; + size_t len; + + explicit StrRange(const std::nullptr_t p_cstring) : + c_str(nullptr), len(0) {} + + explicit StrRange(const Element *p_cstring, const size_t p_len) : + c_str(p_cstring), len(p_len) {} + + template + explicit StrRange(const Element (&p_cstring)[len]) : + c_str(p_cstring), len(strlen(p_cstring)) {} + + static StrRange from_c_str(const Element *p_cstring) { + return StrRange(p_cstring, p_cstring ? strlen(p_cstring) : 0); + } +}; + /*************************************************************************/ /* CharProxy */ /*************************************************************************/ @@ -118,7 +207,8 @@ class Char16String { Char16String &operator+=(char16_t p_char); int length() const { return size() ? size() - 1 : 0; } const char16_t *get_data() const; - operator const char16_t *() const { return get_data(); } + GODOT_STR_CONVERSION_DEPRECATED operator const char16_t *() const { return get_data(); } + explicit operator const StrRange() const { return StrRange(get_data(), length()); } protected: void copy_from(const char16_t *p_cstr); @@ -160,7 +250,8 @@ class CharString { CharString &operator+=(char p_char); int length() const { return size() ? size() - 1 : 0; } const char *get_data() const; - operator const char *() const { return get_data(); } + GODOT_STR_CONVERSION_DEPRECATED operator const char *() const { return get_data(); } + explicit operator const StrRange() const { return StrRange(get_data(), length()); } protected: void copy_from(const char *p_cstr); @@ -170,32 +261,50 @@ class CharString { /* String */ /*************************************************************************/ -struct StrRange { - const char32_t *c_str; - int len; - - StrRange(const char32_t *p_c_str = nullptr, int p_len = 0) { - c_str = p_c_str; - len = p_len; - } -}; - class String { CowData _cowdata; static const char32_t _null; static const char32_t _replacement_char; - void copy_from(const char *p_cstr); - void copy_from(const char *p_cstr, const int p_clip_to); - void copy_from(const wchar_t *p_cstr); - void copy_from(const wchar_t *p_cstr, const int p_clip_to); - void copy_from(const char32_t *p_cstr); - void copy_from(const char32_t *p_cstr, const int p_clip_to); - + // Known-length copy. + void copy_from(const StrRange &p_cstr); + void copy_from(const StrRange &p_cstr); + void copy_from(const StrRange &p_cstr); void copy_from(const char32_t &p_char); - void copy_from_unchecked(const char32_t *p_char, const int p_length); + // Legacy for NULL-terminated c string. + void copy_from(const char *p_cstr) { + copy_from(StrRange::from_c_str(p_cstr)); + } + void copy_from(const char *p_cstr, const int p_clip_to) { + copy_from(StrRange(p_cstr, p_cstr ? _strlen_clipped(p_cstr, p_clip_to) : 0)); + } + void copy_from(const char32_t *p_cstr) { + copy_from(StrRange::from_c_str(p_cstr)); + } + void copy_from(const char32_t *p_cstr, const int p_clip_to) { + copy_from(StrRange(p_cstr, p_cstr ? _strlen_clipped(p_cstr, p_clip_to) : 0)); + } + void copy_from(const wchar_t *p_cstr) { +#ifdef WINDOWS_ENABLED + // wchar_t is 16-bit, parse as UTF-16 + parse_utf16((const char16_t *)p_cstr); +#else + // wchar_t is 32-bit, copy directly + copy_from((const char32_t *)p_cstr); +#endif + } + void copy_from(const wchar_t *p_cstr, const int p_clip_to) { +#ifdef WINDOWS_ENABLED + // wchar_t is 16-bit, parse as UTF-16 + parse_utf16((const char16_t *)p_cstr, p_clip_to); +#else + // wchar_t is 32-bit, copy directly + copy_from((const char32_t *)p_cstr, p_clip_to); +#endif + } + bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const; int _count(const String &p_string, int p_from, int p_to, bool p_case_insensitive) const; int _count(const char *p_string, int p_from, int p_to, bool p_case_insensitive) const; @@ -227,6 +336,8 @@ class String { } _FORCE_INLINE_ CharProxy operator[](int p_index) { return CharProxy(p_index, _cowdata); } + /* Compatibility Operators */ + bool operator==(const String &p_str) const; bool operator!=(const String &p_str) const; String operator+(const String &p_str) const; @@ -238,16 +349,10 @@ class String { String &operator+=(const wchar_t *p_str); String &operator+=(const char32_t *p_str); - /* Compatibility Operators */ - - void operator=(const char *p_str); - void operator=(const wchar_t *p_str); - void operator=(const char32_t *p_str); - bool operator==(const char *p_str) const; bool operator==(const wchar_t *p_str) const; bool operator==(const char32_t *p_str) const; - bool operator==(const StrRange &p_str_range) const; + bool operator==(const StrRange &p_str_range) const; bool operator!=(const char *p_str) const; bool operator!=(const wchar_t *p_str) const; @@ -492,13 +597,65 @@ class String { Vector to_utf32_buffer() const; Vector to_wchar_buffer() const; - String(const char *p_str); - String(const wchar_t *p_str); - String(const char32_t *p_str); - String(const char *p_str, int p_clip_to_len); - String(const wchar_t *p_str, int p_clip_to_len); - String(const char32_t *p_str, int p_clip_to_len); - String(const StrRange &p_range); + // Constructors from known-length strings. + String(const StrRange &p_str) { + copy_from(p_str); + } + String(const StrRange &p_str) { + copy_from(p_str); + } + String(const StrRange &p_str) { + copy_from(p_str); + } + + // Constructor for string literals. + template + String(const Element (&p_str)[len]) : + String(StrRange(p_str, strlen(p_str))) {} + + // Constructor for string literals. + template + String(const Element (&p_str)[len], int p_clip_to) : + String(StrRange(p_str, p_clip_to < 0 ? strlen(p_str) : MIN(strlen(p_str), (size_t)p_clip_to))) {} + + // Legacy constructor from a NULL terminated c-string, which is automatically parsed to find the length. + template >, typename = std::enable_if_t>>, typename = std::enable_if_t>>> + GODOT_STR_CONSTRUCTOR_DEPRECATED String(const Element &p_str, int p_clip_t = -1) { + copy_from(p_str, p_clip_t); + } + + static String from_c_str(const char *p_c_str) { + return String(StrRange::from_c_str(p_c_str)); + } + + static String from_c_str(const wchar_t *p_c_str) { + String s; + s.copy_from(p_c_str); + return s; + } + + static String from_c_str(const char32_t *p_c_str) { + return String(StrRange::from_c_str(p_c_str)); + } + + // Copy assignment for known-length strings. + void operator=(const StrRange &p_str); + void operator=(const StrRange &p_str); + void operator=(const StrRange &p_str); + + // Copy assignment for string literals. + template + void operator=(const Element (&p_str)[len]) { + operator=(StrRange(p_str, strlen(p_str))); + } + + // Legacy copy assignment from a NULL terminated c-string, which is automatically parsed to find the length. + template >, typename = std::enable_if_t>>, typename = std::enable_if_t>>> + GODOT_STR_CONSTRUCTOR_DEPRECATED void operator=(const Element &p_str) { + copy_from(p_str); + } + + explicit operator const StrRange() const { return StrRange(get_data(), length()); } }; bool operator==(const char *p_chr, const String &p_str); diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 17755417578a..4bb6a63fd2cc 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -552,7 +552,7 @@ bool OpenXRAPI::create_instance() { Vector extension_ptrs; for (int i = 0; i < enabled_extensions.size(); i++) { - print_verbose(String("OpenXR: Enabling extension ") + String(enabled_extensions[i])); + print_verbose(String("OpenXR: Enabling extension ") + String(enabled_extensions[i].get_data())); extension_ptrs.push_back(enabled_extensions[i].get_data()); }