Path: blob/master/core/object/callable_method_pointer.h
9903 views
/**************************************************************************/1/* callable_method_pointer.h */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#pragma once3132#include "core/object/object.h"33#include "core/variant/binder_common.h"34#include "core/variant/callable.h"3536#include <type_traits>3738class CallableCustomMethodPointerBase : public CallableCustom {39uint32_t *comp_ptr = nullptr;40uint32_t comp_size;41uint32_t h;42#ifdef DEBUG_ENABLED43const char *text = "";44#endif // DEBUG_ENABLED45static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b);46static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b);4748protected:49void _setup(uint32_t *p_base_ptr, uint32_t p_ptr_size);5051public:52virtual StringName get_method() const {53#ifdef DEBUG_ENABLED54return StringName(text);55#else56return StringName();57#endif // DEBUG_ENABLED58}5960#ifdef DEBUG_ENABLED61void set_text(const char *p_text) {62text = p_text;63}64virtual String get_as_text() const {65return text;66}67#else68virtual String get_as_text() const {69return String();70}71#endif // DEBUG_ENABLED72virtual CompareEqualFunc get_compare_equal_func() const;73virtual CompareLessFunc get_compare_less_func() const;7475virtual uint32_t hash() const;76};7778template <typename T, typename R, typename... P>79class CallableCustomMethodPointer : public CallableCustomMethodPointerBase {80struct Data {81T *instance;82uint64_t object_id;83R (T::*method)(P...);84} data;8586public:87virtual ObjectID get_object() const {88if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) {89return ObjectID();90}91return data.instance->get_instance_id();92}9394virtual int get_argument_count(bool &r_is_valid) const {95r_is_valid = true;96return sizeof...(P);97}9899virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {100ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");101if constexpr (std::is_same<R, void>::value) {102call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error);103} else {104call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);105}106}107108CallableCustomMethodPointer(T *p_instance, R (T::*p_method)(P...)) {109memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.110data.instance = p_instance;111data.object_id = p_instance->get_instance_id();112data.method = p_method;113_setup((uint32_t *)&data, sizeof(Data));114}115};116117template <typename T, typename... P>118Callable create_custom_callable_function_pointer(T *p_instance,119#ifdef DEBUG_ENABLED120const char *p_func_text,121#endif // DEBUG_ENABLED122void (T::*p_method)(P...)) {123typedef CallableCustomMethodPointer<T, void, P...> CCMP; // Messes with memnew otherwise.124CCMP *ccmp = memnew(CCMP(p_instance, p_method));125#ifdef DEBUG_ENABLED126ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.127#endif // DEBUG_ENABLED128return Callable(ccmp);129}130131template <typename T, typename R, typename... P>132Callable create_custom_callable_function_pointer(T *p_instance,133#ifdef DEBUG_ENABLED134const char *p_func_text,135#endif // DEBUG_ENABLED136R (T::*p_method)(P...)) {137typedef CallableCustomMethodPointer<T, R, P...> CCMP; // Messes with memnew otherwise.138CCMP *ccmp = memnew(CCMP(p_instance, p_method));139#ifdef DEBUG_ENABLED140ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.141#endif // DEBUG_ENABLED142return Callable(ccmp);143}144145// CONST VERSION146147template <typename T, typename R, typename... P>148class CallableCustomMethodPointerC : public CallableCustomMethodPointerBase {149struct Data {150T *instance;151uint64_t object_id;152R (T::*method)(P...) const;153} data;154155public:156virtual ObjectID get_object() const override {157if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) {158return ObjectID();159}160return data.instance->get_instance_id();161}162163virtual int get_argument_count(bool &r_is_valid) const override {164r_is_valid = true;165return sizeof...(P);166}167168virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override {169ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");170if constexpr (std::is_same<R, void>::value) {171call_with_variant_argsc(data.instance, data.method, p_arguments, p_argcount, r_call_error);172} else {173call_with_variant_args_retc(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);174}175}176177CallableCustomMethodPointerC(T *p_instance, R (T::*p_method)(P...) const) {178memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.179data.instance = p_instance;180data.object_id = p_instance->get_instance_id();181data.method = p_method;182_setup((uint32_t *)&data, sizeof(Data));183}184};185186template <typename T, typename... P>187Callable create_custom_callable_function_pointer(T *p_instance,188#ifdef DEBUG_ENABLED189const char *p_func_text,190#endif // DEBUG_ENABLED191void (T::*p_method)(P...) const) {192typedef CallableCustomMethodPointerC<T, void, P...> CCMP; // Messes with memnew otherwise.193CCMP *ccmp = memnew(CCMP(p_instance, p_method));194#ifdef DEBUG_ENABLED195ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.196#endif // DEBUG_ENABLED197return Callable(ccmp);198}199200template <typename T, typename R, typename... P>201Callable create_custom_callable_function_pointer(T *p_instance,202#ifdef DEBUG_ENABLED203const char *p_func_text,204#endif205R (T::*p_method)(P...) const) {206typedef CallableCustomMethodPointerC<T, R, P...> CCMP; // Messes with memnew otherwise.207CCMP *ccmp = memnew(CCMP(p_instance, p_method));208#ifdef DEBUG_ENABLED209ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.210#endif // DEBUG_ENABLED211return Callable(ccmp);212}213214#ifdef DEBUG_ENABLED215#define callable_mp(I, M) create_custom_callable_function_pointer(I, #M, M)216#else217#define callable_mp(I, M) create_custom_callable_function_pointer(I, M)218#endif // DEBUG_ENABLED219220// STATIC VERSIONS221222template <typename R, typename... P>223class CallableCustomStaticMethodPointer : public CallableCustomMethodPointerBase {224struct Data {225R (*method)(P...);226} data;227228public:229virtual bool is_valid() const override {230return true;231}232233virtual ObjectID get_object() const override {234return ObjectID();235}236237virtual int get_argument_count(bool &r_is_valid) const override {238r_is_valid = true;239return sizeof...(P);240}241242virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override {243if constexpr (std::is_same<R, void>::value) {244call_with_variant_args_static(data.method, p_arguments, p_argcount, r_call_error);245} else {246call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);247}248}249250CallableCustomStaticMethodPointer(R (*p_method)(P...)) {251memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.252data.method = p_method;253_setup((uint32_t *)&data, sizeof(Data));254}255};256257template <typename... P>258Callable create_custom_callable_static_function_pointer(259#ifdef DEBUG_ENABLED260const char *p_func_text,261#endif // DEBUG_ENABLED262void (*p_method)(P...)) {263typedef CallableCustomStaticMethodPointer<void, P...> CCMP; // Messes with memnew otherwise.264CCMP *ccmp = memnew(CCMP(p_method));265#ifdef DEBUG_ENABLED266ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.267#endif // DEBUG_ENABLED268return Callable(ccmp);269}270271template <typename R, typename... P>272Callable create_custom_callable_static_function_pointer(273#ifdef DEBUG_ENABLED274const char *p_func_text,275#endif // DEBUG_ENABLED276R (*p_method)(P...)) {277typedef CallableCustomStaticMethodPointer<R, P...> CCMP; // Messes with memnew otherwise.278CCMP *ccmp = memnew(CCMP(p_method));279#ifdef DEBUG_ENABLED280ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.281#endif // DEBUG_ENABLED282return Callable(ccmp);283}284285#ifdef DEBUG_ENABLED286#define callable_mp_static(M) create_custom_callable_static_function_pointer(#M, M)287#else288#define callable_mp_static(M) create_custom_callable_static_function_pointer(M)289#endif290291292