Merge pull request #1410 from dsnopek/4.2-cherrypicks-2

Cherry-picks for the godot-cpp 4.2 branch - 2nd batch
pull/1460/head
David Snopek 2024-04-08 13:09:13 -05:00 committed by GitHub
commit 7e5fa8e7a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
57 changed files with 950 additions and 674 deletions

View File

@ -37,7 +37,7 @@
# Todo # Todo
# Test build for Windows, Mac and mingw. # Test build for Windows, Mac and mingw.
cmake_minimum_required(VERSION 3.12) cmake_minimum_required(VERSION 3.13)
project(godot-cpp LANGUAGES CXX) project(godot-cpp LANGUAGES CXX)
option(GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node." ON) option(GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node." ON)

View File

@ -413,6 +413,10 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
if class_name == "PackedVector3Array": if class_name == "PackedVector3Array":
result.append("#include <godot_cpp/variant/vector3.hpp>") result.append("#include <godot_cpp/variant/vector3.hpp>")
if is_packed_array(class_name):
result.append("#include <godot_cpp/core/error_macros.hpp>")
result.append("#include <initializer_list>")
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>")
@ -454,6 +458,8 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
result.append("") result.append("")
result.append("\tstatic struct _MethodBindings {") result.append("\tstatic struct _MethodBindings {")
result.append("\t\tGDExtensionTypeFromVariantConstructorFunc from_variant_constructor;")
if "constructors" in builtin_api: if "constructors" in builtin_api:
for constructor in builtin_api["constructors"]: for constructor in builtin_api["constructors"]:
result.append(f'\t\tGDExtensionPtrConstructor constructor_{constructor["index"]};') result.append(f'\t\tGDExtensionPtrConstructor constructor_{constructor["index"]};')
@ -494,6 +500,9 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
result.append("\tstatic void init_bindings();") result.append("\tstatic void init_bindings();")
result.append("\tstatic void _init_bindings_constructors_destructor();") result.append("\tstatic void _init_bindings_constructors_destructor();")
result.append("")
result.append(f"\t{class_name}(const Variant *p_variant);")
result.append("") result.append("")
result.append("public:") result.append("public:")
@ -558,7 +567,7 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
vararg = method["is_vararg"] vararg = method["is_vararg"]
if vararg: if vararg:
result.append("\ttemplate<class... Args>") result.append("\ttemplate<typename... Args>")
method_signature = "\t" method_signature = "\t"
if "is_static" in method and method["is_static"]: if "is_static" in method and method["is_static"]:
@ -588,17 +597,17 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
# Special cases. # Special cases.
if class_name == "String": if class_name == "String":
result.append("\tstatic String utf8(const char *from, int len = -1);") result.append("\tstatic String utf8(const char *from, int64_t len = -1);")
result.append("\tvoid parse_utf8(const char *from, int len = -1);") result.append("\tvoid parse_utf8(const char *from, int64_t len = -1);")
result.append("\tstatic String utf16(const char16_t *from, int len = -1);") result.append("\tstatic String utf16(const char16_t *from, int64_t len = -1);")
result.append("\tvoid parse_utf16(const char16_t *from, int len = -1);") result.append("\tvoid parse_utf16(const char16_t *from, int64_t len = -1);")
result.append("\tCharString utf8() const;") result.append("\tCharString utf8() const;")
result.append("\tCharString ascii() const;") result.append("\tCharString ascii() const;")
result.append("\tChar16String utf16() const;") result.append("\tChar16String utf16() const;")
result.append("\tChar32String utf32() const;") result.append("\tChar32String utf32() const;")
result.append("\tCharWideString wide_string() const;") result.append("\tCharWideString wide_string() const;")
result.append("\tstatic String num_real(double p_num, bool p_trailing = true);") result.append("\tstatic String num_real(double p_num, bool p_trailing = true);")
result.append("\tError resize(int p_size);") result.append("\tError resize(int64_t p_size);")
if "members" in builtin_api: if "members" in builtin_api:
for member in builtin_api["members"]: for member in builtin_api["members"]:
@ -651,13 +660,13 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
result.append("\tString &operator+=(const wchar_t *p_str);") result.append("\tString &operator+=(const wchar_t *p_str);")
result.append("\tString &operator+=(const char32_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[](int64_t p_index) const;")
result.append("\tchar32_t &operator[](int p_index);") result.append("\tchar32_t &operator[](int64_t p_index);")
result.append("\tconst char32_t *ptr() const;") result.append("\tconst char32_t *ptr() const;")
result.append("\tchar32_t *ptrw();") result.append("\tchar32_t *ptrw();")
if class_name == "Array": if class_name == "Array":
result.append("\ttemplate <class... Args>") result.append("\ttemplate <typename... Args>")
result.append("\tstatic Array make(Args... args) {") result.append("\tstatic Array make(Args... args) {")
result.append("\t\treturn helpers::append_all(Array(), args...);") result.append("\t\treturn helpers::append_all(Array(), args...);")
result.append("\t}") result.append("\t}")
@ -670,8 +679,8 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
return_type = "int32_t" return_type = "int32_t"
elif class_name == "PackedFloat32Array": elif class_name == "PackedFloat32Array":
return_type = "float" return_type = "float"
result.append(f"\tconst {return_type} &operator[](int p_index) const;") result.append(f"\tconst {return_type} &operator[](int64_t p_index) const;")
result.append(f"\t{return_type} &operator[](int p_index);") result.append(f"\t{return_type} &operator[](int64_t p_index);")
result.append(f"\tconst {return_type} *ptr() const;") result.append(f"\tconst {return_type} *ptr() const;")
result.append(f"\t{return_type} *ptrw();") result.append(f"\t{return_type} *ptrw();")
iterators = """ iterators = """
@ -740,10 +749,21 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
} }
""" """
result.append(iterators.replace("$TYPE", return_type)) result.append(iterators.replace("$TYPE", return_type))
init_list = """
_FORCE_INLINE_ $CLASS(std::initializer_list<$TYPE> p_init) {
ERR_FAIL_COND(resize(p_init.size()) != 0);
size_t i = 0;
for (const $TYPE &element : p_init) {
set(i++, element);
}
}
"""
result.append(init_list.replace("$TYPE", return_type).replace("$CLASS", class_name))
if class_name == "Array": if class_name == "Array":
result.append("\tconst Variant &operator[](int p_index) const;") result.append("\tconst Variant &operator[](int64_t p_index) const;")
result.append("\tVariant &operator[](int p_index);") result.append("\tVariant &operator[](int64_t p_index);")
result.append("\tvoid set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script);") result.append("\tvoid set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script);")
result.append("\tvoid _ref(const Array &p_from) const;") result.append("\tvoid _ref(const Array &p_from) const;")
@ -818,6 +838,10 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
result.append(f"void {class_name}::_init_bindings_constructors_destructor() {{") result.append(f"void {class_name}::_init_bindings_constructors_destructor() {{")
result.append(
f"\t_method_bindings.from_variant_constructor = internal::gdextension_interface_get_variant_to_type_constructor({enum_type_name});"
)
if "constructors" in builtin_api: if "constructors" in builtin_api:
for constructor in builtin_api["constructors"]: for constructor in builtin_api["constructors"]:
result.append( result.append(
@ -899,6 +923,11 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
copy_constructor_index = -1 copy_constructor_index = -1
result.append(f"{class_name}::{class_name}(const Variant *p_variant) {{")
result.append("\t_method_bindings.from_variant_constructor(&opaque, p_variant->_native_ptr());")
result.append("}")
result.append("")
if "constructors" in builtin_api: if "constructors" in builtin_api:
for constructor in builtin_api["constructors"]: for constructor in builtin_api["constructors"]:
method_signature = f"{class_name}::{class_name}(" method_signature = f"{class_name}::{class_name}("
@ -964,8 +993,19 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
result.append(method_signature + "{") result.append(method_signature + "{")
method_call = "\t" method_call = "\t"
is_ref = False
if "return_type" in method: if "return_type" in method:
method_call += f'return internal::_call_builtin_method_ptr_ret<{correct_type(method["return_type"])}>(' return_type = method["return_type"]
if is_enum(return_type):
method_call += f"return ({get_gdextension_type(correct_type(return_type))})internal::_call_builtin_method_ptr_ret<int64_t>("
elif is_pod_type(return_type) or is_variant(return_type):
method_call += f"return internal::_call_builtin_method_ptr_ret<{get_gdextension_type(correct_type(return_type))}>("
elif is_refcounted(return_type):
method_call += f"return Ref<{return_type}>::_gde_internal_constructor(internal::_call_builtin_method_ptr_ret_obj<{return_type}>("
is_ref = True
else:
method_call += f"return internal::_call_builtin_method_ptr_ret_obj<{return_type}>("
else: else:
method_call += "internal::_call_builtin_method_ptr_no_ret(" method_call += "internal::_call_builtin_method_ptr_no_ret("
method_call += f'_method_bindings.method_{method["name"]}, ' method_call += f'_method_bindings.method_{method["name"]}, '
@ -986,6 +1026,9 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
result += encode result += encode
arguments.append(arg_name) arguments.append(arg_name)
method_call += ", ".join(arguments) method_call += ", ".join(arguments)
if is_ref:
method_call += ")" # Close Ref<> constructor.
method_call += ");" method_call += ");"
result.append(method_call) result.append(method_call)
@ -1384,7 +1427,7 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
result.append("protected:") result.append("protected:")
# T is the custom class we want to register (from which the call initiates, going up the inheritance chain), # T is the custom class we want to register (from which the call initiates, going up the inheritance chain),
# B is its base class (can be a custom class too, that's why we pass it). # B is its base class (can be a custom class too, that's why we pass it).
result.append("\ttemplate <class T, class B>") result.append("\ttemplate <typename T, typename B>")
result.append("\tstatic void register_virtuals() {") result.append("\tstatic void register_virtuals() {")
if class_name != "Object": if class_name != "Object":
result.append(f"\t\t{inherits}::register_virtuals<T, B>();") result.append(f"\t\t{inherits}::register_virtuals<T, B>();")
@ -1430,16 +1473,16 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
if class_name == "Object": if class_name == "Object":
result.append("") result.append("")
result.append("\ttemplate<class T>") result.append("\ttemplate<typename T>")
result.append("\tstatic T *cast_to(Object *p_object);") result.append("\tstatic T *cast_to(Object *p_object);")
result.append("\ttemplate<class T>") result.append("\ttemplate<typename T>")
result.append("\tstatic const T *cast_to(const Object *p_object);") result.append("\tstatic const T *cast_to(const Object *p_object);")
result.append("\tvirtual ~Object() = default;") result.append("\tvirtual ~Object() = default;")
elif use_template_get_node and class_name == "Node": elif use_template_get_node and class_name == "Node":
result.append("\ttemplate<class T>") result.append("\ttemplate<typename T>")
result.append( result.append(
"\tT *get_node(const NodePath &p_path) const { return Object::cast_to<T>(get_node_internal(p_path)); }" "\tT *get_node(const NodePath &p_path) const { return Object::cast_to<T>(get_node_internal(p_path)); }"
) )
@ -1696,7 +1739,7 @@ def generate_global_constants(api, output_dir):
header.append("") header.append("")
for constant in api["global_constants"]: for constant in api["global_constants"]:
header.append(f'\tconst int {escape_identifier(constant["name"])} = {constant["value"]};') header.append(f'\tconst int64_t {escape_identifier(constant["name"])} = {constant["value"]};')
header.append("") header.append("")
@ -2073,7 +2116,7 @@ def make_varargs_template(
if with_public_declare: if with_public_declare:
function_signature = "public: " function_signature = "public: "
function_signature += "template<class... Args> " function_signature += "template<typename... Args> "
if static: if static:
function_signature += "static " function_signature += "static "

View File

@ -47,11 +47,11 @@ public:
static void remove_plugin_class(const StringName &p_class_name); static void remove_plugin_class(const StringName &p_class_name);
static void deinitialize(GDExtensionInitializationLevel p_level); static void deinitialize(GDExtensionInitializationLevel p_level);
template <class T> template <typename T>
static void add_by_type() { static void add_by_type() {
add_plugin_class(T::get_class_static()); add_plugin_class(T::get_class_static());
} }
template <class T> template <typename T>
static void remove_by_type() { static void remove_by_type() {
remove_plugin_class(T::get_class_static()); remove_plugin_class(T::get_class_static());
} }

View File

@ -45,7 +45,7 @@ namespace godot {
class RefCounted; class RefCounted;
template <class T> template <typename T>
class Ref { class Ref {
T *reference = nullptr; T *reference = nullptr;
@ -108,7 +108,7 @@ public:
ref(p_from); ref(p_from);
} }
template <class T_Other> template <typename T_Other>
void operator=(const Ref<T_Other> &p_from) { void operator=(const Ref<T_Other> &p_from) {
RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr())); RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr()));
if (!refb) { if (!refb) {
@ -144,7 +144,7 @@ public:
} }
} }
template <class T_Other> template <typename T_Other>
void reference_ptr(T_Other *p_ptr) { void reference_ptr(T_Other *p_ptr) {
if (reference == p_ptr) { if (reference == p_ptr) {
return; return;
@ -161,7 +161,7 @@ public:
ref(p_from); ref(p_from);
} }
template <class T_Other> template <typename T_Other>
Ref(const Ref<T_Other> &p_from) { Ref(const Ref<T_Other> &p_from) {
RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr())); RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr()));
if (!refb) { if (!refb) {
@ -226,7 +226,7 @@ public:
} }
}; };
template <class T> template <typename T>
struct PtrToArg<Ref<T>> { struct PtrToArg<Ref<T>> {
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) { _FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
GDExtensionRefPtr ref = (GDExtensionRefPtr)p_ptr; GDExtensionRefPtr ref = (GDExtensionRefPtr)p_ptr;
@ -248,7 +248,7 @@ struct PtrToArg<Ref<T>> {
} }
}; };
template <class T> template <typename T>
struct PtrToArg<const Ref<T> &> { struct PtrToArg<const Ref<T> &> {
typedef Ref<T> EncodeT; typedef Ref<T> EncodeT;
@ -259,7 +259,7 @@ struct PtrToArg<const Ref<T> &> {
} }
}; };
template <class T> template <typename T>
struct GetTypeInfo<Ref<T>, typename EnableIf<TypeInherits<RefCounted, T>::value>::type> { struct GetTypeInfo<Ref<T>, typename EnableIf<TypeInherits<RefCounted, T>::value>::type> {
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT; static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
@ -269,7 +269,7 @@ struct GetTypeInfo<Ref<T>, typename EnableIf<TypeInherits<RefCounted, T>::value>
} }
}; };
template <class T> template <typename T>
struct GetTypeInfo<const Ref<T> &, typename EnableIf<TypeInherits<RefCounted, T>::value>::type> { struct GetTypeInfo<const Ref<T> &, typename EnableIf<TypeInherits<RefCounted, T>::value>::type> {
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT; static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;

View File

@ -117,7 +117,7 @@ void add_engine_class_registration_callback(EngineClassRegistrationCallback p_ca
void register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks); void register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks);
void register_engine_classes(); void register_engine_classes();
template <class T> template <typename T>
struct EngineClassRegistration { struct EngineClassRegistration {
EngineClassRegistration() { EngineClassRegistration() {
add_engine_class_registration_callback(&EngineClassRegistration<T>::callback); add_engine_class_registration_callback(&EngineClassRegistration<T>::callback);
@ -186,7 +186,7 @@ protected:
return (::godot::String(::godot::Wrapped::*)() const) & m_class::_to_string; \ return (::godot::String(::godot::Wrapped::*)() const) & m_class::_to_string; \
} \ } \
\ \
template <class T, class B> \ template <typename T, typename B> \
static void register_virtuals() { \ static void register_virtuals() { \
m_inherits::register_virtuals<T, B>(); \ m_inherits::register_virtuals<T, B>(); \
} \ } \
@ -218,12 +218,17 @@ public:
\ \
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) { \ static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) { \
if (p_instance && m_class::_get_notification()) { \ if (p_instance && m_class::_get_notification()) { \
if (!p_reversed) { \
m_inherits::notification_bind(p_instance, p_what, p_reversed); \
} \
if (m_class::_get_notification() != m_inherits::_get_notification()) { \ if (m_class::_get_notification() != m_inherits::_get_notification()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \ m_class *cls = reinterpret_cast<m_class *>(p_instance); \
return cls->_notification(p_what); \ cls->_notification(p_what); \
} \ } \
if (p_reversed) { \
m_inherits::notification_bind(p_instance, p_what, p_reversed); \ m_inherits::notification_bind(p_instance, p_what, p_reversed); \
} \ } \
} \
} \ } \
\ \
static GDExtensionBool set_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value) { \ static GDExtensionBool set_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value) { \

View File

@ -83,7 +83,7 @@ namespace godot {
}; \ }; \
} }
template <class T> template <typename T>
struct VariantCaster { struct VariantCaster {
static _FORCE_INLINE_ T cast(const Variant &p_variant) { static _FORCE_INLINE_ T cast(const Variant &p_variant) {
using TStripped = std::remove_pointer_t<T>; using TStripped = std::remove_pointer_t<T>;
@ -95,7 +95,7 @@ struct VariantCaster {
} }
}; };
template <class T> template <typename T>
struct VariantCaster<T &> { struct VariantCaster<T &> {
static _FORCE_INLINE_ T cast(const Variant &p_variant) { static _FORCE_INLINE_ T cast(const Variant &p_variant) {
using TStripped = std::remove_pointer_t<T>; using TStripped = std::remove_pointer_t<T>;
@ -107,7 +107,7 @@ struct VariantCaster<T &> {
} }
}; };
template <class T> template <typename T>
struct VariantCaster<const T &> { struct VariantCaster<const T &> {
static _FORCE_INLINE_ T cast(const Variant &p_variant) { static _FORCE_INLINE_ T cast(const Variant &p_variant) {
using TStripped = std::remove_pointer_t<T>; using TStripped = std::remove_pointer_t<T>;
@ -144,7 +144,7 @@ struct VariantObjectClassChecker<const Ref<T> &> {
} }
}; };
template <class T> template <typename T>
struct VariantCasterAndValidate { struct VariantCasterAndValidate {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) { static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE); GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
@ -159,7 +159,7 @@ struct VariantCasterAndValidate {
} }
}; };
template <class T> template <typename T>
struct VariantCasterAndValidate<T &> { struct VariantCasterAndValidate<T &> {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) { static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE); GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
@ -174,7 +174,7 @@ struct VariantCasterAndValidate<T &> {
} }
}; };
template <class T> template <typename T>
struct VariantCasterAndValidate<const T &> { struct VariantCasterAndValidate<const T &> {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) { static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE); GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
@ -189,47 +189,47 @@ struct VariantCasterAndValidate<const T &> {
} }
}; };
template <class T, class... P, size_t... Is> template <typename T, typename... P, size_t... Is>
void call_with_ptr_args_helper(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) { void call_with_ptr_args_helper(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
(p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...); (p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
} }
template <class T, class... P, size_t... Is> template <typename T, typename... P, size_t... Is>
void call_with_ptr_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) { void call_with_ptr_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
(p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...); (p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
} }
template <class T, class R, class... P, size_t... Is> template <typename T, typename R, typename... P, size_t... Is>
void call_with_ptr_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) { void call_with_ptr_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret); PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
} }
template <class T, class R, class... P, size_t... Is> template <typename T, typename R, typename... P, size_t... Is>
void call_with_ptr_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) { void call_with_ptr_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret); PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
} }
template <class T, class... P> template <typename T, typename... P>
void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void * /*ret*/) { void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void * /*ret*/) {
call_with_ptr_args_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{}); call_with_ptr_args_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
} }
template <class T, class... P> template <typename T, typename... P>
void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void * /*ret*/) { void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void * /*ret*/) {
call_with_ptr_argsc_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{}); call_with_ptr_argsc_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
} }
template <class T, class R, class... P> template <typename T, typename R, typename... P>
void call_with_ptr_args(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret) { void call_with_ptr_args(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret) {
call_with_ptr_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{}); call_with_ptr_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
} }
template <class T, class R, class... P> template <typename T, typename R, typename... P>
void call_with_ptr_args(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void *r_ret) { void call_with_ptr_args(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void *r_ret) {
call_with_ptr_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{}); call_with_ptr_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
} }
template <class T, class... P, size_t... Is> template <typename T, typename... P, size_t... Is>
void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) { void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK; r_error.error = GDEXTENSION_CALL_OK;
@ -241,7 +241,7 @@ void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), con
(void)(p_args); // Avoid warning. (void)(p_args); // Avoid warning.
} }
template <class T, class... P, size_t... Is> template <typename T, typename... P, size_t... Is>
void call_with_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) { void call_with_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK; r_error.error = GDEXTENSION_CALL_OK;
@ -253,7 +253,7 @@ void call_with_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) con
(void)(p_args); // Avoid warning. (void)(p_args); // Avoid warning.
} }
template <class T, class R, class... P, size_t... Is> template <typename T, typename R, typename... P, size_t... Is>
void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) { void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK; r_error.error = GDEXTENSION_CALL_OK;
@ -264,7 +264,7 @@ void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), co
#endif #endif
} }
template <class T, class R, class... P, size_t... Is> template <typename T, typename R, typename... P, size_t... Is>
void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) { void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK; r_error.error = GDEXTENSION_CALL_OK;
@ -276,7 +276,7 @@ void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) co
(void)p_args; (void)p_args;
} }
template <class T, class... P> template <typename T, typename... P>
void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, GDExtensionCallError &r_error) { void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) { if ((size_t)p_argcount > sizeof...(P)) {
@ -294,7 +294,7 @@ void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Vari
call_with_variant_args_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{}); call_with_variant_args_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
} }
template <class T, class R, class... P> template <typename T, typename R, typename... P>
void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) { void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) { if ((size_t)p_argcount > sizeof...(P)) {
@ -312,7 +312,7 @@ void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Var
call_with_variant_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{}); call_with_variant_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
} }
template <class T, class R, class... P> template <typename T, typename R, typename... P>
void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) { void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) { if ((size_t)p_argcount > sizeof...(P)) {
@ -330,7 +330,7 @@ void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, co
call_with_variant_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{}); call_with_variant_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
} }
template <class T, class... P> template <typename T, typename... P>
void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) { void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) { if ((size_t)p_argcount > sizeof...(P)) {
@ -365,7 +365,7 @@ void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const G
call_with_variant_args_helper(p_instance, p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{}); call_with_variant_args_helper(p_instance, p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{});
} }
template <class T, class... P> template <typename T, typename... P>
void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) { void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) { if ((size_t)p_argcount > sizeof...(P)) {
@ -400,7 +400,7 @@ void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const,
call_with_variant_argsc_helper(p_instance, p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{}); call_with_variant_argsc_helper(p_instance, p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{});
} }
template <class T, class R, class... P> template <typename T, typename R, typename... P>
void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) { void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) { if ((size_t)p_argcount > sizeof...(P)) {
@ -435,7 +435,7 @@ void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const
call_with_variant_args_ret_helper(p_instance, p_method, argsp.data(), r_ret, r_error, BuildIndexSequence<sizeof...(P)>{}); call_with_variant_args_ret_helper(p_instance, p_method, argsp.data(), r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
} }
template <class T, class R, class... P> template <typename T, typename R, typename... P>
void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) { void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) { if ((size_t)p_argcount > sizeof...(P)) {
@ -477,7 +477,7 @@ void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const,
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter" #pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#endif #endif
template <class Q> template <typename Q>
void call_get_argument_type_helper(int p_arg, int &index, GDExtensionVariantType &type) { void call_get_argument_type_helper(int p_arg, int &index, GDExtensionVariantType &type) {
if (p_arg == index) { if (p_arg == index) {
type = GDExtensionVariantType(GetTypeInfo<Q>::VARIANT_TYPE); type = GDExtensionVariantType(GetTypeInfo<Q>::VARIANT_TYPE);
@ -485,7 +485,7 @@ void call_get_argument_type_helper(int p_arg, int &index, GDExtensionVariantType
index++; index++;
} }
template <class... P> template <typename... P>
GDExtensionVariantType call_get_argument_type(int p_arg) { GDExtensionVariantType call_get_argument_type(int p_arg) {
GDExtensionVariantType type = GDEXTENSION_VARIANT_TYPE_NIL; GDExtensionVariantType type = GDEXTENSION_VARIANT_TYPE_NIL;
int index = 0; int index = 0;
@ -497,7 +497,7 @@ GDExtensionVariantType call_get_argument_type(int p_arg) {
return type; return type;
} }
template <class Q> template <typename Q>
void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &info) { void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &info) {
if (p_arg == index) { if (p_arg == index) {
info = GetTypeInfo<Q>::get_class_info(); info = GetTypeInfo<Q>::get_class_info();
@ -505,7 +505,7 @@ void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &inf
index++; index++;
} }
template <class... P> template <typename... P>
void call_get_argument_type_info(int p_arg, PropertyInfo &info) { void call_get_argument_type_info(int p_arg, PropertyInfo &info) {
int index = 0; int index = 0;
// I think rocket science is simpler than modern C++. // I think rocket science is simpler than modern C++.
@ -515,7 +515,7 @@ void call_get_argument_type_info(int p_arg, PropertyInfo &info) {
(void)index; // Suppress GCC warning. (void)index; // Suppress GCC warning.
} }
template <class Q> template <typename Q>
void call_get_argument_metadata_helper(int p_arg, int &index, GDExtensionClassMethodArgumentMetadata &md) { void call_get_argument_metadata_helper(int p_arg, int &index, GDExtensionClassMethodArgumentMetadata &md) {
if (p_arg == index) { if (p_arg == index) {
md = GetTypeInfo<Q>::METADATA; md = GetTypeInfo<Q>::METADATA;
@ -523,7 +523,7 @@ void call_get_argument_metadata_helper(int p_arg, int &index, GDExtensionClassMe
index++; index++;
} }
template <class... P> template <typename... P>
GDExtensionClassMethodArgumentMetadata call_get_argument_metadata(int p_arg) { GDExtensionClassMethodArgumentMetadata call_get_argument_metadata(int p_arg) {
GDExtensionClassMethodArgumentMetadata md = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; GDExtensionClassMethodArgumentMetadata md = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
@ -536,7 +536,7 @@ GDExtensionClassMethodArgumentMetadata call_get_argument_metadata(int p_arg) {
return md; return md;
} }
template <class... P, size_t... Is> template <typename... P, size_t... Is>
void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) { void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK; r_error.error = GDEXTENSION_CALL_OK;
@ -547,7 +547,7 @@ void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_arg
#endif #endif
} }
template <class... P> template <typename... P>
void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) { void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) { if ((size_t)p_argcount > sizeof...(P)) {
@ -582,17 +582,17 @@ void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionC
call_with_variant_args_static(p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{}); call_with_variant_args_static(p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{});
} }
template <class... P, size_t... Is> template <typename... P, size_t... Is>
void call_with_ptr_args_static_method_helper(void (*p_method)(P...), const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) { void call_with_ptr_args_static_method_helper(void (*p_method)(P...), const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
p_method(PtrToArg<P>::convert(p_args[Is])...); p_method(PtrToArg<P>::convert(p_args[Is])...);
} }
template <class... P> template <typename... P>
void call_with_ptr_args_static_method(void (*p_method)(P...), const GDExtensionConstTypePtr *p_args) { void call_with_ptr_args_static_method(void (*p_method)(P...), const GDExtensionConstTypePtr *p_args) {
call_with_ptr_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{}); call_with_ptr_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
} }
template <class R, class... P> template <typename R, typename... P>
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) { void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) { if ((size_t)p_argcount > sizeof...(P)) {
@ -610,7 +610,7 @@ void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_ar
call_with_variant_args_static_ret<R, P...>(p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{}); call_with_variant_args_static_ret<R, P...>(p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
} }
template <class... P> template <typename... P>
void call_with_variant_args_static_ret(void (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) { void call_with_variant_args_static_ret(void (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) { if ((size_t)p_argcount > sizeof...(P)) {
@ -628,7 +628,7 @@ void call_with_variant_args_static_ret(void (*p_method)(P...), const Variant **p
call_with_variant_args_static<P...>(p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{}); call_with_variant_args_static<P...>(p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
} }
template <class R, class... P, size_t... Is> template <typename R, typename... P, size_t... Is>
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) { void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK; r_error.error = GDEXTENSION_CALL_OK;
@ -639,7 +639,7 @@ void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_ar
#endif #endif
} }
template <class R, class... P> template <typename R, typename... P>
void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) { void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) { if ((size_t)p_argcount > sizeof...(P)) {
@ -674,12 +674,12 @@ void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtension
call_with_variant_args_static_ret(p_method, argsp.data(), r_ret, r_error, BuildIndexSequence<sizeof...(P)>{}); call_with_variant_args_static_ret(p_method, argsp.data(), r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
} }
template <class R, class... P, size_t... Is> template <typename R, typename... P, size_t... Is>
void call_with_ptr_args_static_method_ret_helper(R (*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) { void call_with_ptr_args_static_method_ret_helper(R (*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode(p_method(PtrToArg<P>::convert(p_args[Is])...), r_ret); PtrToArg<R>::encode(p_method(PtrToArg<P>::convert(p_args[Is])...), r_ret);
} }
template <class R, class... P> template <typename R, typename... P>
void call_with_ptr_args_static_method_ret(R (*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret) { void call_with_ptr_args_static_method_ret(R (*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret) {
call_with_ptr_args_static_method_ret_helper<R, P...>(p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{}); call_with_ptr_args_static_method_ret_helper<R, P...>(p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
} }

View File

@ -32,6 +32,7 @@
#define GODOT_BUILTIN_PTRCALL_HPP #define GODOT_BUILTIN_PTRCALL_HPP
#include <gdextension_interface.h> #include <gdextension_interface.h>
#include <godot_cpp/core/object.hpp>
#include <array> #include <array>
@ -39,13 +40,24 @@ namespace godot {
namespace internal { namespace internal {
template <class... Args> template <typename O, typename... Args>
O *_call_builtin_method_ptr_ret_obj(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, const Args &...args) {
GodotObject *ret = nullptr;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
method(base, call_args.data(), &ret, sizeof...(Args));
if (ret == nullptr) {
return nullptr;
}
return reinterpret_cast<O *>(internal::get_object_instance_binding(ret));
}
template <typename... Args>
void _call_builtin_constructor(const GDExtensionPtrConstructor constructor, GDExtensionTypePtr base, Args... args) { void _call_builtin_constructor(const GDExtensionPtrConstructor constructor, GDExtensionTypePtr base, Args... args) {
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } }; std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
constructor(base, call_args.data()); constructor(base, call_args.data());
} }
template <class T, class... Args> template <typename T, typename... Args>
T _call_builtin_method_ptr_ret(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, Args... args) { T _call_builtin_method_ptr_ret(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, Args... args) {
T ret; T ret;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } }; std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
@ -53,20 +65,20 @@ T _call_builtin_method_ptr_ret(const GDExtensionPtrBuiltInMethod method, GDExten
return ret; return ret;
} }
template <class... Args> template <typename... Args>
void _call_builtin_method_ptr_no_ret(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, Args... args) { void _call_builtin_method_ptr_no_ret(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, Args... args) {
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } }; std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
method(base, call_args.data(), nullptr, sizeof...(Args)); method(base, call_args.data(), nullptr, sizeof...(Args));
} }
template <class T> template <typename T>
T _call_builtin_operator_ptr(const GDExtensionPtrOperatorEvaluator op, GDExtensionConstTypePtr left, GDExtensionConstTypePtr right) { T _call_builtin_operator_ptr(const GDExtensionPtrOperatorEvaluator op, GDExtensionConstTypePtr left, GDExtensionConstTypePtr right) {
T ret; T ret;
op(left, right, &ret); op(left, right, &ret);
return ret; return ret;
} }
template <class T> template <typename T>
T _call_builtin_ptr_getter(const GDExtensionPtrGetter getter, GDExtensionConstTypePtr base) { T _call_builtin_ptr_getter(const GDExtensionPtrGetter getter, GDExtensionConstTypePtr base) {
T ret; T ret;
getter(base, &ret); getter(base, &ret);

View File

@ -109,10 +109,10 @@ private:
static void initialize_class(const ClassInfo &cl); static void initialize_class(const ClassInfo &cl);
static void bind_method_godot(const StringName &p_class_name, MethodBind *p_method); static void bind_method_godot(const StringName &p_class_name, MethodBind *p_method);
template <class T, bool is_abstract> template <typename T, bool is_abstract>
static void _register_class(bool p_virtual = false, bool p_exposed = true); static void _register_class(bool p_virtual = false, bool p_exposed = true);
template <class T> template <typename T>
static GDExtensionObjectPtr _create_instance_func(void *data) { static GDExtensionObjectPtr _create_instance_func(void *data) {
if constexpr (!std::is_abstract_v<T>) { if constexpr (!std::is_abstract_v<T>) {
T *new_object = memnew(T); T *new_object = memnew(T);
@ -122,7 +122,7 @@ private:
} }
} }
template <class T> template <typename T>
static GDExtensionClassInstancePtr _recreate_instance_func(void *data, GDExtensionObjectPtr obj) { static GDExtensionClassInstancePtr _recreate_instance_func(void *data, GDExtensionObjectPtr obj) {
if constexpr (!std::is_abstract_v<T>) { if constexpr (!std::is_abstract_v<T>) {
#ifdef HOT_RELOAD_ENABLED #ifdef HOT_RELOAD_ENABLED
@ -140,24 +140,24 @@ private:
} }
public: public:
template <class T> template <typename T>
static void register_class(bool p_virtual = false); static void register_class(bool p_virtual = false);
template <class T> template <typename T>
static void register_abstract_class(); static void register_abstract_class();
template <class T> template <typename T>
static void register_internal_class(); static void register_internal_class();
_FORCE_INLINE_ static void _register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) { _FORCE_INLINE_ static void _register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
instance_binding_callbacks[p_name] = p_callbacks; instance_binding_callbacks[p_name] = p_callbacks;
} }
template <class N, class M, typename... VarArgs> template <typename N, typename M, typename... VarArgs>
static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args); static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args);
template <class N, class M, typename... VarArgs> template <typename N, typename M, typename... VarArgs>
static MethodBind *bind_static_method(StringName p_class, N p_method_name, M p_method, VarArgs... p_args); static MethodBind *bind_static_method(StringName p_class, N p_method_name, M p_method, VarArgs... p_args);
template <class M> template <typename M>
static MethodBind *bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const std::vector<Variant> &p_default_args = std::vector<Variant>{}, bool p_return_nil_is_variant = true); static MethodBind *bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const std::vector<Variant> &p_default_args = std::vector<Variant>{}, bool p_return_nil_is_variant = true);
static void add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix); static void add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix);
@ -179,23 +179,23 @@ public:
}; };
#define BIND_CONSTANT(m_constant) \ #define BIND_CONSTANT(m_constant) \
godot::ClassDB::bind_integer_constant(get_class_static(), "", #m_constant, m_constant); ::godot::ClassDB::bind_integer_constant(get_class_static(), "", #m_constant, m_constant);
#define BIND_ENUM_CONSTANT(m_constant) \ #define BIND_ENUM_CONSTANT(m_constant) \
godot::ClassDB::bind_integer_constant(get_class_static(), godot::_gde_constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant); ::godot::ClassDB::bind_integer_constant(get_class_static(), ::godot::_gde_constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant);
#define BIND_BITFIELD_FLAG(m_constant) \ #define BIND_BITFIELD_FLAG(m_constant) \
godot::ClassDB::bind_integer_constant(get_class_static(), godot::_gde_constant_get_bitfield_name(m_constant, #m_constant), #m_constant, m_constant, true); ::godot::ClassDB::bind_integer_constant(get_class_static(), ::godot::_gde_constant_get_bitfield_name(m_constant, #m_constant), #m_constant, m_constant, true);
#define BIND_VIRTUAL_METHOD(m_class, m_method) \ #define BIND_VIRTUAL_METHOD(m_class, m_method) \
{ \ { \
auto _call##m_method = [](GDExtensionObjectPtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr p_ret) -> void { \ auto _call##m_method = [](GDExtensionObjectPtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr p_ret) -> void { \
call_with_ptr_args(reinterpret_cast<m_class *>(p_instance), &m_class::m_method, p_args, p_ret); \ call_with_ptr_args(reinterpret_cast<m_class *>(p_instance), &m_class::m_method, p_args, p_ret); \
}; \ }; \
godot::ClassDB::bind_virtual_method(m_class::get_class_static(), #m_method, _call##m_method); \ ::godot::ClassDB::bind_virtual_method(m_class::get_class_static(), #m_method, _call##m_method); \
} }
template <class T, bool is_abstract> template <typename T, bool is_abstract>
void ClassDB::_register_class(bool p_virtual, bool p_exposed) { void ClassDB::_register_class(bool p_virtual, bool p_exposed) {
static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS."); static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS.");
instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks; instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks;
@ -248,22 +248,22 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed) {
initialize_class(classes[cl.name]); initialize_class(classes[cl.name]);
} }
template <class T> template <typename T>
void ClassDB::register_class(bool p_virtual) { void ClassDB::register_class(bool p_virtual) {
ClassDB::_register_class<T, false>(p_virtual); ClassDB::_register_class<T, false>(p_virtual);
} }
template <class T> template <typename T>
void ClassDB::register_abstract_class() { void ClassDB::register_abstract_class() {
ClassDB::_register_class<T, true>(); ClassDB::_register_class<T, true>();
} }
template <class T> template <typename T>
void ClassDB::register_internal_class() { void ClassDB::register_internal_class() {
ClassDB::_register_class<T, false>(false, false); ClassDB::_register_class<T, false>(false, false);
} }
template <class N, class M, typename... VarArgs> template <typename N, typename M, typename... VarArgs>
MethodBind *ClassDB::bind_method(N p_method_name, M p_method, VarArgs... p_args) { MethodBind *ClassDB::bind_method(N p_method_name, M p_method, VarArgs... p_args) {
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
const Variant *argptrs[sizeof...(p_args) + 1]; const Variant *argptrs[sizeof...(p_args) + 1];
@ -274,7 +274,7 @@ MethodBind *ClassDB::bind_method(N p_method_name, M p_method, VarArgs... p_args)
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const void **)argptrs, sizeof...(p_args)); return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const void **)argptrs, sizeof...(p_args));
} }
template <class N, class M, typename... VarArgs> template <typename N, typename M, typename... VarArgs>
MethodBind *ClassDB::bind_static_method(StringName p_class, N p_method_name, M p_method, VarArgs... p_args) { MethodBind *ClassDB::bind_static_method(StringName p_class, N p_method_name, M p_method, VarArgs... p_args) {
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
const Variant *argptrs[sizeof...(p_args) + 1]; const Variant *argptrs[sizeof...(p_args) + 1];
@ -286,7 +286,7 @@ MethodBind *ClassDB::bind_static_method(StringName p_class, N p_method_name, M p
return bind_methodfi(0, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const void **)argptrs, sizeof...(p_args)); return bind_methodfi(0, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const void **)argptrs, sizeof...(p_args));
} }
template <class M> template <typename M>
MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info, const std::vector<Variant> &p_default_args, bool p_return_nil_is_variant) { MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info, const std::vector<Variant> &p_default_args, bool p_return_nil_is_variant) {
MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant); MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant);
ERR_FAIL_NULL_V(bind, nullptr); ERR_FAIL_NULL_V(bind, nullptr);

View File

@ -108,7 +108,7 @@ typedef float real_t;
// Generic swap template. // Generic swap template.
#ifndef SWAP #ifndef SWAP
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y)) #define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
template <class T> template <typename T>
inline void __swap_tmpl(T &x, T &y) { inline void __swap_tmpl(T &x, T &y) {
T aux = x; T aux = x;
x = y; x = y;

View File

@ -43,7 +43,7 @@ namespace godot {
namespace internal { namespace internal {
template <class O, class... Args> template <typename O, typename... Args>
O *_call_native_mb_ret_obj(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) { O *_call_native_mb_ret_obj(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
GodotObject *ret = nullptr; GodotObject *ret = nullptr;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } }; std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
@ -54,7 +54,7 @@ O *_call_native_mb_ret_obj(const GDExtensionMethodBindPtr mb, void *instance, co
return reinterpret_cast<O *>(internal::get_object_instance_binding(ret)); return reinterpret_cast<O *>(internal::get_object_instance_binding(ret));
} }
template <class R, class... Args> template <typename R, typename... Args>
R _call_native_mb_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) { R _call_native_mb_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
R ret; R ret;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } }; std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
@ -62,13 +62,13 @@ R _call_native_mb_ret(const GDExtensionMethodBindPtr mb, void *instance, const A
return ret; return ret;
} }
template <class... Args> template <typename... Args>
void _call_native_mb_no_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) { void _call_native_mb_no_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } }; std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), nullptr); internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), nullptr);
} }
template <class R, class... Args> template <typename R, typename... Args>
R _call_utility_ret(GDExtensionPtrUtilityFunction func, const Args &...args) { R _call_utility_ret(GDExtensionPtrUtilityFunction func, const Args &...args) {
R ret; R ret;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } }; std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
@ -76,15 +76,15 @@ R _call_utility_ret(GDExtensionPtrUtilityFunction func, const Args &...args) {
return ret; return ret;
} }
template <class... Args> template <typename... Args>
Object *_call_utility_ret_obj(const GDExtensionPtrUtilityFunction func, void *instance, const Args &...args) { Object *_call_utility_ret_obj(const GDExtensionPtrUtilityFunction func, const Args &...args) {
GodotObject *ret = nullptr; GodotObject *ret = nullptr;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } }; std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
func(&ret, mb_args.data(), mb_args.size()); func(&ret, mb_args.data(), mb_args.size());
return (Object *)internal::get_object_instance_binding(ret); return (Object *)internal::get_object_instance_binding(ret);
} }
template <class... Args> template <typename... Args>
void _call_utility_no_ret(const GDExtensionPtrUtilityFunction func, const Args &...args) { void _call_utility_no_ret(const GDExtensionPtrUtilityFunction func, const Args &...args) {
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } }; std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
func(nullptr, mb_args.data(), mb_args.size()); func(nullptr, mb_args.data(), mb_args.size());

