瀏覽代碼

Merge pull request #1411 from dsnopek/4.1-cherrypicks-8

Cherry-picks for the godot-cpp 4.1 branch - 8th batch
David Snopek 1 年之前
父節點
當前提交
974e6c6f86
共有 56 個文件被更改,包括 907 次插入638 次删除
  1. 1 1
      CMakeLists.txt
  2. 62 19
      binding_generator.py
  3. 2 2
      include/godot_cpp/classes/editor_plugin_registration.hpp
  4. 8 8
      include/godot_cpp/classes/ref.hpp
  5. 4 4
      include/godot_cpp/classes/wrapped.hpp
  6. 36 36
      include/godot_cpp/core/binder_common.hpp
  7. 17 5
      include/godot_cpp/core/builtin_ptrcall.hpp
  8. 16 16
      include/godot_cpp/core/class_db.hpp
  9. 1 1
      include/godot_cpp/core/defs.hpp
  10. 7 7
      include/godot_cpp/core/engine_ptrcall.hpp
  11. 2 2
      include/godot_cpp/core/math.hpp
  12. 41 19
      include/godot_cpp/core/memory.hpp
  13. 21 21
      include/godot_cpp/core/method_bind.hpp
  14. 3 3
      include/godot_cpp/core/method_ptrcall.hpp
  15. 12 12
      include/godot_cpp/core/object.hpp
  16. 5 5
      include/godot_cpp/core/type_info.hpp
  17. 189 99
      include/godot_cpp/templates/cowdata.hpp
  18. 5 5
      include/godot_cpp/templates/hash_map.hpp
  19. 3 3
      include/godot_cpp/templates/hash_set.hpp
  20. 5 5
      include/godot_cpp/templates/hashfuncs.hpp
  21. 5 5
      include/godot_cpp/templates/list.hpp
  22. 3 3
      include/godot_cpp/templates/local_vector.hpp
  23. 8 8
      include/godot_cpp/templates/pair.hpp
  24. 1 1
      include/godot_cpp/templates/rb_map.hpp
  25. 1 1
      include/godot_cpp/templates/rb_set.hpp
  26. 3 3
      include/godot_cpp/templates/rid_owner.hpp
  27. 11 2
      include/godot_cpp/templates/safe_refcount.hpp
  28. 1 1
      include/godot_cpp/templates/search_array.hpp
  29. 1 1
      include/godot_cpp/templates/self_list.hpp
  30. 2 2
      include/godot_cpp/templates/sort_array.hpp
  31. 3 3
      include/godot_cpp/templates/thread_work_pool.hpp
  32. 59 44
      include/godot_cpp/templates/vector.hpp
  33. 1 1
      include/godot_cpp/templates/vmap.hpp
  34. 1 1
      include/godot_cpp/templates/vset.hpp
  35. 13 13
      include/godot_cpp/variant/char_string.hpp
  36. 1 1
      include/godot_cpp/variant/typed_array.hpp
  37. 3 4
      include/godot_cpp/variant/variant.hpp
  38. 6 6
      src/core/memory.cpp
  39. 21 21
      src/variant/char_string.cpp
  40. 20 20
      src/variant/packed_arrays.cpp
  41. 33 51
      src/variant/variant.cpp
  42. 1 1
      test/CMakeLists.txt
  43. 6 0
      test/project/main.gd
  44. 2 0
      test/project/main.tscn
  45. 28 0
      test/src/example.cpp
  46. 26 0
      test/src/example.h
  47. 2 0
      test/src/register_types.cpp
  48. 3 0
      tools/android.py
  49. 86 0
      tools/common_compiler_flags.py
  50. 101 26
      tools/godotcpp.py
  51. 3 0
      tools/ios.py
  52. 3 0
      tools/linux.py
  53. 3 0
      tools/macos.py
  54. 0 144
      tools/targets.py
  55. 3 0
      tools/web.py
  56. 3 2
      tools/windows.py

+ 1 - 1
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)

+ 62 - 19
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 <godot_cpp/variant/vector3.hpp>")
 
+    if is_packed_array(class_name):
+        result.append("#include <godot_cpp/core/error_macros.hpp>")
+        result.append("#include <initializer_list>")
+
     if class_name == "Array":
         result.append("#include <godot_cpp/variant/array_helpers.hpp>")
 
@@ -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<class... Args>")
+                result.append("\ttemplate<typename... Args>")
 
             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 <class... Args>")
