diff --git a/CMakeLists.txt b/CMakeLists.txt index a9603ab6d..dd43a04db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ # Todo # Test build for Windows, Mac and mingw. -cmake_minimum_required(VERSION 3.12) +cmake_minimum_required(VERSION 3.13) project(godot-cpp LANGUAGES CXX) option(GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node." ON) diff --git a/binding_generator.py b/binding_generator.py index aa77a5cb0..86d511a7e 100644 --- a/binding_generator.py +++ b/binding_generator.py @@ -375,6 +375,10 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl if class_name == "PackedVector3Array": result.append("#include ") + if is_packed_array(class_name): + result.append("#include ") + result.append("#include ") + if class_name == "Array": result.append("#include ") @@ -413,6 +417,8 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl result.append("") result.append("\tstatic struct _MethodBindings {") + result.append("\t\tGDExtensionTypeFromVariantConstructorFunc from_variant_constructor;") + if "constructors" in builtin_api: for constructor in builtin_api["constructors"]: result.append(f'\t\tGDExtensionPtrConstructor constructor_{constructor["index"]};') @@ -453,6 +459,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_constructors_destructor();") + result.append("") + result.append(f"\t{class_name}(const Variant *p_variant);") + result.append("") result.append("public:") @@ -511,7 +520,7 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl vararg = method["is_vararg"] if vararg: - result.append("\ttemplate") + result.append("\ttemplate") method_signature = "\t" if "is_static" in method and method["is_static"]: @@ -541,10 +550,10 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl # Special cases. if class_name == "String": - result.append("\tstatic String utf8(const char *from, int len = -1);") - result.append("\tvoid parse_utf8(const char *from, int len = -1);") - result.append("\tstatic String utf16(const char16_t *from, int len = -1);") - result.append("\tvoid parse_utf16(const char16_t *from, int len = -1);") + result.append("\tstatic String utf8(const char *from, int64_t len = -1);") + result.append("\tvoid parse_utf8(const char *from, int64_t len = -1);") + result.append("\tstatic String utf16(const char16_t *from, int64_t len = -1);") + result.append("\tvoid parse_utf16(const char16_t *from, int64_t len = -1);") result.append("\tCharString utf8() const;") result.append("\tCharString ascii() const;") result.append("\tChar16String utf16() const;") @@ -603,13 +612,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 char32_t *p_str);") - result.append("\tconst char32_t &operator[](int p_index) const;") - result.append("\tchar32_t &operator[](int p_index);") + result.append("\tconst char32_t &operator[](int64_t p_index) const;") + result.append("\tchar32_t &operator[](int64_t p_index);") result.append("\tconst char32_t *ptr() const;") result.append("\tchar32_t *ptrw();") if class_name == "Array": - result.append("\ttemplate ") + result.append("\ttemplate ") result.append("\tstatic Array make(Args... args) {") result.append("\t\treturn helpers::append_all(Array(), args...);") result.append("\t}") @@ -622,8 +631,8 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl return_type = "int32_t" elif class_name == "PackedFloat32Array": return_type = "float" - result.append(f"\tconst {return_type} &operator[](int p_index) const;") - result.append(f"\t{return_type} &operator[](int p_index);") + result.append(f"\tconst {return_type} &operator[](int64_t p_index) const;") + result.append(f"\t{return_type} &operator[](int64_t p_index);") result.append(f"\tconst {return_type} *ptr() const;") result.append(f"\t{return_type} *ptrw();") iterators = """ @@ -692,10 +701,21 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl } """ 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": - result.append("\tconst Variant &operator[](int p_index) const;") - result.append("\tVariant &operator[](int p_index);") + result.append("\tconst Variant &operator[](int64_t p_index) const;") + 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 _ref(const Array &p_from) const;") @@ -770,6 +790,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"\t_method_bindings.from_variant_constructor = internal::gdextension_interface_get_variant_to_type_constructor({enum_type_name});" + ) + if "constructors" in builtin_api: for constructor in builtin_api["constructors"]: result.append( @@ -851,6 +875,11 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl 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: for constructor in builtin_api["constructors"]: method_signature = f"{class_name}::{class_name}(" @@ -916,8 +945,19 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl result.append(method_signature + "{") method_call = "\t" + is_ref = False + 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(" + 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: method_call += "internal::_call_builtin_method_ptr_no_ret(" method_call += f'_method_bindings.method_{method["name"]}, ' @@ -938,6 +978,9 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl result += encode arguments.append(arg_name) method_call += ", ".join(arguments) + + if is_ref: + method_call += ")" # Close Ref<> constructor. method_call += ");" result.append(method_call) @@ -1328,7 +1371,7 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us result.append("protected:") # 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). - result.append("\ttemplate ") + result.append("\ttemplate ") result.append("\tstatic void register_virtuals() {") if class_name != "Object": result.append(f"\t\t{inherits}::register_virtuals();") @@ -1374,16 +1417,16 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us if class_name == "Object": result.append("") - result.append("\ttemplate") + result.append("\ttemplate") result.append("\tstatic T *cast_to(Object *p_object);") - result.append("\ttemplate") + result.append("\ttemplate") result.append("\tstatic const T *cast_to(const Object *p_object);") result.append("\tvirtual ~Object() = default;") elif use_template_get_node and class_name == "Node": - result.append("\ttemplate") + result.append("\ttemplate") result.append( "\tT *get_node(const NodePath &p_path) const { return Object::cast_to(get_node_internal(p_path)); }" ) @@ -1638,7 +1681,7 @@ def generate_global_constants(api, output_dir): header.append("") 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("") @@ -1999,7 +2042,7 @@ def make_signature( def make_varargs_template(function_data, static=False): result = [] - function_signature = "\tpublic: template " + function_signature = "\tpublic: template " if static: function_signature += "static " diff --git a/include/godot_cpp/classes/editor_plugin_registration.hpp b/include/godot_cpp/classes/editor_plugin_registration.hpp index 1ccde314e..7870bfc70 100644 --- a/include/godot_cpp/classes/editor_plugin_registration.hpp +++ b/include/godot_cpp/classes/editor_plugin_registration.hpp @@ -47,11 +47,11 @@ class EditorPlugins { static void remove_plugin_class(const StringName &p_class_name); static void deinitialize(GDExtensionInitializationLevel p_level); - template + template static void add_by_type() { add_plugin_class(T::get_class_static()); } - template + template static void remove_by_type() { remove_plugin_class(T::get_class_static()); } diff --git a/include/godot_cpp/classes/ref.hpp b/include/godot_cpp/classes/ref.hpp index f3fc3e942..c4682bcf3 100644 --- a/include/godot_cpp/classes/ref.hpp +++ b/include/godot_cpp/classes/ref.hpp @@ -45,7 +45,7 @@ namespace godot { class RefCounted; -template +template class Ref { T *reference = nullptr; @@ -108,7 +108,7 @@ class Ref { ref(p_from); } - template + template void operator=(const Ref &p_from) { RefCounted *refb = const_cast(static_cast(p_from.ptr())); if (!refb) { @@ -144,7 +144,7 @@ class Ref { } } - template + template void reference_ptr(T_Other *p_ptr) { if (reference == p_ptr) { return; @@ -161,7 +161,7 @@ class Ref { ref(p_from); } - template + template Ref(const Ref &p_from) { RefCounted *refb = const_cast(static_cast(p_from.ptr())); if (!refb) { @@ -226,7 +226,7 @@ class Ref { } }; -template +template struct PtrToArg> { _FORCE_INLINE_ static Ref convert(const void *p_ptr) { GDExtensionRefPtr ref = (GDExtensionRefPtr)p_ptr; @@ -248,7 +248,7 @@ struct PtrToArg> { } }; -template +template struct PtrToArg &> { typedef Ref EncodeT; @@ -259,7 +259,7 @@ struct PtrToArg &> { } }; -template +template struct GetTypeInfo, typename EnableIf::value>::type> { static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT; static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; @@ -269,7 +269,7 @@ struct GetTypeInfo, typename EnableIf::value> } }; -template +template struct GetTypeInfo &, typename EnableIf::value>::type> { static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT; static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index 4683070e0..65c62eb53 100644 --- a/include/godot_cpp/classes/wrapped.hpp +++ b/include/godot_cpp/classes/wrapped.hpp @@ -102,7 +102,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_classes(); -template +template struct EngineClassRegistration { EngineClassRegistration() { add_engine_class_registration_callback(&EngineClassRegistration::callback); @@ -164,7 +164,7 @@ protected: return (::godot::String(::godot::Wrapped::*)() const) & m_class::_to_string; \ } \ \ - template \ + template \ static void register_virtuals() { \ m_inherits::register_virtuals(); \ } \ @@ -201,11 +201,11 @@ public: \ static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what) { \ if (p_instance && m_class::_get_notification()) { \ + m_inherits::notification_bind(p_instance, p_what); \ if (m_class::_get_notification() != m_inherits::_get_notification()) { \ m_class *cls = reinterpret_cast(p_instance); \ - return cls->_notification(p_what); \ + cls->_notification(p_what); \ } \ - m_inherits::notification_bind(p_instance, p_what); \ } \ } \ \ diff --git a/include/godot_cpp/core/binder_common.hpp b/include/godot_cpp/core/binder_common.hpp index 09da62b1b..059350170 100644 --- a/include/godot_cpp/core/binder_common.hpp +++ b/include/godot_cpp/core/binder_common.hpp @@ -83,7 +83,7 @@ namespace godot { }; \ } -template +template struct VariantCaster { static _FORCE_INLINE_ T cast(const Variant &p_variant) { using TStripped = std::remove_pointer_t; @@ -95,7 +95,7 @@ struct VariantCaster { } }; -template +template struct VariantCaster { static _FORCE_INLINE_ T cast(const Variant &p_variant) { using TStripped = std::remove_pointer_t; @@ -107,7 +107,7 @@ struct VariantCaster { } }; -template +template struct VariantCaster { static _FORCE_INLINE_ T cast(const Variant &p_variant) { using TStripped = std::remove_pointer_t; @@ -144,7 +144,7 @@ struct VariantObjectClassChecker &> { } }; -template +template struct VariantCasterAndValidate { static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) { GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo::VARIANT_TYPE); @@ -159,7 +159,7 @@ struct VariantCasterAndValidate { } }; -template +template struct VariantCasterAndValidate { static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) { GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo::VARIANT_TYPE); @@ -174,7 +174,7 @@ struct VariantCasterAndValidate { } }; -template +template struct VariantCasterAndValidate { static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) { GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo::VARIANT_TYPE); @@ -189,47 +189,47 @@ struct VariantCasterAndValidate { } }; -template +template void call_with_ptr_args_helper(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, IndexSequence) { (p_instance->*p_method)(PtrToArg

