Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/object/callable_method_pointer.h
9903 views
1
/**************************************************************************/
2
/* callable_method_pointer.h */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#pragma once
32
33
#include "core/object/object.h"
34
#include "core/variant/binder_common.h"
35
#include "core/variant/callable.h"
36
37
#include <type_traits>
38
39
class CallableCustomMethodPointerBase : public CallableCustom {
40
uint32_t *comp_ptr = nullptr;
41
uint32_t comp_size;
42
uint32_t h;
43
#ifdef DEBUG_ENABLED
44
const char *text = "";
45
#endif // DEBUG_ENABLED
46
static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b);
47
static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b);
48
49
protected:
50
void _setup(uint32_t *p_base_ptr, uint32_t p_ptr_size);
51
52
public:
53
virtual StringName get_method() const {
54
#ifdef DEBUG_ENABLED
55
return StringName(text);
56
#else
57
return StringName();
58
#endif // DEBUG_ENABLED
59
}
60
61
#ifdef DEBUG_ENABLED
62
void set_text(const char *p_text) {
63
text = p_text;
64
}
65
virtual String get_as_text() const {
66
return text;
67
}
68
#else
69
virtual String get_as_text() const {
70
return String();
71
}
72
#endif // DEBUG_ENABLED
73
virtual CompareEqualFunc get_compare_equal_func() const;
74
virtual CompareLessFunc get_compare_less_func() const;
75
76
virtual uint32_t hash() const;
77
};
78
79
template <typename T, typename R, typename... P>
80
class CallableCustomMethodPointer : public CallableCustomMethodPointerBase {
81
struct Data {
82
T *instance;
83
uint64_t object_id;
84
R (T::*method)(P...);
85
} data;
86
87
public:
88
virtual ObjectID get_object() const {
89
if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) {
90
return ObjectID();
91
}
92
return data.instance->get_instance_id();
93
}
94
95
virtual int get_argument_count(bool &r_is_valid) const {
96
r_is_valid = true;
97
return sizeof...(P);
98
}
99
100
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
101
ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
102
if constexpr (std::is_same<R, void>::value) {
103
call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error);
104
} else {
105
call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
106
}
107
}
108
109
CallableCustomMethodPointer(T *p_instance, R (T::*p_method)(P...)) {
110
memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
111
data.instance = p_instance;
112
data.object_id = p_instance->get_instance_id();
113
data.method = p_method;
114
_setup((uint32_t *)&data, sizeof(Data));
115
}
116
};
117
118
template <typename T, typename... P>
119
Callable create_custom_callable_function_pointer(T *p_instance,
120
#ifdef DEBUG_ENABLED
121
const char *p_func_text,
122
#endif // DEBUG_ENABLED
123
void (T::*p_method)(P...)) {
124
typedef CallableCustomMethodPointer<T, void, P...> CCMP; // Messes with memnew otherwise.
125
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
126
#ifdef DEBUG_ENABLED
127
ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.
128
#endif // DEBUG_ENABLED
129
return Callable(ccmp);
130
}
131
132
template <typename T, typename R, typename... P>
133
Callable create_custom_callable_function_pointer(T *p_instance,
134
#ifdef DEBUG_ENABLED
135
const char *p_func_text,
136
#endif // DEBUG_ENABLED
137
R (T::*p_method)(P...)) {
138
typedef CallableCustomMethodPointer<T, R, P...> CCMP; // Messes with memnew otherwise.
139
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
140
#ifdef DEBUG_ENABLED
141
ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.
142
#endif // DEBUG_ENABLED
143
return Callable(ccmp);
144
}
145
146
// CONST VERSION
147
148
template <typename T, typename R, typename... P>
149
class CallableCustomMethodPointerC : public CallableCustomMethodPointerBase {
150
struct Data {
151
T *instance;
152
uint64_t object_id;
153
R (T::*method)(P...) const;
154
} data;
155
156
public:
157
virtual ObjectID get_object() const override {
158
if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) {
159
return ObjectID();
160
}
161
return data.instance->get_instance_id();
162
}
163
164
virtual int get_argument_count(bool &r_is_valid) const override {
165
r_is_valid = true;
166
return sizeof...(P);
167
}
168
169
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override {
170
ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
171
if constexpr (std::is_same<R, void>::value) {
172
call_with_variant_argsc(data.instance, data.method, p_arguments, p_argcount, r_call_error);
173
} else {
174
call_with_variant_args_retc(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
175
}
176
}
177
178
CallableCustomMethodPointerC(T *p_instance, R (T::*p_method)(P...) const) {
179
memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
180
data.instance = p_instance;
181
data.object_id = p_instance->get_instance_id();
182
data.method = p_method;
183
_setup((uint32_t *)&data, sizeof(Data));
184
}
185
};
186
187
template <typename T, typename... P>
188
Callable create_custom_callable_function_pointer(T *p_instance,
189
#ifdef DEBUG_ENABLED
190
const char *p_func_text,
191
#endif // DEBUG_ENABLED
192
void (T::*p_method)(P...) const) {
193
typedef CallableCustomMethodPointerC<T, void, P...> CCMP; // Messes with memnew otherwise.
194
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
195
#ifdef DEBUG_ENABLED
196
ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.
197
#endif // DEBUG_ENABLED
198
return Callable(ccmp);
199
}
200
201
template <typename T, typename R, typename... P>
202
Callable create_custom_callable_function_pointer(T *p_instance,
203
#ifdef DEBUG_ENABLED
204
const char *p_func_text,
205
#endif
206
R (T::*p_method)(P...) const) {
207
typedef CallableCustomMethodPointerC<T, R, P...> CCMP; // Messes with memnew otherwise.
208
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
209
#ifdef DEBUG_ENABLED
210
ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.
211
#endif // DEBUG_ENABLED
212
return Callable(ccmp);
213
}
214
215
#ifdef DEBUG_ENABLED
216
#define callable_mp(I, M) create_custom_callable_function_pointer(I, #M, M)
217
#else
218
#define callable_mp(I, M) create_custom_callable_function_pointer(I, M)
219
#endif // DEBUG_ENABLED
220
221
// STATIC VERSIONS
222
223
template <typename R, typename... P>
224
class CallableCustomStaticMethodPointer : public CallableCustomMethodPointerBase {
225
struct Data {
226
R (*method)(P...);
227
} data;
228
229
public:
230
virtual bool is_valid() const override {
231
return true;
232
}
233
234
virtual ObjectID get_object() const override {
235
return ObjectID();
236
}
237
238
virtual int get_argument_count(bool &r_is_valid) const override {
239
r_is_valid = true;
240
return sizeof...(P);
241
}
242
243
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override {
244
if constexpr (std::is_same<R, void>::value) {
245
call_with_variant_args_static(data.method, p_arguments, p_argcount, r_call_error);
246
} else {
247
call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
248
}
249
}
250
251
CallableCustomStaticMethodPointer(R (*p_method)(P...)) {
252
memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
253
data.method = p_method;
254
_setup((uint32_t *)&data, sizeof(Data));
255
}
256
};
257
258
template <typename... P>
259
Callable create_custom_callable_static_function_pointer(
260
#ifdef DEBUG_ENABLED
261
const char *p_func_text,
262
#endif // DEBUG_ENABLED
263
void (*p_method)(P...)) {
264
typedef CallableCustomStaticMethodPointer<void, P...> CCMP; // Messes with memnew otherwise.
265
CCMP *ccmp = memnew(CCMP(p_method));
266
#ifdef DEBUG_ENABLED
267
ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.
268
#endif // DEBUG_ENABLED
269
return Callable(ccmp);
270
}
271
272
template <typename R, typename... P>
273
Callable create_custom_callable_static_function_pointer(
274
#ifdef DEBUG_ENABLED
275
const char *p_func_text,
276
#endif // DEBUG_ENABLED
277
R (*p_method)(P...)) {
278
typedef CallableCustomStaticMethodPointer<R, P...> CCMP; // Messes with memnew otherwise.
279
CCMP *ccmp = memnew(CCMP(p_method));
280
#ifdef DEBUG_ENABLED
281
ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.
282
#endif // DEBUG_ENABLED
283
return Callable(ccmp);
284
}
285
286
#ifdef DEBUG_ENABLED
287
#define callable_mp_static(M) create_custom_callable_static_function_pointer(#M, M)
288
#else
289
#define callable_mp_static(M) create_custom_callable_static_function_pointer(M)
290
#endif
291
292