+        result.append("\ttemplate <typename... Args>")
         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<int64_t>("
+                elif is_pod_type(return_type) or is_variant(return_type):
+                    method_call += f"return internal::_call_builtin_method_ptr_ret<{get_gdextension_type(correct_type(return_type))}>("
+                elif is_refcounted(return_type):
+                    method_call += f"return Ref<{return_type}>::_gde_internal_constructor(internal::_call_builtin_method_ptr_ret_obj<{return_type}>("
+                    is_ref = True
+                else:
+                    method_call += f"return internal::_call_builtin_method_ptr_ret_obj<{return_type}>("
             else:
                 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 <class T, class B>")
+    result.append("\ttemplate <typename T, typename B>")
     result.append("\tstatic void register_virtuals() {")
     if class_name != "Object":
         result.append(f"\t\t{inherits}::register_virtuals<T, B>();")
@@ -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<class T>")
+        result.append("\ttemplate<typename T>")
         result.append("\tstatic T *cast_to(Object *p_object);")
 
-        result.append("\ttemplate<class T>")
+        result.append("\ttemplate<typename T>")
         result.append("\tstatic const T *cast_to(const Object *p_object);")
 
         result.append("\tvirtual ~Object() = default;")
 
     elif use_template_get_node and class_name == "Node":
-        result.append("\ttemplate<class T>")
+        result.append("\ttemplate<typename T>")
         result.append(
             "\tT *get_node(const NodePath &p_path) const { return Object::cast_to<T>(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<class... Args> "
+    function_signature = "\tpublic: template<typename... Args> "
 
     if static:
         function_signature += "static "

+ 2 - 2
include/godot_cpp/classes/editor_plugin_registration.hpp

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

+ 8 - 8
include/godot_cpp/classes/ref.hpp

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

+ 4 - 4
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 <class T>
+template <typename T>
 struct EngineClassRegistration {
 	EngineClassRegistration() {
 		add_engine_class_registration_callback(&EngineClassRegistration<T>::callback);
@@ -164,7 +164,7 @@ protected:
 		return (::godot::String(::godot::Wrapped::*)() const) & m_class::_to_string;                                                                                                   \
 	}                                                                                                                                                                                  \
                                                                                                                                                                                        \
-	template <class T, class B>                                                                                                                                                        \
+	template <typename T, typename B>                                                                                                                                                  \
 	static void register_virtuals() {                                                                                                                                                  \
 		m_inherits::register_virtuals<T, B>();                                                                                                                                         \
 	}                                                                                                                                                                                  \
@@ -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<m_class *>(p_instance);                                                                                                                \
-				return cls->_notification(p_what);                                                                                                                                     \
+				cls->_notification(p_what);                                                                                                                                            \
 			}                                                                                                                                                                          \
-			m_inherits::notification_bind(p_instance, p_what);                                                                                                                         \
 		}                                                                                                                                                                              \
 	}                                                                                                                                                                                  \
                                                                                                                                                                                        \

+ 36 - 36
include/godot_cpp/core/binder_common.hpp

@@ -83,7 +83,7 @@ namespace godot {
 	};                                                                           \
 	}
 
-template <class T>
+template <typename T>
 struct VariantCaster {
 	static _FORCE_INLINE_ T cast(const Variant &p_variant) {
 		using TStripped = std::remove_pointer_t<T>;
@@ -95,7 +95,7 @@ struct VariantCaster {
 	}
 };
 
-template <class T>
+template <typename T>
 struct VariantCaster<T &> {
 	static _FORCE_INLINE_ T cast(const Variant &p_variant) {
 		using TStripped = std::remove_pointer_t<T>;
@@ -107,7 +107,7 @@ struct VariantCaster<T &> {
 	}
 };
 
-template <class T>
+template <typename T>
 struct VariantCaster<const T &> {
 	static _FORCE_INLINE_ T cast(const Variant &p_variant) {
 		using TStripped = std::remove_pointer_t<T>;
@@ -144,7 +144,7 @@ struct VariantObjectClassChecker<const Ref<T> &> {
 	}
 };
 
-template <class T>
+template <typename T>
 struct VariantCasterAndValidate {
 	static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
 		GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
@@ -159,7 +159,7 @@ struct VariantCasterAndValidate {
 	}
 };
 
-template <class T>
+template <typename T>
 struct VariantCasterAndValidate<T &> {
 	static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
 		GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
@@ -174,7 +174,7 @@ struct VariantCasterAndValidate<T &> {
 	}
 };
 
-template <class T>
+template <typename T>
 struct VariantCasterAndValidate<const T &> {
 	static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
 		GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
@@ -189,47 +189,47 @@ struct VariantCasterAndValidate<const T &> {
 	}
 };
 
-template <class T, class... P, size_t... Is>
+template <typename T, typename... P, size_t... Is>
 void call_with_ptr_args_helper(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
 	(p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
 }
 
-template <class T, class... P, size_t... Is>
+template <typename T, typename... P, size_t... Is>
 void call_with_ptr_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
 	(p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
 }
 
-template <class T, class R, class... P, size_t... Is>
+template <typename T, typename R, typename... P, size_t... Is>
 void call_with_ptr_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
 	PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
 }
 
-template <class T, class R, class... P, size_t... Is>
+template <typename T, typename R, typename... P, size_t... Is>
 void call_with_ptr_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
 	PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
 }
 
-template <class T, class... P>
+template <typename T, typename... P>
 void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void * /*ret*/) {
 	call_with_ptr_args_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
 }
 
-template <class T, class... P>
+template <typename T, typename... P>
 void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void * /*ret*/) {
 	call_with_ptr_argsc_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
 }
 
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
 void call_with_ptr_args(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret) {
 	call_with_ptr_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
 }
 
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
 void call_with_ptr_args(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void *r_ret) {
 	call_with_ptr_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
 }
 
-template <class T, class... P, size_t... Is>
+template <typename T, typename... P, size_t... Is>
 void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
 	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 <class T, class... P, size_t... Is>
+template <typename T, typename... P, size_t... Is>
 void call_with_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
 	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 <class T, class R, class... P, size_t... Is>
+template <typename T, typename R, typename... P, size_t... Is>
 void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
 	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 <class T, class R, class... P, size_t... Is>
+template <typename T, typename R, typename... P, size_t... Is>
 void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
 	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 <class T, class... P>
