From ed3015e97962cfe483e9206601bb9c6ab7648c9a Mon Sep 17 00:00:00 2001 From: Jan Haller Date: Sun, 30 Jul 2023 15:40:38 +0200 Subject: [PATCH] GDExtension: construct StringName directly from char* So far, an indirection via String was necessary, causing at least 2 allocations and copies (String; String inside StringName). Since StringNames often refer to string literals, this allows them to be directly constructed from C strings. There are two formats: Latin-1 and UTF-8. The Latin-1 constructor also provides the `p_is_static` flag: when the source has static storage duration, no copy/allocation will be needed. However, the extension developer needs to uphold this lifetime guarantee. --- core/extension/gdextension_interface.cpp | 21 +++++++++++ core/extension/gdextension_interface.h | 44 ++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp index f57a5c18734..f1eb0fcbbc0 100644 --- a/core/extension/gdextension_interface.cpp +++ b/core/extension/gdextension_interface.cpp @@ -877,6 +877,24 @@ static GDExtensionInt gdextension_string_resize(GDExtensionStringPtr p_self, GDE return (*self).resize(p_length); } +static void gdextension_string_name_new_with_latin1_chars(GDExtensionUninitializedStringNamePtr r_dest, const char *p_contents, GDExtensionBool p_is_static) { + memnew_placement(r_dest, StringName(p_contents, static_cast(p_is_static))); +} + +static void gdextension_string_name_new_with_utf8_chars(GDExtensionUninitializedStringNamePtr r_dest, const char *p_contents) { + String tmp; + tmp.parse_utf8(p_contents); + + memnew_placement(r_dest, StringName(tmp)); +} + +static void gdextension_string_name_new_with_utf8_chars_and_len(GDExtensionUninitializedStringNamePtr r_dest, const char *p_contents, GDExtensionInt p_size) { + String tmp; + tmp.parse_utf8(p_contents, p_size); + + memnew_placement(r_dest, StringName(tmp)); +} + static GDExtensionInt gdextension_xml_parser_open_buffer(GDExtensionObjectPtr p_instance, const uint8_t *p_buffer, size_t p_size) { XMLParser *xml = (XMLParser *)p_instance; return (GDExtensionInt)xml->_open_buffer(p_buffer, p_size); @@ -1426,6 +1444,9 @@ void gdextension_setup_interface() { REGISTER_INTERFACE_FUNC(string_operator_plus_eq_wcstr); REGISTER_INTERFACE_FUNC(string_operator_plus_eq_c32str); REGISTER_INTERFACE_FUNC(string_resize); + REGISTER_INTERFACE_FUNC(string_name_new_with_latin1_chars); + REGISTER_INTERFACE_FUNC(string_name_new_with_utf8_chars); + REGISTER_INTERFACE_FUNC(string_name_new_with_utf8_chars_and_len); REGISTER_INTERFACE_FUNC(xml_parser_open_buffer); REGISTER_INTERFACE_FUNC(file_access_store_buffer); REGISTER_INTERFACE_FUNC(file_access_get_buffer); diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h index 48cb28832af..63a3cb0541b 100644 --- a/core/extension/gdextension_interface.h +++ b/core/extension/gdextension_interface.h @@ -1664,6 +1664,50 @@ typedef void (*GDExtensionInterfaceStringOperatorPlusEqC32str)(GDExtensionString */ typedef GDExtensionInt (*GDExtensionInterfaceStringResize)(GDExtensionStringPtr p_self, GDExtensionInt p_resize); +/* INTERFACE: StringName Utilities */ + +/** + * @name string_name_new_with_latin1_chars + * @since 4.2 + * + * Creates a StringName from a Latin-1 encoded C string. + * + * If `p_is_static` is true, then: + * - The StringName will reuse the `p_contents` buffer instead of copying it. + * You must guarantee that the buffer remains valid for the duration of the application (e.g. string literal). + * - You must not call a destructor for this StringName. Incrementing the initial reference once should achieve this. + * + * `p_is_static` is purely an optimization and can easily introduce undefined behavior if used wrong. In case of doubt, set it to false. + * + * @param r_dest A pointer to uninitialized storage, into which the newly created StringName is constructed. + * @param p_contents A pointer to a C string (null terminated and Latin-1 or ASCII encoded). + * @param p_is_static Whether the StringName reuses the buffer directly (see above). + */ +typedef void (*GDExtensionInterfaceStringNameNewWithLatin1Chars)(GDExtensionUninitializedStringNamePtr r_dest, const char *p_contents, GDExtensionBool p_is_static); + +/** + * @name string_name_new_with_utf8_chars + * @since 4.2 + * + * Creates a StringName from a UTF-8 encoded C string. + * + * @param r_dest A pointer to uninitialized storage, into which the newly created StringName is constructed. + * @param p_contents A pointer to a C string (null terminated and UTF-8 encoded). + */ +typedef void (*GDExtensionInterfaceStringNameNewWithUtf8Chars)(GDExtensionUninitializedStringNamePtr r_dest, const char *p_contents); + +/** + * @name string_name_new_with_utf8_chars_and_len + * @since 4.2 + * + * Creates a StringName from a UTF-8 encoded string with a given number of characters. + * + * @param r_dest A pointer to uninitialized storage, into which the newly created StringName is constructed. + * @param p_contents A pointer to a C string (null terminated and UTF-8 encoded). + * @param p_size The number of bytes (not UTF-8 code points). + */ +typedef void (*GDExtensionInterfaceStringNameNewWithUtf8CharsAndLen)(GDExtensionUninitializedStringNamePtr r_dest, const char *p_contents, GDExtensionInt p_size); + /* INTERFACE: XMLParser Utilities */ /**