Merge pull request #939 from bruvzg/gde_low_level_funcs_cpp

Expose some low level functions and String operators.
pull/1005/head
Rémi Verschelde 2023-01-19 13:55:24 +01:00
commit 07e2e20f7b
No known key found for this signature in database
GPG Key ID: C3336907360768E1
11 changed files with 623 additions and 1049 deletions

View File

@ -367,6 +367,15 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
result.append("#include <godot_cpp/variant/char_utils.hpp>") result.append("#include <godot_cpp/variant/char_utils.hpp>")
result.append("#include <godot_cpp/variant/ucaps.hpp>") result.append("#include <godot_cpp/variant/ucaps.hpp>")
if class_name == "PackedStringArray":
result.append("#include <godot_cpp/variant/string.hpp>")
if class_name == "PackedColorArray":
result.append("#include <godot_cpp/variant/color.hpp>")
if class_name == "PackedVector2Array":
result.append("#include <godot_cpp/variant/vector2.hpp>")
if class_name == "PackedVector3Array":
result.append("#include <godot_cpp/variant/vector3.hpp>")
if class_name == "Array": if class_name == "Array":
result.append("#include <godot_cpp/variant/array_helpers.hpp>") result.append("#include <godot_cpp/variant/array_helpers.hpp>")
@ -584,10 +593,17 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
result.append("\tbool operator!=(const wchar_t *p_str) const;") result.append("\tbool operator!=(const wchar_t *p_str) const;")
result.append("\tbool operator!=(const char16_t *p_str) const;") result.append("\tbool operator!=(const char16_t *p_str) const;")
result.append("\tbool operator!=(const char32_t *p_str) const;") result.append("\tbool operator!=(const char32_t *p_str) const;")
result.append("\tString operator+(const char *p_chr);") result.append("\tString operator+(const char *p_str);")
result.append("\tString operator+(const wchar_t *p_chr);") result.append("\tString operator+(const wchar_t *p_str);")
result.append("\tString operator+(const char16_t *p_chr);") result.append("\tString operator+(const char16_t *p_str);")
result.append("\tString operator+(const char32_t *p_chr);") result.append("\tString operator+(const char32_t *p_str);")
result.append("\tString operator+(char32_t p_char);")
result.append("\tString &operator+=(const String &p_str);")
result.append("\tString &operator+=(char32_t p_char);")
result.append("\tString &operator+=(const char *p_str);")
result.append("\tString &operator+=(const wchar_t *p_str);")
result.append("\tString &operator+=(const char32_t *p_str);")
result.append("\tconst char32_t &operator[](int p_index) const;") result.append("\tconst char32_t &operator[](int p_index) const;")
result.append("\tchar32_t &operator[](int p_index);") result.append("\tchar32_t &operator[](int p_index);")
result.append("\tconst char32_t *ptr() const;") result.append("\tconst char32_t *ptr() const;")
@ -611,6 +627,72 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
result.append(f"\t" + return_type + f" &operator[](int p_index);") result.append(f"\t" + return_type + f" &operator[](int p_index);")
result.append(f"\tconst " + return_type + f" *ptr() const;") result.append(f"\tconst " + return_type + f" *ptr() const;")
result.append(f"\t" + return_type + f" *ptrw();") result.append(f"\t" + return_type + f" *ptrw();")
iterators = """
struct Iterator {
_FORCE_INLINE_ $TYPE &operator*() const {
return *elem_ptr;
}
_FORCE_INLINE_ $TYPE *operator->() const { return elem_ptr; }
_FORCE_INLINE_ Iterator &operator++() {
elem_ptr++;
return *this;
}
_FORCE_INLINE_ Iterator &operator--() {
elem_ptr--;
return *this;
}
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return elem_ptr == b.elem_ptr; }
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return elem_ptr != b.elem_ptr; }
Iterator($TYPE *p_ptr) { elem_ptr = p_ptr; }
Iterator() {}
Iterator(const Iterator &p_it) { elem_ptr = p_it.elem_ptr; }
private:
$TYPE *elem_ptr = nullptr;
};
struct ConstIterator {
_FORCE_INLINE_ const $TYPE &operator*() const {
return *elem_ptr;
}
_FORCE_INLINE_ const $TYPE *operator->() const { return elem_ptr; }
_FORCE_INLINE_ ConstIterator &operator++() {
elem_ptr++;
return *this;
}
_FORCE_INLINE_ ConstIterator &operator--() {
elem_ptr--;
return *this;
}
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return elem_ptr == b.elem_ptr; }
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return elem_ptr != b.elem_ptr; }
ConstIterator(const $TYPE *p_ptr) { elem_ptr = p_ptr; }
ConstIterator() {}
ConstIterator(const ConstIterator &p_it) { elem_ptr = p_it.elem_ptr; }
private:
const $TYPE *elem_ptr = nullptr;
};
_FORCE_INLINE_ Iterator begin() {
return Iterator(ptrw());
}
_FORCE_INLINE_ Iterator end() {
return Iterator(ptrw() + size());
}
_FORCE_INLINE_ ConstIterator begin() const {
return ConstIterator(ptr());
}
_FORCE_INLINE_ ConstIterator end() const {
return ConstIterator(ptr() + size());
}
"""
result.append(iterators.replace("$TYPE", return_type))
if class_name == "Array": if class_name == "Array":
result.append(f"\tconst Variant &operator[](int p_index) const;") result.append(f"\tconst Variant &operator[](int p_index) const;")
@ -636,6 +718,7 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
result.append("String operator+(const wchar_t *p_chr, const String &p_str);") result.append("String operator+(const wchar_t *p_chr, const String &p_str);")
result.append("String operator+(const char16_t *p_chr, const String &p_str);") result.append("String operator+(const char16_t *p_chr, const String &p_str);")
result.append("String operator+(const char32_t *p_chr, const String &p_str);") result.append("String operator+(const char32_t *p_chr, const String &p_str);")
result.append("String operator+(char32_t p_char, const String &p_str);")
result.append("String itos(int64_t p_val);") result.append("String itos(int64_t p_val);")
result.append("String uitos(uint64_t p_val);") result.append("String uitos(uint64_t p_val);")
@ -1252,6 +1335,26 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
result.append("public:") result.append("public:")
# Special cases. # Special cases.
if class_name == "XMLParser":
result.append("\tError _open_buffer(const uint8_t *p_buffer, size_t p_size);")
if class_name == "FileAccess":
result.append("\tuint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;")
result.append("\tvoid store_buffer(const uint8_t *p_src, uint64_t p_length);")
if class_name == "WorkerThreadPool":
result.append("\tenum {")
result.append("\tINVALID_TASK_ID = -1")
result.append("\t};")
result.append("\ttypedef int64_t TaskID;")
result.append("\ttypedef int64_t GroupID;")
result.append(
"\tTaskID add_native_task(void (*p_func)(void *), void *p_userdata, bool p_high_priority = false, const String &p_description = String());"
)
result.append(
"\tGroupID add_native_group_task(void (*p_func)(void *, uint32_t), void *p_userdata, int p_elements, int p_tasks = -1, bool p_high_priority = false, const String &p_description = String());"
)
if class_name == "Object": if class_name == "Object":
result.append("") result.append("")