+template <typename T, typename... P>
 void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
 #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<sizeof...(P)>{});
 }
 
-template <class T, class... P>
+template <typename T, typename... P>
 void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
 #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<sizeof...(P)>{});
 }
 
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
 void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
 #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<sizeof...(P)>{});
 }
 
-template <class T, class R, class... P>
+template <typename T, typename R, typename... P>
 void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
 #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 <class Q>
+template <typename Q>
 void call_get_argument_type_helper(int p_arg, int &index, GDExtensionVariantType &type) {
 	if (p_arg == index) {
 		type = GDExtensionVariantType(GetTypeInfo<Q>::VARIANT_TYPE);
@@ -431,7 +431,7 @@ void call_get_argument_type_helper(int p_arg, int &index, GDExtensionVariantType
 	index++;
 }
 
-template <class... P>
+template <typename... P>
 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 <class Q>
+template <typename Q>
 void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &info) {
 	if (p_arg == index) {
 		info = GetTypeInfo<Q>::get_class_info();
@@ -451,7 +451,7 @@ void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &inf
 	index++;
 }
 
-template <class... P>
+template <typename... P>
 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 <class Q>
+template <typename Q>
 void call_get_argument_metadata_helper(int p_arg, int &index, GDExtensionClassMethodArgumentMetadata &md) {
 	if (p_arg == index) {
 		md = GetTypeInfo<Q>::METADATA;
@@ -469,7 +469,7 @@ void call_get_argument_metadata_helper(int p_arg, int &index, GDExtensionClassMe
 	index++;
 }
 
-template <class... P>
+template <typename... P>
 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 <class... P, size_t... Is>
+template <typename... P, size_t... Is>
 void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
 	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 <class... P>
+template <typename... P>
 void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
 #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<sizeof...(P)>{});
 }
 
-template <class... P, size_t... Is>
+template <typename... P, size_t... Is>
 void call_with_ptr_args_static_method_helper(void (*p_method)(P...), const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
 	p_method(PtrToArg<P>::convert(p_args[Is])...);
 }
 
-template <class... P>
+template <typename... P>
 void call_with_ptr_args_static_method(void (*p_method)(P...), const GDExtensionConstTypePtr *p_args) {
 	call_with_ptr_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
 }
 
-template <class R, class... P, size_t... Is>
+template <typename R, typename... P, size_t... Is>
 void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
 	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 <class R, class... P>
+template <typename R, typename... P>
 void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
 #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<sizeof...(P)>{});
 }
 
-template <class R, class... P, size_t... Is>
+template <typename R, typename... P, size_t... Is>
 void call_with_ptr_args_static_method_ret_helper(R (*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
 	PtrToArg<R>::encode(p_method(PtrToArg<P>::convert(p_args[Is])...), r_ret);
 }
 
-template <class R, class... P>
+template <typename R, typename... P>
 void call_with_ptr_args_static_method_ret(R (*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret) {
 	call_with_ptr_args_static_method_ret_helper<R, P...>(p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
 }

+ 17 - 5
include/godot_cpp/core/builtin_ptrcall.hpp

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

+ 16 - 16
include/godot_cpp/core/class_db.hpp

@@ -114,26 +114,26 @@ private:
 	static void initialize_class(const ClassInfo &cl);
 	static void bind_method_godot(const StringName &p_class_name, MethodBind *p_method);
 
-	template <class T, bool is_abstract>
+	template <typename T, bool is_abstract>
 	static void _register_class(bool p_virtual = false);
 
 public:
-	template <class T>
+	template <typename T>
 	static void register_class(bool p_virtual = false);
-	template <class T>
+	template <typename T>
 	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 <class N, class M, typename... VarArgs>
+	template <typename N, typename M, typename... VarArgs>
 	static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args);
 
-	template <class N, class M, typename... VarArgs>
+	template <typename N, typename M, typename... VarArgs>
 	static MethodBind *bind_static_method(StringName p_class, N p_method_name, M p_method, VarArgs... p_args);
 
-	template <class M>
+	template <typename M>
 	static MethodBind *bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const std::vector<Variant> &p_default_args = std::vector<Variant>{}, bool p_return_nil_is_variant = true);
 
 	static void add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix);
@@ -155,23 +155,23 @@ public:
 };
 
 #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<m_class *>(p_instance), &m_class::m_method, p_args, p_ret);                                   \
 		};                                                                                                                                    \