::convert(p_args[Is])...); } -template +template void call_with_ptr_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, IndexSequence) { (p_instance->*p_method)(PtrToArg

::convert(p_args[Is])...); } -template +template void call_with_ptr_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence) { PtrToArg::encode((p_instance->*p_method)(PtrToArg

::convert(p_args[Is])...), r_ret); } -template +template void call_with_ptr_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence) { PtrToArg::encode((p_instance->*p_method)(PtrToArg

::convert(p_args[Is])...), r_ret); } -template +template void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void * /*ret*/) { call_with_ptr_args_helper(p_instance, p_method, p_args, BuildIndexSequence{}); } -template +template 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(p_instance, p_method, p_args, BuildIndexSequence{}); } -template +template 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(p_instance, p_method, p_args, r_ret, BuildIndexSequence{}); } -template +template 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(p_instance, p_method, p_args, r_ret, BuildIndexSequence{}); } -template +template void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, GDExtensionCallError &r_error, IndexSequence) { 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. } -template +template void call_with_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, GDExtensionCallError &r_error, IndexSequence) { 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. } -template +template 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) { 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 } -template +template 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) { 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; } -template +template 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 &default_values) { #ifdef DEBUG_ENABLED if ((size_t)p_argcount > sizeof...(P)) { @@ -311,7 +311,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{}); } -template +template 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 &default_values) { #ifdef DEBUG_ENABLED if ((size_t)p_argcount > sizeof...(P)) { @@ -346,7 +346,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{}); } -template +template 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 &default_values) { #ifdef DEBUG_ENABLED if ((size_t)p_argcount > sizeof...(P)) { @@ -381,7 +381,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{}); } -template +template 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 &default_values) { #ifdef DEBUG_ENABLED if ((size_t)p_argcount > sizeof...(P)) { @@ -423,7 +423,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" #endif -template +template void call_get_argument_type_helper(int p_arg, int &index, GDExtensionVariantType &type) { if (p_arg == index) { type = GDExtensionVariantType(GetTypeInfo::VARIANT_TYPE); @@ -431,7 +431,7 @@ void call_get_argument_type_helper(int p_arg, int &index, GDExtensionVariantType index++; } -template +template GDExtensionVariantType call_get_argument_type(int p_arg) { GDExtensionVariantType type = GDEXTENSION_VARIANT_TYPE_NIL; int index = 0; @@ -443,7 +443,7 @@ GDExtensionVariantType call_get_argument_type(int p_arg) { return type; } -template +template void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &info) { if (p_arg == index) { info = GetTypeInfo::get_class_info(); @@ -451,7 +451,7 @@ void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &inf index++; } -template +template void call_get_argument_type_info(int p_arg, PropertyInfo &info) { int index = 0; // I think rocket science is simpler than modern C++. @@ -461,7 +461,7 @@ void call_get_argument_type_info(int p_arg, PropertyInfo &info) { (void)index; // Suppress GCC warning. } -template +template void call_get_argument_metadata_helper(int p_arg, int &index, GDExtensionClassMethodArgumentMetadata &md) { if (p_arg == index) { md = GetTypeInfo::METADATA; @@ -469,7 +469,7 @@ void call_get_argument_metadata_helper(int p_arg, int &index, GDExtensionClassMe index++; } -template +template GDExtensionClassMethodArgumentMetadata call_get_argument_metadata(int p_arg) { GDExtensionClassMethodArgumentMetadata md = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; @@ -482,7 +482,7 @@ GDExtensionClassMethodArgumentMetadata call_get_argument_metadata(int p_arg) { return md; } -template +template void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_args, GDExtensionCallError &r_error, IndexSequence) { r_error.error = GDEXTENSION_CALL_OK; @@ -493,7 +493,7 @@ void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_arg #endif } -template +template void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector &default_values) { #ifdef DEBUG_ENABLED if ((size_t)p_argcount > sizeof...(P)) { @@ -528,17 +528,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{}); } -template +template void call_with_ptr_args_static_method_helper(void (*p_method)(P...), const GDExtensionConstTypePtr *p_args, IndexSequence) { p_method(PtrToArg

::convert(p_args[Is])...); } -template +template void call_with_ptr_args_static_method(void (*p_method)(P...), const GDExtensionConstTypePtr *p_args) { call_with_ptr_args_static_method_helper(p_method, p_args, BuildIndexSequence{}); } -template +template void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence) { r_error.error = GDEXTENSION_CALL_OK; @@ -549,7 +549,7 @@ void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_ar #endif } -template +template 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 &default_values) { #ifdef DEBUG_ENABLED if ((size_t)p_argcount > sizeof...(P)) { @@ -584,12 +584,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{}); } -template +template void call_with_ptr_args_static_method_ret_helper(R (*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence) { PtrToArg::encode(p_method(PtrToArg

::convert(p_args[Is])...), r_ret); } -template +template 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(p_method, p_args, r_ret, BuildIndexSequence{}); } diff --git a/include/godot_cpp/core/builtin_ptrcall.hpp b/include/godot_cpp/core/builtin_ptrcall.hpp index 87311b8a9..286051fa8 100644 --- a/include/godot_cpp/core/builtin_ptrcall.hpp +++ b/include/godot_cpp/core/builtin_ptrcall.hpp @@ -32,6 +32,7 @@ #define GODOT_BUILTIN_PTRCALL_HPP #include +#include #include @@ -39,13 +40,24 @@ namespace godot { namespace internal { -template +template +O *_call_builtin_method_ptr_ret_obj(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, const Args &...args) { + GodotObject *ret = nullptr; + std::array call_args = { { (GDExtensionConstTypePtr)args... } }; + method(base, call_args.data(), &ret, sizeof...(Args)); + if (ret == nullptr) { + return nullptr; + } + return reinterpret_cast(internal::get_object_instance_binding(ret)); +} + +template void _call_builtin_constructor(const GDExtensionPtrConstructor constructor, GDExtensionTypePtr base, Args... args) { std::array call_args = { { (GDExtensionConstTypePtr)args... } }; constructor(base, call_args.data()); } -template +template T _call_builtin_method_ptr_ret(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, Args... args) { T ret; std::array call_args = { { (GDExtensionConstTypePtr)args... } }; @@ -53,20 +65,20 @@ T _call_builtin_method_ptr_ret(const GDExtensionPtrBuiltInMethod method, GDExten return ret; } -template +template void _call_builtin_method_ptr_no_ret(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, Args... args) { std::array call_args = { { (GDExtensionConstTypePtr)args... } }; method(base, call_args.data(), nullptr, sizeof...(Args)); } -template +template T _call_builtin_operator_ptr(const GDExtensionPtrOperatorEvaluator op, GDExtensionConstTypePtr left, GDExtensionConstTypePtr right) { T ret; op(left, right, &ret); return ret; } -template +template T _call_builtin_ptr_getter(const GDExtensionPtrGetter getter, GDExtensionConstTypePtr base) { T ret; getter(base, &ret); diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index bafd2ce1b..26f58e4af 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -114,26 +114,26 @@ class ClassDB { static void initialize_class(const ClassInfo &cl); static void bind_method_godot(const StringName &p_class_name, MethodBind *p_method); - template + template static void _register_class(bool p_virtual = false); public: - template + template static void register_class(bool p_virtual = false); - template + template static void register_abstract_class(); _FORCE_INLINE_ static void _register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) { instance_binding_callbacks[p_name] = p_callbacks; } - template + template static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args); - template + template static MethodBind *bind_static_method(StringName p_class, N p_method_name, M p_method, VarArgs... p_args); - template + template static MethodBind *bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const std::vector &p_default_args = std::vector{}, bool p_return_nil_is_variant = true); static void add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix); @@ -155,23 +155,23 @@ class ClassDB { }; #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) \ - 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) \ - 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) \ { \ auto _call##m_method = [](GDExtensionObjectPtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr p_ret) -> void { \ call_with_ptr_args(reinterpret_cast(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 +template void ClassDB::_register_class(bool p_virtual) { static_assert(TypesAreSame::value, "Class not declared properly, please use GDCLASS."); instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks; @@ -219,17 +219,17 @@ void ClassDB::_register_class(bool p_virtual) { initialize_class(classes[cl.name]); } -template +template void ClassDB::register_class(bool p_virtual) { ClassDB::_register_class(p_virtual); } -template +template void ClassDB::register_abstract_class() { ClassDB::_register_class(); } -template +template 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. const Variant *argptrs[sizeof...(p_args) + 1]; @@ -240,7 +240,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)); } -template +template 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. const Variant *argptrs[sizeof...(p_args) + 1]; @@ -252,7 +252,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)); } -template +template MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info, const std::vector &p_default_args, bool 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); diff --git a/include/godot_cpp/core/defs.hpp b/include/godot_cpp/core/defs.hpp index c03db5035..16812c2b4 100644 --- a/include/godot_cpp/core/defs.hpp +++ b/include/godot_cpp/core/defs.hpp @@ -108,7 +108,7 @@ typedef float real_t; // Generic swap template. #ifndef SWAP #define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y)) -template +template inline void __swap_tmpl(T &x, T &y) { T aux = x; x = y; diff --git a/include/godot_cpp/core/engine_ptrcall.hpp b/include/godot_cpp/core/engine_ptrcall.hpp index 69ab196bf..555806b8e 100644 --- a/include/godot_cpp/core/engine_ptrcall.hpp +++ b/include/godot_cpp/core/engine_ptrcall.hpp @@ -43,7 +43,7 @@ namespace godot { namespace internal { -template +template O *_call_native_mb_ret_obj(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) { GodotObject *ret = nullptr; std::array mb_args = { { (GDExtensionConstTypePtr)args... } }; @@ -54,7 +54,7 @@ O *_call_native_mb_ret_obj(const GDExtensionMethodBindPtr mb, void *instance, co return reinterpret_cast(internal::get_object_instance_binding(ret)); } -template +template R _call_native_mb_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) { R ret; std::array mb_args = { { (GDExtensionConstTypePtr)args... } }; @@ -62,13 +62,13 @@ R _call_native_mb_ret(const GDExtensionMethodBindPtr mb, void *instance, const A return ret; } -template +template void _call_native_mb_no_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) { std::array mb_args = { { (GDExtensionConstTypePtr)args... } }; internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), nullptr); } -template +template R _call_utility_ret(GDExtensionPtrUtilityFunction func, const Args &...args) { R ret; std::array mb_args = { { (GDExtensionConstTypePtr)args... } }; @@ -76,15 +76,15 @@ R _call_utility_ret(GDExtensionPtrUtilityFunction func, const Args &...args) { return ret; } -template -Object *_call_utility_ret_obj(const GDExtensionPtrUtilityFunction func, void *instance, const Args &...args) { +template +Object *_call_utility_ret_obj(const GDExtensionPtrUtilityFunction func, const Args &...args) { GodotObject *ret = nullptr; std::array mb_args = { { (GDExtensionConstTypePtr)args... } }; func(&ret, mb_args.data(), mb_args.size()); return (Object *)internal::get_object_instance_binding(ret); } -template +template void _call_utility_no_ret(const GDExtensionPtrUtilityFunction func, const Args &...args) { std::array mb_args = { { (GDExtensionConstTypePtr)args... } }; func(nullptr, mb_args.data(), mb_args.size()); diff --git a/include/godot_cpp/core/math.hpp b/include/godot_cpp/core/math.hpp index db97ba5db..2cbbe2726 100644 --- a/include/godot_cpp/core/math.hpp +++ b/include/godot_cpp/core/math.hpp @@ -84,7 +84,7 @@ constexpr auto CLAMP(const T m_a, const T2 m_min, const T3 m_max) { // Generic swap template. #ifndef SWAP #define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y)) -template +template inline void __swap_tmpl(T &x, T &y) { T aux = x; x = y; @@ -138,7 +138,7 @@ static inline int get_shift_from_power_of_2(unsigned int p_bits) { return -1; } -template +template static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) { --x; diff --git a/include/godot_cpp/core/memory.hpp b/include/godot_cpp/core/memory.hpp index 548f33015..750509455 100644 --- a/include/godot_cpp/core/memory.hpp +++ b/include/godot_cpp/core/memory.hpp @@ -40,10 +40,6 @@ #include -#ifndef PAD_ALIGN -#define PAD_ALIGN 16 //must always be greater than this at much -#endif - void *operator new(size_t p_size, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description); ///< operator new that takes a description and uses a pointer to the preallocated memory @@ -68,6 +64,18 @@ class Memory { Memory(); 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 *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); @@ -75,7 +83,7 @@ class Memory { _ALWAYS_INLINE_ void postinitialize_handler(void *) {} -template +template _ALWAYS_INLINE_ T *_post_initialize(T *p_obj) { postinitialize_handler(p_obj); return p_obj; @@ -91,28 +99,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) // Generic comparator used in Map, List, etc. -template +template struct Comparator { _ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); } }; -template +template void memdelete(T *p_class, typename std::enable_if>::type * = nullptr) { - if (!std::is_trivially_destructible::value) { + if constexpr (!std::is_trivially_destructible_v) { p_class->~T(); } Memory::free_static(p_class); } -template , bool> = true> +template , bool> = true> void memdelete(T *p_class) { godot::internal::gdextension_interface_object_destroy(p_class->_owner); } -template +template void memdelete_allocator(T *p_class) { - if (!std::is_trivially_destructible::value) { + if constexpr (!std::is_trivially_destructible_v) { p_class->~T(); } @@ -125,16 +133,20 @@ class DefaultAllocator { _ALWAYS_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr); } }; -template +template class DefaultTypedAllocator { public: - template + template _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); } }; #define memnew_arr(m_class, m_count) memnew_arr_template(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 T *memnew_arr_template(size_t p_elements, const char *p_descr = "") { if (p_elements == 0) { @@ -144,12 +156,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.*/ 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. ERR_FAIL_NULL_V(mem, failptr); - *(mem - 1) = p_elements; - if (!std::is_trivially_destructible::value) { + uint64_t *_elem_count_ptr = _get_element_count_ptr(mem); + *(_elem_count_ptr) = p_elements; + + if constexpr (!std::is_trivially_destructible_v) { T *elems = (T *)mem; /* call operator new */ @@ -161,12 +175,20 @@ T *memnew_arr_template(size_t p_elements, const char *p_descr = "") { return (T *)mem; } +template +size_t memarr_len(const T *p_class) { + uint8_t *ptr = (uint8_t *)p_class; + uint64_t *_elem_count_ptr = _get_element_count_ptr(ptr); + return *(_elem_count_ptr); +} + template void memdelete_arr(T *p_class) { - uint64_t *ptr = (uint64_t *)p_class; + uint8_t *ptr = (uint8_t *)p_class; - if (!std::is_trivially_destructible::value) { - uint64_t elem_count = *(ptr - 1); + if constexpr (!std::is_trivially_destructible_v) { + 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++) { p_class[i].~T(); diff --git a/include/godot_cpp/core/method_bind.hpp b/include/godot_cpp/core/method_bind.hpp index 37ae73176..4afd7b8a1 100644 --- a/include/godot_cpp/core/method_bind.hpp +++ b/include/godot_cpp/core/method_bind.hpp @@ -147,7 +147,7 @@ class MethodBind { virtual ~MethodBind(); }; -template +template class MethodBindVarArgBase : public MethodBind { protected: R(T::*method) @@ -208,7 +208,7 @@ class MethodBindVarArgBase : public MethodBind { } }; -template +template class MethodBindVarArgT : public MethodBindVarArgBase, T, void, false> { friend class MethodBindVarArgBase, T, void, false>; @@ -231,14 +231,14 @@ class MethodBindVarArgT : public MethodBindVarArgBase, T, v } }; -template +template 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)(p_method, p_info, p_return_nil_is_variant)); a->set_instance_class(T::get_class_static()); return a; } -template +template class MethodBindVarArgTR : public MethodBindVarArgBase, T, R, true> { friend class MethodBindVarArgBase, T, R, true>; @@ -260,7 +260,7 @@ class MethodBindVarArgTR : public MethodBindVarArgBase, } }; -template +template 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)(p_method, p_info, p_return_nil_is_variant)); a->set_instance_class(T::get_class_static()); @@ -277,9 +277,9 @@ class _gde_UnexistingClass; // No return, not const. #ifdef TYPED_METHOD_BIND -template +template #else -template +template #endif // TYPED_METHOD_BIND class MethodBindT : public MethodBind { void (MB_T::*method)(P...); @@ -339,7 +339,7 @@ class MethodBindT : public MethodBind { } }; -template +template MethodBind *create_method_bind(void (T::*p_method)(P...)) { #ifdef TYPED_METHOD_BIND MethodBind *a = memnew((MethodBindT)(p_method)); @@ -353,9 +353,9 @@ MethodBind *create_method_bind(void (T::*p_method)(P...)) { // No return, const. #ifdef TYPED_METHOD_BIND -template +template #else -template +template #endif // TYPED_METHOD_BIND class MethodBindTC : public MethodBind { void (MB_T::*method)(P...) const; @@ -415,7 +415,7 @@ class MethodBindTC : public MethodBind { } }; -template +template MethodBind *create_method_bind(void (T::*p_method)(P...) const) { #ifdef TYPED_METHOD_BIND MethodBind *a = memnew((MethodBindTC)(p_method)); @@ -429,9 +429,9 @@ MethodBind *create_method_bind(void (T::*p_method)(P...) const) { // Return, not const. #ifdef TYPED_METHOD_BIND -template +template #else -template +template #endif // TYPED_METHOD_BIND class MethodBindTR : public MethodBind { R(MB_T::*method) @@ -498,7 +498,7 @@ class MethodBindTR : public MethodBind { } }; -template +template MethodBind *create_method_bind(R (T::*p_method)(P...)) { #ifdef TYPED_METHOD_BIND MethodBind *a = memnew((MethodBindTR)(p_method)); @@ -512,9 +512,9 @@ MethodBind *create_method_bind(R (T::*p_method)(P...)) { // Return, const. #ifdef TYPED_METHOD_BIND -template +template #else -template +template #endif // TYPED_METHOD_BIND class MethodBindTRC : public MethodBind { R(MB_T::*method) @@ -581,7 +581,7 @@ class MethodBindTRC : public MethodBind { } }; -template +template MethodBind *create_method_bind(R (T::*p_method)(P...) const) { #ifdef TYPED_METHOD_BIND MethodBind *a = memnew((MethodBindTRC)(p_method)); @@ -596,7 +596,7 @@ MethodBind *create_method_bind(R (T::*p_method)(P...) const) { // no return -template +template class MethodBindTS : public MethodBind { void (*function)(P...); @@ -652,7 +652,7 @@ class MethodBindTS : public MethodBind { } }; -template +template MethodBind *create_static_method_bind(void (*p_method)(P...)) { MethodBind *a = memnew((MethodBindTS)(p_method)); return a; @@ -660,7 +660,7 @@ MethodBind *create_static_method_bind(void (*p_method)(P...)) { // return -template +template class MethodBindTRS : public MethodBind { R(*function) (P...); @@ -722,7 +722,7 @@ class MethodBindTRS : public MethodBind { } }; -template +template MethodBind *create_static_method_bind(R (*p_method)(P...)) { MethodBind *a = memnew((MethodBindTRS)(p_method)); return a; diff --git a/include/godot_cpp/core/method_ptrcall.hpp b/include/godot_cpp/core/method_ptrcall.hpp index 32f3f459d..ca3327ed9 100644 --- a/include/godot_cpp/core/method_ptrcall.hpp +++ b/include/godot_cpp/core/method_ptrcall.hpp @@ -39,7 +39,7 @@ namespace godot { -template +template struct PtrToArg {}; #define MAKE_PTRARG(m_type) \ @@ -166,7 +166,7 @@ MAKE_PTRARG_BY_REFERENCE(Variant); // This is for Object. -template +template struct PtrToArg { static_assert(std::is_base_of::value, "Cannot encode non-Object value as an Object"); _FORCE_INLINE_ static T *convert(const void *p_ptr) { @@ -178,7 +178,7 @@ struct PtrToArg { } }; -template +template struct PtrToArg { static_assert(std::is_base_of::value, "Cannot encode non-Object value as an Object"); _FORCE_INLINE_ static const T *convert(const void *p_ptr) { diff --git a/include/godot_cpp/core/object.hpp b/include/godot_cpp/core/object.hpp index d66e38894..a10cde0ef 100644 --- a/include/godot_cpp/core/object.hpp +++ b/include/godot_cpp/core/object.hpp @@ -45,10 +45,10 @@ #include -#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_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_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_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) namespace godot { @@ -75,31 +75,31 @@ struct MethodInfo { MethodInfo(); MethodInfo(StringName p_name); - template + template MethodInfo(StringName p_name, const Args &...args); MethodInfo(Variant::Type ret); MethodInfo(Variant::Type ret, StringName p_name); - template + template MethodInfo(Variant::Type ret, StringName p_name, const Args &...args); MethodInfo(const PropertyInfo &p_ret, StringName p_name); - template + template MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...); }; -template +template MethodInfo::MethodInfo(StringName p_name, const Args &...args) : name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) { arguments = { args... }; } -template +template MethodInfo::MethodInfo(Variant::Type ret, StringName p_name, const Args &...args) : name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) { return_val.type = ret; arguments = { args... }; } -template +template MethodInfo::MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...args) : name(p_name), return_val(p_ret), flags(GDEXTENSION_METHOD_FLAG_NORMAL) { arguments = { args... }; @@ -138,7 +138,7 @@ class ObjectDB { } }; -template +template T *Object::cast_to(Object *p_object) { if (p_object == nullptr) { return nullptr; @@ -151,7 +151,7 @@ T *Object::cast_to(Object *p_object) { return dynamic_cast(internal::get_object_instance_binding(casted)); } -template +template const T *Object::cast_to(const Object *p_object) { if (p_object == nullptr) { return nullptr; diff --git a/include/godot_cpp/core/type_info.hpp b/include/godot_cpp/core/type_info.hpp index f0edda5c6..2c4f8e404 100644 --- a/include/godot_cpp/core/type_info.hpp +++ b/include/godot_cpp/core/type_info.hpp @@ -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 // include the actual declaration of 'T' in the source file where 'GetTypeInfo' is instantiated. -template +template struct GetTypeInfo; #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::get_class_info().class_name; } -template +template class BitField { int64_t value = 0; public: _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_ 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_ operator int64_t() 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>::get_class_info().class_name; } -template +template struct PtrToArg> { _FORCE_INLINE_ static TypedArray convert(const void *p_ptr) { return TypedArray(*reinterpret_cast(p_ptr)); @@ -306,7 +306,7 @@ struct PtrToArg> { } }; -template +template struct PtrToArg &> { typedef Array EncodeT; _FORCE_INLINE_ static TypedArray diff --git a/include/godot_cpp/templates/cowdata.hpp b/include/godot_cpp/templates/cowdata.hpp index 9b36538d0..dcb74eccc 100644 --- a/include/godot_cpp/templates/cowdata.hpp +++ b/include/godot_cpp/templates/cowdata.hpp @@ -43,78 +43,120 @@ namespace godot { -template +template class Vector; -template +template class VMap; -template +template class CharStringT; +static_assert(std::is_trivially_destructible_v>); + // Silence a false positive warning (see GH-52119). #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wplacement-new" #endif -template +template class CowData { - template + template friend class Vector; - template + template friend class VMap; - template + template friend class CharStringT; +public: + typedef int64_t Size; + typedef uint64_t USize; + static constexpr USize MAX_INT = INT64_MAX; + 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 │░░│ 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)) % alignof(USize) == 0) ? (REF_COUNT_OFFSET + sizeof(SafeNumeric)) : ((REF_COUNT_OFFSET + sizeof(SafeNumeric)) + alignof(USize) - ((REF_COUNT_OFFSET + sizeof(SafeNumeric)) % 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; // internal helpers - _FORCE_INLINE_ SafeNumeric *_get_refcount() const { - if (!_ptr) { - return nullptr; - } + static _FORCE_INLINE_ SafeNumeric *_get_refcount_ptr(uint8_t *p_ptr) { + return (SafeNumeric *)(p_ptr + REF_COUNT_OFFSET); + } - return reinterpret_cast *>(_ptr) - 2; + static _FORCE_INLINE_ USize *_get_size_ptr(uint8_t *p_ptr) { + return (USize *)(p_ptr + SIZE_OFFSET); } - _FORCE_INLINE_ uint32_t *_get_size() const { + static _FORCE_INLINE_ T *_get_data_ptr(uint8_t *p_ptr) { + return (T *)(p_ptr + DATA_OFFSET); + } + + _FORCE_INLINE_ SafeNumeric *_get_refcount() const { if (!_ptr) { return nullptr; } - return reinterpret_cast(_ptr) - 1; + return (SafeNumeric *)((uint8_t *)_ptr - DATA_OFFSET + REF_COUNT_OFFSET); } - _FORCE_INLINE_ T *_get_data() const { + _FORCE_INLINE_ USize *_get_size() const { if (!_ptr) { return nullptr; } - return reinterpret_cast(_ptr); + + return (USize *)((uint8_t *)_ptr - DATA_OFFSET + SIZE_OFFSET); } - _FORCE_INLINE_ size_t _get_alloc_size(size_t p_elements) const { - return next_power_of_2(p_elements * sizeof(T)); + _FORCE_INLINE_ USize _get_alloc_size(USize p_elements) const { + return next_po2(p_elements * sizeof(T)); } - _FORCE_INLINE_ bool _get_alloc_size_checked(size_t p_elements, size_t *out) const { + _FORCE_INLINE_ bool _get_alloc_size_checked(USize p_elements, USize *out) const { if (unlikely(p_elements == 0)) { *out = 0; return true; } -#if defined(__GNUC__) - size_t o; - size_t p; +#if defined(__GNUC__) && defined(IS_32_BIT) + USize o; + USize p; if (__builtin_mul_overflow(p_elements, sizeof(T), &o)) { *out = 0; return false; } - *out = next_power_of_2(o); - if (__builtin_add_overflow(o, static_cast(32), &p)) { + *out = next_po2(o); + if (__builtin_add_overflow(o, static_cast(32), &p)) { return false; // No longer allocated here. } #else @@ -128,22 +170,22 @@ class CowData { void _unref(void *p_data); void _ref(const CowData *p_from); void _ref(const CowData &p_from); - uint32_t _copy_on_write(); + USize _copy_on_write(); public: void operator=(const CowData &p_from) { _ref(p_from); } _FORCE_INLINE_ T *ptrw() { _copy_on_write(); - return (T *)_get_data(); + return _ptr; } _FORCE_INLINE_ const T *ptr() const { - return _get_data(); + return _ptr; } - _FORCE_INLINE_ int size() const { - uint32_t *size = (uint32_t *)_get_size(); + _FORCE_INLINE_ Size size() const { + USize *size = (USize *)_get_size(); if (size) { return *size; } else { @@ -154,41 +196,42 @@ class CowData { _FORCE_INLINE_ void clear() { resize(0); } _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()); _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()); _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()); - return _get_data()[p_index]; + return _ptr[p_index]; } - Error resize(int p_size); + template + 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()); T *p = ptrw(); - int len = size(); - for (int i = p_index; i < len - 1; i++) { + Size len = size(); + for (Size i = p_index; i < len - 1; i++) { p[i] = p[i + 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); 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(p_pos, p_val); @@ -196,83 +239,88 @@ class CowData { 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(CowData &p_from) { _ref(p_from); } + _FORCE_INLINE_ CowData(CowData &p_from) { _ref(p_from); }; }; -template +template void CowData::_unref(void *p_data) { if (!p_data) { return; } - SafeNumeric *refc = _get_refcount(); + SafeNumeric *refc = _get_refcount(); if (refc->decrement() > 0) { return; // still in use } - // clean up - if (!std::is_trivially_destructible::value) { - uint32_t *count = _get_size(); + + if constexpr (!std::is_trivially_destructible_v) { + USize *count = _get_size(); T *data = (T *)(count + 1); - for (uint32_t i = 0; i < *count; ++i) { + for (USize i = 0; i < *count; ++i) { // call destructors data[i].~T(); } } // free mem - Memory::free_static((uint8_t *)p_data, true); + Memory::free_static(((uint8_t *)p_data) - DATA_OFFSET, false); } -template -uint32_t CowData::_copy_on_write() { +template +typename CowData::USize CowData::_copy_on_write() { if (!_ptr) { return 0; } - SafeNumeric *refc = _get_refcount(); + SafeNumeric *refc = _get_refcount(); - uint32_t rc = refc->get(); + USize rc = refc->get(); if (unlikely(rc > 1)) { /* 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(1); // refcount - *(mem_new - 1) = current_size; // size + SafeNumeric *_refc_ptr = _get_refcount_ptr(mem_new); + 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(1); //refcount + *(_size_ptr) = current_size; //size // initialize new elements - if (std::is_trivially_copyable::value) { - memcpy(mem_new, _ptr, current_size * sizeof(T)); - + if constexpr (std::is_trivially_copyable_v) { + memcpy((uint8_t *)_data_ptr, _ptr, current_size * sizeof(T)); } else { - for (uint32_t i = 0; i < current_size; i++) { - memnew_placement(&_data[i], T(_get_data()[i])); + for (USize i = 0; i < current_size; i++) { + memnew_placement(&_data_ptr[i], T(_ptr[i])); } } _unref(_ptr); - _ptr = _data; + _ptr = _data_ptr; rc = 1; } return rc; } -template -Error CowData::resize(int p_size) { +template +template +Error CowData::resize(Size p_size) { ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER); - int current_size = size(); + Size current_size = size(); if (p_size == current_size) { return OK; @@ -286,59 +334,71 @@ Error CowData::resize(int p_size) { } // 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); - size_t alloc_size; + USize current_alloc_size = _get_alloc_size(current_size); + USize alloc_size; ERR_FAIL_COND_V(!_get_alloc_size_checked(p_size, &alloc_size), ERR_OUT_OF_MEMORY); if (p_size > current_size) { if (alloc_size != current_alloc_size) { if (current_size == 0) { // alloc from scratch - uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true); - ERR_FAIL_NULL_V(ptr, ERR_OUT_OF_MEMORY); - *(ptr - 1) = 0; // size, currently none - new (ptr - 2) SafeNumeric(1); // refcount + uint8_t *mem_new = (uint8_t *)Memory::alloc_static(alloc_size + DATA_OFFSET, false); + ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY); + + SafeNumeric *_refc_ptr = _get_refcount_ptr(mem_new); + USize *_size_ptr = _get_size_ptr(mem_new); + T *_data_ptr = _get_data_ptr(mem_new); - _ptr = (T *)ptr; + new (_refc_ptr) SafeNumeric(1); //refcount + *(_size_ptr) = 0; //size, currently none + _ptr = _data_ptr; } else { - uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true); - ERR_FAIL_NULL_V(_ptrnew, ERR_OUT_OF_MEMORY); - new (_ptrnew - 2) SafeNumeric(rc); // refcount + uint8_t *mem_new = (uint8_t *)Memory::realloc_static(((uint8_t *)_ptr) - DATA_OFFSET, alloc_size + DATA_OFFSET, false); + ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY); + + SafeNumeric *_refc_ptr = _get_refcount_ptr(mem_new); + T *_data_ptr = _get_data_ptr(mem_new); - _ptr = (T *)(_ptrnew); + new (_refc_ptr) SafeNumeric(rc); //refcount + + _ptr = _data_ptr; } } // construct the newly created elements - if (!std::is_trivially_constructible::value) { - T *elems = _get_data(); - - for (int i = *_get_size(); i < p_size; i++) { - memnew_placement(&elems[i], T); + if constexpr (!std::is_trivially_constructible_v) { + for (Size i = *_get_size(); i < p_size; i++) { + memnew_placement(&_ptr[i], T); } + } else if (p_ensure_zero) { + memset((void *)(_ptr + current_size), 0, (p_size - current_size) * sizeof(T)); } *_get_size() = p_size; } else if (p_size < current_size) { - if (!std::is_trivially_destructible::value) { + if constexpr (!std::is_trivially_destructible_v) { // deinitialize no longer needed elements - for (uint32_t i = p_size; i < *_get_size(); i++) { - T *t = &_get_data()[i]; + for (USize i = p_size; i < *_get_size(); i++) { + T *t = &_ptr[i]; t->~T(); } } if (alloc_size != current_alloc_size) { - uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true); - ERR_FAIL_NULL_V(_ptrnew, ERR_OUT_OF_MEMORY); - new (_ptrnew - 2) SafeNumeric(rc); // refcount + uint8_t *mem_new = (uint8_t *)Memory::realloc_static(((uint8_t *)_ptr) - DATA_OFFSET, alloc_size + DATA_OFFSET, false); + ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY); + + SafeNumeric *_refc_ptr = _get_refcount_ptr(mem_new); + T *_data_ptr = _get_data_ptr(mem_new); - _ptr = (T *)(_ptrnew); + new (_refc_ptr) SafeNumeric(rc); //refcount + + _ptr = _data_ptr; } *_get_size() = p_size; @@ -347,15 +407,15 @@ Error CowData::resize(int p_size) { return OK; } -template -int CowData::find(const T &p_val, int p_from) const { - int ret = -1; +template +typename CowData::Size CowData::find(const T &p_val, Size p_from) const { + Size ret = -1; if (p_from < 0 || size() == 0) { return ret; } - for (int i = p_from; i < size(); i++) { + for (Size i = p_from; i < size(); i++) { if (get(i) == p_val) { ret = i; break; @@ -365,12 +425,42 @@ int CowData::find(const T &p_val, int p_from) const { return ret; } -template +template +typename CowData::Size CowData::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 CowData::Size CowData::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 void CowData::_ref(const CowData *p_from) { _ref(*p_from); } -template +template void CowData::_ref(const CowData &p_from) { if (_ptr == p_from._ptr) { return; // self assign, do nothing. @@ -388,7 +478,7 @@ void CowData::_ref(const CowData &p_from) { } } -template +template CowData::~CowData() { _unref(_ptr); } diff --git a/include/godot_cpp/templates/hash_map.hpp b/include/godot_cpp/templates/hash_map.hpp index 77c7b7a91..59cd8e0b0 100644 --- a/include/godot_cpp/templates/hash_map.hpp +++ b/include/godot_cpp/templates/hash_map.hpp @@ -52,7 +52,7 @@ namespace godot { * The assignment operator copy the pairs from one map to the other. */ -template +template struct HashMapElement { HashMapElement *next = nullptr; HashMapElement *prev = nullptr; @@ -62,10 +62,10 @@ struct HashMapElement { data(p_key, p_value) {} }; -template , - class Allocator = DefaultTypedAllocator>> +template , + typename Allocator = DefaultTypedAllocator>> class HashMap { public: const uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime. diff --git a/include/godot_cpp/templates/hash_set.hpp b/include/godot_cpp/templates/hash_set.hpp index 884ae4db7..1845a1bb4 100644 --- a/include/godot_cpp/templates/hash_set.hpp +++ b/include/godot_cpp/templates/hash_set.hpp @@ -48,9 +48,9 @@ namespace godot { * */ -template > +template > class HashSet { public: static constexpr uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime. diff --git a/include/godot_cpp/templates/hashfuncs.hpp b/include/godot_cpp/templates/hashfuncs.hpp index d6f340029..40b10a9e2 100644 --- a/include/godot_cpp/templates/hashfuncs.hpp +++ b/include/godot_cpp/templates/hashfuncs.hpp @@ -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); } -template +template static _FORCE_INLINE_ uint32_t hash_make_uint32_t(T p_in) { union { 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; } -template +template static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) { union { T t; @@ -298,15 +298,15 @@ static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) { return _u._u64; } -template +template class Ref; struct HashMapHasherDefault { // Generic hash function for any type. - template + template static _FORCE_INLINE_ uint32_t hash(const T *p_pointer) { return hash_one_uint64((uint64_t)p_pointer); } - template + template static _FORCE_INLINE_ uint32_t hash(const Ref &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(); } diff --git a/include/godot_cpp/templates/list.hpp b/include/godot_cpp/templates/list.hpp index 2c8a7c874..376e3ea87 100644 --- a/include/godot_cpp/templates/list.hpp +++ b/include/godot_cpp/templates/list.hpp @@ -45,7 +45,7 @@ namespace godot { -template +template class List { struct _Data; @@ -410,7 +410,7 @@ class List { /** * find an element in the list, */ - template + template Element *find(const T_v &p_val) { Element *it = front(); while (it) { @@ -646,7 +646,7 @@ class List { sort_custom>(); } - template + template void sort_custom_inplace() { if (size() < 2) { return; @@ -693,7 +693,7 @@ class List { _data->last = to; } - template + template struct AuxiliaryComparator { C compare; _FORCE_INLINE_ bool operator()(const Element *a, const Element *b) const { @@ -701,7 +701,7 @@ class List { } }; - template + template void sort_custom() { // this version uses auxiliary memory for speed. // if you don't want to use auxiliary memory, use the in_place version diff --git a/include/godot_cpp/templates/local_vector.hpp b/include/godot_cpp/templates/local_vector.hpp index 8ce4e6552..5dad32e0e 100644 --- a/include/godot_cpp/templates/local_vector.hpp +++ b/include/godot_cpp/templates/local_vector.hpp @@ -43,7 +43,7 @@ namespace godot { // If tight, it grows strictly as much as needed. // Otherwise, it grows exponentially (the default and what you want in most cases). -template +template class LocalVector { private: U count = 0; @@ -257,7 +257,7 @@ class LocalVector { return -1; } - template + template void sort_custom() { U len = count; if (len == 0) { @@ -331,7 +331,7 @@ class LocalVector { } }; -template +template using TightLocalVector = LocalVector; } // namespace godot diff --git a/include/godot_cpp/templates/pair.hpp b/include/godot_cpp/templates/pair.hpp index ed35302b1..f87541305 100644 --- a/include/godot_cpp/templates/pair.hpp +++ b/include/godot_cpp/templates/pair.hpp @@ -33,7 +33,7 @@ namespace godot { -template +template struct Pair { F first; S second; @@ -49,17 +49,17 @@ struct Pair { } }; -template +template bool operator==(const Pair &pair, const Pair &other) { return (pair.first == other.first) && (pair.second == other.second); } -template +template bool operator!=(const Pair &pair, const Pair &other) { return (pair.first != other.first) || (pair.second != other.second); } -template +template struct PairSort { bool operator()(const Pair &A, const Pair &B) const { if (A.first != B.first) { @@ -69,7 +69,7 @@ struct PairSort { } }; -template +template struct KeyValue { const K key; V value; @@ -85,17 +85,17 @@ struct KeyValue { } }; -template +template bool operator==(const KeyValue &pair, const KeyValue &other) { return (pair.key == other.key) && (pair.value == other.value); } -template +template bool operator!=(const KeyValue &pair, const KeyValue &other) { return (pair.key != other.key) || (pair.value != other.value); } -template +template struct KeyValueSort { bool operator()(const KeyValue &A, const KeyValue &B) const { return A.key < B.key; diff --git a/include/godot_cpp/templates/rb_map.hpp b/include/godot_cpp/templates/rb_map.hpp index cce1e91b9..6ab71fd7e 100644 --- a/include/godot_cpp/templates/rb_map.hpp +++ b/include/godot_cpp/templates/rb_map.hpp @@ -40,7 +40,7 @@ namespace godot { // 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 -template , class A = DefaultAllocator> +template , typename A = DefaultAllocator> class RBMap { enum Color { RED, diff --git a/include/godot_cpp/templates/rb_set.hpp b/include/godot_cpp/templates/rb_set.hpp index c803f8183..69aa8d7f9 100644 --- a/include/godot_cpp/templates/rb_set.hpp +++ b/include/godot_cpp/templates/rb_set.hpp @@ -38,7 +38,7 @@ namespace godot { -template , class A = DefaultAllocator> +template , typename A = DefaultAllocator> class RBSet { enum Color { RED, diff --git a/include/godot_cpp/templates/rid_owner.hpp b/include/godot_cpp/templates/rid_owner.hpp index 005fc876f..1dd4a3933 100644 --- a/include/godot_cpp/templates/rid_owner.hpp +++ b/include/godot_cpp/templates/rid_owner.hpp @@ -42,7 +42,7 @@ namespace godot { -template +template class RID_Alloc { T **chunks = nullptr; uint32_t **free_list_chunks = nullptr; @@ -347,7 +347,7 @@ class RID_Alloc { } }; -template +template class RID_PtrOwner { RID_Alloc alloc; @@ -406,7 +406,7 @@ class RID_PtrOwner { alloc(p_target_chunk_byte_size) {} }; -template +template class RID_Owner { RID_Alloc alloc; diff --git a/include/godot_cpp/templates/safe_refcount.hpp b/include/godot_cpp/templates/safe_refcount.hpp index f86504168..12e6840ae 100644 --- a/include/godot_cpp/templates/safe_refcount.hpp +++ b/include/godot_cpp/templates/safe_refcount.hpp @@ -48,7 +48,16 @@ namespace godot { // value and, as an important benefit, you can be sure the value is properly synchronized // even with threads that are already running. -template +// 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) == sizeof(m_type)); \ + static_assert(alignof(SafeNumeric) == alignof(m_type)); \ + static_assert(std::is_trivially_destructible>::value); +#define SAFE_FLAG_TYPE_PUN_GUARANTEES \ + static_assert(sizeof(SafeFlag) == sizeof(bool)); \ + static_assert(alignof(SafeFlag) == alignof(bool)); + +template class SafeNumeric { std::atomic value; @@ -186,7 +195,7 @@ class SafeRefCount { #else -template +template class SafeNumeric { protected: T value; diff --git a/include/godot_cpp/templates/search_array.hpp b/include/godot_cpp/templates/search_array.hpp index ce2713bdc..11a9db525 100644 --- a/include/godot_cpp/templates/search_array.hpp +++ b/include/godot_cpp/templates/search_array.hpp @@ -35,7 +35,7 @@ namespace godot { -template > +template > class SearchArray { public: Comparator compare; diff --git a/include/godot_cpp/templates/self_list.hpp b/include/godot_cpp/templates/self_list.hpp index 3bb13a354..f7a65f689 100644 --- a/include/godot_cpp/templates/self_list.hpp +++ b/include/godot_cpp/templates/self_list.hpp @@ -36,7 +36,7 @@ namespace godot { -template +template class SelfList { public: class List { diff --git a/include/godot_cpp/templates/sort_array.hpp b/include/godot_cpp/templates/sort_array.hpp index 5dda5782c..7ce5c7842 100644 --- a/include/godot_cpp/templates/sort_array.hpp +++ b/include/godot_cpp/templates/sort_array.hpp @@ -41,7 +41,7 @@ namespace godot { break; \ } -template +template struct _DefaultComparator { _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 #endif -template , bool Validate = SORT_ARRAY_VALIDATE_ENABLED> +template , bool Validate = SORT_ARRAY_VALIDATE_ENABLED> class SortArray { enum { INTROSORT_THRESHOLD = 16 diff --git a/include/godot_cpp/templates/thread_work_pool.hpp b/include/godot_cpp/templates/thread_work_pool.hpp index a3efd42e0..cb20c6e97 100644 --- a/include/godot_cpp/templates/thread_work_pool.hpp +++ b/include/godot_cpp/templates/thread_work_pool.hpp @@ -52,7 +52,7 @@ class ThreadWorkPool { virtual ~BaseWork() = default; }; - template + template struct Work : public BaseWork { C *instance; M method; @@ -94,7 +94,7 @@ class ThreadWorkPool { } public: - template + template void begin_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) { ERR_FAIL_NULL(threads); // Never initialized. ERR_FAIL_COND(current_work != nullptr); @@ -145,7 +145,7 @@ class ThreadWorkPool { current_work = nullptr; } - template + template void do_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) { switch (p_elements) { case 0: diff --git a/include/godot_cpp/templates/vector.hpp b/include/godot_cpp/templates/vector.hpp index f5626af0d..aaa84f338 100644 --- a/include/godot_cpp/templates/vector.hpp +++ b/include/godot_cpp/templates/vector.hpp @@ -47,38 +47,42 @@ namespace godot { -template +template class VectorWriteProxy { public: - _FORCE_INLINE_ T &operator[](int p_index) { + _FORCE_INLINE_ T &operator[](typename CowData::Size p_index) { CRASH_BAD_INDEX(p_index, ((Vector *)(this))->_cowdata.size()); return ((Vector *)(this))->_cowdata.ptrw()[p_index]; } }; -template +template class Vector { friend class VectorWriteProxy; public: VectorWriteProxy write; + typedef typename CowData::Size Size; private: CowData _cowdata; public: bool push_back(T p_elem); - _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 remove_at(int p_index) { _cowdata.remove_at(p_index); } - void erase(const T &p_val) { - int idx = find(p_val); + void remove_at(Size p_index) { _cowdata.remove_at(p_index); } + _FORCE_INLINE_ bool erase(const T &p_val) { + Size idx = find(p_val); if (idx >= 0) { remove_at(idx); + return true; } + return false; } + void reverse(); _FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); } @@ -86,37 +90,45 @@ class Vector { _FORCE_INLINE_ void clear() { resize(0); } _FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); } - _FORCE_INLINE_ T get(int p_index) { return _cowdata.get(p_index); } - _FORCE_INLINE_ const T &get(int 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_ int size() const { return _cowdata.size(); } - Error resize(int p_size) { return _cowdata.resize(p_size); } - _FORCE_INLINE_ const T &operator[](int p_index) const { return _cowdata.get(p_index); } - Error insert(int p_pos, T p_val) { return _cowdata.insert(p_pos, p_val); } - int find(const T &p_val, int p_from = 0) const { return _cowdata.find(p_val, p_from); } + _FORCE_INLINE_ T get(Size p_index) { return _cowdata.get(p_index); } + _FORCE_INLINE_ const T &get(Size p_index) const { return _cowdata.get(p_index); } + _FORCE_INLINE_ void set(Size p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); } + _FORCE_INLINE_ Size size() const { return _cowdata.size(); } + Error resize(Size p_size) { return _cowdata.resize(p_size); } + Error resize_zeroed(Size p_size) { return _cowdata.template resize(p_size); } + _FORCE_INLINE_ const T &operator[](Size p_index) const { return _cowdata.get(p_index); } + 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 p_other); _FORCE_INLINE_ bool has(const T &p_val) const { return find(p_val) != -1; } - template - void sort_custom() { - int len = _cowdata.size(); + void sort() { + sort_custom<_DefaultComparator>(); + } + + template + void sort_custom(Args &&...args) { + Size len = _cowdata.size(); if (len == 0) { return; } T *data = ptrw(); - SortArray sorter; + SortArray sorter{ args... }; sorter.sort(data, len); } - void sort() { - sort_custom<_DefaultComparator>(); + Size bsearch(const T &p_value, bool p_before) { + return bsearch_custom<_DefaultComparator>(p_value, p_before); } - int bsearch(const T &p_value, bool p_before) { - SearchArray search; + template + Size bsearch_custom(const Value &p_value, bool p_before, Args &&...args) { + SearchArray search{ args... }; return search.bisect(ptrw(), size(), p_value, p_before); } @@ -125,7 +137,7 @@ class Vector { } void ordered_insert(const T &p_val) { - int i; + Size i; for (i = 0; i < _cowdata.size(); i++) { if (p_val < operator[](i)) { break; @@ -140,33 +152,36 @@ class Vector { Vector to_byte_array() const { Vector ret; + if (is_empty()) { + return ret; + } ret.resize(size() * sizeof(T)); memcpy(ret.ptrw(), ptr(), sizeof(T) * size()); return ret; } - Vector slice(int p_begin, int p_end = INT_MAX) const { + Vector slice(Size p_begin, Size p_end = CowData::MAX_INT) const { Vector 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) { begin += s; } - int end = Math::clamp(p_end, -s, s); + Size end = CLAMP(p_end, -s, s); if (end < 0) { end += s; } ERR_FAIL_COND_V(begin > end, result); - int result_size = end - begin; + Size result_size = end - begin; result.resize(result_size); const T *const r = ptr(); 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]; } @@ -174,11 +189,11 @@ class Vector { } bool operator==(const Vector &p_arr) const { - int s = size(); + Size s = size(); if (s != p_arr.size()) { return false; } - for (int i = 0; i < s; i++) { + for (Size i = 0; i < s; i++) { if (operator[](i) != p_arr[i]) { return false; } @@ -187,11 +202,11 @@ class Vector { } bool operator!=(const Vector &p_arr) const { - int s = size(); + Size s = size(); if (s != p_arr.size()) { return true; } - for (int i = 0; i < s; i++) { + for (Size i = 0; i < s; i++) { if (operator[](i) != p_arr[i]) { return true; } @@ -268,7 +283,7 @@ class Vector { Error err = _cowdata.resize(p_init.size()); ERR_FAIL_COND(err); - int i = 0; + Size i = 0; for (const T &element : p_init) { _cowdata.set(i++, element); } @@ -278,28 +293,28 @@ class Vector { _FORCE_INLINE_ ~Vector() {} }; -template +template void Vector::reverse() { - for (int i = 0; i < size() / 2; i++) { + for (Size i = 0; i < size() / 2; i++) { T *p = ptrw(); SWAP(p[i], p[size() - i - 1]); } } -template +template void Vector::append_array(Vector p_other) { - const int ds = p_other.size(); + const Size ds = p_other.size(); if (ds == 0) { return; } - const int bs = size(); + const Size bs = size(); resize(bs + ds); - for (int i = 0; i < ds; ++i) { + for (Size i = 0; i < ds; ++i) { ptrw()[bs + i] = p_other[i]; } } -template +template bool Vector::push_back(T p_elem) { Error err = resize(size() + 1); ERR_FAIL_COND_V(err, true); @@ -308,10 +323,10 @@ bool Vector::push_back(T p_elem) { return false; } -template +template void Vector::fill(T p_elem) { T *p = ptrw(); - for (int i = 0; i < size(); i++) { + for (Size i = 0; i < size(); i++) { p[i] = p_elem; } } diff --git a/include/godot_cpp/templates/vmap.hpp b/include/godot_cpp/templates/vmap.hpp index 881ac25e6..926ccd390 100644 --- a/include/godot_cpp/templates/vmap.hpp +++ b/include/godot_cpp/templates/vmap.hpp @@ -35,7 +35,7 @@ namespace godot { -template +template class VMap { public: struct Pair { diff --git a/include/godot_cpp/templates/vset.hpp b/include/godot_cpp/templates/vset.hpp index 29f0cefe9..ce21ba83f 100644 --- a/include/godot_cpp/templates/vset.hpp +++ b/include/godot_cpp/templates/vset.hpp @@ -35,7 +35,7 @@ namespace godot { -template +template class VSet { Vector _data; diff --git a/include/godot_cpp/variant/char_string.hpp b/include/godot_cpp/variant/char_string.hpp index fef6a7187..991c0392a 100644 --- a/include/godot_cpp/variant/char_string.hpp +++ b/include/godot_cpp/variant/char_string.hpp @@ -38,19 +38,19 @@ namespace godot { -template +template class CharStringT; -template +template class CharProxy { - template + template friend class CharStringT; - const int _index; + const int64_t _index; CowData &_cowdata; static inline const T _null = 0; - _FORCE_INLINE_ CharProxy(const int &p_index, CowData &p_cowdata) : + _FORCE_INLINE_ CharProxy(const int64_t &p_index, CowData &p_cowdata) : _index(p_index), _cowdata(p_cowdata) {} @@ -80,7 +80,7 @@ class CharProxy { } }; -template +template class CharStringT { friend class String; @@ -90,19 +90,19 @@ class CharStringT { public: _FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); } _FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); } - _FORCE_INLINE_ int size() const { return _cowdata.size(); } - Error resize(int p_size) { return _cowdata.resize(p_size); } + _FORCE_INLINE_ int64_t size() const { return _cowdata.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_ void set(int p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); } - _FORCE_INLINE_ const T &operator[](int p_index) const { + _FORCE_INLINE_ T get(int64_t p_index) const { return _cowdata.get(p_index); } + _FORCE_INLINE_ void set(int64_t p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); } + _FORCE_INLINE_ const T &operator[](int64_t p_index) const { if (unlikely(p_index == _cowdata.size())) { return _null; } return _cowdata.get(p_index); } - _FORCE_INLINE_ CharProxy operator[](int p_index) { return CharProxy(p_index, _cowdata); } + _FORCE_INLINE_ CharProxy operator[](int64_t p_index) { return CharProxy(p_index, _cowdata); } _FORCE_INLINE_ CharStringT() {} _FORCE_INLINE_ CharStringT(const CharStringT &p_str) { _cowdata._ref(p_str._cowdata); } @@ -112,7 +112,7 @@ class CharStringT { void operator=(const T *p_cstr); bool operator<(const CharStringT &p_right) const; CharStringT &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; operator const T *() const { return get_data(); }; diff --git a/include/godot_cpp/variant/typed_array.hpp b/include/godot_cpp/variant/typed_array.hpp index 5e7084e4a..54738a640 100644 --- a/include/godot_cpp/variant/typed_array.hpp +++ b/include/godot_cpp/variant/typed_array.hpp @@ -36,7 +36,7 @@ namespace godot { -template +template class TypedArray : public Array { public: _FORCE_INLINE_ void operator=(const Array &p_array) { diff --git a/include/godot_cpp/variant/variant.hpp b/include/godot_cpp/variant/variant.hpp index 7b82d5eb3..76fb8d111 100644 --- a/include/godot_cpp/variant/variant.hpp +++ b/include/godot_cpp/variant/variant.hpp @@ -47,8 +47,6 @@ class ObjectID; class Variant { uint8_t opaque[GODOT_CPP_VARIANT_SIZE]{ 0 }; - _FORCE_INLINE_ GDExtensionVariantPtr _native_ptr() const { return const_cast(&opaque); } - friend class GDExtensionBinding; friend class MethodBind; @@ -145,6 +143,7 @@ class Variant { static GDExtensionTypeFromVariantConstructorFunc to_type_constructor[VARIANT_MAX]; public: + _FORCE_INLINE_ GDExtensionVariantPtr _native_ptr() const { return const_cast(&opaque); } Variant(); Variant(std::nullptr_t n) : Variant() {} @@ -270,7 +269,7 @@ class Variant { void callp(const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error); - template + template Variant call(const StringName &method, Args... args) { std::array vargs = { args... }; std::array argptrs; @@ -285,7 +284,7 @@ class Variant { static void callp_static(Variant::Type type, const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error); - template + template static Variant call_static(Variant::Type type, const StringName &method, Args... args) { std::array vargs = { args... }; std::array argptrs; diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 80e71ec52..3a85f1fbf 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -41,12 +41,12 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) { bool prepad = p_pad_align; #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); if (prepad) { uint8_t *s8 = (uint8_t *)mem; - return s8 + PAD_ALIGN; + return s8 + DATA_OFFSET; } else { return mem; } @@ -69,10 +69,10 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) { #endif if (prepad) { - mem -= PAD_ALIGN; - mem = (uint8_t *)internal::gdextension_interface_mem_realloc(mem, p_bytes + PAD_ALIGN); + mem -= DATA_OFFSET; + mem = (uint8_t *)internal::gdextension_interface_mem_realloc(mem, p_bytes + DATA_OFFSET); ERR_FAIL_NULL_V(mem, nullptr); - return mem + PAD_ALIGN; + return mem + DATA_OFFSET; } else { 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 if (prepad) { - mem -= PAD_ALIGN; + mem -= DATA_OFFSET; } internal::gdextension_interface_mem_free(mem); } diff --git a/src/variant/char_string.cpp b/src/variant/char_string.cpp index 856037c43..37b41f6ac 100644 --- a/src/variant/char_string.cpp +++ b/src/variant/char_string.cpp @@ -65,7 +65,7 @@ _FORCE_INLINE_ bool is_str_less(const L *l_ptr, const R *r_ptr) { } } -template +template bool CharStringT::operator<(const CharStringT &p_right) const { if (length() == 0) { return p_right.length() != 0; @@ -74,9 +74,9 @@ bool CharStringT::operator<(const CharStringT &p_right) const { return is_str_less(get_data(), p_right.get_data()); } -template +template CharStringT &CharStringT::operator+=(T p_char) { - const int lhs_len = length(); + const int64_t lhs_len = length(); resize(lhs_len + 2); T *dst = ptrw(); @@ -86,7 +86,7 @@ CharStringT &CharStringT::operator+=(T p_char) { return *this; } -template +template void CharStringT::operator=(const T *p_cstr) { copy_from(p_cstr); } @@ -127,7 +127,7 @@ const wchar_t *CharStringT::get_data() const { } } -template +template void CharStringT::copy_from(const T *p_cstr) { if (!p_cstr) { resize(0); @@ -172,23 +172,23 @@ String::String(const char32_t *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; ret.parse_utf8(from, len); 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); } -String String::utf16(const char16_t *from, int len) { +String String::utf16(const char16_t *from, int64_t len) { String ret; ret.parse_utf16(from, len); 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); } @@ -230,8 +230,8 @@ String rtoss(double p_val) { } CharString String::utf8() const { - int length = internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), nullptr, 0); - int size = length + 1; + int64_t length = internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), nullptr, 0); + int64_t size = length + 1; CharString str; str.resize(size); internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), str.ptrw(), length); @@ -242,8 +242,8 @@ CharString String::utf8() const { } CharString String::ascii() const { - int length = internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), nullptr, 0); - int size = length + 1; + int64_t length = internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), nullptr, 0); + int64_t size = length + 1; CharString str; str.resize(size); internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), str.ptrw(), length); @@ -254,8 +254,8 @@ CharString String::ascii() const { } Char16String String::utf16() const { - int length = internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), nullptr, 0); - int size = length + 1; + int64_t length = internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), nullptr, 0); + int64_t size = length + 1; Char16String str; str.resize(size); internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), str.ptrw(), length); @@ -266,8 +266,8 @@ Char16String String::utf16() const { } Char32String String::utf32() const { - int length = internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), nullptr, 0); - int size = length + 1; + int64_t length = internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), nullptr, 0); + int64_t size = length + 1; Char32String str; str.resize(size); 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 { - int length = internal::gdextension_interface_string_to_wide_chars(_native_ptr(), nullptr, 0); - int size = length + 1; + int64_t length = internal::gdextension_interface_string_to_wide_chars(_native_ptr(), nullptr, 0); + int64_t size = length + 1; CharWideString str; str.resize(size); internal::gdextension_interface_string_to_wide_chars(_native_ptr(), str.ptrw(), length); @@ -386,11 +386,11 @@ String &String::operator+=(const char32_t *p_str) { 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); } -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); } diff --git a/src/variant/packed_arrays.cpp b/src/variant/packed_arrays.cpp index 65b00025c..fe8b3597f 100644 --- a/src/variant/packed_arrays.cpp +++ b/src/variant/packed_arrays.cpp @@ -46,11 +46,11 @@ 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); } -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); } @@ -62,12 +62,12 @@ uint8_t *PackedByteArray::ptrw() { 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); 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); return *color; } @@ -80,11 +80,11 @@ Color *PackedColorArray::ptrw() { 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); } -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); } @@ -96,11 +96,11 @@ float *PackedFloat32Array::ptrw() { 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); } -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); } @@ -112,11 +112,11 @@ double *PackedFloat64Array::ptrw() { 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); } -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); } @@ -128,11 +128,11 @@ int32_t *PackedInt32Array::ptrw() { 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); } -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); } @@ -144,12 +144,12 @@ int64_t *PackedInt64Array::ptrw() { 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); 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); return *string; } @@ -162,12 +162,12 @@ String *PackedStringArray::ptrw() { 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); 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); return *vec; } @@ -180,12 +180,12 @@ Vector2 *PackedVector2Array::ptrw() { 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); 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); return *vec; } @@ -198,12 +198,12 @@ Vector3 *PackedVector3Array::ptrw() { 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); 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); return *var; } diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index 945d6f406..161362b29 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -303,123 +303,131 @@ Variant::operator float() const { } Variant::operator String() const { - String result; - to_type_constructor[STRING](result._native_ptr(), _native_ptr()); - return result; + return String(this); } Variant::operator Vector2() const { + // @todo Avoid initializing result before calling constructor (which will initialize it again) Vector2 result; to_type_constructor[VECTOR2]((GDExtensionTypePtr)&result, _native_ptr()); return result; } Variant::operator Vector2i() const { + // @todo Avoid initializing result before calling constructor (which will initialize it again) Vector2i result; to_type_constructor[VECTOR2I]((GDExtensionTypePtr)&result, _native_ptr()); return result; } Variant::operator Rect2() const { + // @todo Avoid initializing result before calling constructor (which will initialize it again) Rect2 result; to_type_constructor[RECT2]((GDExtensionTypePtr)&result, _native_ptr()); return result; } Variant::operator Rect2i() const { + // @todo Avoid initializing result before calling constructor (which will initialize it again) Rect2i result; to_type_constructor[RECT2I]((GDExtensionTypePtr)&result, _native_ptr()); return result; } Variant::operator Vector3() const { + // @todo Avoid initializing result before calling constructor (which will initialize it again) Vector3 result; to_type_constructor[VECTOR3]((GDExtensionTypePtr)&result, _native_ptr()); return result; } Variant::operator Vector3i() const { + // @todo Avoid initializing result before calling constructor (which will initialize it again) Vector3i result; to_type_constructor[VECTOR3I]((GDExtensionTypePtr)&result, _native_ptr()); return result; } Variant::operator Transform2D() const { + // @todo Avoid initializing result before calling constructor (which will initialize it again) Transform2D result; to_type_constructor[TRANSFORM2D]((GDExtensionTypePtr)&result, _native_ptr()); return result; } Variant::operator Vector4() const { + // @todo Avoid initializing result before calling constructor (which will initialize it again) Vector4 result; to_type_constructor[VECTOR4]((GDExtensionTypePtr)&result, _native_ptr()); return result; } Variant::operator Vector4i() const { + // @todo Avoid initializing result before calling constructor (which will initialize it again) Vector4i result; to_type_constructor[VECTOR4I]((GDExtensionTypePtr)&result, _native_ptr()); return result; } Variant::operator Plane() const { + // @todo Avoid initializing result before calling constructor (which will initialize it again) Plane result; to_type_constructor[PLANE]((GDExtensionTypePtr)&result, _native_ptr()); return result; } Variant::operator Quaternion() const { + // @todo Avoid initializing result before calling constructor (which will initialize it again) Quaternion result; to_type_constructor[QUATERNION]((GDExtensionTypePtr)&result, _native_ptr()); return result; } Variant::operator godot::AABB() const { + // @todo Avoid initializing result before calling constructor (which will initialize it again) godot::AABB result; to_type_constructor[AABB]((GDExtensionTypePtr)&result, _native_ptr()); return result; } Variant::operator Basis() const { + // @todo Avoid initializing result before calling constructor (which will initialize it again) Basis result; to_type_constructor[BASIS]((GDExtensionTypePtr)&result, _native_ptr()); return result; } Variant::operator Transform3D() const { + // @todo Avoid initializing result before calling constructor (which will initialize it again) Transform3D result; to_type_constructor[TRANSFORM3D]((GDExtensionTypePtr)&result, _native_ptr()); return result; } Variant::operator Projection() const { + // @todo Avoid initializing result before calling constructor (which will initialize it again) Projection result; to_type_constructor[PROJECTION]((GDExtensionTypePtr)&result, _native_ptr()); return result; } Variant::operator Color() const { + // @todo Avoid initializing result before calling constructor (which will initialize it again) Color result; to_type_constructor[COLOR]((GDExtensionTypePtr)&result, _native_ptr()); return result; } Variant::operator StringName() const { - StringName result; - to_type_constructor[STRING_NAME](result._native_ptr(), _native_ptr()); - return result; + return StringName(this); } Variant::operator NodePath() const { - NodePath result; - to_type_constructor[NODE_PATH](result._native_ptr(), _native_ptr()); - return result; + return NodePath(this); } Variant::operator godot::RID() const { - godot::RID result; - to_type_constructor[RID](result._native_ptr(), _native_ptr()); - return result; + return godot::RID(this); } Variant::operator Object *() const { @@ -447,81 +455,55 @@ Variant::operator ObjectID() const { } Variant::operator Callable() const { - Callable result; - to_type_constructor[CALLABLE](result._native_ptr(), _native_ptr()); - return result; + return Callable(this); } Variant::operator Signal() const { - Signal result; - to_type_constructor[SIGNAL](result._native_ptr(), _native_ptr()); - return result; + return Signal(this); } Variant::operator Dictionary() const { - Dictionary result; - to_type_constructor[DICTIONARY](result._native_ptr(), _native_ptr()); - return result; + return Dictionary(this); } Variant::operator Array() const { - Array result; - to_type_constructor[ARRAY](result._native_ptr(), _native_ptr()); - return result; + return Array(this); } Variant::operator PackedByteArray() const { - PackedByteArray result; - to_type_constructor[PACKED_BYTE_ARRAY](result._native_ptr(), _native_ptr()); - return result; + return PackedByteArray(this); } Variant::operator PackedInt32Array() const { - PackedInt32Array result; - to_type_constructor[PACKED_INT32_ARRAY](result._native_ptr(), _native_ptr()); - return result; + return PackedInt32Array(this); } Variant::operator PackedInt64Array() const { - PackedInt64Array result; - to_type_constructor[PACKED_INT64_ARRAY](result._native_ptr(), _native_ptr()); - return result; + return PackedInt64Array(this); } Variant::operator PackedFloat32Array() const { - PackedFloat32Array result; - to_type_constructor[PACKED_FLOAT32_ARRAY](result._native_ptr(), _native_ptr()); - return result; + return PackedFloat32Array(this); } Variant::operator PackedFloat64Array() const { - PackedFloat64Array result; - to_type_constructor[PACKED_FLOAT64_ARRAY](result._native_ptr(), _native_ptr()); - return result; + return PackedFloat64Array(this); } Variant::operator PackedStringArray() const { - PackedStringArray result; - to_type_constructor[PACKED_STRING_ARRAY](result._native_ptr(), _native_ptr()); - return result; + return PackedStringArray(this); } Variant::operator PackedVector2Array() const { - PackedVector2Array result; - to_type_constructor[PACKED_VECTOR2_ARRAY](result._native_ptr(), _native_ptr()); - return result; + return PackedVector2Array(this); } Variant::operator PackedVector3Array() const { - PackedVector3Array result; - to_type_constructor[PACKED_VECTOR3_ARRAY](result._native_ptr(), _native_ptr()); - return result; + return PackedVector3Array(this); } Variant::operator PackedColorArray() const { - PackedColorArray result; - to_type_constructor[PACKED_COLOR_ARRAY](result._native_ptr(), _native_ptr()); - return result; + return PackedColorArray(this); } Variant &Variant::operator=(const Variant &other) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a17b9aacd..c0457bfbd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,5 +1,5 @@ +cmake_minimum_required(VERSION 3.13) project(godot-cpp-test) -cmake_minimum_required(VERSION 3.6) set(GODOT_GDEXTENSION_DIR ../gdextension/ CACHE STRING "Path to GDExtension interface header directory") set(CPP_BINDINGS_PATH ../ CACHE STRING "Path to C++ bindings") diff --git a/test/project/main.gd b/test/project/main.gd index e0b186bb2..9717eca22 100644 --- a/test/project/main.gd +++ b/test/project/main.gd @@ -91,6 +91,7 @@ func _ready(): # PackedArray iterators assert_equal(example.test_vector_ops(), 105) + assert_equal(example.test_vector_init_list(), 105) # Properties. assert_equal(example.group_subgroup_custom_position, Vector2(0, 0)) @@ -174,6 +175,11 @@ func _ready(): assert_equal(new_example_ref.was_post_initialized(), 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) + exit_with_status() func _on_Example_custom_signal(signal_name, value): diff --git a/test/project/main.tscn b/test/project/main.tscn index 2b98e0f0d..14e0aed5b 100644 --- a/test/project/main.tscn +++ b/test/project/main.tscn @@ -22,4 +22,6 @@ offset_right = 79.0 offset_bottom = 29.0 text = "Click me!" +[node name="ExampleChild" type="ExampleChild" parent="."] + [connection signal="custom_signal" from="Example" to="." method="_on_Example_custom_signal"] diff --git a/test/src/example.cpp b/test/src/example.cpp index 848f50352..8094f7d5e 100644 --- a/test/src/example.cpp +++ b/test/src/example.cpp @@ -148,6 +148,7 @@ void Example::_bind_methods() { ClassDB::bind_method(D_METHOD("test_str_utility"), &Example::test_str_utility); ClassDB::bind_method(D_METHOD("test_string_is_fourty_two"), &Example::test_string_is_fourty_two); 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_control", "object"), &Example::test_object_cast_to_control); @@ -339,6 +340,15 @@ int Example::test_vector_ops() const { 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; +} + int Example::test_tarray_arg(const TypedArray &p_array) { int sum = 0; for (int i = 0; i < p_array.size(); i++) { @@ -455,3 +465,21 @@ void Example::_input(const Ref &event) { 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; + } +} diff --git a/test/src/example.h b/test/src/example.h index d0130765b..79c1e4d62 100644 --- a/test/src/example.h +++ b/test/src/example.h @@ -127,6 +127,7 @@ class Example : public Control { String test_str_utility() const; bool test_string_is_fourty_two(const String &p_str) 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_control(Object *p_object) const; @@ -186,4 +187,29 @@ class ExampleAbstract : public Object { static void _bind_methods() {} }; +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 diff --git a/test/src/register_types.cpp b/test/src/register_types.cpp index dbb37d90b..560dd907c 100644 --- a/test/src/register_types.cpp +++ b/test/src/register_types.cpp @@ -26,6 +26,8 @@ void initialize_example_module(ModuleInitializationLevel p_level) { ClassDB::register_class(); ClassDB::register_class(true); ClassDB::register_abstract_class(); + ClassDB::register_class(); + ClassDB::register_class(); } void uninitialize_example_module(ModuleInitializationLevel p_level) { diff --git a/tools/android.py b/tools/android.py index 0c2535410..8454d479a 100644 --- a/tools/android.py +++ b/tools/android.py @@ -1,6 +1,7 @@ import os import sys import my_spawn +import common_compiler_flags 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(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED"]) + + common_compiler_flags.generate(env) diff --git a/tools/common_compiler_flags.py b/tools/common_compiler_flags.py new file mode 100644 index 000000000..437f256b3 --- /dev/null +++ b/tools/common_compiler_flags.py @@ -0,0 +1,86 @@ +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"]) + + # 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"]) diff --git a/tools/godotcpp.py b/tools/godotcpp.py index 5e0f06559..71199c18d 100644 --- a/tools/godotcpp.py +++ b/tools/godotcpp.py @@ -1,9 +1,12 @@ import os, sys, platform from SCons.Variables import EnumVariable, PathVariable, BoolVariable +from SCons.Variables.BoolVariable import _text2bool from SCons.Tool import Tool from SCons.Builder import Builder from SCons.Errors import UserError +from SCons.Script import ARGUMENTS + from binding_generator import scons_generate_bindings, scons_emit_files @@ -14,6 +17,17 @@ def add_sources(sources, dir, extension): 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): 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))) -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. architecture_array = [ @@ -82,12 +115,25 @@ def options(opts, env): else: raise ValueError("Could not detect platform automatically, please specify with 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( EnumVariable( key="platform", help="Target platform", default=env.get("platform", default_platform), - allowed_values=platforms, + allowed_values=platforms + custom_platforms, ignorecase=2, ) ) @@ -183,16 +229,23 @@ def options(opts, env): ) ) - # Add platform options - for pl in platforms: - tool = Tool(pl, toolpath=["tools"]) + 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)) + + # 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"): tool.options(opts) - # Targets flags tool (optimizations, debug symbols) - target_tool = Tool("targets", toolpath=["tools"]) - target_tool.options(opts) - def generate(env): # Default num_jobs to local cpu count if not user specified. @@ -239,30 +292,52 @@ def generate(env): print("Building for architecture " + env["arch"] + " on platform " + env["platform"]) - tool = Tool(env["platform"], toolpath=["tools"]) + # These defaults may be needed by platform tools + 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) + + tool = Tool(env["platform"], toolpath=get_platform_tools_paths(env)) if tool is None or not tool.exists(env): raise ValueError("Required toolchain not found for platform " + env["platform"]) tool.generate(env) - target_tool = Tool("targets", toolpath=["tools"]) - target_tool.generate(env) - - # 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"]) - # Require C++17 - if env.get("is_msvc", False): - env.Append(CXXFLAGS=["/std:c++17"]) + if env.editor_build: + 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: - env.Append(CXXFLAGS=["-std=c++17"]) + # Disable assert() for production targets (only used in thirdparty code). + env.Append(CPPDEFINES=["NDEBUG"]) if env["precision"] == "double": env.Append(CPPDEFINES=["REAL_T_IS_DOUBLE"]) diff --git a/tools/ios.py b/tools/ios.py index e387f4264..28415ce40 100644 --- a/tools/ios.py +++ b/tools/ios.py @@ -1,6 +1,7 @@ import os import sys import subprocess +import common_compiler_flags from SCons.Variables import * 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(CPPDEFINES=["IOS_ENABLED", "UNIX_ENABLED"]) + + common_compiler_flags.generate(env) diff --git a/tools/linux.py b/tools/linux.py index cb48ae586..ee6cdc636 100644 --- a/tools/linux.py +++ b/tools/linux.py @@ -1,3 +1,4 @@ +import common_compiler_flags from SCons.Variables import * from SCons.Tool import clang, clangxx @@ -34,3 +35,5 @@ def generate(env): env.Append(LINKFLAGS=["-march=rv64gc"]) env.Append(CPPDEFINES=["LINUX_ENABLED", "UNIX_ENABLED"]) + + common_compiler_flags.generate(env) diff --git a/tools/macos.py b/tools/macos.py index 0c75e4a76..883d21ec3 100644 --- a/tools/macos.py +++ b/tools/macos.py @@ -1,5 +1,6 @@ import os import sys +import common_compiler_flags def has_osxcross(): @@ -70,3 +71,5 @@ def generate(env): ) env.Append(CPPDEFINES=["MACOS_ENABLED", "UNIX_ENABLED"]) + + common_compiler_flags.generate(env) diff --git a/tools/targets.py b/tools/targets.py deleted file mode 100644 index 216113494..000000000 --- a/tools/targets.py +++ /dev/null @@ -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"]) diff --git a/tools/web.py b/tools/web.py index a4620c37a..c7440bcd4 100644 --- a/tools/web.py +++ b/tools/web.py @@ -1,4 +1,5 @@ import os +import common_compiler_flags from SCons.Util import WhereIs @@ -42,3 +43,5 @@ def generate(env): env.Append(LINKFLAGS=["-s", "SIDE_MODULE=1"]) env.Append(CPPDEFINES=["WEB_ENABLED", "UNIX_ENABLED"]) + + common_compiler_flags.generate(env) diff --git a/tools/windows.py b/tools/windows.py index d5a729c58..a263241aa 100644 --- a/tools/windows.py +++ b/tools/windows.py @@ -1,7 +1,6 @@ import sys - import my_spawn - +import common_compiler_flags from SCons.Tool import msvc, mingw from SCons.Variables import * @@ -90,3 +89,5 @@ def generate(env): ) env.Append(CPPDEFINES=["WINDOWS_ENABLED"]) + + common_compiler_flags.generate(env)