File diff suppressed because it is too large Load Diff

View File

@ -503,6 +503,26 @@ typedef struct {
char32_t *(*string_operator_index)(GDExtensionStringPtr p_self, GDExtensionInt p_index); char32_t *(*string_operator_index)(GDExtensionStringPtr p_self, GDExtensionInt p_index);
const char32_t *(*string_operator_index_const)(GDExtensionConstStringPtr p_self, GDExtensionInt p_index); const char32_t *(*string_operator_index_const)(GDExtensionConstStringPtr p_self, GDExtensionInt p_index);
void (*string_operator_plus_eq_string)(GDExtensionStringPtr p_self, GDExtensionConstStringPtr p_b);
void (*string_operator_plus_eq_char)(GDExtensionStringPtr p_self, char32_t p_b);
void (*string_operator_plus_eq_cstr)(GDExtensionStringPtr p_self, const char *p_b);
void (*string_operator_plus_eq_wcstr)(GDExtensionStringPtr p_self, const wchar_t *p_b);
void (*string_operator_plus_eq_c32str)(GDExtensionStringPtr p_self, const char32_t *p_b);
/* XMLParser extra utilities */
GDExtensionInt (*xml_parser_open_buffer)(GDExtensionObjectPtr p_instance, const uint8_t *p_buffer, size_t p_size);
/* FileAccess extra utilities */
void (*file_access_store_buffer)(GDExtensionObjectPtr p_instance, const uint8_t *p_src, uint64_t p_length);
uint64_t (*file_access_get_buffer)(GDExtensionConstObjectPtr p_instance, uint8_t *p_dst, uint64_t p_length);
/* WorkerThreadPool extra utilities */
int64_t (*worker_thread_pool_add_native_group_task)(GDExtensionObjectPtr p_instance, void (*p_func)(void *, uint32_t), void *p_userdata, int p_elements, int p_tasks, bool p_high_priority, GDExtensionConstStringPtr p_description);
int64_t (*worker_thread_pool_add_native_task)(GDExtensionObjectPtr p_instance, void (*p_func)(void *), void *p_userdata, bool p_high_priority, GDExtensionConstStringPtr p_description);
/* Packed array functions */ /* Packed array functions */
uint8_t *(*packed_byte_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedByteArray uint8_t *(*packed_byte_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedByteArray

View File

@ -38,6 +38,171 @@
#include <cmath> #include <cmath>
namespace godot { namespace godot {
#define Math_SQRT12 0.7071067811865475244008443621048490
#define Math_SQRT2 1.4142135623730950488016887242
#define Math_LN2 0.6931471805599453094172321215
#define Math_PI 3.1415926535897932384626433833
#define Math_TAU 6.2831853071795864769252867666
#define Math_E 2.7182818284590452353602874714
#define Math_INF INFINITY
#define Math_NAN NAN
// Make room for our constexpr's below by overriding potential system-specific macros.
#undef ABS
#undef SIGN
#undef MIN
#undef MAX
#undef CLAMP
// Generic ABS function, for math uses please use Math::abs.
template <typename T>
constexpr T ABS(T m_v) {
return m_v < 0 ? -m_v : m_v;
}
template <typename T>
constexpr const T SIGN(const T m_v) {
return m_v == 0 ? 0.0f : (m_v < 0 ? -1.0f : +1.0f);
}
template <typename T, typename T2>
constexpr auto MIN(const T m_a, const T2 m_b) {
return m_a < m_b ? m_a : m_b;
}
template <typename T, typename T2>
constexpr auto MAX(const T m_a, const T2 m_b) {
return m_a > m_b ? m_a : m_b;
}
template <typename T, typename T2, typename T3>
constexpr auto CLAMP(const T m_a, const T2 m_min, const T3 m_max) {
return m_a < m_min ? m_min : (m_a > m_max ? m_max : m_a);
}
// Generic swap template.
#ifndef SWAP
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
template <class T>
inline void __swap_tmpl(T &x, T &y) {
T aux = x;
x = y;
y = aux;
}
#endif // SWAP
/* Functions to handle powers of 2 and shifting. */
// Function to find the next power of 2 to an integer.
static _FORCE_INLINE_ unsigned int next_power_of_2(unsigned int x) {
if (x == 0) {
return 0;
}
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return ++x;
}
// Function to find the previous power of 2 to an integer.
static _FORCE_INLINE_ unsigned int previous_power_of_2(unsigned int x) {
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x - (x >> 1);
}
// Function to find the closest power of 2 to an integer.
static _FORCE_INLINE_ unsigned int closest_power_of_2(unsigned int x) {
unsigned int nx = next_power_of_2(x);
unsigned int px = previous_power_of_2(x);
return (nx - x) > (x - px) ? px : nx;
}
// Get a shift value from a power of 2.
static inline int get_shift_from_power_of_2(unsigned int p_bits) {
for (unsigned int i = 0; i < 32; i++) {
if (p_bits == (unsigned int)(1 << i)) {
return i;
}
}
return -1;
}
template <class T>
static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) {
--x;
// The number of operations on x is the base two logarithm
// of the number of bits in the type. Add three to account
// for sizeof(T) being in bytes.
size_t num = get_shift_from_power_of_2(sizeof(T)) + 3;
// If the compiler is smart, it unrolls this loop.
// If it's dumb, this is a bit slow.
for (size_t i = 0; i < num; i++) {
x |= x >> (1 << i);
}
return ++x;
}
// Function to find the nearest (bigger) power of 2 to an integer.
static inline unsigned int nearest_shift(unsigned int p_number) {
for (int i = 30; i >= 0; i--) {
if (p_number & (1 << i)) {
return i + 1;
}
}
return 0;
}
// constexpr function to find the floored log2 of a number
template <typename T>
constexpr T floor_log2(T x) {
return x < 2 ? x : 1 + floor_log2(x >> 1);
}
// Get the number of bits needed to represent the number.
// IE, if you pass in 8, you will get 4.
// If you want to know how many bits are needed to store 8 values however, pass in (8 - 1).
template <typename T>
constexpr T get_num_bits(T x) {
return floor_log2(x);
}
// Swap 16, 32 and 64 bits value for endianness.
#if defined(__GNUC__)
#define BSWAP16(x) __builtin_bswap16(x)
#define BSWAP32(x) __builtin_bswap32(x)
#define BSWAP64(x) __builtin_bswap64(x)
#else
static inline uint16_t BSWAP16(uint16_t x) {
return (x >> 8) | (x << 8);
}
static inline uint32_t BSWAP32(uint32_t x) {
return ((x << 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x >> 24));
}
static inline uint64_t BSWAP64(uint64_t x) {
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
return x;
}
#endif
namespace Math { namespace Math {
// This epsilon should match the one used by Godot for consistency. // This epsilon should match the one used by Godot for consistency.
@ -53,43 +218,6 @@ namespace Math {
#define UNIT_EPSILON 0.001 #define UNIT_EPSILON 0.001
#endif #endif
#define Math_SQRT12 0.7071067811865475244008443621048490
#define Math_SQRT2 1.4142135623730950488016887242
#define Math_LN2 0.6931471805599453094172321215
#define Math_PI 3.1415926535897932384626433833
#define Math_TAU 6.2831853071795864769252867666
#define Math_E 2.7182818284590452353602874714
#define Math_INF INFINITY
#define Math_NAN NAN
// Windows badly defines a lot of stuff we'll never use. Undefine it.
#ifdef _WIN32
#undef MIN // override standard definition
#undef MAX // override standard definition
#undef CLAMP // override standard definition
#endif
// Generic ABS function, for math uses please use Math::abs.
#ifndef ABS
#define ABS(m_v) (((m_v) < 0) ? (-(m_v)) : (m_v))
#endif
#ifndef SIGN
#define SIGN(m_v) (((m_v) == 0) ? (0.0) : (((m_v) < 0) ? (-1.0) : (+1.0)))
#endif
#ifndef MIN
#define MIN(m_a, m_b) (((m_a) < (m_b)) ? (m_a) : (m_b))
#endif
#ifndef MAX
#define MAX(m_a, m_b) (((m_a) > (m_b)) ? (m_a) : (m_b))
#endif
#ifndef CLAMP
#define CLAMP(m_a, m_min, m_max) (((m_a) < (m_min)) ? (m_min) : (((m_a) > (m_max)) ? m_max : m_a))
#endif
// Functions reproduced as in Godot's source code `math_funcs.h`. // Functions reproduced as in Godot's source code `math_funcs.h`.
// Some are overloads to automatically support changing real_t into either double or float in the way Godot does. // Some are overloads to automatically support changing real_t into either double or float in the way Godot does.
@ -628,20 +756,6 @@ inline double pingpong(double value, double length) {
return (length != 0.0) ? abs(fract((value - length) / (length * 2.0)) * length * 2.0 - length) : 0.0; return (length != 0.0) ? abs(fract((value - length) / (length * 2.0)) * length * 2.0 - length) : 0.0;
} }
inline unsigned int next_power_of_2(unsigned int x) {
if (x == 0)
return 0;
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return ++x;
}
// This function should be as fast as possible and rounding mode should not matter. // This function should be as fast as possible and rounding mode should not matter.
inline int fast_ftoi(float a) { inline int fast_ftoi(float a) {
static int b; static int b;

View File

@ -91,7 +91,7 @@ private:
} }
_FORCE_INLINE_ size_t _get_alloc_size(size_t p_elements) const { _FORCE_INLINE_ size_t _get_alloc_size(size_t p_elements) const {
return Math::next_power_of_2(p_elements * sizeof(T)); return next_power_of_2(p_elements * sizeof(T));
} }
_FORCE_INLINE_ bool _get_alloc_size_checked(size_t p_elements, size_t *out) const { _FORCE_INLINE_ bool _get_alloc_size_checked(size_t p_elements, size_t *out) const {
@ -102,7 +102,7 @@ private:
*out = 0; *out = 0;
return false; return false;
} }
*out = Math::next_power_of_2(o); *out = next_power_of_2(o);
if (__builtin_add_overflow(o, static_cast<size_t>(32), &p)) { if (__builtin_add_overflow(o, static_cast<size_t>(32), &p)) {
return false; // No longer allocated here. return false; // No longer allocated here.
} }

View File

@ -322,6 +322,18 @@ struct VariantComparator {
static _FORCE_INLINE_ bool compare(const Variant &p_lhs, const Variant &p_rhs) { return p_lhs.hash_compare(p_rhs); } static _FORCE_INLINE_ bool compare(const Variant &p_lhs, const Variant &p_rhs) { return p_lhs.hash_compare(p_rhs); }
}; };
template <typename... VarArgs>
String vformat(const String &p_text, const VarArgs... p_args) {
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
Array args_array;
args_array.resize(sizeof...(p_args));
for (uint32_t i = 0; i < sizeof...(p_args); i++) {
args_array[i] = args[i];
}
return p_text % args_array;
}
} // namespace godot } // namespace godot
#endif // GODOT_VARIANT_HPP #endif // GODOT_VARIANT_HPP

58
src/classes/low_level.cpp Normal file
View File

@ -0,0 +1,58 @@
/**************************************************************************/
/* low_level.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 <godot_cpp/classes/file_access.hpp>
#include <godot_cpp/classes/worker_thread_pool.hpp>
#include <godot_cpp/classes/xml_parser.hpp>
#include <godot_cpp/godot.hpp>
namespace godot {
Error XMLParser::_open_buffer(const uint8_t *p_buffer, size_t p_size) {
return (Error)internal::gde_interface->xml_parser_open_buffer(_owner, p_buffer, p_size);
}
uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
return internal::gde_interface->file_access_get_buffer(_owner, p_dst, p_length);
}
void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) {
internal::gde_interface->file_access_store_buffer(_owner, p_src, p_length);
}
WorkerThreadPool::TaskID WorkerThreadPool::add_native_task(void (*p_func)(void *), void *p_userdata, bool p_high_priority, const String &p_description) {
return (TaskID)internal::gde_interface->worker_thread_pool_add_native_task(_owner, p_func, p_userdata, p_high_priority, (const GDExtensionStringPtr)&p_description);
}
WorkerThreadPool::GroupID WorkerThreadPool::add_native_group_task(void (*p_func)(void *, uint32_t), void *p_userdata, int p_elements, int p_tasks, bool p_high_priority, const String &p_description) {
return (GroupID)internal::gde_interface->worker_thread_pool_add_native_group_task(_owner, p_func, p_userdata, p_elements, p_tasks, p_high_priority, (const GDExtensionStringPtr)&p_description);
}
} // namespace godot

View File

@ -332,20 +332,49 @@ bool String::operator!=(const char32_t *p_str) const {
return *this != String(p_str); return *this != String(p_str);
} }
String String::operator+(const char *p_chr) { String String::operator+(const char *p_str) {
return *this + String(p_chr); return *this + String(p_str);
} }
String String::operator+(const wchar_t *p_chr) { String String::operator+(const wchar_t *p_str) {
return *this + String(p_chr); return *this + String(p_str);
} }
String String::operator+(const char16_t *p_chr) { String String::operator+(const char16_t *p_str) {
return *this + String(p_chr); return *this + String(p_str);
} }
String String::operator+(const char32_t *p_chr) { String String::operator+(const char32_t *p_str) {
return *this + String(p_chr); return *this + String(p_str);
}
String String::operator+(const char32_t p_char) {
return *this + String::chr(p_char);
}
String &String::operator+=(const String &p_str) {
internal::gde_interface->string_operator_plus_eq_string((GDExtensionStringPtr)this, (const GDExtensionStringPtr)&p_str);
return *this;
}
String &String::operator+=(char32_t p_char) {
internal::gde_interface->string_operator_plus_eq_char((GDExtensionStringPtr)this, p_char);
return *this;
}
String &String::operator+=(const char *p_str) {
internal::gde_interface->string_operator_plus_eq_cstr((GDExtensionStringPtr)this, p_str);
return *this;
}
String &String::operator+=(const wchar_t *p_str) {
internal::gde_interface->string_operator_plus_eq_wcstr((GDExtensionStringPtr)this, p_str);
return *this;
}
String &String::operator+=(const char32_t *p_str) {
internal::gde_interface->string_operator_plus_eq_c32str((GDExtensionStringPtr)this, p_str);
return *this;
} }
const char32_t &String::operator[](int p_index) const { const char32_t &String::operator[](int p_index) const {
@ -412,6 +441,10 @@ String operator+(const char32_t *p_chr, const String &p_str) {
return String(p_chr) + p_str; return String(p_chr) + p_str;
} }
String operator+(char32_t p_char, const String &p_str) {
return String::chr(p_char) + p_str;
}
StringName::StringName(const char *from) : StringName::StringName(const char *from) :
StringName(String(from)) {} StringName(String(from)) {}

View File

@ -54,6 +54,15 @@ func _ready():
var array: Array[int] = [1, 2, 3] var array: Array[int] = [1, 2, 3]
$Example.test_tarray_arg(array) $Example.test_tarray_arg(array)
prints("String += operator")
prints(" test string +=", $Example.test_string_ops())
prints("WorkerThreadPool")
prints(" test worker_thread_pool", $Example.test_workpool_ops())
prints("PackedArray iterators")
prints(" test packed array iterators", $Example.test_vector_ops())
prints("Properties") prints("Properties")
prints(" custom position is", $Example.group_subgroup_custom_position) prints(" custom position is", $Example.group_subgroup_custom_position)
$Example.group_subgroup_custom_position = Vector2(50, 50) $Example.group_subgroup_custom_position = Vector2(50, 50)

View File

@ -123,6 +123,8 @@ void Example::_bind_methods() {
ClassDB::bind_method(D_METHOD("test_tarray"), &Example::test_tarray); ClassDB::bind_method(D_METHOD("test_tarray"), &Example::test_tarray);
ClassDB::bind_method(D_METHOD("test_dictionary"), &Example::test_dictionary); ClassDB::bind_method(D_METHOD("test_dictionary"), &Example::test_dictionary);
ClassDB::bind_method(D_METHOD("test_node_argument"), &Example::test_node_argument); ClassDB::bind_method(D_METHOD("test_node_argument"), &Example::test_node_argument);
ClassDB::bind_method(D_METHOD("test_string_ops"), &Example::test_string_ops);
ClassDB::bind_method(D_METHOD("test_vector_ops"), &Example::test_vector_ops);
ClassDB::bind_method(D_METHOD("def_args", "a", "b"), &Example::def_args, DEFVAL(100), DEFVAL(200)); ClassDB::bind_method(D_METHOD("def_args", "a", "b"), &Example::def_args, DEFVAL(100), DEFVAL(200));
@ -255,6 +257,28 @@ Array Example::test_array() const {
return arr; return arr;
} }
String Example::test_string_ops() const {
String s = String("A");
s += "B";
s += "C";
s += char32_t(0x010E);
s = s + "E";
return s;
}
int Example::test_vector_ops() const {
PackedInt32Array arr;
arr.push_back(10);
arr.push_back(20);
arr.push_back(30);
arr.push_back(45);
int ret = 0;
for (const int32_t &E : arr) {
ret += E;
}
return ret;
}
void Example::test_tarray_arg(const TypedArray<int64_t> &p_array) { void Example::test_tarray_arg(const TypedArray<int64_t> &p_array) {
for (int i = 0; i < p_array.size(); i++) { for (int i = 0; i < p_array.size(); i++) {
UtilityFunctions::print(p_array[i]); UtilityFunctions::print(p_array[i]);

View File

@ -101,6 +101,8 @@ public:
TypedArray<Vector2> test_tarray() const; TypedArray<Vector2> test_tarray() const;
Dictionary test_dictionary() const; Dictionary test_dictionary() const;
Example *test_node_argument(Example *p_node) const; Example *test_node_argument(Example *p_node) const;
String test_string_ops() const;
int test_vector_ops() const;
// Property. // Property.
void set_custom_position(const Vector2 &pos); void set_custom_position(const Vector2 &pos);