-		godot::ClassDB::bind_virtual_method(m_class::get_class_static(), #m_method, _call##m_method);                                         \
+		::godot::ClassDB::bind_virtual_method(m_class::get_class_static(), #m_method, _call##m_method);                                       \
 	}
 
-template <class T, bool is_abstract>
+template <typename T, bool is_abstract>
 void ClassDB::_register_class(bool p_virtual) {
 	static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS.");
 	instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks;
@@ -219,17 +219,17 @@ void ClassDB::_register_class(bool p_virtual) {
 	initialize_class(classes[cl.name]);
 }
 
-template <class T>
+template <typename T>
 void ClassDB::register_class(bool p_virtual) {
 	ClassDB::_register_class<T, false>(p_virtual);
 }
 
-template <class T>
+template <typename T>
 void ClassDB::register_abstract_class() {
 	ClassDB::_register_class<T, true>();
 }
 
-template <class N, class M, typename... VarArgs>
+template <typename N, typename M, typename... VarArgs>
 MethodBind *ClassDB::bind_method(N p_method_name, M p_method, VarArgs... p_args) {
 	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 <class N, class M, typename... VarArgs>
+template <typename N, typename M, typename... VarArgs>
 MethodBind *ClassDB::bind_static_method(StringName p_class, N p_method_name, M p_method, VarArgs... p_args) {
 	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 <class M>
+template <typename M>
 MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info, const std::vector<Variant> &p_default_args, bool p_return_nil_is_variant) {
 	MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant);
 	ERR_FAIL_NULL_V(bind, nullptr);

+ 1 - 1
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 <class T>
+template <typename T>
 inline void __swap_tmpl(T &x, T &y) {
 	T aux = x;
 	x = y;

+ 7 - 7
include/godot_cpp/core/engine_ptrcall.hpp

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

+ 2 - 2
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 <class T>
+template <typename T>
 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 <class T>
+template <typename T>
 static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) {
 	--x;
 

+ 41 - 19
include/godot_cpp/core/memory.hpp

@@ -40,10 +40,6 @@
 
 #include <type_traits>
 
-#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 @@ public:
 
 _ALWAYS_INLINE_ void postinitialize_handler(void *) {}
 
-template <class T>
+template <typename T>
 _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 <class T>
+template <typename T>
 struct Comparator {
 	_ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); }
 };
 
-template <class T>
+template <typename T>
 void memdelete(T *p_class, typename std::enable_if<!std::is_base_of_v<godot::Wrapped, T>>::type * = nullptr) {
-	if (!std::is_trivially_destructible<T>::value) {
+	if constexpr (!std::is_trivially_destructible_v<T>) {
 		p_class->~T();
 	}
 
 	Memory::free_static(p_class);
 }
 
-template <class T, std::enable_if_t<std::is_base_of_v<godot::Wrapped, T>, bool> = true>
+template <typename T, std::enable_if_t<std::is_base_of_v<godot::Wrapped, T>, bool> = true>
 void memdelete(T *p_class) {
 	godot::internal::gdextension_interface_object_destroy(p_class->_owner);
 }
 
-template <class T, class A>
+template <typename T, typename A>
 void memdelete_allocator(T *p_class) {
-	if (!std::is_trivially_destructible<T>::value) {
+	if constexpr (!std::is_trivially_destructible_v<T>) {
 		p_class->~T();
 	}
 
@@ -125,16 +133,20 @@ public:
 	_ALWAYS_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr); }
 };
 
-template <class T>
+template <typename T>
 class DefaultTypedAllocator {
 public:
-	template <class... Args>
+	template <typename... Args>
 	_ALWAYS_INLINE_ T *new_allocation(const Args &&...p_args) { return memnew(T(p_args...)); }
 	_ALWAYS_INLINE_ void delete_allocation(T *p_allocation) { memdelete(p_allocation); }
 };
 
 #define memnew_arr(m_class, m_count) memnew_arr_template<m_class>(m_count)
 
+_FORCE_INLINE_ uint64_t *_get_element_count_ptr(uint8_t *p_ptr) {
+	return (uint64_t *)(p_ptr - Memory::DATA_OFFSET + Memory::ELEMENT_OFFSET);
+}
+
 template <typename T>
 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<T>::value) {
+	uint64_t *_elem_count_ptr = _get_element_count_ptr(mem);
+	*(_elem_count_ptr) = p_elements;
+
+	if constexpr (!std::is_trivially_destructible_v<T>) {
 		T *elems = (T *)mem;
 
 		/* call operator new */
@@ -161,12 +175,20 @@ T *memnew_arr_template(size_t p_elements, const char *p_descr = "") {
 	return (T *)mem;
 }
 
+template <typename T>
+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 <typename T>
 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<T>::value) {
-		uint64_t elem_count = *(ptr - 1);
+	if constexpr (!std::is_trivially_destructible_v<T>) {
+		uint64_t *_elem_count_ptr = _get_element_count_ptr(ptr);
+		uint64_t elem_count = *(_elem_count_ptr);
 
 		for (uint64_t i = 0; i < elem_count; i++) {
 			p_class[i].~T();

+ 21 - 21
include/godot_cpp/core/method_bind.hpp

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

+ 3 - 3
include/godot_cpp/core/method_ptrcall.hpp

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

+ 12 - 12
include/godot_cpp/core/object.hpp

@@ -45,10 +45,10 @@
 
 #include <vector>
 
-#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 <class... Args>
+	template <typename... Args>
 	MethodInfo(StringName p_name, const Args &...args);
 	MethodInfo(Variant::Type ret);
 	MethodInfo(Variant::Type ret, StringName p_name);
-	template <class... Args>
+	template <typename... Args>
 	MethodInfo(Variant::Type ret, StringName p_name, const Args &...args);
 	MethodInfo(const PropertyInfo &p_ret, StringName p_name);
-	template <class... Args>
+	template <typename... Args>
 	MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...);
 };
 
-template <class... Args>
+template <typename... Args>
 MethodInfo::MethodInfo(StringName p_name, const Args &...args) :
 		name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
 	arguments = { args... };
 }
 
-template <class... Args>
+template <typename... Args>
 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 <class... Args>
+template <typename... Args>
 MethodInfo::MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...args) :
 		name(p_name), return_val(p_ret), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
 	arguments = { args... };
@@ -138,7 +138,7 @@ public:
 	}
 };
 
-template <class T>
+template <typename T>
 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<T *>(internal::get_object_instance_binding(casted));
 }
 
