diff --git a/core/object/object.h b/core/object/object.h index 60451ce43c..0d27075972 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -39,7 +39,6 @@ #include "core/templates/hash_set.h" #include "core/templates/list.h" #include "core/templates/safe_refcount.h" -#include "core/variant/required_ptr.h" #include "core/variant/variant.h" template @@ -1137,3 +1136,222 @@ public: static void debug_objects(DebugFunc p_func, void *p_user_data); static int get_object_count(); }; + +// Using `RequiredResult` as the return type indicates that null will only be returned in the case of an error. +// This allows GDExtension language bindings to use the appropriate error handling mechanism for that language +// when null is returned (for example, throwing an exception), rather than simply returning the value. +template +class RequiredResult { + static_assert(!is_fully_defined_v || std::is_base_of_v, "T must be an Object subtype"); + +public: + using element_type = T; + using ptr_type = std::conditional_t, Ref, T *>; + +private: + ptr_type _value = ptr_type(); + +public: + _FORCE_INLINE_ RequiredResult() = default; + + RequiredResult(const RequiredResult &p_other) = default; + RequiredResult(RequiredResult &&p_other) = default; + RequiredResult &operator=(const RequiredResult &p_other) = default; + RequiredResult &operator=(RequiredResult &&p_other) = default; + + _FORCE_INLINE_ RequiredResult(std::nullptr_t) : + RequiredResult() {} + _FORCE_INLINE_ RequiredResult &operator=(std::nullptr_t) { _value = nullptr; } + + // These functions should not be called directly, they are only for internal use. + _FORCE_INLINE_ ptr_type _internal_ptr_dont_use() const { return _value; } + _FORCE_INLINE_ static RequiredResult _err_return_dont_use() { return RequiredResult(); } + + template , int> = 0> + _FORCE_INLINE_ RequiredResult(const RequiredResult &p_other) : + _value(p_other._value) {} + template , int> = 0> + _FORCE_INLINE_ RequiredResult &operator=(const RequiredResult &p_other) { + _value = p_other._value; + return *this; + } + + template , int> = 0> + _FORCE_INLINE_ RequiredResult(T_Other *p_ptr) : + _value(p_ptr) {} + template , int> = 0> + _FORCE_INLINE_ RequiredResult &operator=(T_Other *p_ptr) { + _value = p_ptr; + return *this; + } + + template , int> = 0> + _FORCE_INLINE_ RequiredResult(const Ref &p_ref) : + _value(p_ref) {} + template , int> = 0> + _FORCE_INLINE_ RequiredResult &operator=(const Ref &p_ref) { + _value = p_ref; + return *this; + } + + template , int> = 0> + _FORCE_INLINE_ RequiredResult(Ref &&p_ref) : + _value(std::move(p_ref)) {} + template , int> = 0> + _FORCE_INLINE_ RequiredResult &operator=(Ref &&p_ref) { + _value = std::move(p_ref); + return &this; + } + + template , int> = 0> + _FORCE_INLINE_ RequiredResult(const Variant &p_variant) : + _value(Object::cast_to(p_variant.get_validated_object())) {} + template , int> = 0> + _FORCE_INLINE_ RequiredResult &operator=(const Variant &p_variant) { + _value = Object::cast_to(p_variant.get_validated_object()); + return *this; + } + + template , int> = 0> + _FORCE_INLINE_ RequiredResult(const Variant &p_variant) : + _value(Object::cast_to(p_variant.operator Object *())) {} + template , int> = 0> + _FORCE_INLINE_ RequiredResult &operator=(const Variant &p_variant) { + _value = Object::cast_to(p_variant.operator Object *()); + return *this; + } + + template , int> = 0> + _FORCE_INLINE_ element_type *ptr() const { + return *_value; + } + + template , int> = 0> + _FORCE_INLINE_ element_type *ptr() const { + return _value; + } + + _FORCE_INLINE_ operator ptr_type() const { + return _value; + } + + template && std::is_base_of_v, int> = 0> + _FORCE_INLINE_ operator Ref() const { + return Ref(_value); + } + + _FORCE_INLINE_ element_type *operator*() const { + return ptr(); + } + + _FORCE_INLINE_ element_type *operator->() const { + return ptr(); + } +}; + +// Using `RequiredParam` as an argument type indicates that passing null as that parameter is an error, +// that will prevent the method from doing its intended function. +// This allows GDExtension bindings to use language-specific mechanisms to prevent users from passing null, +// because it is never valid to do so. +template +class RequiredParam { + static_assert(!is_fully_defined_v || std::is_base_of_v, "T must be an Object subtype"); + +public: + static constexpr bool is_ref = std::is_base_of_v; + + using element_type = T; + using extracted_type = std::conditional_t &, T *>; + using persistent_type = std::conditional_t, T *>; + +private: + T *_value = nullptr; + + _FORCE_INLINE_ RequiredParam() = default; + +public: + // These functions should not be called directly, they are only for internal use. + _FORCE_INLINE_ extracted_type _internal_ptr_dont_use() const { + if constexpr (is_ref) { + // Pretend _value is a Ref, for ease of use with existing `const Ref &` accepting APIs. + // This only works as long as Ref is internally T *. + // The double indirection should be optimized away by the compiler. + static_assert(sizeof(Ref) == sizeof(T *)); + return *((const Ref *)&_value); + } else { + return _value; + } + } + _FORCE_INLINE_ bool _is_null_dont_use() const { return _value == nullptr; } + _FORCE_INLINE_ static RequiredParam _err_return_dont_use() { return RequiredParam(); } + + // Prevent erroneously assigning null values by explicitly removing nullptr constructor/assignment. + RequiredParam(std::nullptr_t) = delete; + RequiredParam &operator=(std::nullptr_t) = delete; + + RequiredParam(const RequiredParam &p_other) = default; + RequiredParam(RequiredParam &&p_other) = default; + RequiredParam &operator=(const RequiredParam &p_other) = default; + RequiredParam &operator=(RequiredParam &&p_other) = default; + + template , int> = 0> + _FORCE_INLINE_ RequiredParam(const RequiredParam &p_other) : + _value(p_other._internal_ptr_dont_use()) {} + template , int> = 0> + _FORCE_INLINE_ RequiredParam &operator=(const RequiredParam &p_other) { + _value = p_other._internal_ptr_dont_use(); + return *this; + } + + template , int> = 0> + _FORCE_INLINE_ RequiredParam(T_Other *p_ptr) : + _value(p_ptr) {} + template , int> = 0> + _FORCE_INLINE_ RequiredParam &operator=(T_Other *p_ptr) { + _value = p_ptr; + return *this; + } + + template , int> = 0> + _FORCE_INLINE_ RequiredParam(const Ref &p_ref) : + _value(*p_ref) {} + template , int> = 0> + _FORCE_INLINE_ RequiredParam &operator=(const Ref &p_ref) { + _value = *p_ref; + return *this; + } + + template , int> = 0> + _FORCE_INLINE_ RequiredParam(const Variant &p_variant) : + _value(Object::cast_to(p_variant.get_validated_object())) {} + template , int> = 0> + _FORCE_INLINE_ RequiredParam &operator=(const Variant &p_variant) { + _value = Object::cast_to(p_variant.get_validated_object()); + return *this; + } + + template , int> = 0> + _FORCE_INLINE_ RequiredParam(const Variant &p_variant) : + _value(Object::cast_to(p_variant.operator Object *())) {} + template , int> = 0> + _FORCE_INLINE_ RequiredParam &operator=(const Variant &p_variant) { + _value = Object::cast_to(p_variant.operator Object *()); + return *this; + } +}; + +#define TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, m_retval, m_msg, m_editor) \ + if (unlikely(m_param._is_null_dont_use())) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Required object \"" _STR(m_param) "\" is null.", m_msg, m_editor); \ + return m_retval; \ + } \ + typename std::decay_t::extracted_type m_name = m_param._internal_ptr_dont_use(); \ + static_assert(true) + +// These macros are equivalent to the ERR_FAIL_NULL*() family of macros, only for RequiredParam instead of raw pointers. +#define EXTRACT_PARAM_OR_FAIL(m_name, m_param) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, void(), "", false) +#define EXTRACT_PARAM_OR_FAIL_MSG(m_name, m_param, m_msg) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, void(), m_msg, false) +#define EXTRACT_PARAM_OR_FAIL_EDMSG(m_name, m_param, m_msg) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, void(), m_msg, true) +#define EXTRACT_PARAM_OR_FAIL_V(m_name, m_param, m_retval) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, m_retval, "", false) +#define EXTRACT_PARAM_OR_FAIL_V_MSG(m_name, m_param, m_retval, m_msg) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, m_retval, m_msg, false) +#define EXTRACT_PARAM_OR_FAIL_V_EDMSG(m_name, m_param, m_retval, m_msg) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, m_retval, m_msg, true) diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h index dbdb9bc7fe..ab48898676 100644 --- a/core/variant/binder_common.h +++ b/core/variant/binder_common.h @@ -36,7 +36,6 @@ #include "core/templates/simple_type.h" #include "core/typedefs.h" #include "core/variant/method_ptrcall.h" -#include "core/variant/required_ptr.h" #include "core/variant/type_info.h" #include "core/variant/variant.h" #include "core/variant/variant_internal.h" diff --git a/core/variant/required_ptr.h b/core/variant/required_ptr.h deleted file mode 100644 index 6283267603..0000000000 --- a/core/variant/required_ptr.h +++ /dev/null @@ -1,252 +0,0 @@ -/**************************************************************************/ -/* required_ptr.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#pragma once - -#include "core/variant/variant.h" - -// Using `RequiredResult` as the return type indicates that null will only be returned in the case of an error. -// This allows GDExtension language bindings to use the appropriate error handling mechanism for that language -// when null is returned (for example, throwing an exception), rather than simply returning the value. -template -class RequiredResult { - static_assert(!is_fully_defined_v || std::is_base_of_v, "T must be an Object subtype"); - -public: - using element_type = T; - using ptr_type = std::conditional_t, Ref, T *>; - -private: - ptr_type _value = ptr_type(); - -public: - _FORCE_INLINE_ RequiredResult() = default; - - RequiredResult(const RequiredResult &p_other) = default; - RequiredResult(RequiredResult &&p_other) = default; - RequiredResult &operator=(const RequiredResult &p_other) = default; - RequiredResult &operator=(RequiredResult &&p_other) = default; - - _FORCE_INLINE_ RequiredResult(std::nullptr_t) : - RequiredResult() {} - _FORCE_INLINE_ RequiredResult &operator=(std::nullptr_t) { _value = nullptr; } - - // These functions should not be called directly, they are only for internal use. - _FORCE_INLINE_ ptr_type _internal_ptr_dont_use() const { return _value; } - _FORCE_INLINE_ static RequiredResult _err_return_dont_use() { return RequiredResult(); } - - template , int> = 0> - _FORCE_INLINE_ RequiredResult(const RequiredResult &p_other) : - _value(p_other._value) {} - template , int> = 0> - _FORCE_INLINE_ RequiredResult &operator=(const RequiredResult &p_other) { - _value = p_other._value; - return *this; - } - - template , int> = 0> - _FORCE_INLINE_ RequiredResult(T_Other *p_ptr) : - _value(p_ptr) {} - template , int> = 0> - _FORCE_INLINE_ RequiredResult &operator=(T_Other *p_ptr) { - _value = p_ptr; - return *this; - } - - template , int> = 0> - _FORCE_INLINE_ RequiredResult(const Ref &p_ref) : - _value(p_ref) {} - template , int> = 0> - _FORCE_INLINE_ RequiredResult &operator=(const Ref &p_ref) { - _value = p_ref; - return *this; - } - - template , int> = 0> - _FORCE_INLINE_ RequiredResult(Ref &&p_ref) : - _value(std::move(p_ref)) {} - template , int> = 0> - _FORCE_INLINE_ RequiredResult &operator=(Ref &&p_ref) { - _value = std::move(p_ref); - return &this; - } - - template , int> = 0> - _FORCE_INLINE_ RequiredResult(const Variant &p_variant) : - _value(static_cast(p_variant.get_validated_object())) {} - template , int> = 0> - _FORCE_INLINE_ RequiredResult &operator=(const Variant &p_variant) { - _value = static_cast(p_variant.get_validated_object()); - return *this; - } - - template , int> = 0> - _FORCE_INLINE_ RequiredResult(const Variant &p_variant) : - _value(static_cast(p_variant.operator Object *())) {} - template , int> = 0> - _FORCE_INLINE_ RequiredResult &operator=(const Variant &p_variant) { - _value = static_cast(p_variant.operator Object *()); - return *this; - } - - template , int> = 0> - _FORCE_INLINE_ element_type *ptr() const { - return *_value; - } - - template , int> = 0> - _FORCE_INLINE_ element_type *ptr() const { - return _value; - } - - _FORCE_INLINE_ operator ptr_type() const { - return _value; - } - - template && std::is_base_of_v, int> = 0> - _FORCE_INLINE_ operator Ref() const { - return Ref(_value); - } - - _FORCE_INLINE_ element_type *operator*() const { - return ptr(); - } - - _FORCE_INLINE_ element_type *operator->() const { - return ptr(); - } -}; - -// Using `RequiredParam` as an argument type indicates that passing null as that parameter is an error, -// that will prevent the method from doing its intended function. -// This allows GDExtension bindings to use language-specific mechanisms to prevent users from passing null, -// because it is never valid to do so. -template -class RequiredParam { - static_assert(!is_fully_defined_v || std::is_base_of_v, "T must be an Object subtype"); - -public: - static constexpr bool is_ref = std::is_base_of_v; - - using element_type = T; - using extracted_type = std::conditional_t &, T *>; - using persistent_type = std::conditional_t, T *>; - -private: - T *_value = nullptr; - - _FORCE_INLINE_ RequiredParam() = default; - -public: - // These functions should not be called directly, they are only for internal use. - _FORCE_INLINE_ extracted_type _internal_ptr_dont_use() const { - if constexpr (is_ref) { - // Pretend _value is a Ref, for ease of use with existing `const Ref &` accepting APIs. - // This only works as long as Ref is internally T *. - // The double indirection should be optimized away by the compiler. - static_assert(sizeof(Ref) == sizeof(T *)); - return *((const Ref *)&_value); - } else { - return _value; - } - } - _FORCE_INLINE_ bool _is_null_dont_use() const { return _value == nullptr; } - _FORCE_INLINE_ static RequiredParam _err_return_dont_use() { return RequiredParam(); } - - // Prevent erroneously assigning null values by explicitly removing nullptr constructor/assignment. - RequiredParam(std::nullptr_t) = delete; - RequiredParam &operator=(std::nullptr_t) = delete; - - RequiredParam(const RequiredParam &p_other) = default; - RequiredParam(RequiredParam &&p_other) = default; - RequiredParam &operator=(const RequiredParam &p_other) = default; - RequiredParam &operator=(RequiredParam &&p_other) = default; - - template , int> = 0> - _FORCE_INLINE_ RequiredParam(const RequiredParam &p_other) : - _value(p_other._internal_ptr_dont_use()) {} - template , int> = 0> - _FORCE_INLINE_ RequiredParam &operator=(const RequiredParam &p_other) { - _value = p_other._internal_ptr_dont_use(); - return *this; - } - - template , int> = 0> - _FORCE_INLINE_ RequiredParam(T_Other *p_ptr) : - _value(p_ptr) {} - template , int> = 0> - _FORCE_INLINE_ RequiredParam &operator=(T_Other *p_ptr) { - _value = p_ptr; - return *this; - } - - template , int> = 0> - _FORCE_INLINE_ RequiredParam(const Ref &p_ref) : - _value(*p_ref) {} - template , int> = 0> - _FORCE_INLINE_ RequiredParam &operator=(const Ref &p_ref) { - _value = *p_ref; - return *this; - } - - template , int> = 0> - _FORCE_INLINE_ RequiredParam(const Variant &p_variant) : - _value(static_cast(p_variant.get_validated_object())) {} - template , int> = 0> - _FORCE_INLINE_ RequiredParam &operator=(const Variant &p_variant) { - _value = static_cast(p_variant.get_validated_object()); - return *this; - } - - template , int> = 0> - _FORCE_INLINE_ RequiredParam(const Variant &p_variant) : - _value(static_cast(p_variant.operator Object *())) {} - template , int> = 0> - _FORCE_INLINE_ RequiredParam &operator=(const Variant &p_variant) { - _value = static_cast(p_variant.operator Object *()); - return *this; - } -}; - -#define TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, m_retval, m_msg, m_editor) \ - if (unlikely(m_param._is_null_dont_use())) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Required object \"" _STR(m_param) "\" is null.", m_msg, m_editor); \ - return m_retval; \ - } \ - typename std::decay_t::extracted_type m_name = m_param._internal_ptr_dont_use(); \ - static_assert(true) - -// These macros are equivalent to the ERR_FAIL_NULL*() family of macros, only for RequiredParam instead of raw pointers. -#define EXTRACT_PARAM_OR_FAIL(m_name, m_param) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, void(), "", false) -#define EXTRACT_PARAM_OR_FAIL_MSG(m_name, m_param, m_msg) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, void(), m_msg, false) -#define EXTRACT_PARAM_OR_FAIL_EDMSG(m_name, m_param, m_msg) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, void(), m_msg, true) -#define EXTRACT_PARAM_OR_FAIL_V(m_name, m_param, m_retval) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, m_retval, "", false) -#define EXTRACT_PARAM_OR_FAIL_V_MSG(m_name, m_param, m_retval, m_msg) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, m_retval, m_msg, false) -#define EXTRACT_PARAM_OR_FAIL_V_EDMSG(m_name, m_param, m_retval, m_msg) TMPL_EXTRACT_PARAM_OR_FAIL(m_name, m_param, m_retval, m_msg, true)