View File

@ -84,7 +84,7 @@ constexpr auto CLAMP(const T m_a, const T2 m_min, const T3 m_max) {
// Generic swap template. // Generic swap template.
#ifndef SWAP #ifndef SWAP
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y)) #define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
template <class T> template <typename T>
inline void __swap_tmpl(T &x, T &y) { inline void __swap_tmpl(T &x, T &y) {
T aux = x; T aux = x;
x = y; x = y;
@ -138,7 +138,7 @@ static inline int get_shift_from_power_of_2(unsigned int p_bits) {
return -1; return -1;
} }
template <class T> template <typename T>
static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) { static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) {
--x; --x;

View File

@ -40,10 +40,6 @@
#include <type_traits> #include <type_traits>
#ifndef PAD_ALIGN
#define PAD_ALIGN 16 //must always be greater than this at much
#endif
// p_dummy argument is added to avoid conflicts with the engine functions when both engine and GDExtension are built as a static library on iOS. // p_dummy argument is added to avoid conflicts with the engine functions when both engine and GDExtension are built as a static library on iOS.
void *operator new(size_t p_size, const char *p_dummy, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool void *operator new(size_t p_size, const char *p_dummy, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool
void *operator new(size_t p_size, const char *p_dummy, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool void *operator new(size_t p_size, const char *p_dummy, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool
@ -69,6 +65,18 @@ class Memory {
Memory(); Memory();
public: public:
// Alignment: ↓ max_align_t ↓ uint64_t ↓ max_align_t
// ┌─────────────────┬──┬────────────────┬──┬───────────...
// │ uint64_t │░░│ uint64_t │░░│ T[]
// │ alloc size │░░│ element count │░░│ data
// └─────────────────┴──┴────────────────┴──┴───────────...
// Offset: ↑ SIZE_OFFSET ↑ ELEMENT_OFFSET ↑ DATA_OFFSET
// Note: "alloc size" is used and set by the engine and is never accessed or changed for the extension.
static constexpr size_t SIZE_OFFSET = 0;
static constexpr size_t ELEMENT_OFFSET = ((SIZE_OFFSET + sizeof(uint64_t)) % alignof(uint64_t) == 0) ? (SIZE_OFFSET + sizeof(uint64_t)) : ((SIZE_OFFSET + sizeof(uint64_t)) + alignof(uint64_t) - ((SIZE_OFFSET + sizeof(uint64_t)) % alignof(uint64_t)));
static constexpr size_t DATA_OFFSET = ((ELEMENT_OFFSET + sizeof(uint64_t)) % alignof(max_align_t) == 0) ? (ELEMENT_OFFSET + sizeof(uint64_t)) : ((ELEMENT_OFFSET + sizeof(uint64_t)) + alignof(max_align_t) - ((ELEMENT_OFFSET + sizeof(uint64_t)) % alignof(max_align_t)));
static void *alloc_static(size_t p_bytes, bool p_pad_align = false); static void *alloc_static(size_t p_bytes, bool p_pad_align = false);
static void *realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align = false); static void *realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align = false);
static void free_static(void *p_ptr, bool p_pad_align = false); static void free_static(void *p_ptr, bool p_pad_align = false);
@ -76,7 +84,7 @@ public:
_ALWAYS_INLINE_ void postinitialize_handler(void *) {} _ALWAYS_INLINE_ void postinitialize_handler(void *) {}
template <class T> template <typename T>
_ALWAYS_INLINE_ T *_post_initialize(T *p_obj) { _ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
postinitialize_handler(p_obj); postinitialize_handler(p_obj);
return p_obj; return p_obj;
@ -92,28 +100,28 @@ _ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
#define memnew_placement(m_placement, m_class) ::godot::_post_initialize(new ("", m_placement, sizeof(m_class), "") m_class) #define memnew_placement(m_placement, m_class) ::godot::_post_initialize(new ("", m_placement, sizeof(m_class), "") m_class)
// Generic comparator used in Map, List, etc. // Generic comparator used in Map, List, etc.
template <class T> template <typename T>
struct Comparator { struct Comparator {
_ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); } _ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); }
}; };
template <class T> template <typename T>
void memdelete(T *p_class, typename std::enable_if<!std::is_base_of_v<godot::Wrapped, T>>::type * = nullptr) { void memdelete(T *p_class, typename std::enable_if<!std::is_base_of_v<godot::Wrapped, T>>::type * = nullptr) {
if (!std::is_trivially_destructible<T>::value) { if constexpr (!std::is_trivially_destructible_v<T>) {
p_class->~T(); p_class->~T();
} }
Memory::free_static(p_class); Memory::free_static(p_class);
} }
template <class T, std::enable_if_t<std::is_base_of_v<godot::Wrapped, T>, bool> = true> template <typename T, std::enable_if_t<std::is_base_of_v<godot::Wrapped, T>, bool> = true>
void memdelete(T *p_class) { void memdelete(T *p_class) {
godot::internal::gdextension_interface_object_destroy(p_class->_owner); godot::internal::gdextension_interface_object_destroy(p_class->_owner);
} }
template <class T, class A> template <typename T, typename A>
void memdelete_allocator(T *p_class) { void memdelete_allocator(T *p_class) {
if (!std::is_trivially_destructible<T>::value) { if constexpr (!std::is_trivially_destructible_v<T>) {
p_class->~T(); p_class->~T();
} }
@ -126,16 +134,20 @@ public:
_ALWAYS_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr); } _ALWAYS_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr); }
}; };
template <class T> template <typename T>
class DefaultTypedAllocator { class DefaultTypedAllocator {
public: public:
template <class... Args> template <typename... Args>
_ALWAYS_INLINE_ T *new_allocation(const Args &&...p_args) { return memnew(T(p_args...)); } _ALWAYS_INLINE_ T *new_allocation(const Args &&...p_args) { return memnew(T(p_args...)); }
_ALWAYS_INLINE_ void delete_allocation(T *p_allocation) { memdelete(p_allocation); } _ALWAYS_INLINE_ void delete_allocation(T *p_allocation) { memdelete(p_allocation); }
}; };
#define memnew_arr(m_class, m_count) memnew_arr_template<m_class>(m_count) #define memnew_arr(m_class, m_count) memnew_arr_template<m_class>(m_count)
_FORCE_INLINE_ uint64_t *_get_element_count_ptr(uint8_t *p_ptr) {
return (uint64_t *)(p_ptr - Memory::DATA_OFFSET + Memory::ELEMENT_OFFSET);
}
template <typename T> template <typename T>
T *memnew_arr_template(size_t p_elements, const char *p_descr = "") { T *memnew_arr_template(size_t p_elements, const char *p_descr = "") {
if (p_elements == 0) { if (p_elements == 0) {
@ -145,12 +157,14 @@ T *memnew_arr_template(size_t p_elements, const char *p_descr = "") {
same strategy used by std::vector, and the Vector class, so it should be safe.*/ same strategy used by std::vector, and the Vector class, so it should be safe.*/
size_t len = sizeof(T) * p_elements; size_t len = sizeof(T) * p_elements;
uint64_t *mem = (uint64_t *)Memory::alloc_static(len, true); uint8_t *mem = (uint8_t *)Memory::alloc_static(len, true);
T *failptr = nullptr; // Get rid of a warning. T *failptr = nullptr; // Get rid of a warning.
ERR_FAIL_NULL_V(mem, failptr); ERR_FAIL_NULL_V(mem, failptr);
*(mem - 1) = p_elements;
if (!std::is_trivially_destructible<T>::value) { uint64_t *_elem_count_ptr = _get_element_count_ptr(mem);
*(_elem_count_ptr) = p_elements;
if constexpr (!std::is_trivially_destructible_v<T>) {
T *elems = (T *)mem; T *elems = (T *)mem;
/* call operator new */ /* call operator new */
@ -163,11 +177,19 @@ T *memnew_arr_template(size_t p_elements, const char *p_descr = "") {
} }
template <typename T> template <typename T>
void memdelete_arr(T *p_class) { size_t memarr_len(const T *p_class) {
uint64_t *ptr = (uint64_t *)p_class; uint8_t *ptr = (uint8_t *)p_class;
uint64_t *_elem_count_ptr = _get_element_count_ptr(ptr);
return *(_elem_count_ptr);
}
if (!std::is_trivially_destructible<T>::value) { template <typename T>
uint64_t elem_count = *(ptr - 1); void memdelete_arr(T *p_class) {
uint8_t *ptr = (uint8_t *)p_class;
if constexpr (!std::is_trivially_destructible_v<T>) {
uint64_t *_elem_count_ptr = _get_element_count_ptr(ptr);
uint64_t elem_count = *(_elem_count_ptr);
for (uint64_t i = 0; i < elem_count; i++) { for (uint64_t i = 0; i < elem_count; i++) {
p_class[i].~T(); p_class[i].~T();

View File

@ -147,7 +147,7 @@ public:
virtual ~MethodBind(); virtual ~MethodBind();
}; };
template <class Derived, class T, class R, bool should_returns> template <typename Derived, typename T, typename R, bool should_returns>
class MethodBindVarArgBase : public MethodBind { class MethodBindVarArgBase : public MethodBind {
protected: protected:
R(T::*method) R(T::*method)
@ -208,7 +208,7 @@ private:
} }
}; };
template <class T> template <typename T>
class MethodBindVarArgT : public MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false> { class MethodBindVarArgT : public MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false> {
friend class MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>; friend class MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>;
@ -231,14 +231,14 @@ private:
} }
}; };
template <class T> template <typename T>
MethodBind *create_vararg_method_bind(void (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) { MethodBind *create_vararg_method_bind(void (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
MethodBind *a = memnew((MethodBindVarArgT<T>)(p_method, p_info, p_return_nil_is_variant)); MethodBind *a = memnew((MethodBindVarArgT<T>)(p_method, p_info, p_return_nil_is_variant));
a->set_instance_class(T::get_class_static()); a->set_instance_class(T::get_class_static());
return a; return a;
} }
template <class T, class R> template <typename T, typename R>
class MethodBindVarArgTR : public MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true> { class MethodBindVarArgTR : public MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true> {
friend class MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>; friend class MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>;
@ -260,7 +260,7 @@ private:
} }
}; };
template <class T, class R> template <typename T, typename R>
MethodBind *create_vararg_method_bind(R (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) { MethodBind *create_vararg_method_bind(R (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
MethodBind *a = memnew((MethodBindVarArgTR<T, R>)(p_method, p_info, p_return_nil_is_variant)); MethodBind *a = memnew((MethodBindVarArgTR<T, R>)(p_method, p_info, p_return_nil_is_variant));
a->set_instance_class(T::get_class_static()); a->set_instance_class(T::get_class_static());
@ -277,9 +277,9 @@ class _gde_UnexistingClass;
// No return, not const. // No return, not const.
#ifdef TYPED_METHOD_BIND #ifdef TYPED_METHOD_BIND
template <class T, class... P> template <typename T, typename... P>
#else #else
template <class... P> template <typename... P>
#endif // TYPED_METHOD_BIND #endif // TYPED_METHOD_BIND
class MethodBindT : public MethodBind { class MethodBindT : public MethodBind {
void (MB_T::*method)(P...); void (MB_T::*method)(P...);
@ -339,7 +339,7 @@ public:
} }
}; };
template <class T, class... P> template <typename T, typename... P>
MethodBind *create_method_bind(void (T::*p_method)(P...)) { MethodBind *create_method_bind(void (T::*p_method)(P...)) {
#ifdef TYPED_METHOD_BIND #ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindT<T, P...>)(p_method)); MethodBind *a = memnew((MethodBindT<T, P...>)(p_method));
@ -353,9 +353,9 @@ MethodBind *create_method_bind(void (T::*p_method)(P...)) {
// No return, const. // No return, const.
#ifdef TYPED_METHOD_BIND #ifdef TYPED_METHOD_BIND
template <class T, class... P> template <typename T, typename... P>
#else #else
template <class... P> template <typename... P>
#endif // TYPED_METHOD_BIND #endif // TYPED_METHOD_BIND
class MethodBindTC : public MethodBind { class MethodBindTC : public MethodBind {
void (MB_T::*method)(P...) const; void (MB_T::*method)(P...) const;
@ -415,7 +415,7 @@ public:
} }
}; };
template <class T, class... P> template <typename T, typename... P>
MethodBind *create_method_bind(void (T::*p_method)(P...) const) { MethodBind *create_method_bind(void (T::*p_method)(P...) const) {
#ifdef TYPED_METHOD_BIND #ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindTC<T, P...>)(p_method)); MethodBind *a = memnew((MethodBindTC<T, P...>)(p_method));
@ -429,9 +429,9 @@ MethodBind *create_method_bind(void (T::*p_method)(P...) const) {
// Return, not const. // Return, not const.
#ifdef TYPED_METHOD_BIND #ifdef TYPED_METHOD_BIND
template <class T, class R, class... P> template <typename T, typename R, typename... P>
#else #else
template <class R, class... P> template <typename R, typename... P>
#endif // TYPED_METHOD_BIND #endif // TYPED_METHOD_BIND
class MethodBindTR : public MethodBind { class MethodBindTR : public MethodBind {
R(MB_T::*method) R(MB_T::*method)
@ -498,7 +498,7 @@ public:
} }
}; };
template <class T, class R, class... P> template <typename T, typename R, typename... P>
MethodBind *create_method_bind(R (T::*p_method)(P...)) { MethodBind *create_method_bind(R (T::*p_method)(P...)) {
#ifdef TYPED_METHOD_BIND #ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindTR<T, R, P...>)(p_method)); MethodBind *a = memnew((MethodBindTR<T, R, P...>)(p_method));
@ -512,9 +512,9 @@ MethodBind *create_method_bind(R (T::*p_method)(P...)) {
// Return, const. // Return, const.
#ifdef TYPED_METHOD_BIND #ifdef TYPED_METHOD_BIND
template <class T, class R, class... P> template <typename T, typename R, typename... P>
#else #else
template <class R, class... P> template <typename R, typename... P>
#endif // TYPED_METHOD_BIND #endif // TYPED_METHOD_BIND
class MethodBindTRC : public MethodBind { class MethodBindTRC : public MethodBind {
R(MB_T::*method) R(MB_T::*method)
@ -581,7 +581,7 @@ public:
} }
}; };
template <class T, class R, class... P> template <typename T, typename R, typename... P>
MethodBind *create_method_bind(R (T::*p_method)(P...) const) { MethodBind *create_method_bind(R (T::*p_method)(P...) const) {
#ifdef TYPED_METHOD_BIND #ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindTRC<T, R, P...>)(p_method)); MethodBind *a = memnew((MethodBindTRC<T, R, P...>)(p_method));
@ -596,7 +596,7 @@ MethodBind *create_method_bind(R (T::*p_method)(P...) const) {
// no return // no return
template <class... P> template <typename... P>
class MethodBindTS : public MethodBind { class MethodBindTS : public MethodBind {
void (*function)(P...); void (*function)(P...);
@ -652,7 +652,7 @@ public:
} }
}; };
template <class... P> template <typename... P>
MethodBind *create_static_method_bind(void (*p_method)(P...)) { MethodBind *create_static_method_bind(void (*p_method)(P...)) {
MethodBind *a = memnew((MethodBindTS<P...>)(p_method)); MethodBind *a = memnew((MethodBindTS<P...>)(p_method));
return a; return a;
@ -660,7 +660,7 @@ MethodBind *create_static_method_bind(void (*p_method)(P...)) {
// return // return
template <class R, class... P> template <typename R, typename... P>
class MethodBindTRS : public MethodBind { class MethodBindTRS : public MethodBind {
R(*function) R(*function)
(P...); (P...);
@ -722,7 +722,7 @@ public:
} }
}; };
template <class R, class... P> template <typename R, typename... P>
MethodBind *create_static_method_bind(R (*p_method)(P...)) { MethodBind *create_static_method_bind(R (*p_method)(P...)) {
MethodBind *a = memnew((MethodBindTRS<R, P...>)(p_method)); MethodBind *a = memnew((MethodBindTRS<R, P...>)(p_method));
return a; return a;

View File

@ -39,7 +39,7 @@
namespace godot { namespace godot {
template <class T> template <typename T>
struct PtrToArg {}; struct PtrToArg {};
#define MAKE_PTRARG(m_type) \ #define MAKE_PTRARG(m_type) \
@ -166,7 +166,7 @@ MAKE_PTRARG_BY_REFERENCE(Variant);
// This is for Object. // This is for Object.
template <class T> template <typename T>
struct PtrToArg<T *> { struct PtrToArg<T *> {
static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object"); static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object");
_FORCE_INLINE_ static T *convert(const void *p_ptr) { _FORCE_INLINE_ static T *convert(const void *p_ptr) {
@ -178,7 +178,7 @@ struct PtrToArg<T *> {
} }
}; };
template <class T> template <typename T>
struct PtrToArg<const T *> { struct PtrToArg<const T *> {
static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object"); static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object");
_FORCE_INLINE_ static const T *convert(const void *p_ptr) { _FORCE_INLINE_ static const T *convert(const void *p_ptr) {

View File

@ -47,11 +47,11 @@
#include <vector> #include <vector>
#define ADD_SIGNAL(m_signal) godot::ClassDB::add_signal(get_class_static(), m_signal) #define ADD_SIGNAL(m_signal) ::godot::ClassDB::add_signal(get_class_static(), m_signal)
#define ADD_GROUP(m_name, m_prefix) godot::ClassDB::add_property_group(get_class_static(), m_name, m_prefix) #define ADD_GROUP(m_name, m_prefix) ::godot::ClassDB::add_property_group(get_class_static(), m_name, m_prefix)
#define ADD_SUBGROUP(m_name, m_prefix) godot::ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix) #define ADD_SUBGROUP(m_name, m_prefix) ::godot::ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix)
#define ADD_PROPERTY(m_property, m_setter, m_getter) godot::ClassDB::add_property(get_class_static(), m_property, m_setter, m_getter) #define ADD_PROPERTY(m_property, m_setter, m_getter) ::godot::ClassDB::add_property(get_class_static(), m_property, m_setter, m_getter)
#define ADD_PROPERTYI(m_property, m_setter, m_getter, m_index) godot::ClassDB::add_property(get_class_static(), m_property, m_setter, m_getter, m_index) #define ADD_PROPERTYI(m_property, m_setter, m_getter, m_index) ::godot::ClassDB::add_property(get_class_static(), m_property, m_setter, m_getter, m_index)
namespace godot { namespace godot {
@ -78,31 +78,31 @@ struct MethodInfo {
MethodInfo(); MethodInfo();
MethodInfo(StringName p_name); MethodInfo(StringName p_name);
template <class... Args> template <typename... Args>
MethodInfo(StringName p_name, const Args &...args); MethodInfo(StringName p_name, const Args &...args);
MethodInfo(Variant::Type ret); MethodInfo(Variant::Type ret);
MethodInfo(Variant::Type ret, StringName p_name); MethodInfo(Variant::Type ret, StringName p_name);
template <class... Args> template <typename... Args>
MethodInfo(Variant::Type ret, StringName p_name, const Args &...args); MethodInfo(Variant::Type ret, StringName p_name, const Args &...args);
MethodInfo(const PropertyInfo &p_ret, StringName p_name); MethodInfo(const PropertyInfo &p_ret, StringName p_name);
template <class... Args> template <typename... Args>
MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...); MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...);
}; };
template <class... Args> template <typename... Args>
MethodInfo::MethodInfo(StringName p_name, const Args &...args) : MethodInfo::MethodInfo(StringName p_name, const Args &...args) :
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) { name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
arguments = { args... }; arguments = { args... };
} }
template <class... Args> template <typename... Args>
MethodInfo::MethodInfo(Variant::Type ret, StringName p_name, const Args &...args) : MethodInfo::MethodInfo(Variant::Type ret, StringName p_name, const Args &...args) :
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) { name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
return_val.type = ret; return_val.type = ret;
arguments = { args... }; arguments = { args... };
} }
template <class... Args> template <typename... Args>
MethodInfo::MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...args) : MethodInfo::MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...args) :
name(p_name), return_val(p_ret), flags(GDEXTENSION_METHOD_FLAG_NORMAL) { name(p_name), return_val(p_ret), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
arguments = { args... }; arguments = { args... };
@ -119,7 +119,7 @@ public:
} }
}; };
template <class T> template <typename T>
T *Object::cast_to(Object *p_object) { T *Object::cast_to(Object *p_object) {
if (p_object == nullptr) { if (p_object == nullptr) {
return nullptr; return nullptr;
@ -132,7 +132,7 @@ T *Object::cast_to(Object *p_object) {
return dynamic_cast<T *>(internal::get_object_instance_binding(casted)); return dynamic_cast<T *>(internal::get_object_instance_binding(casted));
} }
template <class T> template <typename T>
const T *Object::cast_to(const Object *p_object) { const T *Object::cast_to(const Object *p_object) {
if (p_object == nullptr) { if (p_object == nullptr) {
return nullptr; return nullptr;

View File

@ -90,7 +90,7 @@ static PropertyInfo make_property_info(Variant::Type p_type, const StringName &p
// instead of a forward declaration. You can always forward declare 'T' in a header file, and then // instead of a forward declaration. You can always forward declare 'T' in a header file, and then
// include the actual declaration of 'T' in the source file where 'GetTypeInfo<T>' is instantiated. // include the actual declaration of 'T' in the source file where 'GetTypeInfo<T>' is instantiated.
template <class T, typename = void> template <typename T, typename = void>
struct GetTypeInfo; struct GetTypeInfo;
#define MAKE_TYPE_INFO(m_type, m_var_type) \ #define MAKE_TYPE_INFO(m_type, m_var_type) \
@ -248,14 +248,14 @@ inline StringName _gde_constant_get_enum_name(T param, StringName p_constant) {
return GetTypeInfo<T>::get_class_info().class_name; return GetTypeInfo<T>::get_class_info().class_name;
} }
template <class T> template <typename T>
class BitField { class BitField {
int64_t value = 0; int64_t value = 0;
public: public:
_FORCE_INLINE_ void set_flag(T p_flag) { value |= p_flag; } _FORCE_INLINE_ void set_flag(T p_flag) { value |= p_flag; }
_FORCE_INLINE_ bool has_flag(T p_flag) const { return value & p_flag; } _FORCE_INLINE_ bool has_flag(T p_flag) const { return value & p_flag; }
_FORCE_INLINE_ void clear_flag(T p_flag) { return value &= ~p_flag; } _FORCE_INLINE_ void clear_flag(T p_flag) { value &= ~p_flag; }
_FORCE_INLINE_ BitField(int64_t p_value) { value = p_value; } _FORCE_INLINE_ BitField(int64_t p_value) { value = p_value; }
_FORCE_INLINE_ operator int64_t() const { return value; } _FORCE_INLINE_ operator int64_t() const { return value; }
_FORCE_INLINE_ operator Variant() const { return value; } _FORCE_INLINE_ operator Variant() const { return value; }
@ -295,7 +295,7 @@ inline StringName _gde_constant_get_bitfield_name(T param, StringName p_constant
return GetTypeInfo<BitField<T>>::get_class_info().class_name; return GetTypeInfo<BitField<T>>::get_class_info().class_name;
} }
template <class T> template <typename T>
struct PtrToArg<TypedArray<T>> { struct PtrToArg<TypedArray<T>> {
_FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) { _FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) {
return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr)); return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
@ -306,7 +306,7 @@ struct PtrToArg<TypedArray<T>> {
} }
}; };
template <class T> template <typename T>
struct PtrToArg<const TypedArray<T> &> { struct PtrToArg<const TypedArray<T> &> {
typedef Array EncodeT; typedef Array EncodeT;
_FORCE_INLINE_ static TypedArray<T> _FORCE_INLINE_ static TypedArray<T>

View File

@ -43,78 +43,120 @@
namespace godot { namespace godot {
template <class T> template <typename T>
class Vector; class Vector;
template <class T, class V> template <typename T, typename V>
class VMap; class VMap;
template <class T> template <typename T>
class CharStringT; class CharStringT;
static_assert(std::is_trivially_destructible_v<std::atomic<uint64_t>>);
// Silence a false positive warning (see GH-52119). // Silence a false positive warning (see GH-52119).
#if defined(__GNUC__) && !defined(__clang__) #if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wplacement-new" #pragma GCC diagnostic ignored "-Wplacement-new"
#endif #endif
template <class T> template <typename T>
class CowData { class CowData {
template <class TV> template <typename TV>
friend class Vector; friend class Vector;
template <class TV, class VV> template <typename TV, typename VV>
friend class VMap; friend class VMap;
template <class TS> template <typename TS>
friend class CharStringT; friend class CharStringT;
public:
typedef int64_t Size;
typedef uint64_t USize;
static constexpr USize MAX_INT = INT64_MAX;
private: private:
// Function to find the next power of 2 to an integer.
static _FORCE_INLINE_ USize next_po2(USize x) {
if (x == 0) {
return 0;
}
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
if (sizeof(USize) == 8) {
x |= x >> 32;
}
return ++x;
}
// Alignment: ↓ max_align_t ↓ USize ↓ max_align_t
// ┌────────────────────┬──┬─────────────┬──┬───────────...
// │ SafeNumeric<USize> │░░│ USize │░░│ T[]
// │ ref. count │░░│ data size │░░│ data
// └────────────────────┴──┴─────────────┴──┴───────────...
// Offset: ↑ REF_COUNT_OFFSET ↑ SIZE_OFFSET ↑ DATA_OFFSET
static constexpr size_t REF_COUNT_OFFSET = 0;
static constexpr size_t SIZE_OFFSET = ((REF_COUNT_OFFSET + sizeof(SafeNumeric<USize>)) % alignof(USize) == 0) ? (REF_COUNT_OFFSET + sizeof(SafeNumeric<USize>)) : ((REF_COUNT_OFFSET + sizeof(SafeNumeric<USize>)) + alignof(USize) - ((REF_COUNT_OFFSET + sizeof(SafeNumeric<USize>)) % alignof(USize)));
static constexpr size_t DATA_OFFSET = ((SIZE_OFFSET + sizeof(USize)) % alignof(max_align_t) == 0) ? (SIZE_OFFSET + sizeof(USize)) : ((SIZE_OFFSET + sizeof(USize)) + alignof(max_align_t) - ((SIZE_OFFSET + sizeof(USize)) % alignof(max_align_t)));
mutable T *_ptr = nullptr; mutable T *_ptr = nullptr;
// internal helpers // internal helpers
_FORCE_INLINE_ SafeNumeric<uint32_t> *_get_refcount() const { static _FORCE_INLINE_ SafeNumeric<USize> *_get_refcount_ptr(uint8_t *p_ptr) {
return (SafeNumeric<USize> *)(p_ptr + REF_COUNT_OFFSET);
}
static _FORCE_INLINE_ USize *_get_size_ptr(uint8_t *p_ptr) {
return (USize *)(p_ptr + SIZE_OFFSET);
}
static _FORCE_INLINE_ T *_get_data_ptr(uint8_t *p_ptr) {
return (T *)(p_ptr + DATA_OFFSET);
}
_FORCE_INLINE_ SafeNumeric<USize> *_get_refcount() const {
if (!_ptr) { if (!_ptr) {
return nullptr; return nullptr;
} }
return reinterpret_cast<SafeNumeric<uint32_t> *>(_ptr) - 2; return (SafeNumeric<USize> *)((uint8_t *)_ptr - DATA_OFFSET + REF_COUNT_OFFSET);
} }
_FORCE_INLINE_ uint32_t *_get_size() const { _FORCE_INLINE_ USize *_get_size() const {
if (!_ptr) { if (!_ptr) {
return nullptr; return nullptr;
} }
return reinterpret_cast<uint32_t *>(_ptr) - 1; return (USize *)((uint8_t *)_ptr - DATA_OFFSET + SIZE_OFFSET);
} }
_FORCE_INLINE_ T *_get_data() const { _FORCE_INLINE_ USize _get_alloc_size(USize p_elements) const {
if (!_ptr) { return next_po2(p_elements * sizeof(T));
return nullptr;
}
return reinterpret_cast<T *>(_ptr);
} }
_FORCE_INLINE_ size_t _get_alloc_size(size_t p_elements) const { _FORCE_INLINE_ bool _get_alloc_size_checked(USize p_elements, USize *out) const {
return next_power_of_2(p_elements * sizeof(T));
}
_FORCE_INLINE_ bool _get_alloc_size_checked(size_t p_elements, size_t *out) const {
if (unlikely(p_elements == 0)) { if (unlikely(p_elements == 0)) {
*out = 0; *out = 0;
return true; return true;
} }
#if defined(__GNUC__) #if defined(__GNUC__) && defined(IS_32_BIT)
size_t o; USize o;
size_t p; USize p;
if (__builtin_mul_overflow(p_elements, sizeof(T), &o)) { if (__builtin_mul_overflow(p_elements, sizeof(T), &o)) {
*out = 0; *out = 0;
return false; return false;
} }
*out = next_power_of_2(o); *out = next_po2(o);
if (__builtin_add_overflow(o, static_cast<size_t>(32), &p)) { if (__builtin_add_overflow(o, static_cast<USize>(32), &p)) {
return false; // No longer allocated here. return false; // No longer allocated here.
} }
#else #else
@ -128,22 +170,22 @@ private:
void _unref(void *p_data); void _unref(void *p_data);
void _ref(const CowData *p_from); void _ref(const CowData *p_from);
void _ref(const CowData &p_from); void _ref(const CowData &p_from);
uint32_t _copy_on_write(); USize _copy_on_write();
public: public:
void operator=(const CowData<T> &p_from) { _ref(p_from); } void operator=(const CowData<T> &p_from) { _ref(p_from); }
_FORCE_INLINE_ T *ptrw() { _FORCE_INLINE_ T *ptrw() {
_copy_on_write(); _copy_on_write();
return (T *)_get_data(); return _ptr;
} }
_FORCE_INLINE_ const T *ptr() const { _FORCE_INLINE_ const T *ptr() const {
return _get_data(); return _ptr;
} }
_FORCE_INLINE_ int size() const { _FORCE_INLINE_ Size size() const {
uint32_t *size = (uint32_t *)_get_size(); USize *size = (USize *)_get_size();
if (size) { if (size) {
return *size; return *size;
} else { } else {
@ -154,41 +196,42 @@ public:
_FORCE_INLINE_ void clear() { resize(0); } _FORCE_INLINE_ void clear() { resize(0); }
_FORCE_INLINE_ bool is_empty() const { return _ptr == nullptr; } _FORCE_INLINE_ bool is_empty() const { return _ptr == nullptr; }
_FORCE_INLINE_ void set(int p_index, const T &p_elem) { _FORCE_INLINE_ void set(Size p_index, const T &p_elem) {
ERR_FAIL_INDEX(p_index, size()); ERR_FAIL_INDEX(p_index, size());
_copy_on_write(); _copy_on_write();
_get_data()[p_index] = p_elem; _ptr[p_index] = p_elem;
} }
_FORCE_INLINE_ T &get_m(int p_index) { _FORCE_INLINE_ T &get_m(Size p_index) {
CRASH_BAD_INDEX(p_index, size()); CRASH_BAD_INDEX(p_index, size());
_copy_on_write(); _copy_on_write();
return _get_data()[p_index]; return _ptr[p_index];
} }
_FORCE_INLINE_ const T &get(int p_index) const { _FORCE_INLINE_ const T &get(Size p_index) const {
CRASH_BAD_INDEX(p_index, size()); CRASH_BAD_INDEX(p_index, size());
return _get_data()[p_index]; return _ptr[p_index];
} }
Error resize(int p_size); template <bool p_ensure_zero = false>
Error resize(Size p_size);
_FORCE_INLINE_ void remove_at(int p_index) { _FORCE_INLINE_ void remove_at(Size p_index) {
ERR_FAIL_INDEX(p_index, size()); ERR_FAIL_INDEX(p_index, size());
T *p = ptrw(); T *p = ptrw();
int len = size(); Size len = size();
for (int i = p_index; i < len - 1; i++) { for (Size i = p_index; i < len - 1; i++) {
p[i] = p[i + 1]; p[i] = p[i + 1];
} }
resize(len - 1); resize(len - 1);
} }
Error insert(int p_pos, const T &p_val) { Error insert(Size p_pos, const T &p_val) {
ERR_FAIL_INDEX_V(p_pos, size() + 1, ERR_INVALID_PARAMETER); ERR_FAIL_INDEX_V(p_pos, size() + 1, ERR_INVALID_PARAMETER);
resize(size() + 1); resize(size() + 1);
for (int i = (size() - 1); i > p_pos; i--) { for (Size i = (size() - 1); i > p_pos; i--) {
set(i, get(i - 1)); set(i, get(i - 1));
} }
set(p_pos, p_val); set(p_pos, p_val);
@ -196,83 +239,88 @@ public:
return OK; return OK;
} }
int find(const T &p_val, int p_from = 0) const; Size find(const T &p_val, Size p_from = 0) const;
Size rfind(const T &p_val, Size p_from = -1) const;
Size count(const T &p_val) const;
_FORCE_INLINE_ CowData() {} _FORCE_INLINE_ CowData() {}
_FORCE_INLINE_ ~CowData(); _FORCE_INLINE_ ~CowData();
_FORCE_INLINE_ CowData(CowData<T> &p_from) { _ref(p_from); } _FORCE_INLINE_ CowData(CowData<T> &p_from) { _ref(p_from); };
}; };
template <class T> template <typename T>
void CowData<T>::_unref(void *p_data) { void CowData<T>::_unref(void *p_data) {
if (!p_data) { if (!p_data) {
return; return;
} }
SafeNumeric<uint32_t> *refc = _get_refcount(); SafeNumeric<USize> *refc = _get_refcount();
if (refc->decrement() > 0) { if (refc->decrement() > 0) {
return; // still in use return; // still in use
} }
// clean up // clean up
if (!std::is_trivially_destructible<T>::value) {
uint32_t *count = _get_size(); if constexpr (!std::is_trivially_destructible_v<T>) {
USize *count = _get_size();
T *data = (T *)(count + 1); T *data = (T *)(count + 1);
for (uint32_t i = 0; i < *count; ++i) { for (USize i = 0; i < *count; ++i) {
// call destructors // call destructors
data[i].~T(); data[i].~T();
} }
} }
// free mem // free mem
Memory::free_static((uint8_t *)p_data, true); Memory::free_static(((uint8_t *)p_data) - DATA_OFFSET, false);
} }
template <class T> template <typename T>
uint32_t CowData<T>::_copy_on_write() { typename CowData<T>::USize CowData<T>::_copy_on_write() {
if (!_ptr) { if (!_ptr) {
return 0; return 0;
} }
SafeNumeric<uint32_t> *refc = _get_refcount(); SafeNumeric<USize> *refc = _get_refcount();
uint32_t rc = refc->get(); USize rc = refc->get();
if (unlikely(rc > 1)) { if (unlikely(rc > 1)) {
/* in use by more than me */ /* in use by more than me */
uint32_t current_size = *_get_size(); USize current_size = *_get_size();
uint32_t *mem_new = (uint32_t *)Memory::alloc_static(_get_alloc_size(current_size), true); uint8_t *mem_new = (uint8_t *)Memory::alloc_static(_get_alloc_size(current_size) + DATA_OFFSET, false);
ERR_FAIL_NULL_V(mem_new, 0);
new (mem_new - 2) SafeNumeric<uint32_t>(1); // refcount SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
*(mem_new - 1) = current_size; // size USize *_size_ptr = _get_size_ptr(mem_new);
T *_data_ptr = _get_data_ptr(mem_new);
T *_data = (T *)(mem_new); new (_refc_ptr) SafeNumeric<USize>(1); //refcount
*(_size_ptr) = current_size; //size
// initialize new elements // initialize new elements
if (std::is_trivially_copyable<T>::value) { if constexpr (std::is_trivially_copyable_v<T>) {
memcpy(mem_new, _ptr, current_size * sizeof(T)); memcpy((uint8_t *)_data_ptr, _ptr, current_size * sizeof(T));
} else { } else {
for (uint32_t i = 0; i < current_size; i++) { for (USize i = 0; i < current_size; i++) {
memnew_placement(&_data[i], T(_get_data()[i])); memnew_placement(&_data_ptr[i], T(_ptr[i]));
} }
} }
_unref(_ptr); _unref(_ptr);
_ptr = _data; _ptr = _data_ptr;
rc = 1; rc = 1;
} }
return rc; return rc;
} }
template <class T> template <typename T>
Error CowData<T>::resize(int p_size) { template <bool p_ensure_zero>
Error CowData<T>::resize(Size p_size) {
ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER);
int current_size = size(); Size current_size = size();
if (p_size == current_size) { if (p_size == current_size) {
return OK; return OK;
@ -286,59 +334,71 @@ Error CowData<T>::resize(int p_size) {
} }
// possibly changing size, copy on write // possibly changing size, copy on write
uint32_t rc = _copy_on_write(); USize rc = _copy_on_write();
size_t current_alloc_size = _get_alloc_size(current_size); USize current_alloc_size = _get_alloc_size(current_size);
size_t alloc_size; USize alloc_size;
ERR_FAIL_COND_V(!_get_alloc_size_checked(p_size, &alloc_size), ERR_OUT_OF_MEMORY); ERR_FAIL_COND_V(!_get_alloc_size_checked(p_size, &alloc_size), ERR_OUT_OF_MEMORY);
if (p_size > current_size) { if (p_size > current_size) {
if (alloc_size != current_alloc_size) { if (alloc_size != current_alloc_size) {
if (current_size == 0) { if (current_size == 0) {
// alloc from scratch // alloc from scratch
uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true); uint8_t *mem_new = (uint8_t *)Memory::alloc_static(alloc_size + DATA_OFFSET, false);
ERR_FAIL_NULL_V(ptr, ERR_OUT_OF_MEMORY); ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY);
*(ptr - 1) = 0; // size, currently none
new (ptr - 2) SafeNumeric<uint32_t>(1); // refcount
_ptr = (T *)ptr; SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
USize *_size_ptr = _get_size_ptr(mem_new);
T *_data_ptr = _get_data_ptr(mem_new);
new (_refc_ptr) SafeNumeric<USize>(1); //refcount
*(_size_ptr) = 0; //size, currently none
_ptr = _data_ptr;
} else { } else {
uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true); uint8_t *mem_new = (uint8_t *)Memory::realloc_static(((uint8_t *)_ptr) - DATA_OFFSET, alloc_size + DATA_OFFSET, false);
ERR_FAIL_NULL_V(_ptrnew, ERR_OUT_OF_MEMORY); ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY);
new (_ptrnew - 2) SafeNumeric<uint32_t>(rc); // refcount
_ptr = (T *)(_ptrnew); SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
T *_data_ptr = _get_data_ptr(mem_new);
new (_refc_ptr) SafeNumeric<USize>(rc); //refcount
_ptr = _data_ptr;
} }
} }
// construct the newly created elements // construct the newly created elements
if (!std::is_trivially_constructible<T>::value) { if constexpr (!std::is_trivially_constructible_v<T>) {
T *elems = _get_data(); for (Size i = *_get_size(); i < p_size; i++) {
memnew_placement(&_ptr[i], T);
for (int i = *_get_size(); i < p_size; i++) {
memnew_placement(&elems[i], T);
} }
} else if (p_ensure_zero) {
memset((void *)(_ptr + current_size), 0, (p_size - current_size) * sizeof(T));
} }
*_get_size() = p_size; *_get_size() = p_size;
} else if (p_size < current_size) { } else if (p_size < current_size) {
if (!std::is_trivially_destructible<T>::value) { if constexpr (!std::is_trivially_destructible_v<T>) {
// deinitialize no longer needed elements // deinitialize no longer needed elements
for (uint32_t i = p_size; i < *_get_size(); i++) { for (USize i = p_size; i < *_get_size(); i++) {
T *t = &_get_data()[i]; T *t = &_ptr[i];
t->~T(); t->~T();
} }
} }
if (alloc_size != current_alloc_size) { if (alloc_size != current_alloc_size) {
uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true); uint8_t *mem_new = (uint8_t *)Memory::realloc_static(((uint8_t *)_ptr) - DATA_OFFSET, alloc_size + DATA_OFFSET, false);
ERR_FAIL_NULL_V(_ptrnew, ERR_OUT_OF_MEMORY); ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY);
new (_ptrnew - 2) SafeNumeric<uint32_t>(rc); // refcount
_ptr = (T *)(_ptrnew); SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
T *_data_ptr = _get_data_ptr(mem_new);
new (_refc_ptr) SafeNumeric<USize>(rc); //refcount
_ptr = _data_ptr;
} }
*_get_size() = p_size; *_get_size() = p_size;
@ -347,15 +407,15 @@ Error CowData<T>::resize(int p_size) {
return OK; return OK;
} }
template <class T> template <typename T>
int CowData<T>::find(const T &p_val, int p_from) const { typename CowData<T>::Size CowData<T>::find(const T &p_val, Size p_from) const {
int ret = -1; Size ret = -1;
if (p_from < 0 || size() == 0) { if (p_from < 0 || size() == 0) {
return ret; return ret;
} }
for (int i = p_from; i < size(); i++) { for (Size i = p_from; i < size(); i++) {
if (get(i) == p_val) { if (get(i) == p_val) {
ret = i; ret = i;
break; break;
@ -365,12 +425,42 @@ int CowData<T>::find(const T &p_val, int p_from) const {
return ret; return ret;
} }
template <class T> template <typename T>
typename CowData<T>::Size CowData<T>::rfind(const T &p_val, Size p_from) const {
const Size s = size();
if (p_from < 0) {
p_from = s + p_from;
}
if (p_from < 0 || p_from >= s) {
p_from = s - 1;
}
for (Size i = p_from; i >= 0; i--) {
if (get(i) == p_val) {
return i;
}
}
return -1;
}
template <typename T>
typename CowData<T>::Size CowData<T>::count(const T &p_val) const {
Size amount = 0;
for (Size i = 0; i < size(); i++) {
if (get(i) == p_val) {
amount++;
}
}
return amount;
}
template <typename T>
void CowData<T>::_ref(const CowData *p_from) { void CowData<T>::_ref(const CowData *p_from) {
_ref(*p_from); _ref(*p_from);
} }
template <class T> template <typename T>
void CowData<T>::_ref(const CowData &p_from) { void CowData<T>::_ref(const CowData &p_from) {
if (_ptr == p_from._ptr) { if (_ptr == p_from._ptr) {
return; // self assign, do nothing. return; // self assign, do nothing.
@ -388,7 +478,7 @@ void CowData<T>::_ref(const CowData &p_from) {
} }
} }
template <class T> template <typename T>
CowData<T>::~CowData() { CowData<T>::~CowData() {
_unref(_ptr); _unref(_ptr);
} }

View File

@ -52,7 +52,7 @@ namespace godot {
* The assignment operator copy the pairs from one map to the other. * The assignment operator copy the pairs from one map to the other.
*/ */
template <class TKey, class TValue> template <typename TKey, typename TValue>
struct HashMapElement { struct HashMapElement {
HashMapElement *next = nullptr; HashMapElement *next = nullptr;
HashMapElement *prev = nullptr; HashMapElement *prev = nullptr;
@ -62,10 +62,10 @@ struct HashMapElement {
data(p_key, p_value) {} data(p_key, p_value) {}
}; };
template <class TKey, class TValue, template <typename TKey, typename TValue,
class Hasher = HashMapHasherDefault, typename Hasher = HashMapHasherDefault,
class Comparator = HashMapComparatorDefault<TKey>, typename Comparator = HashMapComparatorDefault<TKey>,
class Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>> typename Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
class HashMap { class HashMap {
public: public:
const uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime. const uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.

View File

@ -48,9 +48,9 @@ namespace godot {
* *
*/ */
template <class TKey, template <typename TKey,
class Hasher = HashMapHasherDefault, typename Hasher = HashMapHasherDefault,
class Comparator = HashMapComparatorDefault<TKey>> typename Comparator = HashMapComparatorDefault<TKey>>
class HashSet { class HashSet {
public: public:
static constexpr uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime. static constexpr uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.

View File

@ -253,7 +253,7 @@ static _FORCE_INLINE_ uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev
return ((p_prev << 5) + p_prev) + hash_one_uint64(u.i); return ((p_prev << 5) + p_prev) + hash_one_uint64(u.i);
} }
template <class T> template <typename T>
static _FORCE_INLINE_ uint32_t hash_make_uint32_t(T p_in) { static _FORCE_INLINE_ uint32_t hash_make_uint32_t(T p_in) {
union { union {
T t; T t;
@ -286,7 +286,7 @@ static _FORCE_INLINE_ uint64_t hash_djb2_one_64(uint64_t p_in, uint64_t p_prev =
return ((p_prev << 5) + p_prev) ^ p_in; return ((p_prev << 5) + p_prev) ^ p_in;
} }
template <class T> template <typename T>
static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) { static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) {
union { union {
T t; T t;
@ -298,15 +298,15 @@ static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) {
return _u._u64; return _u._u64;
} }
template <class T> template <typename T>
class Ref; class Ref;
struct HashMapHasherDefault { struct HashMapHasherDefault {
// Generic hash function for any type. // Generic hash function for any type.
template <class T> template <typename T>
static _FORCE_INLINE_ uint32_t hash(const T *p_pointer) { return hash_one_uint64((uint64_t)p_pointer); } static _FORCE_INLINE_ uint32_t hash(const T *p_pointer) { return hash_one_uint64((uint64_t)p_pointer); }
template <class T> template <typename T>
static _FORCE_INLINE_ uint32_t hash(const Ref<T> &p_ref) { return hash_one_uint64((uint64_t)p_ref.operator->()); } static _FORCE_INLINE_ uint32_t hash(const Ref<T> &p_ref) { return hash_one_uint64((uint64_t)p_ref.operator->()); }
static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); } static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); }

View File

@ -45,7 +45,7 @@
namespace godot { namespace godot {
template <class T, class A = DefaultAllocator> template <typename T, typename A = DefaultAllocator>
class List { class List {
struct _Data; struct _Data;
@ -410,7 +410,7 @@ public:
/** /**
* find an element in the list, * find an element in the list,
*/ */
template <class T_v> template <typename T_v>
Element *find(const T_v &p_val) { Element *find(const T_v &p_val) {
Element *it = front(); Element *it = front();
while (it) { while (it) {
@ -646,7 +646,7 @@ public:
sort_custom<Comparator<T>>(); sort_custom<Comparator<T>>();
} }
template <class C> template <typename C>
void sort_custom_inplace() { void sort_custom_inplace() {
if (size() < 2) { if (size() < 2) {
return; return;
@ -693,7 +693,7 @@ public:
_data->last = to; _data->last = to;
} }
template <class C> template <typename C>
struct AuxiliaryComparator { struct AuxiliaryComparator {
C compare; C compare;
_FORCE_INLINE_ bool operator()(const Element *a, const Element *b) const { _FORCE_INLINE_ bool operator()(const Element *a, const Element *b) const {
@ -701,7 +701,7 @@ public:
} }
}; };
template <class C> template <typename C>
void sort_custom() { void sort_custom() {
// this version uses auxiliary memory for speed. // this version uses auxiliary memory for speed.
// if you don't want to use auxiliary memory, use the in_place version // if you don't want to use auxiliary memory, use the in_place version

View File

@ -43,7 +43,7 @@ namespace godot {
// If tight, it grows strictly as much as needed. // If tight, it grows strictly as much as needed.
// Otherwise, it grows exponentially (the default and what you want in most cases). // Otherwise, it grows exponentially (the default and what you want in most cases).
template <class T, class U = uint32_t, bool force_trivial = false, bool tight = false> template <typename T, typename U = uint32_t, bool force_trivial = false, bool tight = false>
class LocalVector { class LocalVector {
private: private:
U count = 0; U count = 0;
@ -257,7 +257,7 @@ public:
return -1; return -1;
} }
template <class C> template <typename C>
void sort_custom() { void sort_custom() {
U len = count; U len = count;
if (len == 0) { if (len == 0) {
@ -331,7 +331,7 @@ public:
} }
}; };
template <class T, class U = uint32_t, bool force_trivial = false> template <typename T, typename U = uint32_t, bool force_trivial = false>
using TightLocalVector = LocalVector<T, U, force_trivial, true>; using TightLocalVector = LocalVector<T, U, force_trivial, true>;
} // namespace godot } // namespace godot

View File

@ -33,7 +33,7 @@
namespace godot { namespace godot {
template <class F, class S> template <typename F, typename S>
struct Pair { struct Pair {
F first; F first;
S second; S second;
@ -49,17 +49,17 @@ struct Pair {
} }
}; };
template <class F, class S> template <typename F, typename S>
bool operator==(const Pair<F, S> &pair, const Pair<F, S> &other) { bool operator==(const Pair<F, S> &pair, const Pair<F, S> &other) {
return (pair.first == other.first) && (pair.second == other.second); return (pair.first == other.first) && (pair.second == other.second);
} }
template <class F, class S> template <typename F, typename S>
bool operator!=(const Pair<F, S> &pair, const Pair<F, S> &other) { bool operator!=(const Pair<F, S> &pair, const Pair<F, S> &other) {
return (pair.first != other.first) || (pair.second != other.second); return (pair.first != other.first) || (pair.second != other.second);
} }
template <class F, class S> template <typename F, typename S>
struct PairSort { struct PairSort {
bool operator()(const Pair<F, S> &A, const Pair<F, S> &B) const { bool operator()(const Pair<F, S> &A, const Pair<F, S> &B) const {
if (A.first != B.first) { if (A.first != B.first) {
@ -69,7 +69,7 @@ struct PairSort {
} }
}; };
template <class K, class V> template <typename K, typename V>
struct KeyValue { struct KeyValue {
const K key; const K key;
V value; V value;
@ -85,17 +85,17 @@ struct KeyValue {
} }
}; };
template <class K, class V> template <typename K, typename V>
bool operator==(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) { bool operator==(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
return (pair.key == other.key) && (pair.value == other.value); return (pair.key == other.key) && (pair.value == other.value);
} }
template <class K, class V> template <typename K, typename V>
bool operator!=(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) { bool operator!=(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
return (pair.key != other.key) || (pair.value != other.value); return (pair.key != other.key) || (pair.value != other.value);
} }
template <class K, class V> template <typename K, typename V>
struct KeyValueSort { struct KeyValueSort {
bool operator()(const KeyValue<K, V> &A, const KeyValue<K, V> &B) const { bool operator()(const KeyValue<K, V> &A, const KeyValue<K, V> &B) const {
return A.key < B.key; return A.key < B.key;

View File

@ -40,7 +40,7 @@ namespace godot {
// based on the very nice implementation of rb-trees by: // based on the very nice implementation of rb-trees by:
// https://web.archive.org/web/20120507164830/https://web.mit.edu/~emin/www/source_code/red_black_tree/index.html // https://web.archive.org/web/20120507164830/https://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
template <class K, class V, class C = Comparator<K>, class A = DefaultAllocator> template <typename K, typename V, typename C = Comparator<K>, typename A = DefaultAllocator>
class RBMap { class RBMap {
enum Color { enum Color {
RED, RED,

View File

@ -38,7 +38,7 @@
namespace godot { namespace godot {
template <class T, class C = Comparator<T>, class A = DefaultAllocator> template <typename T, typename C = Comparator<T>, typename A = DefaultAllocator>
class RBSet { class RBSet {
enum Color { enum Color {
RED, RED,

View File

@ -42,7 +42,7 @@
namespace godot { namespace godot {
template <class T, bool THREAD_SAFE = false> template <typename T, bool THREAD_SAFE = false>
class RID_Alloc { class RID_Alloc {
T **chunks = nullptr; T **chunks = nullptr;
uint32_t **free_list_chunks = nullptr; uint32_t **free_list_chunks = nullptr;
@ -347,7 +347,7 @@ public:
} }
}; };
template <class T, bool THREAD_SAFE = false> template <typename T, bool THREAD_SAFE = false>
class RID_PtrOwner { class RID_PtrOwner {
RID_Alloc<T *, THREAD_SAFE> alloc; RID_Alloc<T *, THREAD_SAFE> alloc;
@ -406,7 +406,7 @@ public:
alloc(p_target_chunk_byte_size) {} alloc(p_target_chunk_byte_size) {}
}; };
template <class T, bool THREAD_SAFE = false> template <typename T, bool THREAD_SAFE = false>
class RID_Owner { class RID_Owner {
RID_Alloc<T, THREAD_SAFE> alloc; RID_Alloc<T, THREAD_SAFE> alloc;

View File

@ -48,7 +48,16 @@ namespace godot {
// value and, as an important benefit, you can be sure the value is properly synchronized // value and, as an important benefit, you can be sure the value is properly synchronized
// even with threads that are already running. // even with threads that are already running.
template <class T> // These are used in very specific areas of the engine where it's critical that these guarantees are held
#define SAFE_NUMERIC_TYPE_PUN_GUARANTEES(m_type) \
static_assert(sizeof(SafeNumeric<m_type>) == sizeof(m_type)); \
static_assert(alignof(SafeNumeric<m_type>) == alignof(m_type)); \
static_assert(std::is_trivially_destructible<std::atomic<m_type>>::value);
#define SAFE_FLAG_TYPE_PUN_GUARANTEES \
static_assert(sizeof(SafeFlag) == sizeof(bool)); \
static_assert(alignof(SafeFlag) == alignof(bool));
template <typename T>
class SafeNumeric { class SafeNumeric {
std::atomic<T> value; std::atomic<T> value;
@ -186,7 +195,7 @@ public:
#else #else
template <class T> template <typename T>
class SafeNumeric { class SafeNumeric {
protected: protected:
T value; T value;

View File

@ -35,7 +35,7 @@
namespace godot { namespace godot {
template <class T, class Comparator = _DefaultComparator<T>> template <typename T, typename Comparator = _DefaultComparator<T>>
class SearchArray { class SearchArray {
public: public:
Comparator compare; Comparator compare;

View File

@ -36,7 +36,7 @@
namespace godot { namespace godot {
template <class T> template <typename T>
class SelfList { class SelfList {
public: public:
class List { class List {

View File

@ -41,7 +41,7 @@ namespace godot {
break; \ break; \
} }
template <class T> template <typename T>
struct _DefaultComparator { struct _DefaultComparator {
_FORCE_INLINE_ bool operator()(const T &a, const T &b) const { return (a < b); } _FORCE_INLINE_ bool operator()(const T &a, const T &b) const { return (a < b); }
}; };
@ -52,7 +52,7 @@ struct _DefaultComparator {
#define SORT_ARRAY_VALIDATE_ENABLED false #define SORT_ARRAY_VALIDATE_ENABLED false
#endif #endif
template <class T, class Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED> template <typename T, typename Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED>
class SortArray { class SortArray {
enum { enum {
INTROSORT_THRESHOLD = 16 INTROSORT_THRESHOLD = 16

View File

@ -52,7 +52,7 @@ class ThreadWorkPool {
virtual ~BaseWork() = default; virtual ~BaseWork() = default;
}; };
template <class C, class M, class U> template <typename C, typename M, typename U>
struct Work : public BaseWork { struct Work : public BaseWork {
C *instance; C *instance;
M method; M method;
@ -94,7 +94,7 @@ class ThreadWorkPool {
} }
public: public:
template <class C, class M, class U> template <typename C, typename M, typename U>
void begin_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) { void begin_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
ERR_FAIL_NULL(threads); // Never initialized. ERR_FAIL_NULL(threads); // Never initialized.
ERR_FAIL_COND(current_work != nullptr); ERR_FAIL_COND(current_work != nullptr);
@ -145,7 +145,7 @@ public:
current_work = nullptr; current_work = nullptr;
} }
template <class C, class M, class U> template <typename C, typename M, typename U>
void do_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) { void do_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
switch (p_elements) { switch (p_elements) {
case 0: case 0:

View File

@ -47,22 +47,23 @@
namespace godot { namespace godot {
template <class T> template <typename T>
class VectorWriteProxy { class VectorWriteProxy {
public: public:
_FORCE_INLINE_ T &operator[](int p_index) { _FORCE_INLINE_ T &operator[](typename CowData<T>::Size p_index) {
CRASH_BAD_INDEX(p_index, ((Vector<T> *)(this))->_cowdata.size()); CRASH_BAD_INDEX(p_index, ((Vector<T> *)(this))->_cowdata.size());
return ((Vector<T> *)(this))->_cowdata.ptrw()[p_index]; return ((Vector<T> *)(this))->_cowdata.ptrw()[p_index];
} }
}; };
template <class T> template <typename T>
class Vector { class Vector {
friend class VectorWriteProxy<T>; friend class VectorWriteProxy<T>;
public: public:
VectorWriteProxy<T> write; VectorWriteProxy<T> write;
typedef typename CowData<T>::Size Size;
private: private:
CowData<T> _cowdata; CowData<T> _cowdata;
@ -72,13 +73,16 @@ public:
_FORCE_INLINE_ bool append(const T &p_elem) { return push_back(p_elem); } //alias _FORCE_INLINE_ bool append(const T &p_elem) { return push_back(p_elem); } //alias
void fill(T p_elem); void fill(T p_elem);
void remove_at(int p_index) { _cowdata.remove_at(p_index); } void remove_at(Size p_index) { _cowdata.remove_at(p_index); }
void erase(const T &p_val) { _FORCE_INLINE_ bool erase(const T &p_val) {
int idx = find(p_val); Size idx = find(p_val);
if (idx >= 0) { if (idx >= 0) {
remove_at(idx); remove_at(idx);
return true;
} }
return false;
} }
void reverse(); void reverse();
_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); } _FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
@ -86,37 +90,45 @@ public:
_FORCE_INLINE_ void clear() { resize(0); } _FORCE_INLINE_ void clear() { resize(0); }
_FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); } _FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); }
_FORCE_INLINE_ T get(int p_index) { return _cowdata.get(p_index); } _FORCE_INLINE_ T get(Size p_index) { return _cowdata.get(p_index); }
_FORCE_INLINE_ const T &get(int p_index) const { return _cowdata.get(p_index); } _FORCE_INLINE_ const T &get(Size p_index) const { return _cowdata.get(p_index); }
_FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); } _FORCE_INLINE_ void set(Size p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); }
_FORCE_INLINE_ int size() const { return _cowdata.size(); } _FORCE_INLINE_ Size size() const { return _cowdata.size(); }
Error resize(int p_size) { return _cowdata.resize(p_size); } Error resize(Size p_size) { return _cowdata.resize(p_size); }
_FORCE_INLINE_ const T &operator[](int p_index) const { return _cowdata.get(p_index); } Error resize_zeroed(Size p_size) { return _cowdata.template resize<true>(p_size); }
Error insert(int p_pos, T p_val) { return _cowdata.insert(p_pos, p_val); } _FORCE_INLINE_ const T &operator[](Size p_index) const { return _cowdata.get(p_index); }
int find(const T &p_val, int p_from = 0) const { return _cowdata.find(p_val, p_from); } Error insert(Size p_pos, T p_val) { return _cowdata.insert(p_pos, p_val); }
Size find(const T &p_val, Size p_from = 0) const { return _cowdata.find(p_val, p_from); }
Size rfind(const T &p_val, Size p_from = -1) const { return _cowdata.rfind(p_val, p_from); }
Size count(const T &p_val) const { return _cowdata.count(p_val); }
void append_array(Vector<T> p_other); void append_array(Vector<T> p_other);
_FORCE_INLINE_ bool has(const T &p_val) const { return find(p_val) != -1; } _FORCE_INLINE_ bool has(const T &p_val) const { return find(p_val) != -1; }
template <class C> void sort() {
void sort_custom() { sort_custom<_DefaultComparator<T>>();
int len = _cowdata.size(); }
template <typename Comparator, bool Validate = SORT_ARRAY_VALIDATE_ENABLED, typename... Args>
void sort_custom(Args &&...args) {
Size len = _cowdata.size();
if (len == 0) { if (len == 0) {
return; return;
} }
T *data = ptrw(); T *data = ptrw();
SortArray<T, C> sorter; SortArray<T, Comparator, Validate> sorter{ args... };
sorter.sort(data, len); sorter.sort(data, len);
} }
void sort() { Size bsearch(const T &p_value, bool p_before) {
sort_custom<_DefaultComparator<T>>(); return bsearch_custom<_DefaultComparator<T>>(p_value, p_before);
} }
int bsearch(const T &p_value, bool p_before) { template <typename Comparator, typename Value, typename... Args>
SearchArray<T> search; Size bsearch_custom(const Value &p_value, bool p_before, Args &&...args) {
SearchArray<T, Comparator> search{ args... };
return search.bisect(ptrw(), size(), p_value, p_before); return search.bisect(ptrw(), size(), p_value, p_before);
} }
@ -125,7 +137,7 @@ public:
} }
void ordered_insert(const T &p_val) { void ordered_insert(const T &p_val) {
int i; Size i;
for (i = 0; i < _cowdata.size(); i++) { for (i = 0; i < _cowdata.size(); i++) {
if (p_val < operator[](i)) { if (p_val < operator[](i)) {
break; break;
@ -140,33 +152,36 @@ public:
Vector<uint8_t> to_byte_array() const { Vector<uint8_t> to_byte_array() const {
Vector<uint8_t> ret; Vector<uint8_t> ret;
if (is_empty()) {
return ret;
}
ret.resize(size() * sizeof(T)); ret.resize(size() * sizeof(T));
memcpy(ret.ptrw(), ptr(), sizeof(T) * size()); memcpy(ret.ptrw(), ptr(), sizeof(T) * size());
return ret; return ret;
} }
Vector<T> slice(int p_begin, int p_end = INT_MAX) const { Vector<T> slice(Size p_begin, Size p_end = CowData<T>::MAX_INT) const {
Vector<T> result; Vector<T> result;
const int s = size(); const Size s = size();
int begin = Math::clamp(p_begin, -s, s); Size begin = CLAMP(p_begin, -s, s);
if (begin < 0) { if (begin < 0) {
begin += s; begin += s;
} }
int end = Math::clamp(p_end, -s, s); Size end = CLAMP(p_end, -s, s);
if (end < 0) { if (end < 0) {
end += s; end += s;
} }
ERR_FAIL_COND_V(begin > end, result); ERR_FAIL_COND_V(begin > end, result);
int result_size = end - begin; Size result_size = end - begin;
result.resize(result_size); result.resize(result_size);
const T *const r = ptr(); const T *const r = ptr();
T *const w = result.ptrw(); T *const w = result.ptrw();
for (int i = 0; i < result_size; ++i) { for (Size i = 0; i < result_size; ++i) {
w[i] = r[begin + i]; w[i] = r[begin + i];
} }
@ -174,11 +189,11 @@ public:
} }
bool operator==(const Vector<T> &p_arr) const { bool operator==(const Vector<T> &p_arr) const {
int s = size(); Size s = size();
if (s != p_arr.size()) { if (s != p_arr.size()) {
return false; return false;
} }
for (int i = 0; i < s; i++) { for (Size i = 0; i < s; i++) {
if (operator[](i) != p_arr[i]) { if (operator[](i) != p_arr[i]) {
return false; return false;
} }
@ -187,11 +202,11 @@ public:
} }
bool operator!=(const Vector<T> &p_arr) const { bool operator!=(const Vector<T> &p_arr) const {
int s = size(); Size s = size();
if (s != p_arr.size()) { if (s != p_arr.size()) {
return true; return true;
} }
for (int i = 0; i < s; i++) { for (Size i = 0; i < s; i++) {
if (operator[](i) != p_arr[i]) { if (operator[](i) != p_arr[i]) {
return true; return true;
} }
@ -268,7 +283,7 @@ public:
Error err = _cowdata.resize(p_init.size()); Error err = _cowdata.resize(p_init.size());
ERR_FAIL_COND(err); ERR_FAIL_COND(err);
int i = 0; Size i = 0;
for (const T &element : p_init) { for (const T &element : p_init) {
_cowdata.set(i++, element); _cowdata.set(i++, element);
} }
@ -278,28 +293,28 @@ public:
_FORCE_INLINE_ ~Vector() {} _FORCE_INLINE_ ~Vector() {}
}; };
template <class T> template <typename T>
void Vector<T>::reverse() { void Vector<T>::reverse() {
for (int i = 0; i < size() / 2; i++) { for (Size i = 0; i < size() / 2; i++) {
T *p = ptrw(); T *p = ptrw();
SWAP(p[i], p[size() - i - 1]); SWAP(p[i], p[size() - i - 1]);
} }
} }
template <class T> template <typename T>
void Vector<T>::append_array(Vector<T> p_other) { void Vector<T>::append_array(Vector<T> p_other) {
const int ds = p_other.size(); const Size ds = p_other.size();
if (ds == 0) { if (ds == 0) {
return; return;
} }
const int bs = size(); const Size bs = size();
resize(bs + ds); resize(bs + ds);
for (int i = 0; i < ds; ++i) { for (Size i = 0; i < ds; ++i) {
ptrw()[bs + i] = p_other[i]; ptrw()[bs + i] = p_other[i];
} }
} }
template <class T> template <typename T>
bool Vector<T>::push_back(T p_elem) { bool Vector<T>::push_back(T p_elem) {
Error err = resize(size() + 1); Error err = resize(size() + 1);
ERR_FAIL_COND_V(err, true); ERR_FAIL_COND_V(err, true);
@ -308,10 +323,10 @@ bool Vector<T>::push_back(T p_elem) {
return false; return false;
} }
template <class T> template <typename T>
void Vector<T>::fill(T p_elem) { void Vector<T>::fill(T p_elem) {
T *p = ptrw(); T *p = ptrw();
for (int i = 0; i < size(); i++) { for (Size i = 0; i < size(); i++) {
p[i] = p_elem; p[i] = p_elem;
} }
} }

View File

@ -35,7 +35,7 @@
namespace godot { namespace godot {
template <class T, class V> template <typename T, typename V>
class VMap { class VMap {
public: public:
struct Pair { struct Pair {

View File

@ -35,7 +35,7 @@
namespace godot { namespace godot {
template <class T> template <typename T>
class VSet { class VSet {
Vector<T> _data; Vector<T> _data;

View File

@ -60,7 +60,7 @@ Callable create_callable_from_ccmp(CallableCustomMethodPointerBase *p_callable_m
// No return value. // No return value.
// //
template <class T, class... P> template <typename T, typename... P>
class CallableCustomMethodPointer : public CallableCustomMethodPointerBase { class CallableCustomMethodPointer : public CallableCustomMethodPointerBase {
struct Data { struct Data {
T *instance; T *instance;
@ -85,7 +85,7 @@ public:
} }
}; };
template <class T, class... P> template <typename T, typename... P>
Callable create_custom_callable_function_pointer(T *p_instance, void (T::*p_method)(P...)) { Callable create_custom_callable_function_pointer(T *p_instance, void (T::*p_method)(P...)) {
typedef CallableCustomMethodPointer<T, P...> CCMP; typedef CallableCustomMethodPointer<T, P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_instance, p_method)); CCMP *ccmp = memnew(CCMP(p_instance, p_method));
@ -96,7 +96,7 @@ Callable create_custom_callable_function_pointer(T *p_instance, void (T::*p_meth
// With return value. // With return value.
// //
template <class T, class R, class... P> template <typename T, typename R, typename... P>
class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase { class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase {
struct Data { struct Data {
T *instance; T *instance;
@ -122,7 +122,7 @@ public:
} }
}; };
template <class T, class R, class... P> template <typename T, typename R, typename... P>
Callable create_custom_callable_function_pointer(T *p_instance, R (T::*p_method)(P...)) { Callable create_custom_callable_function_pointer(T *p_instance, R (T::*p_method)(P...)) {
typedef CallableCustomMethodPointerRet<T, R, P...> CCMP; // Messes with memnew otherwise. typedef CallableCustomMethodPointerRet<T, R, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method)); CCMP *ccmp = memnew(CCMP(p_instance, p_method));
@ -133,7 +133,7 @@ Callable create_custom_callable_function_pointer(T *p_instance, R (T::*p_method)
// Const with return value. // Const with return value.
// //
template <class T, class R, class... P> template <typename T, typename R, typename... P>
class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase { class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase {
struct Data { struct Data {
T *instance; T *instance;
@ -159,7 +159,7 @@ public:
} }
}; };
template <class T, class R, class... P> template <typename T, typename R, typename... P>
Callable create_custom_callable_function_pointer(const T *p_instance, R (T::*p_method)(P...) const) { Callable create_custom_callable_function_pointer(const T *p_instance, R (T::*p_method)(P...) const) {
typedef CallableCustomMethodPointerRetC<T, R, P...> CCMP; // Messes with memnew otherwise. typedef CallableCustomMethodPointerRetC<T, R, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method)); CCMP *ccmp = memnew(CCMP(p_instance, p_method));
@ -170,7 +170,7 @@ Callable create_custom_callable_function_pointer(const T *p_instance, R (T::*p_m
// Static method with no return value. // Static method with no return value.
// //
template <class... P> template <typename... P>
class CallableCustomStaticMethodPointer : public CallableCustomMethodPointerBase { class CallableCustomStaticMethodPointer : public CallableCustomMethodPointerBase {
struct Data { struct Data {
void (*method)(P...); void (*method)(P...);
@ -194,7 +194,7 @@ public:
} }
}; };
template <class... P> template <typename... P>
Callable create_custom_callable_static_function_pointer(void (*p_method)(P...)) { Callable create_custom_callable_static_function_pointer(void (*p_method)(P...)) {
typedef CallableCustomStaticMethodPointer<P...> CCMP; typedef CallableCustomStaticMethodPointer<P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_method)); CCMP *ccmp = memnew(CCMP(p_method));
@ -205,7 +205,7 @@ Callable create_custom_callable_static_function_pointer(void (*p_method)(P...))
// Static method with return value. // Static method with return value.
// //
template <class R, class... P> template <typename R, typename... P>
class CallableCustomStaticMethodPointerRet : public CallableCustomMethodPointerBase { class CallableCustomStaticMethodPointerRet : public CallableCustomMethodPointerBase {
struct Data { struct Data {
R(*method) R(*method)
@ -229,7 +229,7 @@ public:
} }
}; };
template <class R, class... P> template <typename R, typename... P>
Callable create_custom_callable_static_function_pointer(R (*p_method)(P...)) { Callable create_custom_callable_static_function_pointer(R (*p_method)(P...)) {
typedef CallableCustomStaticMethodPointerRet<R, P...> CCMP; typedef CallableCustomStaticMethodPointerRet<R, P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_method)); CCMP *ccmp = memnew(CCMP(p_method));

View File

@ -38,19 +38,19 @@
namespace godot { namespace godot {
template <class T> template <typename T>
class CharStringT; class CharStringT;
template <class T> template <typename T>
class CharProxy { class CharProxy {
template <class TS> template <typename TS>
friend class CharStringT; friend class CharStringT;
const int _index; const int64_t _index;
CowData<T> &_cowdata; CowData<T> &_cowdata;
static inline const T _null = 0; static inline const T _null = 0;
_FORCE_INLINE_ CharProxy(const int &p_index, CowData<T> &p_cowdata) : _FORCE_INLINE_ CharProxy(const int64_t &p_index, CowData<T> &p_cowdata) :
_index(p_index), _index(p_index),
_cowdata(p_cowdata) {} _cowdata(p_cowdata) {}
@ -80,7 +80,7 @@ public:
} }
}; };
template <class T> template <typename T>
class CharStringT { class CharStringT {
friend class String; friend class String;
@ -90,19 +90,19 @@ class CharStringT {
public: public:
_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); } _FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
_FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); } _FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); }
_FORCE_INLINE_ int size() const { return _cowdata.size(); } _FORCE_INLINE_ int64_t size() const { return _cowdata.size(); }
Error resize(int p_size) { return _cowdata.resize(p_size); } Error resize(int64_t p_size) { return _cowdata.resize(p_size); }
_FORCE_INLINE_ T get(int p_index) const { return _cowdata.get(p_index); } _FORCE_INLINE_ T get(int64_t p_index) const { return _cowdata.get(p_index); }
_FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); } _FORCE_INLINE_ void set(int64_t p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); }
_FORCE_INLINE_ const T &operator[](int p_index) const { _FORCE_INLINE_ const T &operator[](int64_t p_index) const {
if (unlikely(p_index == _cowdata.size())) { if (unlikely(p_index == _cowdata.size())) {
return _null; return _null;
} }
return _cowdata.get(p_index); return _cowdata.get(p_index);
} }
_FORCE_INLINE_ CharProxy<T> operator[](int p_index) { return CharProxy<T>(p_index, _cowdata); } _FORCE_INLINE_ CharProxy<T> operator[](int64_t p_index) { return CharProxy<T>(p_index, _cowdata); }
_FORCE_INLINE_ CharStringT() {} _FORCE_INLINE_ CharStringT() {}
_FORCE_INLINE_ CharStringT(const CharStringT<T> &p_str) { _cowdata._ref(p_str._cowdata); } _FORCE_INLINE_ CharStringT(const CharStringT<T> &p_str) { _cowdata._ref(p_str._cowdata); }
@ -112,7 +112,7 @@ public:
void operator=(const T *p_cstr); void operator=(const T *p_cstr);
bool operator<(const CharStringT<T> &p_right) const; bool operator<(const CharStringT<T> &p_right) const;
CharStringT<T> &operator+=(T p_char); CharStringT<T> &operator+=(T p_char);
int length() const { return size() ? size() - 1 : 0; } int64_t length() const { return size() ? size() - 1 : 0; }
const T *get_data() const; const T *get_data() const;
operator const T *() const { return get_data(); }; operator const T *() const { return get_data(); };

View File

@ -36,7 +36,7 @@
namespace godot { namespace godot {
template <class T> template <typename T>
class TypedArray : public Array { class TypedArray : public Array {
public: public:
_FORCE_INLINE_ void operator=(const Array &p_array) { _FORCE_INLINE_ void operator=(const Array &p_array) {

View File

@ -47,8 +47,6 @@ class ObjectID;
class Variant { class Variant {
uint8_t opaque[GODOT_CPP_VARIANT_SIZE]{ 0 }; uint8_t opaque[GODOT_CPP_VARIANT_SIZE]{ 0 };
_FORCE_INLINE_ GDExtensionVariantPtr _native_ptr() const { return const_cast<uint8_t(*)[GODOT_CPP_VARIANT_SIZE]>(&opaque); }
friend class GDExtensionBinding; friend class GDExtensionBinding;
friend class MethodBind; friend class MethodBind;
@ -145,6 +143,7 @@ private:
static GDExtensionTypeFromVariantConstructorFunc to_type_constructor[VARIANT_MAX]; static GDExtensionTypeFromVariantConstructorFunc to_type_constructor[VARIANT_MAX];
public: public:
_FORCE_INLINE_ GDExtensionVariantPtr _native_ptr() const { return const_cast<uint8_t(*)[GODOT_CPP_VARIANT_SIZE]>(&opaque); }
Variant(); Variant();
Variant(std::nullptr_t n) : Variant(std::nullptr_t n) :
Variant() {} Variant() {}
@ -270,7 +269,7 @@ public:
void callp(const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error); void callp(const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error);
template <class... Args> template <typename... Args>
Variant call(const StringName &method, Args... args) { Variant call(const StringName &method, Args... args) {
std::array<Variant, sizeof...(args)> vargs = { args... }; std::array<Variant, sizeof...(args)> vargs = { args... };
std::array<const Variant *, sizeof...(args)> argptrs; std::array<const Variant *, sizeof...(args)> argptrs;
@ -285,7 +284,7 @@ public:
static void callp_static(Variant::Type type, const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error); static void callp_static(Variant::Type type, const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error);
template <class... Args> template <typename... Args>
static Variant call_static(Variant::Type type, const StringName &method, Args... args) { static Variant call_static(Variant::Type type, const StringName &method, Args... args) {
std::array<Variant, sizeof...(args)> vargs = { args... }; std::array<Variant, sizeof...(args)> vargs = { args... };
std::array<const Variant *, sizeof...(args)> argptrs; std::array<const Variant *, sizeof...(args)> argptrs;

View File

@ -41,12 +41,12 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
bool prepad = p_pad_align; bool prepad = p_pad_align;
#endif #endif
void *mem = internal::gdextension_interface_mem_alloc(p_bytes + (prepad ? PAD_ALIGN : 0)); void *mem = internal::gdextension_interface_mem_alloc(p_bytes + (prepad ? DATA_OFFSET : 0));
ERR_FAIL_NULL_V(mem, nullptr); ERR_FAIL_NULL_V(mem, nullptr);
if (prepad) { if (prepad) {
uint8_t *s8 = (uint8_t *)mem; uint8_t *s8 = (uint8_t *)mem;
return s8 + PAD_ALIGN; return s8 + DATA_OFFSET;
} else { } else {
return mem; return mem;
} }
@ -69,10 +69,10 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) {
#endif #endif
if (prepad) { if (prepad) {
mem -= PAD_ALIGN; mem -= DATA_OFFSET;
mem = (uint8_t *)internal::gdextension_interface_mem_realloc(mem, p_bytes + PAD_ALIGN); mem = (uint8_t *)internal::gdextension_interface_mem_realloc(mem, p_bytes + DATA_OFFSET);
ERR_FAIL_NULL_V(mem, nullptr); ERR_FAIL_NULL_V(mem, nullptr);
return mem + PAD_ALIGN; return mem + DATA_OFFSET;
} else { } else {
return (uint8_t *)internal::gdextension_interface_mem_realloc(mem, p_bytes); return (uint8_t *)internal::gdextension_interface_mem_realloc(mem, p_bytes);
} }
@ -88,7 +88,7 @@ void Memory::free_static(void *p_ptr, bool p_pad_align) {
#endif #endif
if (prepad) { if (prepad) {
mem -= PAD_ALIGN; mem -= DATA_OFFSET;
} }
internal::gdextension_interface_mem_free(mem); internal::gdextension_interface_mem_free(mem);
} }

View File

@ -65,7 +65,7 @@ _FORCE_INLINE_ bool is_str_less(const L *l_ptr, const R *r_ptr) {
} }
} }
template <class T> template <typename T>
bool CharStringT<T>::operator<(const CharStringT<T> &p_right) const { bool CharStringT<T>::operator<(const CharStringT<T> &p_right) const {
if (length() == 0) { if (length() == 0) {
return p_right.length() != 0; return p_right.length() != 0;
@ -74,9 +74,9 @@ bool CharStringT<T>::operator<(const CharStringT<T> &p_right) const {
return is_str_less(get_data(), p_right.get_data()); return is_str_less(get_data(), p_right.get_data());
} }
template <class T> template <typename T>
CharStringT<T> &CharStringT<T>::operator+=(T p_char) { CharStringT<T> &CharStringT<T>::operator+=(T p_char) {
const int lhs_len = length(); const int64_t lhs_len = length();
resize(lhs_len + 2); resize(lhs_len + 2);
T *dst = ptrw(); T *dst = ptrw();
@ -86,7 +86,7 @@ CharStringT<T> &CharStringT<T>::operator+=(T p_char) {
return *this; return *this;
} }
template <class T> template <typename T>
void CharStringT<T>::operator=(const T *p_cstr) { void CharStringT<T>::operator=(const T *p_cstr) {
copy_from(p_cstr); copy_from(p_cstr);
} }
@ -127,7 +127,7 @@ const wchar_t *CharStringT<wchar_t>::get_data() const {
} }
} }
template <class T> template <typename T>
void CharStringT<T>::copy_from(const T *p_cstr) { void CharStringT<T>::copy_from(const T *p_cstr) {
if (!p_cstr) { if (!p_cstr) {
resize(0); resize(0);
@ -172,23 +172,23 @@ String::String(const char32_t *from) {
internal::gdextension_interface_string_new_with_utf32_chars(_native_ptr(), from); internal::gdextension_interface_string_new_with_utf32_chars(_native_ptr(), from);
} }
String String::utf8(const char *from, int len) { String String::utf8(const char *from, int64_t len) {
String ret; String ret;
ret.parse_utf8(from, len); ret.parse_utf8(from, len);
return ret; return ret;
} }
void String::parse_utf8(const char *from, int len) { void String::parse_utf8(const char *from, int64_t len) {
internal::gdextension_interface_string_new_with_utf8_chars_and_len(_native_ptr(), from, len); internal::gdextension_interface_string_new_with_utf8_chars_and_len(_native_ptr(), from, len);
} }
String String::utf16(const char16_t *from, int len) { String String::utf16(const char16_t *from, int64_t len) {
String ret; String ret;
ret.parse_utf16(from, len); ret.parse_utf16(from, len);
return ret; return ret;
} }
void String::parse_utf16(const char16_t *from, int len) { void String::parse_utf16(const char16_t *from, int64_t len) {
internal::gdextension_interface_string_new_with_utf16_chars_and_len(_native_ptr(), from, len); internal::gdextension_interface_string_new_with_utf16_chars_and_len(_native_ptr(), from, len);
} }
@ -230,8 +230,8 @@ String rtoss(double p_val) {
} }
CharString String::utf8() const { CharString String::utf8() const {
int length = internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), nullptr, 0); int64_t length = internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), nullptr, 0);
int size = length + 1; int64_t size = length + 1;
CharString str; CharString str;
str.resize(size); str.resize(size);
internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), str.ptrw(), length); internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), str.ptrw(), length);
@ -242,8 +242,8 @@ CharString String::utf8() const {
} }
CharString String::ascii() const { CharString String::ascii() const {
int length = internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), nullptr, 0); int64_t length = internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), nullptr, 0);
int size = length + 1; int64_t size = length + 1;
CharString str; CharString str;
str.resize(size); str.resize(size);
internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), str.ptrw(), length); internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), str.ptrw(), length);
@ -254,8 +254,8 @@ CharString String::ascii() const {
} }
Char16String String::utf16() const { Char16String String::utf16() const {
int length = internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), nullptr, 0); int64_t length = internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), nullptr, 0);
int size = length + 1; int64_t size = length + 1;
Char16String str; Char16String str;
str.resize(size); str.resize(size);
internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), str.ptrw(), length); internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), str.ptrw(), length);
@ -266,8 +266,8 @@ Char16String String::utf16() const {
} }
Char32String String::utf32() const { Char32String String::utf32() const {
int length = internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), nullptr, 0); int64_t length = internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), nullptr, 0);
int size = length + 1; int64_t size = length + 1;
Char32String str; Char32String str;
str.resize(size); str.resize(size);
internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), str.ptrw(), length); internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), str.ptrw(), length);
@ -278,8 +278,8 @@ Char32String String::utf32() const {
} }
CharWideString String::wide_string() const { CharWideString String::wide_string() const {
int length = internal::gdextension_interface_string_to_wide_chars(_native_ptr(), nullptr, 0); int64_t length = internal::gdextension_interface_string_to_wide_chars(_native_ptr(), nullptr, 0);
int size = length + 1; int64_t size = length + 1;
CharWideString str; CharWideString str;
str.resize(size); str.resize(size);
internal::gdextension_interface_string_to_wide_chars(_native_ptr(), str.ptrw(), length); internal::gdextension_interface_string_to_wide_chars(_native_ptr(), str.ptrw(), length);
@ -289,7 +289,7 @@ CharWideString String::wide_string() const {
return str; return str;
} }
Error String::resize(int p_size) { Error String::resize(int64_t p_size) {
return (Error)internal::gdextension_interface_string_resize(_native_ptr(), p_size); return (Error)internal::gdextension_interface_string_resize(_native_ptr(), p_size);
} }
@ -390,11 +390,11 @@ String &String::operator+=(const char32_t *p_str) {
return *this; return *this;
} }
const char32_t &String::operator[](int p_index) const { const char32_t &String::operator[](int64_t p_index) const {
return *internal::gdextension_interface_string_operator_index_const((GDExtensionStringPtr)this, p_index); return *internal::gdextension_interface_string_operator_index_const((GDExtensionStringPtr)this, p_index);
} }
char32_t &String::operator[](int p_index) { char32_t &String::operator[](int64_t p_index) {
return *internal::gdextension_interface_string_operator_index((GDExtensionStringPtr)this, p_index); return *internal::gdextension_interface_string_operator_index((GDExtensionStringPtr)this, p_index);
} }

View File

@ -46,11 +46,11 @@
namespace godot { namespace godot {
const uint8_t &PackedByteArray::operator[](int p_index) const { const uint8_t &PackedByteArray::operator[](int64_t p_index) const {
return *internal::gdextension_interface_packed_byte_array_operator_index_const((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_byte_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
} }
uint8_t &PackedByteArray::operator[](int p_index) { uint8_t &PackedByteArray::operator[](int64_t p_index) {
return *internal::gdextension_interface_packed_byte_array_operator_index((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_byte_array_operator_index((GDExtensionTypePtr *)this, p_index);
} }
@ -62,12 +62,12 @@ uint8_t *PackedByteArray::ptrw() {
return internal::gdextension_interface_packed_byte_array_operator_index((GDExtensionTypePtr *)this, 0); return internal::gdextension_interface_packed_byte_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const Color &PackedColorArray::operator[](int p_index) const { const Color &PackedColorArray::operator[](int64_t p_index) const {
const Color *color = (const Color *)internal::gdextension_interface_packed_color_array_operator_index_const((GDExtensionTypePtr *)this, p_index); const Color *color = (const Color *)internal::gdextension_interface_packed_color_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *color; return *color;
} }
Color &PackedColorArray::operator[](int p_index) { Color &PackedColorArray::operator[](int64_t p_index) {
Color *color = (Color *)internal::gdextension_interface_packed_color_array_operator_index((GDExtensionTypePtr *)this, p_index); Color *color = (Color *)internal::gdextension_interface_packed_color_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *color; return *color;
} }
@ -80,11 +80,11 @@ Color *PackedColorArray::ptrw() {
return (Color *)internal::gdextension_interface_packed_color_array_operator_index((GDExtensionTypePtr *)this, 0); return (Color *)internal::gdextension_interface_packed_color_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const float &PackedFloat32Array::operator[](int p_index) const { const float &PackedFloat32Array::operator[](int64_t p_index) const {
return *internal::gdextension_interface_packed_float32_array_operator_index_const((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_float32_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
} }
float &PackedFloat32Array::operator[](int p_index) { float &PackedFloat32Array::operator[](int64_t p_index) {
return *internal::gdextension_interface_packed_float32_array_operator_index((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_float32_array_operator_index((GDExtensionTypePtr *)this, p_index);
} }
@ -96,11 +96,11 @@ float *PackedFloat32Array::ptrw() {
return internal::gdextension_interface_packed_float32_array_operator_index((GDExtensionTypePtr *)this, 0); return internal::gdextension_interface_packed_float32_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const double &PackedFloat64Array::operator[](int p_index) const { const double &PackedFloat64Array::operator[](int64_t p_index) const {
return *internal::gdextension_interface_packed_float64_array_operator_index_const((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_float64_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
} }
double &PackedFloat64Array::operator[](int p_index) { double &PackedFloat64Array::operator[](int64_t p_index) {
return *internal::gdextension_interface_packed_float64_array_operator_index((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_float64_array_operator_index((GDExtensionTypePtr *)this, p_index);
} }
@ -112,11 +112,11 @@ double *PackedFloat64Array::ptrw() {
return internal::gdextension_interface_packed_float64_array_operator_index((GDExtensionTypePtr *)this, 0); return internal::gdextension_interface_packed_float64_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const int32_t &PackedInt32Array::operator[](int p_index) const { const int32_t &PackedInt32Array::operator[](int64_t p_index) const {
return *internal::gdextension_interface_packed_int32_array_operator_index_const((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_int32_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
} }
int32_t &PackedInt32Array::operator[](int p_index) { int32_t &PackedInt32Array::operator[](int64_t p_index) {
return *internal::gdextension_interface_packed_int32_array_operator_index((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_int32_array_operator_index((GDExtensionTypePtr *)this, p_index);
} }
@ -128,11 +128,11 @@ int32_t *PackedInt32Array::ptrw() {
return internal::gdextension_interface_packed_int32_array_operator_index((GDExtensionTypePtr *)this, 0); return internal::gdextension_interface_packed_int32_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const int64_t &PackedInt64Array::operator[](int p_index) const { const int64_t &PackedInt64Array::operator[](int64_t p_index) const {
return *internal::gdextension_interface_packed_int64_array_operator_index_const((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_int64_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
} }
int64_t &PackedInt64Array::operator[](int p_index) { int64_t &PackedInt64Array::operator[](int64_t p_index) {
return *internal::gdextension_interface_packed_int64_array_operator_index((GDExtensionTypePtr *)this, p_index); return *internal::gdextension_interface_packed_int64_array_operator_index((GDExtensionTypePtr *)this, p_index);
} }
@ -144,12 +144,12 @@ int64_t *PackedInt64Array::ptrw() {
return internal::gdextension_interface_packed_int64_array_operator_index((GDExtensionTypePtr *)this, 0); return internal::gdextension_interface_packed_int64_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const String &PackedStringArray::operator[](int p_index) const { const String &PackedStringArray::operator[](int64_t p_index) const {
const String *string = (const String *)internal::gdextension_interface_packed_string_array_operator_index_const((GDExtensionTypePtr *)this, p_index); const String *string = (const String *)internal::gdextension_interface_packed_string_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *string; return *string;
} }
String &PackedStringArray::operator[](int p_index) { String &PackedStringArray::operator[](int64_t p_index) {
String *string = (String *)internal::gdextension_interface_packed_string_array_operator_index((GDExtensionTypePtr *)this, p_index); String *string = (String *)internal::gdextension_interface_packed_string_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *string; return *string;
} }
@ -162,12 +162,12 @@ String *PackedStringArray::ptrw() {
return (String *)internal::gdextension_interface_packed_string_array_operator_index((GDExtensionTypePtr *)this, 0); return (String *)internal::gdextension_interface_packed_string_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const Vector2 &PackedVector2Array::operator[](int p_index) const { const Vector2 &PackedVector2Array::operator[](int64_t p_index) const {
const Vector2 *vec = (const Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index_const((GDExtensionTypePtr *)this, p_index); const Vector2 *vec = (const Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *vec; return *vec;
} }
Vector2 &PackedVector2Array::operator[](int p_index) { Vector2 &PackedVector2Array::operator[](int64_t p_index) {
Vector2 *vec = (Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index((GDExtensionTypePtr *)this, p_index); Vector2 *vec = (Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *vec; return *vec;
} }
@ -180,12 +180,12 @@ Vector2 *PackedVector2Array::ptrw() {
return (Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index((GDExtensionTypePtr *)this, 0); return (Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const Vector3 &PackedVector3Array::operator[](int p_index) const { const Vector3 &PackedVector3Array::operator[](int64_t p_index) const {
const Vector3 *vec = (const Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index_const((GDExtensionTypePtr *)this, p_index); const Vector3 *vec = (const Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *vec; return *vec;
} }
Vector3 &PackedVector3Array::operator[](int p_index) { Vector3 &PackedVector3Array::operator[](int64_t p_index) {
Vector3 *vec = (Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index((GDExtensionTypePtr *)this, p_index); Vector3 *vec = (Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *vec; return *vec;
} }
@ -198,12 +198,12 @@ Vector3 *PackedVector3Array::ptrw() {
return (Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index((GDExtensionTypePtr *)this, 0); return (Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index((GDExtensionTypePtr *)this, 0);
} }
const Variant &Array::operator[](int p_index) const { const Variant &Array::operator[](int64_t p_index) const {
const Variant *var = (const Variant *)internal::gdextension_interface_array_operator_index_const((GDExtensionTypePtr *)this, p_index); const Variant *var = (const Variant *)internal::gdextension_interface_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
return *var; return *var;
} }
Variant &Array::operator[](int p_index) { Variant &Array::operator[](int64_t p_index) {
Variant *var = (Variant *)internal::gdextension_interface_array_operator_index((GDExtensionTypePtr *)this, p_index); Variant *var = (Variant *)internal::gdextension_interface_array_operator_index((GDExtensionTypePtr *)this, p_index);
return *var; return *var;
} }

View File

@ -303,123 +303,131 @@ Variant::operator float() const {
} }
Variant::operator String() const { Variant::operator String() const {
String result; return String(this);
to_type_constructor[STRING](result._native_ptr(), _native_ptr());
return result;
} }
Variant::operator Vector2() const { Variant::operator Vector2() const {
// @todo Avoid initializing result before calling constructor (which will initialize it again)
Vector2 result; Vector2 result;
to_type_constructor[VECTOR2]((GDExtensionTypePtr)&result, _native_ptr()); to_type_constructor[VECTOR2]((GDExtensionTypePtr)&result, _native_ptr());
return result; return result;
} }
Variant::operator Vector2i() const { Variant::operator Vector2i() const {
// @todo Avoid initializing result before calling constructor (which will initialize it again)
Vector2i result; Vector2i result;
to_type_constructor[VECTOR2I]((GDExtensionTypePtr)&result, _native_ptr()); to_type_constructor[VECTOR2I]((GDExtensionTypePtr)&result, _native_ptr());
return result; return result;
} }
Variant::operator Rect2() const { Variant::operator Rect2() const {
// @todo Avoid initializing result before calling constructor (which will initialize it again)
Rect2 result; Rect2 result;
to_type_constructor[RECT2]((GDExtensionTypePtr)&result, _native_ptr()); to_type_constructor[RECT2]((GDExtensionTypePtr)&result, _native_ptr());
return result; return result;
} }
Variant::operator Rect2i() const { Variant::operator Rect2i() const {
// @todo Avoid initializing result before calling constructor (which will initialize it again)
Rect2i result; Rect2i result;
to_type_constructor[RECT2I]((GDExtensionTypePtr)&result, _native_ptr()); to_type_constructor[RECT2I]((GDExtensionTypePtr)&result, _native_ptr());
return result; return result;
} }
Variant::operator Vector3() const { Variant::operator Vector3() const {
// @todo Avoid initializing result before calling constructor (which will initialize it again)
Vector3 result; Vector3 result;
to_type_constructor[VECTOR3]((GDExtensionTypePtr)&result, _native_ptr()); to_type_constructor[VECTOR3]((GDExtensionTypePtr)&result, _native_ptr());
return result; return result;
} }
Variant::operator Vector3i() const { Variant::operator Vector3i() const {
// @todo Avoid initializing result before calling constructor (which will initialize it again)
Vector3i result; Vector3i result;
to_type_constructor[VECTOR3I]((GDExtensionTypePtr)&result, _native_ptr()); to_type_constructor[VECTOR3I]((GDExtensionTypePtr)&result, _native_ptr());
return result; return result;
} }
Variant::operator Transform2D() const { Variant::operator Transform2D() const {
// @todo Avoid initializing result before calling constructor (which will initialize it again)
Transform2D result; Transform2D result;
to_type_constructor[TRANSFORM2D]((GDExtensionTypePtr)&result, _native_ptr()); to_type_constructor[TRANSFORM2D]((GDExtensionTypePtr)&result, _native_ptr());
return result; return result;
} }
Variant::operator Vector4() const { Variant::operator Vector4() const {
// @todo Avoid initializing result before calling constructor (which will initialize it again)
Vector4 result; Vector4 result;
to_type_constructor[VECTOR4]((GDExtensionTypePtr)&result, _native_ptr()); to_type_constructor[VECTOR4]((GDExtensionTypePtr)&result, _native_ptr());
return result; return result;
} }
Variant::operator Vector4i() const { Variant::operator Vector4i() const {
// @todo Avoid initializing result before calling constructor (which will initialize it again)
Vector4i result; Vector4i result;
to_type_constructor[VECTOR4I]((GDExtensionTypePtr)&result, _native_ptr()); to_type_constructor[VECTOR4I]((GDExtensionTypePtr)&result, _native_ptr());
return result; return result;
} }
Variant::operator Plane() const { Variant::operator Plane() const {
// @todo Avoid initializing result before calling constructor (which will initialize it again)
Plane result; Plane result;
to_type_constructor[PLANE]((GDExtensionTypePtr)&result, _native_ptr()); to_type_constructor[PLANE]((GDExtensionTypePtr)&result, _native_ptr());
return result; return result;
} }
Variant::operator Quaternion() const { Variant::operator Quaternion() const {
// @todo Avoid initializing result before calling constructor (which will initialize it again)
Quaternion result; Quaternion result;
to_type_constructor[QUATERNION]((GDExtensionTypePtr)&result, _native_ptr()); to_type_constructor[QUATERNION]((GDExtensionTypePtr)&result, _native_ptr());
return result; return result;
} }
Variant::operator godot::AABB() const { Variant::operator godot::AABB() const {
// @todo Avoid initializing result before calling constructor (which will initialize it again)
godot::AABB result; godot::AABB result;
to_type_constructor[AABB]((GDExtensionTypePtr)&result, _native_ptr()); to_type_constructor[AABB]((GDExtensionTypePtr)&result, _native_ptr());
return result; return result;
} }
Variant::operator Basis() const { Variant::operator Basis() const {
// @todo Avoid initializing result before calling constructor (which will initialize it again)
Basis result; Basis result;
to_type_constructor[BASIS]((GDExtensionTypePtr)&result, _native_ptr()); to_type_constructor[BASIS]((GDExtensionTypePtr)&result, _native_ptr());
return result; return result;
} }
Variant::operator Transform3D() const { Variant::operator Transform3D() const {
// @todo Avoid initializing result before calling constructor (which will initialize it again)
Transform3D result; Transform3D result;
to_type_constructor[TRANSFORM3D]((GDExtensionTypePtr)&result, _native_ptr()); to_type_constructor[TRANSFORM3D]((GDExtensionTypePtr)&result, _native_ptr());
return result; return result;
} }
Variant::operator Projection() const { Variant::operator Projection() const {
// @todo Avoid initializing result before calling constructor (which will initialize it again)
Projection result; Projection result;
to_type_constructor[PROJECTION]((GDExtensionTypePtr)&result, _native_ptr()); to_type_constructor[PROJECTION]((GDExtensionTypePtr)&result, _native_ptr());
return result; return result;
} }
Variant::operator Color() const { Variant::operator Color() const {
// @todo Avoid initializing result before calling constructor (which will initialize it again)
Color result; Color result;
to_type_constructor[COLOR]((GDExtensionTypePtr)&result, _native_ptr()); to_type_constructor[COLOR]((GDExtensionTypePtr)&result, _native_ptr());
return result; return result;
} }
Variant::operator StringName() const { Variant::operator StringName() const {
StringName result; return StringName(this);
to_type_constructor[STRING_NAME](result._native_ptr(), _native_ptr());
return result;
} }
Variant::operator NodePath() const { Variant::operator NodePath() const {
NodePath result; return NodePath(this);
to_type_constructor[NODE_PATH](result._native_ptr(), _native_ptr());
return result;
} }
Variant::operator godot::RID() const { Variant::operator godot::RID() const {
godot::RID result; return godot::RID(this);
to_type_constructor[RID](result._native_ptr(), _native_ptr());
return result;
} }
Variant::operator Object *() const { Variant::operator Object *() const {
@ -447,81 +455,55 @@ Variant::operator ObjectID() const {
} }
Variant::operator Callable() const { Variant::operator Callable() const {
Callable result; return Callable(this);
to_type_constructor[CALLABLE](result._native_ptr(), _native_ptr());
return result;
} }
Variant::operator Signal() const { Variant::operator Signal() const {
Signal result; return Signal(this);
to_type_constructor[SIGNAL](result._native_ptr(), _native_ptr());
return result;
} }
Variant::operator Dictionary() const { Variant::operator Dictionary() const {
Dictionary result; return Dictionary(this);
to_type_constructor[DICTIONARY](result._native_ptr(), _native_ptr());
return result;
} }
Variant::operator Array() const { Variant::operator Array() const {
Array result; return Array(this);
to_type_constructor[ARRAY](result._native_ptr(), _native_ptr());
return result;
} }
Variant::operator PackedByteArray() const { Variant::operator PackedByteArray() const {
PackedByteArray result; return PackedByteArray(this);
to_type_constructor[PACKED_BYTE_ARRAY](result._native_ptr(), _native_ptr());
return result;
} }
Variant::operator PackedInt32Array() const { Variant::operator PackedInt32Array() const {
PackedInt32Array result; return PackedInt32Array(this);
to_type_constructor[PACKED_INT32_ARRAY](result._native_ptr(), _native_ptr());
return result;
} }
Variant::operator PackedInt64Array() const { Variant::operator PackedInt64Array() const {
PackedInt64Array result; return PackedInt64Array(this);
to_type_constructor[PACKED_INT64_ARRAY](result._native_ptr(), _native_ptr());
return result;
} }
Variant::operator PackedFloat32Array() const { Variant::operator PackedFloat32Array() const {
PackedFloat32Array result; return PackedFloat32Array(this);
to_type_constructor[PACKED_FLOAT32_ARRAY](result._native_ptr(), _native_ptr());
return result;
} }
Variant::operator PackedFloat64Array() const { Variant::operator PackedFloat64Array() const {
PackedFloat64Array result; return PackedFloat64Array(this);
to_type_constructor[PACKED_FLOAT64_ARRAY](result._native_ptr(), _native_ptr());
return result;
} }
Variant::operator PackedStringArray() const { Variant::operator PackedStringArray() const {
PackedStringArray result; return PackedStringArray(this);
to_type_constructor[PACKED_STRING_ARRAY](result._native_ptr(), _native_ptr());
return result;
} }
Variant::operator PackedVector2Array() const { Variant::operator PackedVector2Array() const {
PackedVector2Array result; return PackedVector2Array(this);
to_type_constructor[PACKED_VECTOR2_ARRAY](result._native_ptr(), _native_ptr());
return result;
} }
Variant::operator PackedVector3Array() const { Variant::operator PackedVector3Array() const {
PackedVector3Array result; return PackedVector3Array(this);
to_type_constructor[PACKED_VECTOR3_ARRAY](result._native_ptr(), _native_ptr());
return result;
} }
Variant::operator PackedColorArray() const { Variant::operator PackedColorArray() const {
PackedColorArray result; return PackedColorArray(this);
to_type_constructor[PACKED_COLOR_ARRAY](result._native_ptr(), _native_ptr());
return result;
} }
Variant &Variant::operator=(const Variant &other) { Variant &Variant::operator=(const Variant &other) {

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.13)
project(godot-cpp-test) project(godot-cpp-test)
cmake_minimum_required(VERSION 3.6)
set(GODOT_GDEXTENSION_DIR ../gdextension/ CACHE STRING "Path to GDExtension interface header directory") set(GODOT_GDEXTENSION_DIR ../gdextension/ CACHE STRING "Path to GDExtension interface header directory")
set(CPP_BINDINGS_PATH ../ CACHE STRING "Path to C++ bindings") set(CPP_BINDINGS_PATH ../ CACHE STRING "Path to C++ bindings")

View File

@ -154,6 +154,7 @@ func _ready():
# PackedArray iterators # PackedArray iterators
assert_equal(example.test_vector_ops(), 105) assert_equal(example.test_vector_ops(), 105)
assert_equal(example.test_vector_init_list(), 105)
# Properties. # Properties.
assert_equal(example.group_subgroup_custom_position, Vector2(0, 0)) assert_equal(example.group_subgroup_custom_position, Vector2(0, 0))
@ -241,6 +242,14 @@ func _ready():
assert_equal(new_example_ref.was_post_initialized(), true) assert_equal(new_example_ref.was_post_initialized(), true)
assert_equal(example.test_post_initialize(), true) assert_equal(example.test_post_initialize(), true)
# Test that notifications happen on both parent and child classes.
var example_child = $ExampleChild
assert_equal(example_child.get_value1(), 11)
assert_equal(example_child.get_value2(), 33)
example_child.notification(NOTIFICATION_ENTER_TREE, true)
assert_equal(example_child.get_value1(), 11)
assert_equal(example_child.get_value2(), 22)
exit_with_status() exit_with_status()
func _on_Example_custom_signal(signal_name, value): func _on_Example_custom_signal(signal_name, value):

View File

@ -22,4 +22,6 @@ offset_right = 79.0
offset_bottom = 29.0 offset_bottom = 29.0
text = "Click me!" text = "Click me!"
[node name="ExampleChild" type="ExampleChild" parent="."]
[connection signal="custom_signal" from="Example" to="." method="_on_Example_custom_signal"] [connection signal="custom_signal" from="Example" to="." method="_on_Example_custom_signal"]

View File

@ -197,6 +197,7 @@ void Example::_bind_methods() {
ClassDB::bind_method(D_METHOD("test_string_is_fourty_two"), &Example::test_string_is_fourty_two); ClassDB::bind_method(D_METHOD("test_string_is_fourty_two"), &Example::test_string_is_fourty_two);
ClassDB::bind_method(D_METHOD("test_string_resize"), &Example::test_string_resize); ClassDB::bind_method(D_METHOD("test_string_resize"), &Example::test_string_resize);
ClassDB::bind_method(D_METHOD("test_vector_ops"), &Example::test_vector_ops); ClassDB::bind_method(D_METHOD("test_vector_ops"), &Example::test_vector_ops);
ClassDB::bind_method(D_METHOD("test_vector_init_list"), &Example::test_vector_init_list);
ClassDB::bind_method(D_METHOD("test_object_cast_to_node", "object"), &Example::test_object_cast_to_node); ClassDB::bind_method(D_METHOD("test_object_cast_to_node", "object"), &Example::test_object_cast_to_node);
ClassDB::bind_method(D_METHOD("test_object_cast_to_control", "object"), &Example::test_object_cast_to_control); ClassDB::bind_method(D_METHOD("test_object_cast_to_control", "object"), &Example::test_object_cast_to_control);
@ -408,6 +409,15 @@ int Example::test_vector_ops() const {
return ret; return ret;
} }
int Example::test_vector_init_list() const {
PackedInt32Array arr = { 10, 20, 30, 45 };
int ret = 0;
for (const int32_t &E : arr) {
ret += E;
}
return ret;
}
Callable Example::test_callable_mp() { Callable Example::test_callable_mp() {
return callable_mp(this, &Example::unbound_method1); return callable_mp(this, &Example::unbound_method1);
} }
@ -626,3 +636,21 @@ void Example::_input(const Ref<InputEvent> &event) {
emit_custom_signal(String("_input: ") + key_event->get_key_label(), key_event->get_unicode()); emit_custom_signal(String("_input: ") + key_event->get_key_label(), key_event->get_unicode());
} }
} }
void ExampleBase::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_value1"), &ExampleBase::get_value1);
ClassDB::bind_method(D_METHOD("get_value2"), &ExampleBase::get_value2);
}
void ExampleBase::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
value1 = 11;
value2 = 22;
}
}
void ExampleChild::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
value2 = 33;
}
}

View File

@ -129,6 +129,7 @@ public:
bool test_string_is_fourty_two(const String &p_str) const; bool test_string_is_fourty_two(const String &p_str) const;
String test_string_resize(String p_original) const; String test_string_resize(String p_original) const;
int test_vector_ops() const; int test_vector_ops() const;
int test_vector_init_list() const;
bool test_object_cast_to_node(Object *p_object) const; bool test_object_cast_to_node(Object *p_object) const;
bool test_object_cast_to_control(Object *p_object) const; bool test_object_cast_to_control(Object *p_object) const;
@ -216,4 +217,29 @@ protected:
virtual int test_function() override { return 25; } virtual int test_function() override { return 25; }
}; };
class ExampleBase : public Node {
GDCLASS(ExampleBase, Node);
protected:
int value1 = 0;
int value2 = 0;
static void _bind_methods();
void _notification(int p_what);
public:
int get_value1() { return value1; }
int get_value2() { return value2; }
};
class ExampleChild : public ExampleBase {
GDCLASS(ExampleChild, ExampleBase);
protected:
static void _bind_methods() {}
void _notification(int p_what);
};
#endif // EXAMPLE_CLASS_H #endif // EXAMPLE_CLASS_H

View File

@ -27,6 +27,8 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
ClassDB::register_class<ExampleVirtual>(true); ClassDB::register_class<ExampleVirtual>(true);
ClassDB::register_abstract_class<ExampleAbstractBase>(); ClassDB::register_abstract_class<ExampleAbstractBase>();
ClassDB::register_class<ExampleConcrete>(); ClassDB::register_class<ExampleConcrete>();
ClassDB::register_class<ExampleBase>();
ClassDB::register_class<ExampleChild>();
} }
void uninitialize_example_module(ModuleInitializationLevel p_level) { void uninitialize_example_module(ModuleInitializationLevel p_level) {

View File

@ -1,6 +1,7 @@
import os import os
import sys import sys
import my_spawn import my_spawn
import common_compiler_flags
from SCons.Script import ARGUMENTS from SCons.Script import ARGUMENTS
@ -118,3 +119,5 @@ def generate(env):
env.Append(LINKFLAGS=["--target=" + arch_info["target"] + env["android_api_level"], "-march=" + arch_info["march"]]) env.Append(LINKFLAGS=["--target=" + arch_info["target"] + env["android_api_level"], "-march=" + arch_info["march"]])
env.Append(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED"]) env.Append(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED"])
common_compiler_flags.generate(env)

View File

@ -0,0 +1,94 @@
import os
import subprocess
import sys
def using_clang(env):
return "clang" in os.path.basename(env["CC"])
def is_vanilla_clang(env):
if not using_clang(env):
return False
try:
version = subprocess.check_output([env.subst(env["CXX"]), "--version"]).strip().decode("utf-8")
except (subprocess.CalledProcessError, OSError):
print("Couldn't parse CXX environment variable to infer compiler version.")
return False
return not version.startswith("Apple")
def exists(env):
return True
def generate(env):
# Require C++17
if env.get("is_msvc", False):
env.Append(CXXFLAGS=["/std:c++17"])
else:
env.Append(CXXFLAGS=["-std=c++17"])
# Disable exception handling. Godot doesn't use exceptions anywhere, and this
# saves around 20% of binary size and very significant build time.
if env["disable_exceptions"]:
if env.get("is_msvc", False):
env.Append(CPPDEFINES=[("_HAS_EXCEPTIONS", 0)])
else:
env.Append(CXXFLAGS=["-fno-exceptions"])
elif env.get("is_msvc", False):
env.Append(CXXFLAGS=["/EHsc"])
if not env.get("is_msvc", False):
if env["symbols_visibility"] == "visible":
env.Append(CCFLAGS=["-fvisibility=default"])
env.Append(LINKFLAGS=["-fvisibility=default"])
elif env["symbols_visibility"] == "hidden":
env.Append(CCFLAGS=["-fvisibility=hidden"])
env.Append(LINKFLAGS=["-fvisibility=hidden"])
# Set optimize and debug_symbols flags.
# "custom" means do nothing and let users set their own optimization flags.
if env.get("is_msvc", False):
if env["debug_symbols"]:
env.Append(CCFLAGS=["/Zi", "/FS"])
env.Append(LINKFLAGS=["/DEBUG:FULL"])
if env["optimize"] == "speed":
env.Append(CCFLAGS=["/O2"])
env.Append(LINKFLAGS=["/OPT:REF"])
elif env["optimize"] == "speed_trace":
env.Append(CCFLAGS=["/O2"])
env.Append(LINKFLAGS=["/OPT:REF", "/OPT:NOICF"])
elif env["optimize"] == "size":
env.Append(CCFLAGS=["/O1"])
env.Append(LINKFLAGS=["/OPT:REF"])
elif env["optimize"] == "debug" or env["optimize"] == "none":
env.Append(CCFLAGS=["/Od"])
else:
if env["debug_symbols"]:
# Adding dwarf-4 explicitly makes stacktraces work with clang builds,
# otherwise addr2line doesn't understand them.
env.Append(CCFLAGS=["-gdwarf-4"])
if env.dev_build:
env.Append(CCFLAGS=["-g3"])
else:
env.Append(CCFLAGS=["-g2"])
else:
if using_clang(env) and not is_vanilla_clang(env):
# Apple Clang, its linker doesn't like -s.
env.Append(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"])
else:
env.Append(LINKFLAGS=["-s"])
if env["optimize"] == "speed":
env.Append(CCFLAGS=["-O3"])
# `-O2` is friendlier to debuggers than `-O3`, leading to better crash backtraces.
elif env["optimize"] == "speed_trace":
env.Append(CCFLAGS=["-O2"])
elif env["optimize"] == "size":
env.Append(CCFLAGS=["-Os"])
elif env["optimize"] == "debug":
env.Append(CCFLAGS=["-Og"])
elif env["optimize"] == "none":
env.Append(CCFLAGS=["-O0"])

View File

@ -1,9 +1,12 @@
import os, sys, platform import os, sys, platform
from SCons.Variables import EnumVariable, PathVariable, BoolVariable from SCons.Variables import EnumVariable, PathVariable, BoolVariable
from SCons.Variables.BoolVariable import _text2bool
from SCons.Tool import Tool from SCons.Tool import Tool
from SCons.Builder import Builder from SCons.Builder import Builder
from SCons.Errors import UserError from SCons.Errors import UserError
from SCons.Script import ARGUMENTS
from binding_generator import scons_generate_bindings, scons_emit_files from binding_generator import scons_generate_bindings, scons_emit_files
@ -14,6 +17,17 @@ def add_sources(sources, dir, extension):
sources.append(dir + "/" + f) sources.append(dir + "/" + f)
def get_cmdline_bool(option, default):
"""We use `ARGUMENTS.get()` to check if options were manually overridden on the command line,
and SCons' _text2bool helper to convert them to booleans, otherwise they're handled as strings.
"""
cmdline_val = ARGUMENTS.get(option)
if cmdline_val is not None:
return _text2bool(cmdline_val)
else:
return default
def normalize_path(val, env): def normalize_path(val, env):
return val if os.path.isabs(val) else os.path.join(env.Dir("#").abspath, val) return val if os.path.isabs(val) else os.path.join(env.Dir("#").abspath, val)
@ -33,7 +47,26 @@ def validate_parent_dir(key, val, env):
raise UserError("'%s' is not a directory: %s" % (key, os.path.dirname(val))) raise UserError("'%s' is not a directory: %s" % (key, os.path.dirname(val)))
platforms = ("linux", "macos", "windows", "android", "ios", "web") def get_platform_tools_paths(env):
path = env.get("custom_tools", None)
if path is None:
return ["tools"]
return [normalize_path(path, env), "tools"]
def get_custom_platforms(env):
path = env.get("custom_tools", None)
if path is None:
return []
platforms = []
for x in os.listdir(normalize_path(path, env)):
if not x.endswith(".py"):
continue
platforms.append(x.removesuffix(".py"))
return platforms
platforms = ["linux", "macos", "windows", "android", "ios", "web"]
# CPU architecture options. # CPU architecture options.
architecture_array = [ architecture_array = [
@ -82,12 +115,25 @@ def options(opts, env):
else: else:
raise ValueError("Could not detect platform automatically, please specify with platform=<platform>") raise ValueError("Could not detect platform automatically, please specify with platform=<platform>")
opts.Add(
PathVariable(
key="custom_tools",
help="Path to directory containing custom tools",
default=env.get("custom_tools", None),
validator=validate_dir,
)
)
opts.Update(env)
custom_platforms = get_custom_platforms(env)
opts.Add( opts.Add(
EnumVariable( EnumVariable(
key="platform", key="platform",
help="Target platform", help="Target platform",
default=env.get("platform", default_platform), default=env.get("platform", default_platform),
allowed_values=platforms, allowed_values=platforms + custom_platforms,
ignorecase=2, ignorecase=2,
) )
) )
@ -198,16 +244,23 @@ def options(opts, env):
) )
) )
# Add platform options opts.Add(
for pl in platforms: EnumVariable(
tool = Tool(pl, toolpath=["tools"]) "optimize",
"The desired optimization flags",
"speed_trace",
("none", "custom", "debug", "speed", "speed_trace", "size"),
)
)
opts.Add(BoolVariable("debug_symbols", "Build with debugging symbols", True))
opts.Add(BoolVariable("dev_build", "Developer build with dev-only debugging code (DEV_ENABLED)", False))
# Add platform options (custom tools can override platforms)
for pl in sorted(set(platforms + custom_platforms)):
tool = Tool(pl, toolpath=get_platform_tools_paths(env))
if hasattr(tool, "options"): if hasattr(tool, "options"):
tool.options(opts) tool.options(opts)
# Targets flags tool (optimizations, debug symbols)
target_tool = Tool("targets", toolpath=["tools"])
target_tool.options(opts)
def generate(env): def generate(env):
# Default num_jobs to local cpu count if not user specified. # Default num_jobs to local cpu count if not user specified.
@ -254,43 +307,56 @@ def generate(env):
print("Building for architecture " + env["arch"] + " on platform " + env["platform"]) print("Building for architecture " + env["arch"] + " on platform " + env["platform"])
if env.get("use_hot_reload") is None: # These defaults may be needed by platform tools
env["use_hot_reload"] = env["target"] != "template_release" env.use_hot_reload = env.get("use_hot_reload", env["target"] != "template_release")
if env["use_hot_reload"]: env.editor_build = env["target"] == "editor"
env.Append(CPPDEFINES=["HOT_RELOAD_ENABLED"]) env.dev_build = env["dev_build"]
env.debug_features = env["target"] in ["editor", "template_debug"]
tool = Tool(env["platform"], toolpath=["tools"]) if env.dev_build:
opt_level = "none"
elif env.debug_features:
opt_level = "speed_trace"
else: # Release
opt_level = "speed"
env["optimize"] = ARGUMENTS.get("optimize", opt_level)
env["debug_symbols"] = get_cmdline_bool("debug_symbols", env.dev_build)
tool = Tool(env["platform"], toolpath=get_platform_tools_paths(env))
if tool is None or not tool.exists(env): if tool is None or not tool.exists(env):
raise ValueError("Required toolchain not found for platform " + env["platform"]) raise ValueError("Required toolchain not found for platform " + env["platform"])
tool.generate(env) tool.generate(env)
target_tool = Tool("targets", toolpath=["tools"])
target_tool.generate(env)
# Disable exception handling. Godot doesn't use exceptions anywhere, and this if env.use_hot_reload:
# saves around 20% of binary size and very significant build time. env.Append(CPPDEFINES=["HOT_RELOAD_ENABLED"])
if env["disable_exceptions"]:
if env.get("is_msvc", False): if env.editor_build:
env.Append(CPPDEFINES=[("_HAS_EXCEPTIONS", 0)]) env.Append(CPPDEFINES=["TOOLS_ENABLED"])
# Configuration of build targets:
# - Editor or template
# - Debug features (DEBUG_ENABLED code)
# - Dev only code (DEV_ENABLED code)
# - Optimization level
# - Debug symbols for crash traces / debuggers
# Keep this configuration in sync with SConstruct in upstream Godot.
if env.debug_features:
# DEBUG_ENABLED enables debugging *features* and debug-only code, which is intended
# to give *users* extra debugging information for their game development.
env.Append(CPPDEFINES=["DEBUG_ENABLED"])
# In upstream Godot this is added in typedefs.h when DEBUG_ENABLED is set.
env.Append(CPPDEFINES=["DEBUG_METHODS_ENABLED"])
if env.dev_build:
# DEV_ENABLED enables *engine developer* code which should only be compiled for those
# working on the engine itself.
env.Append(CPPDEFINES=["DEV_ENABLED"])
else: else:
env.Append(CXXFLAGS=["-fno-exceptions"]) # Disable assert() for production targets (only used in thirdparty code).
elif env.get("is_msvc", False): env.Append(CPPDEFINES=["NDEBUG"])
env.Append(CXXFLAGS=["/EHsc"])
if not env.get("is_msvc", False):
if env["symbols_visibility"] == "visible":
env.Append(CCFLAGS=["-fvisibility=default"])
env.Append(LINKFLAGS=["-fvisibility=default"])
elif env["symbols_visibility"] == "hidden":
env.Append(CCFLAGS=["-fvisibility=hidden"])
env.Append(LINKFLAGS=["-fvisibility=hidden"])
# Require C++17
if env.get("is_msvc", False):
env.Append(CXXFLAGS=["/std:c++17"])
else:
env.Append(CXXFLAGS=["-std=c++17"])
if env["precision"] == "double": if env["precision"] == "double":
env.Append(CPPDEFINES=["REAL_T_IS_DOUBLE"]) env.Append(CPPDEFINES=["REAL_T_IS_DOUBLE"])

View File

@ -1,6 +1,7 @@
import os import os
import sys import sys
import subprocess import subprocess
import common_compiler_flags
from SCons.Variables import * from SCons.Variables import *
if sys.version_info < (3,): if sys.version_info < (3,):
@ -104,3 +105,5 @@ def generate(env):
env.Append(LINKFLAGS=["-isysroot", env["IOS_SDK_PATH"], "-F" + env["IOS_SDK_PATH"]]) env.Append(LINKFLAGS=["-isysroot", env["IOS_SDK_PATH"], "-F" + env["IOS_SDK_PATH"]])
env.Append(CPPDEFINES=["IOS_ENABLED", "UNIX_ENABLED"]) env.Append(CPPDEFINES=["IOS_ENABLED", "UNIX_ENABLED"])
common_compiler_flags.generate(env)

View File

@ -1,3 +1,4 @@
import common_compiler_flags
from SCons.Variables import * from SCons.Variables import *
from SCons.Tool import clang, clangxx from SCons.Tool import clang, clangxx
@ -14,7 +15,7 @@ def generate(env):
if env["use_llvm"]: if env["use_llvm"]:
clang.generate(env) clang.generate(env)
clangxx.generate(env) clangxx.generate(env)
elif env["use_hot_reload"]: elif env.use_hot_reload:
# Required for extensions to truly unload. # Required for extensions to truly unload.
env.Append(CXXFLAGS=["-fno-gnu-unique"]) env.Append(CXXFLAGS=["-fno-gnu-unique"])
@ -37,3 +38,5 @@ def generate(env):
env.Append(LINKFLAGS=["-march=rv64gc"]) env.Append(LINKFLAGS=["-march=rv64gc"])
env.Append(CPPDEFINES=["LINUX_ENABLED", "UNIX_ENABLED"]) env.Append(CPPDEFINES=["LINUX_ENABLED", "UNIX_ENABLED"])
common_compiler_flags.generate(env)

View File

@ -1,5 +1,6 @@
import os import os
import sys import sys
import common_compiler_flags
def has_osxcross(): def has_osxcross():
@ -70,3 +71,5 @@ def generate(env):
) )
env.Append(CPPDEFINES=["MACOS_ENABLED", "UNIX_ENABLED"]) env.Append(CPPDEFINES=["MACOS_ENABLED", "UNIX_ENABLED"])
common_compiler_flags.generate(env)

View File

@ -1,144 +0,0 @@
import os
import subprocess
import sys
from SCons.Script import ARGUMENTS
from SCons.Variables import *
from SCons.Variables.BoolVariable import _text2bool
# Helper methods
def get_cmdline_bool(option, default):
"""We use `ARGUMENTS.get()` to check if options were manually overridden on the command line,
and SCons' _text2bool helper to convert them to booleans, otherwise they're handled as strings.
"""
cmdline_val = ARGUMENTS.get(option)
if cmdline_val is not None:
return _text2bool(cmdline_val)
else:
return default
def using_clang(env):
return "clang" in os.path.basename(env["CC"])
def is_vanilla_clang(env):
if not using_clang(env):
return False
try:
version = subprocess.check_output([env.subst(env["CXX"]), "--version"]).strip().decode("utf-8")
except (subprocess.CalledProcessError, OSError):
print("Couldn't parse CXX environment variable to infer compiler version.")
return False
return not version.startswith("Apple")
# Main tool definition
def options(opts):
opts.Add(
EnumVariable(
"optimize",
"The desired optimization flags",
"speed_trace",
("none", "custom", "debug", "speed", "speed_trace", "size"),
)
)
opts.Add(BoolVariable("debug_symbols", "Build with debugging symbols", True))
opts.Add(BoolVariable("dev_build", "Developer build with dev-only debugging code (DEV_ENABLED)", False))
def exists(env):
return True
def generate(env):
# Configuration of build targets:
# - Editor or template
# - Debug features (DEBUG_ENABLED code)
# - Dev only code (DEV_ENABLED code)
# - Optimization level
# - Debug symbols for crash traces / debuggers
# Keep this configuration in sync with SConstruct in upstream Godot.
env.editor_build = env["target"] == "editor"
env.dev_build = env["dev_build"]
env.debug_features = env["target"] in ["editor", "template_debug"]
if env.dev_build:
opt_level = "none"
elif env.debug_features:
opt_level = "speed_trace"
else: # Release
opt_level = "speed"
env["optimize"] = ARGUMENTS.get("optimize", opt_level)
env["debug_symbols"] = get_cmdline_bool("debug_symbols", env.dev_build)
if env.editor_build:
env.Append(CPPDEFINES=["TOOLS_ENABLED"])
if env.debug_features:
# DEBUG_ENABLED enables debugging *features* and debug-only code, which is intended
# to give *users* extra debugging information for their game development.
env.Append(CPPDEFINES=["DEBUG_ENABLED"])
# In upstream Godot this is added in typedefs.h when DEBUG_ENABLED is set.
env.Append(CPPDEFINES=["DEBUG_METHODS_ENABLED"])
if env.dev_build:
# DEV_ENABLED enables *engine developer* code which should only be compiled for those
# working on the engine itself.
env.Append(CPPDEFINES=["DEV_ENABLED"])
else:
# Disable assert() for production targets (only used in thirdparty code).
env.Append(CPPDEFINES=["NDEBUG"])
# Set optimize and debug_symbols flags.
# "custom" means do nothing and let users set their own optimization flags.
if env.get("is_msvc", False):
if env["debug_symbols"]:
env.Append(CCFLAGS=["/Zi", "/FS"])
env.Append(LINKFLAGS=["/DEBUG:FULL"])
if env["optimize"] == "speed":
env.Append(CCFLAGS=["/O2"])
env.Append(LINKFLAGS=["/OPT:REF"])
elif env["optimize"] == "speed_trace":
env.Append(CCFLAGS=["/O2"])
env.Append(LINKFLAGS=["/OPT:REF", "/OPT:NOICF"])
elif env["optimize"] == "size":
env.Append(CCFLAGS=["/O1"])
env.Append(LINKFLAGS=["/OPT:REF"])
elif env["optimize"] == "debug" or env["optimize"] == "none":
env.Append(CCFLAGS=["/Od"])
else:
if env["debug_symbols"]:
# Adding dwarf-4 explicitly makes stacktraces work with clang builds,
# otherwise addr2line doesn't understand them.
env.Append(CCFLAGS=["-gdwarf-4"])
if env.dev_build:
env.Append(CCFLAGS=["-g3"])
else:
env.Append(CCFLAGS=["-g2"])
else:
if using_clang(env) and not is_vanilla_clang(env):
# Apple Clang, its linker doesn't like -s.
env.Append(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"])
else:
env.Append(LINKFLAGS=["-s"])
if env["optimize"] == "speed":
env.Append(CCFLAGS=["-O3"])
# `-O2` is friendlier to debuggers than `-O3`, leading to better crash backtraces.
elif env["optimize"] == "speed_trace":
env.Append(CCFLAGS=["-O2"])
elif env["optimize"] == "size":
env.Append(CCFLAGS=["-Os"])
elif env["optimize"] == "debug":
env.Append(CCFLAGS=["-Og"])
elif env["optimize"] == "none":
env.Append(CCFLAGS=["-O0"])

View File

@ -1,4 +1,5 @@
import os import os
import common_compiler_flags
from SCons.Util import WhereIs from SCons.Util import WhereIs
@ -42,3 +43,5 @@ def generate(env):
env.Append(LINKFLAGS=["-s", "SIDE_MODULE=1"]) env.Append(LINKFLAGS=["-s", "SIDE_MODULE=1"])
env.Append(CPPDEFINES=["WEB_ENABLED", "UNIX_ENABLED"]) env.Append(CPPDEFINES=["WEB_ENABLED", "UNIX_ENABLED"])
common_compiler_flags.generate(env)

View File

@ -1,7 +1,6 @@
import sys import sys
import my_spawn import my_spawn
import common_compiler_flags
from SCons.Tool import msvc, mingw from SCons.Tool import msvc, mingw
from SCons.Variables import * from SCons.Variables import *
@ -90,3 +89,5 @@ def generate(env):
) )
env.Append(CPPDEFINES=["WINDOWS_ENABLED"]) env.Append(CPPDEFINES=["WINDOWS_ENABLED"])
common_compiler_flags.generate(env)