-template <class T>
+template <typename T>
 const T *Object::cast_to(const Object *p_object) {
 	if (p_object == nullptr) {
 		return nullptr;

+ 5 - 5
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<T>' is instantiated.
 
-template <class T, typename = void>
+template <typename T, typename = void>
 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<T>::get_class_info().class_name;
 }
 
-template <class T>
+template <typename T>
 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<BitField<T>>::get_class_info().class_name;
 }
 
-template <class T>
+template <typename T>
 struct PtrToArg<TypedArray<T>> {
 	_FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) {
 		return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
@@ -306,7 +306,7 @@ struct PtrToArg<TypedArray<T>> {
 	}
 };
 
-template <class T>
+template <typename T>
 struct PtrToArg<const TypedArray<T> &> {
 	typedef Array EncodeT;
 	_FORCE_INLINE_ static TypedArray<T>

+ 189 - 99
include/godot_cpp/templates/cowdata.hpp

@@ -43,78 +43,120 @@
 
 namespace godot {
 
-template <class T>
+template <typename T>
 class Vector;
 
-template <class T, class V>
+template <typename T, typename V>
 class VMap;
 
-template <class T>
+template <typename T>
 class CharStringT;
 
+static_assert(std::is_trivially_destructible_v<std::atomic<uint64_t>>);
+
 // 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 <class T>
+template <typename T>
 class CowData {
-	template <class TV>
+	template <typename TV>
 	friend class Vector;
 
-	template <class TV, class VV>
+	template <typename TV, typename VV>
 	friend class VMap;
 
-	template <class TS>
+	template <typename TS>
 	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> │░░│ USize       │░░│ T[]
+	//             │ ref. count         │░░│ data size   │░░│ data
+	//             └────────────────────┴──┴─────────────┴──┴───────────...
+	// Offset:     ↑ REF_COUNT_OFFSET      ↑ SIZE_OFFSET    ↑ DATA_OFFSET
+
+	static constexpr size_t REF_COUNT_OFFSET = 0;
+	static constexpr size_t SIZE_OFFSET = ((REF_COUNT_OFFSET + sizeof(SafeNumeric<USize>)) % alignof(USize) == 0) ? (REF_COUNT_OFFSET + sizeof(SafeNumeric<USize>)) : ((REF_COUNT_OFFSET + sizeof(SafeNumeric<USize>)) + alignof(USize) - ((REF_COUNT_OFFSET + sizeof(SafeNumeric<USize>)) % alignof(USize)));
+	static constexpr size_t DATA_OFFSET = ((SIZE_OFFSET + sizeof(USize)) % alignof(max_align_t) == 0) ? (SIZE_OFFSET + sizeof(USize)) : ((SIZE_OFFSET + sizeof(USize)) + alignof(max_align_t) - ((SIZE_OFFSET + sizeof(USize)) % alignof(max_align_t)));
+
 	mutable T *_ptr = nullptr;
 
 	// internal helpers
 
-	_FORCE_INLINE_ SafeNumeric<uint32_t> *_get_refcount() const {
-		if (!_ptr) {
-			return nullptr;
-		}
+	static _FORCE_INLINE_ SafeNumeric<USize> *_get_refcount_ptr(uint8_t *p_ptr) {
+		return (SafeNumeric<USize> *)(p_ptr + REF_COUNT_OFFSET);
+	}
 
-		return reinterpret_cast<SafeNumeric<uint32_t> *>(_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<USize> *_get_refcount() const {
 		if (!_ptr) {
 			return nullptr;
 		}
 
-		return reinterpret_cast<uint32_t *>(_ptr) - 1;
+		return (SafeNumeric<USize> *)((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<T *>(_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<size_t>(32), &p)) {
+		*out = next_po2(o);
+		if (__builtin_add_overflow(o, static_cast<USize>(32), &p)) {
 			return false; // No longer allocated here.
 		}
 #else
@@ -128,22 +170,22 @@ private:
 	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<T> &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 @@ public:
 	_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 <bool p_ensure_zero = false>
+	Error resize(Size p_size);
 
-	_FORCE_INLINE_ void remove_at(int p_index) {
+	_FORCE_INLINE_ void remove_at(Size p_index) {
 		ERR_FAIL_INDEX(p_index, size());
 		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 @@ public:
 		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<T> &p_from) { _ref(p_from); }
+	_FORCE_INLINE_ CowData(CowData<T> &p_from) { _ref(p_from); };
 };
 
-template <class T>
+template <typename T>
 void CowData<T>::_unref(void *p_data) {
 	if (!p_data) {
 		return;
 	}
 
-	SafeNumeric<uint32_t> *refc = _get_refcount();
+	SafeNumeric<USize> *refc = _get_refcount();
 
 	if (refc->decrement() > 0) {
 		return; // still in use
 	}
-
 	// clean up
-	if (!std::is_trivially_destructible<T>::value) {
-		uint32_t *count = _get_size();
+
+	if constexpr (!std::is_trivially_destructible_v<T>) {
+		USize *count = _get_size();
 		T *data = (T *)(count + 1);
 
-		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 <class T>
-uint32_t CowData<T>::_copy_on_write() {
+template <typename T>
+typename CowData<T>::USize CowData<T>::_copy_on_write() {
 	if (!_ptr) {
 		return 0;
 	}
 
-	SafeNumeric<uint32_t> *refc = _get_refcount();
+	SafeNumeric<USize> *refc = _get_refcount();
 
-	uint32_t rc = refc->get();
+	USize rc = refc->get();
 	if (unlikely(rc > 1)) {
 		/* in use by more than me */
-		uint32_t current_size = *_get_size();
+		USize current_size = *_get_size();
 
-		uint32_t *mem_new = (uint32_t *)Memory::alloc_static(_get_alloc_size(current_size), true);
+		uint8_t *mem_new = (uint8_t *)Memory::alloc_static(_get_alloc_size(current_size) + DATA_OFFSET, false);
+		ERR_FAIL_NULL_V(mem_new, 0);
 
-		new (mem_new - 2) SafeNumeric<uint32_t>(1); // refcount
-		*(mem_new - 1) = current_size; // size
+		SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
+		USize *_size_ptr = _get_size_ptr(mem_new);
+		T *_data_ptr = _get_data_ptr(mem_new);
 
-		T *_data = (T *)(mem_new);
+		new (_refc_ptr) SafeNumeric<USize>(1); //refcount
+		*(_size_ptr) = current_size; //size
 
 		// initialize new elements
-		if (std::is_trivially_copyable<T>::value) {
-			memcpy(mem_new, _ptr, current_size * sizeof(T));
-
+		if constexpr (std::is_trivially_copyable_v<T>) {
+			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 <class T>
-Error CowData<T>::resize(int p_size) {
+template <typename T>
+template <bool p_ensure_zero>
+Error CowData<T>::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<T>::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<uint32_t>(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<USize> *_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<USize>(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<uint32_t>(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<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
+				T *_data_ptr = _get_data_ptr(mem_new);
 
-				_ptr = (T *)(_ptrnew);
+				new (_refc_ptr) SafeNumeric<USize>(rc); //refcount
+
+				_ptr = _data_ptr;
 			}
 		}
 
 		// construct the newly created elements
 
-		if (!std::is_trivially_constructible<T>::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<T>) {
+			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<T>::value) {
+		if constexpr (!std::is_trivially_destructible_v<T>) {
 			// 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<uint32_t>(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<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
+			T *_data_ptr = _get_data_ptr(mem_new);
 
-			_ptr = (T *)(_ptrnew);
+			new (_refc_ptr) SafeNumeric<USize>(rc); //refcount
+
+			_ptr = _data_ptr;
 		}
 
 		*_get_size() = p_size;
@@ -347,15 +407,15 @@ Error CowData<T>::resize(int p_size) {
 	return OK;
 }
 
-template <class T>
-int CowData<T>::find(const T &p_val, int p_from) const {
-	int ret = -1;
+template <typename T>
+typename CowData<T>::Size CowData<T>::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<T>::find(const T &p_val, int p_from) const {
 	return ret;
 }
 
-template <class T>
+template <typename T>
+typename CowData<T>::Size CowData<T>::rfind(const T &p_val, Size p_from) const {
+	const Size s = size();
+
+	if (p_from < 0) {
+		p_from = s + p_from;
+	}
+	if (p_from < 0 || p_from >= s) {
+		p_from = s - 1;
+	}
+
+	for (Size i = p_from; i >= 0; i--) {
+		if (get(i) == p_val) {
+			return i;
+		}
+	}
+	return -1;
+}
+
+template <typename T>
+typename CowData<T>::Size CowData<T>::count(const T &p_val) const {
+	Size amount = 0;
+	for (Size i = 0; i < size(); i++) {
+		if (get(i) == p_val) {
+			amount++;
+		}
+	}
+	return amount;
+}
+
+template <typename T>
 void CowData<T>::_ref(const CowData *p_from) {
 	_ref(*p_from);
 }
 
-template <class T>
+template <typename T>
 void CowData<T>::_ref(const CowData &p_from) {
 	if (_ptr == p_from._ptr) {
 		return; // self assign, do nothing.
@@ -388,7 +478,7 @@ void CowData<T>::_ref(const CowData &p_from) {
 	}
 }
 
-template <class T>
+template <typename T>
 CowData<T>::~CowData() {
 	_unref(_ptr);
 }

+ 5 - 5
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 <class TKey, class TValue>
+template <typename TKey, typename TValue>
 struct HashMapElement {
 	HashMapElement *next = nullptr;
 	HashMapElement *prev = nullptr;
@@ -62,10 +62,10 @@ struct HashMapElement {
 			data(p_key, p_value) {}
 };
 
-template <class TKey, class TValue,
-		class Hasher = HashMapHasherDefault,
-		class Comparator = HashMapComparatorDefault<TKey>,
-		class Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
+template <typename TKey, typename TValue,
+		typename Hasher = HashMapHasherDefault,
+		typename Comparator = HashMapComparatorDefault<TKey>,
+		typename Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
 class HashMap {
 public:
 	const uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.

+ 3 - 3
include/godot_cpp/templates/hash_set.hpp

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

+ 5 - 5
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 <class T>
+template <typename T>
 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 <class T>
+template <typename T>
 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 <class T>
+template <typename T>
 class Ref;
 
 struct HashMapHasherDefault {
 	// Generic hash function for any type.
-	template <class T>
+	template <typename T>
 	static _FORCE_INLINE_ uint32_t hash(const T *p_pointer) { return hash_one_uint64((uint64_t)p_pointer); }
 
-	template <class T>
+	template <typename T>
 	static _FORCE_INLINE_ uint32_t hash(const Ref<T> &p_ref) { return hash_one_uint64((uint64_t)p_ref.operator->()); }
 
 	static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); }

+ 5 - 5
include/godot_cpp/templates/list.hpp

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

+ 3 - 3
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 <class T, class U = uint32_t, bool force_trivial = false, bool tight = false>
+template <typename T, typename U = uint32_t, bool force_trivial = false, bool tight = false>
 class LocalVector {
 private:
 	U count = 0;
@@ -257,7 +257,7 @@ public:
 		return -1;
 	}
 
-	template <class C>
+	template <typename C>
 	void sort_custom() {
 		U len = count;
 		if (len == 0) {
@@ -331,7 +331,7 @@ public:
 	}
 };
 
-template <class T, class U = uint32_t, bool force_trivial = false>
+template <typename T, typename U = uint32_t, bool force_trivial = false>
 using TightLocalVector = LocalVector<T, U, force_trivial, true>;
 
 } // namespace godot

+ 8 - 8
include/godot_cpp/templates/pair.hpp

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

+ 1 - 1
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 K, class V, class C = Comparator<K>, class A = DefaultAllocator>
+template <typename K, typename V, typename C = Comparator<K>, typename A = DefaultAllocator>
 class RBMap {
 	enum Color {
 		RED,

+ 1 - 1
include/godot_cpp/templates/rb_set.hpp

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

+ 3 - 3
include/godot_cpp/templates/rid_owner.hpp

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

+ 11 - 2
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 <class T>
+// These are used in very specific areas of the engine where it's critical that these guarantees are held
+#define SAFE_NUMERIC_TYPE_PUN_GUARANTEES(m_type)                    \
+	static_assert(sizeof(SafeNumeric<m_type>) == sizeof(m_type));   \
+	static_assert(alignof(SafeNumeric<m_type>) == alignof(m_type)); \
+	static_assert(std::is_trivially_destructible<std::atomic<m_type>>::value);
+#define SAFE_FLAG_TYPE_PUN_GUARANTEES                \
+	static_assert(sizeof(SafeFlag) == sizeof(bool)); \
+	static_assert(alignof(SafeFlag) == alignof(bool));
+
+template <typename T>
 class SafeNumeric {
 	std::atomic<T> value;
 
@@ -186,7 +195,7 @@ public:
 
 #else
 
-template <class T>
+template <typename T>
 class SafeNumeric {
 protected:
 	T value;

+ 1 - 1
include/godot_cpp/templates/search_array.hpp

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

+ 1 - 1
include/godot_cpp/templates/self_list.hpp

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

+ 2 - 2
include/godot_cpp/templates/sort_array.hpp

@@ -41,7 +41,7 @@ namespace godot {
 		break;                                                        \
 	}
 
-template <class T>
+template <typename T>
 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 <class T, class Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED>
+template <typename T, typename Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED>
 class SortArray {
 	enum {
 		INTROSORT_THRESHOLD = 16

+ 3 - 3
include/godot_cpp/templates/thread_work_pool.hpp

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

+ 59 - 44
include/godot_cpp/templates/vector.hpp

@@ -47,38 +47,42 @@
 
 namespace godot {
 
-template <class T>
+template <typename T>
 class VectorWriteProxy {
 public:
-	_FORCE_INLINE_ T &operator[](int p_index) {
+	_FORCE_INLINE_ T &operator[](typename CowData<T>::Size p_index) {
 		CRASH_BAD_INDEX(p_index, ((Vector<T> *)(this))->_cowdata.size());
 
 		return ((Vector<T> *)(this))->_cowdata.ptrw()[p_index];
 	}
 };
 
-template <class T>
+template <typename T>
 class Vector {
 	friend class VectorWriteProxy<T>;
 
 public:
 	VectorWriteProxy<T> write;
+	typedef typename CowData<T>::Size Size;
 
 private:
 	CowData<T> _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 @@ public:
 	_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<true>(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<T> p_other);
 
 	_FORCE_INLINE_ bool has(const T &p_val) const { return find(p_val) != -1; }
 
-	template <class C>
-	void sort_custom() {
-		int len = _cowdata.size();
+	void sort() {
+		sort_custom<_DefaultComparator<T>>();
+	}
+
+	template <typename Comparator, bool Validate = SORT_ARRAY_VALIDATE_ENABLED, typename... Args>
+	void sort_custom(Args &&...args) {
+		Size len = _cowdata.size();
 		if (len == 0) {
 			return;
 		}
 
 		T *data = ptrw();
-		SortArray<T, C> sorter;
+		SortArray<T, Comparator, Validate> sorter{ args... };
 		sorter.sort(data, len);
 	}
 
-	void sort() {
-		sort_custom<_DefaultComparator<T>>();
+	Size bsearch(const T &p_value, bool p_before) {
+		return bsearch_custom<_DefaultComparator<T>>(p_value, p_before);
 	}
 
-	int bsearch(const T &p_value, bool p_before) {
-		SearchArray<T> search;
+	template <typename Comparator, typename Value, typename... Args>
+	Size bsearch_custom(const Value &p_value, bool p_before, Args &&...args) {
+		SearchArray<T, Comparator> search{ args... };
 		return search.bisect(ptrw(), size(), p_value, p_before);
 	}
 
@@ -125,7 +137,7 @@ public:
 	}
 
 	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 @@ public:
 
 	Vector<uint8_t> to_byte_array() const {
 		Vector<uint8_t> ret;
+		if (is_empty()) {
+			return ret;
+		}
 		ret.resize(size() * sizeof(T));
 		memcpy(ret.ptrw(), ptr(), sizeof(T) * size());
 		return ret;
 	}
 
-	Vector<T> slice(int p_begin, int p_end = INT_MAX) const {
+	Vector<T> slice(Size p_begin, Size p_end = CowData<T>::MAX_INT) const {
 		Vector<T> result;
 
-		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 @@ public:
 	}
 
 	bool operator==(const Vector<T> &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 @@ public:
 	}
 
 	bool operator!=(const Vector<T> &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 @@ public:
 		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 @@ public:
 	_FORCE_INLINE_ ~Vector() {}
 };
 
-template <class T>
+template <typename T>
 void Vector<T>::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 <class T>
+template <typename T>
 void Vector<T>::append_array(Vector<T> 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 <class T>
+template <typename T>
 bool Vector<T>::push_back(T p_elem) {
 	Error err = resize(size() + 1);
 	ERR_FAIL_COND_V(err, true);
@@ -308,10 +323,10 @@ bool Vector<T>::push_back(T p_elem) {
 	return false;
 }
 
-template <class T>
+template <typename T>
 void Vector<T>::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;
 	}
 }

+ 1 - 1
include/godot_cpp/templates/vmap.hpp

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

+ 1 - 1
include/godot_cpp/templates/vset.hpp

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

+ 13 - 13
include/godot_cpp/variant/char_string.hpp

@@ -38,19 +38,19 @@
 
 namespace godot {
 
-template <class T>
+template <typename T>
 class CharStringT;
 
-template <class T>
+template <typename T>
 class CharProxy {
-	template <class TS>
+	template <typename TS>
 	friend class CharStringT;
 
-	const int _index;
+	const int64_t _index;
 	CowData<T> &_cowdata;
 	static inline const T _null = 0;
 
-	_FORCE_INLINE_ CharProxy(const int &p_index, CowData<T> &p_cowdata) :
+	_FORCE_INLINE_ CharProxy(const int64_t &p_index, CowData<T> &p_cowdata) :
 			_index(p_index),
 			_cowdata(p_cowdata) {}
 
@@ -80,7 +80,7 @@ public:
 	}
 };
 
-template <class T>
+template <typename T>
 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<T> operator[](int p_index) { return CharProxy<T>(p_index, _cowdata); }
+	_FORCE_INLINE_ CharProxy<T> operator[](int64_t p_index) { return CharProxy<T>(p_index, _cowdata); }
 
 	_FORCE_INLINE_ CharStringT() {}
 	_FORCE_INLINE_ CharStringT(const CharStringT<T> &p_str) { _cowdata._ref(p_str._cowdata); }
@@ -112,7 +112,7 @@ public:
 	void operator=(const T *p_cstr);
 	bool operator<(const CharStringT<T> &p_right) const;
 	CharStringT<T> &operator+=(T p_char);
-	int length() const { return size() ? size() - 1 : 0; }
+	int64_t length() const { return size() ? size() - 1 : 0; }
 	const T *get_data() const;
 	operator const T *() const { return get_data(); };
 

+ 1 - 1
include/godot_cpp/variant/typed_array.hpp

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

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

+ 6 - 6
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);
 }

+ 21 - 21
src/variant/char_string.cpp

@@ -65,7 +65,7 @@ _FORCE_INLINE_ bool is_str_less(const L *l_ptr, const R *r_ptr) {
 	}
 }
 
-template <class T>
+template <typename T>
 bool CharStringT<T>::operator<(const CharStringT<T> &p_right) const {
 	if (length() == 0) {
 		return p_right.length() != 0;
@@ -74,9 +74,9 @@ bool CharStringT<T>::operator<(const CharStringT<T> &p_right) const {
 	return is_str_less(get_data(), p_right.get_data());
 }
 
-template <class T>
+template <typename T>
 CharStringT<T> &CharStringT<T>::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<T> &CharStringT<T>::operator+=(T p_char) {
 	return *this;
 }
 
-template <class T>
+template <typename T>
 void CharStringT<T>::operator=(const T *p_cstr) {
 	copy_from(p_cstr);
 }
@@ -127,7 +127,7 @@ const wchar_t *CharStringT<wchar_t>::get_data() const {
 	}
 }
 
-template <class T>
+template <typename T>
 void CharStringT<T>::copy_from(const T *p_cstr) {
 	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);
 }
 

+ 20 - 20
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;
 }

+ 33 - 51
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) {

+ 1 - 1
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")

+ 6 - 0
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):

+ 2 - 0
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"]

+ 28 - 0
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<int64_t> &p_array) {
 	int sum = 0;
 	for (int i = 0; i < p_array.size(); i++) {
@@ -455,3 +465,21 @@ void Example::_input(const Ref<InputEvent> &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;
+	}
+}

+ 26 - 0
test/src/example.h

@@ -127,6 +127,7 @@ public:
 	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 @@ protected:
 	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

+ 2 - 0
test/src/register_types.cpp

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

+ 3 - 0
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)

+ 86 - 0
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"])

+ 101 - 26
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=<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"])

+ 3 - 0
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)

+ 3 - 0
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)

+ 3 - 0
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)

+ 0 - 144
tools/targets.py

@@ -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"])

+ 3 - 0
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)

+ 3 - 2
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)