1 | /**************************************************************************/ |
2 | /* ref_counted.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 | #ifndef REF_COUNTED_H |
32 | #define REF_COUNTED_H |
33 | |
34 | #include "core/object/class_db.h" |
35 | #include "core/templates/safe_refcount.h" |
36 | |
37 | class RefCounted : public Object { |
38 | GDCLASS(RefCounted, Object); |
39 | SafeRefCount refcount; |
40 | SafeRefCount refcount_init; |
41 | |
42 | protected: |
43 | static void _bind_methods(); |
44 | |
45 | public: |
46 | _FORCE_INLINE_ bool is_referenced() const { return refcount_init.get() != 1; } |
47 | bool init_ref(); |
48 | bool reference(); // returns false if refcount is at zero and didn't get increased |
49 | bool unreference(); |
50 | int get_reference_count() const; |
51 | |
52 | RefCounted(); |
53 | ~RefCounted() {} |
54 | }; |
55 | |
56 | template <class T> |
57 | class Ref { |
58 | T *reference = nullptr; |
59 | |
60 | void ref(const Ref &p_from) { |
61 | if (p_from.reference == reference) { |
62 | return; |
63 | } |
64 | |
65 | unref(); |
66 | |
67 | reference = p_from.reference; |
68 | if (reference) { |
69 | reference->reference(); |
70 | } |
71 | } |
72 | |
73 | void ref_pointer(T *p_ref) { |
74 | ERR_FAIL_NULL(p_ref); |
75 | |
76 | if (p_ref->init_ref()) { |
77 | reference = p_ref; |
78 | } |
79 | } |
80 | |
81 | //virtual RefCounted * get_reference() const { return reference; } |
82 | public: |
83 | _FORCE_INLINE_ bool operator==(const T *p_ptr) const { |
84 | return reference == p_ptr; |
85 | } |
86 | _FORCE_INLINE_ bool operator!=(const T *p_ptr) const { |
87 | return reference != p_ptr; |
88 | } |
89 | |
90 | _FORCE_INLINE_ bool operator<(const Ref<T> &p_r) const { |
91 | return reference < p_r.reference; |
92 | } |
93 | _FORCE_INLINE_ bool operator==(const Ref<T> &p_r) const { |
94 | return reference == p_r.reference; |
95 | } |
96 | _FORCE_INLINE_ bool operator!=(const Ref<T> &p_r) const { |
97 | return reference != p_r.reference; |
98 | } |
99 | |
100 | _FORCE_INLINE_ T *operator*() const { |
101 | return reference; |
102 | } |
103 | |
104 | _FORCE_INLINE_ T *operator->() const { |
105 | return reference; |
106 | } |
107 | |
108 | _FORCE_INLINE_ T *ptr() const { |
109 | return reference; |
110 | } |
111 | |
112 | operator Variant() const { |
113 | return Variant(reference); |
114 | } |
115 | |
116 | void operator=(const Ref &p_from) { |
117 | ref(p_from); |
118 | } |
119 | |
120 | template <class T_Other> |
121 | void operator=(const Ref<T_Other> &p_from) { |
122 | RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr())); |
123 | if (!refb) { |
124 | unref(); |
125 | return; |
126 | } |
127 | Ref r; |
128 | r.reference = Object::cast_to<T>(refb); |
129 | ref(r); |
130 | r.reference = nullptr; |
131 | } |
132 | |
133 | void operator=(const Variant &p_variant) { |
134 | Object *object = p_variant.get_validated_object(); |
135 | |
136 | if (object == reference) { |
137 | return; |
138 | } |
139 | |
140 | unref(); |
141 | |
142 | if (!object) { |
143 | return; |
144 | } |
145 | |
146 | T *r = Object::cast_to<T>(object); |
147 | if (r && r->reference()) { |
148 | reference = r; |
149 | } |
150 | } |
151 | |
152 | template <class T_Other> |
153 | void reference_ptr(T_Other *p_ptr) { |
154 | if (reference == p_ptr) { |
155 | return; |
156 | } |
157 | unref(); |
158 | |
159 | T *r = Object::cast_to<T>(p_ptr); |
160 | if (r) { |
161 | ref_pointer(r); |
162 | } |
163 | } |
164 | |
165 | Ref(const Ref &p_from) { |
166 | ref(p_from); |
167 | } |
168 | |
169 | template <class T_Other> |
170 | Ref(const Ref<T_Other> &p_from) { |
171 | RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr())); |
172 | if (!refb) { |
173 | unref(); |
174 | return; |
175 | } |
176 | Ref r; |
177 | r.reference = Object::cast_to<T>(refb); |
178 | ref(r); |
179 | r.reference = nullptr; |
180 | } |
181 | |
182 | Ref(T *p_reference) { |
183 | if (p_reference) { |
184 | ref_pointer(p_reference); |
185 | } |
186 | } |
187 | |
188 | Ref(const Variant &p_variant) { |
189 | Object *object = p_variant.get_validated_object(); |
190 | |
191 | if (!object) { |
192 | return; |
193 | } |
194 | |
195 | T *r = Object::cast_to<T>(object); |
196 | if (r && r->reference()) { |
197 | reference = r; |
198 | } |
199 | } |
200 | |
201 | inline bool is_valid() const { return reference != nullptr; } |
202 | inline bool is_null() const { return reference == nullptr; } |
203 | |
204 | void unref() { |
205 | // TODO: this should be moved to mutexes, since this engine does not really |
206 | // do a lot of referencing on references and stuff |
207 | // mutexes will avoid more crashes? |
208 | |
209 | if (reference && reference->unreference()) { |
210 | memdelete(reference); |
211 | } |
212 | reference = nullptr; |
213 | } |
214 | |
215 | void instantiate() { |
216 | ref(memnew(T)); |
217 | } |
218 | |
219 | Ref() {} |
220 | |
221 | ~Ref() { |
222 | unref(); |
223 | } |
224 | }; |
225 | |
226 | class WeakRef : public RefCounted { |
227 | GDCLASS(WeakRef, RefCounted); |
228 | |
229 | ObjectID ref; |
230 | |
231 | protected: |
232 | static void _bind_methods(); |
233 | |
234 | public: |
235 | Variant get_ref() const; |
236 | void set_obj(Object *p_object); |
237 | void set_ref(const Ref<RefCounted> &p_ref); |
238 | |
239 | WeakRef() {} |
240 | }; |
241 | |
242 | template <class T> |
243 | struct PtrToArg<Ref<T>> { |
244 | _FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) { |
245 | if (p_ptr == nullptr) { |
246 | return Ref<T>(); |
247 | } |
248 | // p_ptr points to a RefCounted object |
249 | return Ref<T>(const_cast<T *>(*reinterpret_cast<T *const *>(p_ptr))); |
250 | } |
251 | |
252 | typedef Ref<T> EncodeT; |
253 | |
254 | _FORCE_INLINE_ static void encode(Ref<T> p_val, const void *p_ptr) { |
255 | // p_ptr points to an EncodeT object which is a Ref<T> object. |
256 | *(const_cast<Ref<RefCounted> *>(reinterpret_cast<const Ref<RefCounted> *>(p_ptr))) = p_val; |
257 | } |
258 | }; |
259 | |
260 | template <class T> |
261 | struct PtrToArg<const Ref<T> &> { |
262 | typedef Ref<T> EncodeT; |
263 | |
264 | _FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) { |
265 | if (p_ptr == nullptr) { |
266 | return Ref<T>(); |
267 | } |
268 | // p_ptr points to a RefCounted object |
269 | return Ref<T>(*((T *const *)p_ptr)); |
270 | } |
271 | }; |
272 | |
273 | template <class T> |
274 | struct GetTypeInfo<Ref<T>> { |
275 | static const Variant::Type VARIANT_TYPE = Variant::OBJECT; |
276 | static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; |
277 | |
278 | static inline PropertyInfo get_class_info() { |
279 | return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static()); |
280 | } |
281 | }; |
282 | |
283 | template <class T> |
284 | struct GetTypeInfo<const Ref<T> &> { |
285 | static const Variant::Type VARIANT_TYPE = Variant::OBJECT; |
286 | static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; |
287 | |
288 | static inline PropertyInfo get_class_info() { |
289 | return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static()); |
290 | } |
291 | }; |
292 | |
293 | template <class T> |
294 | struct VariantInternalAccessor<Ref<T>> { |
295 | static _FORCE_INLINE_ Ref<T> get(const Variant *v) { return Ref<T>(*VariantInternal::get_object(v)); } |
296 | static _FORCE_INLINE_ void set(Variant *v, const Ref<T> &p_ref) { VariantInternal::refcounted_object_assign(v, p_ref.ptr()); } |
297 | }; |
298 | |
299 | template <class T> |
300 | struct VariantInternalAccessor<const Ref<T> &> { |
301 | static _FORCE_INLINE_ Ref<T> get(const Variant *v) { return Ref<T>(*VariantInternal::get_object(v)); } |
302 | static _FORCE_INLINE_ void set(Variant *v, const Ref<T> &p_ref) { VariantInternal::refcounted_object_assign(v, p_ref.ptr()); } |
303 | }; |
304 | |
305 | #endif // REF_COUNTED_H |
306 | |