1 /*************************************************************************/
2 /*  reference.h                                                          */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
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 REFERENCE_H
32 #define REFERENCE_H
33 
34 #include "core/class_db.h"
35 #include "core/object.h"
36 #include "core/ref_ptr.h"
37 #include "core/safe_refcount.h"
38 
39 class Reference : public Object {
40 
41 	GDCLASS(Reference, Object);
42 	friend class RefBase;
43 	SafeRefCount refcount;
44 	SafeRefCount refcount_init;
45 
46 protected:
47 	static void _bind_methods();
48 
49 public:
is_referenced()50 	_FORCE_INLINE_ bool is_referenced() const { return refcount_init.get() != 1; }
51 	bool init_ref();
52 	bool reference(); // returns false if refcount is at zero and didn't get increased
53 	bool unreference();
54 	int reference_get_count() const;
55 
56 	Reference();
57 	~Reference();
58 };
59 
60 template <class T>
61 class Ref {
62 
63 	T *reference;
64 
ref(const Ref & p_from)65 	void ref(const Ref &p_from) {
66 
67 		if (p_from.reference == reference)
68 			return;
69 
70 		unref();
71 
72 		reference = p_from.reference;
73 		if (reference)
74 			reference->reference();
75 	}
76 
ref_pointer(T * p_ref)77 	void ref_pointer(T *p_ref) {
78 
79 		ERR_FAIL_COND(!p_ref);
80 
81 		if (p_ref->init_ref())
82 			reference = p_ref;
83 	}
84 
85 	//virtual Reference * get_reference() const { return reference; }
86 public:
87 	_FORCE_INLINE_ bool operator==(const T *p_ptr) const {
88 		return reference == p_ptr;
89 	}
90 	_FORCE_INLINE_ bool operator!=(const T *p_ptr) const {
91 		return reference != p_ptr;
92 	}
93 
94 	_FORCE_INLINE_ bool operator<(const Ref<T> &p_r) const {
95 
96 		return reference < p_r.reference;
97 	}
98 	_FORCE_INLINE_ bool operator==(const Ref<T> &p_r) const {
99 
100 		return reference == p_r.reference;
101 	}
102 	_FORCE_INLINE_ bool operator!=(const Ref<T> &p_r) const {
103 
104 		return reference != p_r.reference;
105 	}
106 
107 	_FORCE_INLINE_ T *operator->() {
108 
109 		return reference;
110 	}
111 
112 	_FORCE_INLINE_ T *operator*() {
113 
114 		return reference;
115 	}
116 
117 	_FORCE_INLINE_ const T *operator->() const {
118 
119 		return reference;
120 	}
121 
ptr()122 	_FORCE_INLINE_ const T *ptr() const {
123 
124 		return reference;
125 	}
ptr()126 	_FORCE_INLINE_ T *ptr() {
127 
128 		return reference;
129 	}
130 
131 	_FORCE_INLINE_ const T *operator*() const {
132 
133 		return reference;
134 	}
135 
get_ref_ptr()136 	RefPtr get_ref_ptr() const {
137 
138 		RefPtr refptr;
139 		Ref<Reference> *irr = reinterpret_cast<Ref<Reference> *>(refptr.get_data());
140 		*irr = *this;
141 		return refptr;
142 	};
143 
Variant()144 	operator Variant() const {
145 
146 		return Variant(get_ref_ptr());
147 	}
148 
149 	void operator=(const Ref &p_from) {
150 
151 		ref(p_from);
152 	}
153 
154 	template <class T_Other>
155 	void operator=(const Ref<T_Other> &p_from) {
156 
157 		Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr()));
158 		if (!refb) {
159 			unref();
160 			return;
161 		}
162 		Ref r;
163 		r.reference = Object::cast_to<T>(refb);
164 		ref(r);
165 		r.reference = NULL;
166 	}
167 
168 	void operator=(const RefPtr &p_refptr) {
169 
170 		Ref<Reference> *irr = reinterpret_cast<Ref<Reference> *>(p_refptr.get_data());
171 		Reference *refb = irr->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 = NULL;
180 	}
181 
182 	void operator=(const Variant &p_variant) {
183 
184 		RefPtr refptr = p_variant;
185 		Ref<Reference> *irr = reinterpret_cast<Ref<Reference> *>(refptr.get_data());
186 		Reference *refb = irr->ptr();
187 		if (!refb) {
188 			unref();
189 			return;
190 		}
191 		Ref r;
192 		r.reference = Object::cast_to<T>(refb);
193 		ref(r);
194 		r.reference = NULL;
195 	}
196 
197 	template <class T_Other>
reference_ptr(T_Other * p_ptr)198 	void reference_ptr(T_Other *p_ptr) {
199 		if (reference == p_ptr) {
200 			return;
201 		}
202 		unref();
203 
204 		T *r = Object::cast_to<T>(p_ptr);
205 		if (r) {
206 			ref_pointer(r);
207 		}
208 	}
209 
Ref(const Ref & p_from)210 	Ref(const Ref &p_from) {
211 
212 		reference = NULL;
213 		ref(p_from);
214 	}
215 
216 	template <class T_Other>
Ref(const Ref<T_Other> & p_from)217 	Ref(const Ref<T_Other> &p_from) {
218 
219 		reference = NULL;
220 		Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr()));
221 		if (!refb) {
222 			unref();
223 			return;
224 		}
225 		Ref r;
226 		r.reference = Object::cast_to<T>(refb);
227 		ref(r);
228 		r.reference = NULL;
229 	}
230 
Ref(T * p_reference)231 	Ref(T *p_reference) {
232 
233 		reference = NULL;
234 		if (p_reference)
235 			ref_pointer(p_reference);
236 	}
237 
Ref(const Variant & p_variant)238 	Ref(const Variant &p_variant) {
239 
240 		RefPtr refptr = p_variant;
241 		Ref<Reference> *irr = reinterpret_cast<Ref<Reference> *>(refptr.get_data());
242 		reference = NULL;
243 		Reference *refb = irr->ptr();
244 		if (!refb) {
245 			unref();
246 			return;
247 		}
248 		Ref r;
249 		r.reference = Object::cast_to<T>(refb);
250 		ref(r);
251 		r.reference = NULL;
252 	}
253 
Ref(const RefPtr & p_refptr)254 	Ref(const RefPtr &p_refptr) {
255 
256 		Ref<Reference> *irr = reinterpret_cast<Ref<Reference> *>(p_refptr.get_data());
257 		reference = NULL;
258 		Reference *refb = irr->ptr();
259 		if (!refb) {
260 			unref();
261 			return;
262 		}
263 		Ref r;
264 		r.reference = Object::cast_to<T>(refb);
265 		ref(r);
266 		r.reference = NULL;
267 	}
268 
is_valid()269 	inline bool is_valid() const { return reference != NULL; }
is_null()270 	inline bool is_null() const { return reference == NULL; }
271 
unref()272 	void unref() {
273 		//TODO this should be moved to mutexes, since this engine does not really
274 		// do a lot of referencing on references and stuff
275 		// mutexes will avoid more crashes?
276 
277 		if (reference && reference->unreference()) {
278 
279 			memdelete(reference);
280 		}
281 		reference = NULL;
282 	}
283 
instance()284 	void instance() {
285 		ref(memnew(T));
286 	}
287 
Ref()288 	Ref() {
289 
290 		reference = NULL;
291 	}
292 
~Ref()293 	~Ref() {
294 
295 		unref();
296 	}
297 };
298 
299 typedef Ref<Reference> REF;
300 
301 class WeakRef : public Reference {
302 
303 	GDCLASS(WeakRef, Reference);
304 
305 	ObjectID ref;
306 
307 protected:
308 	static void _bind_methods();
309 
310 public:
311 	Variant get_ref() const;
312 	void set_obj(Object *p_object);
313 	void set_ref(const REF &p_ref);
314 
315 	WeakRef();
316 };
317 
318 #ifdef PTRCALL_ENABLED
319 
320 template <class T>
321 struct PtrToArg<Ref<T> > {
322 
323 	_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
324 
325 		return Ref<T>(const_cast<T *>(reinterpret_cast<const T *>(p_ptr)));
326 	}
327 
328 	_FORCE_INLINE_ static void encode(Ref<T> p_val, const void *p_ptr) {
329 
330 		*(Ref<Reference> *)p_ptr = p_val;
331 	}
332 };
333 
334 template <class T>
335 struct PtrToArg<const Ref<T> &> {
336 
337 	_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
338 
339 		return Ref<T>((T *)p_ptr);
340 	}
341 };
342 
343 //this is for RefPtr
344 
345 template <>
346 struct PtrToArg<RefPtr> {
347 
348 	_FORCE_INLINE_ static RefPtr convert(const void *p_ptr) {
349 
350 		return Ref<Reference>(const_cast<Reference *>(reinterpret_cast<const Reference *>(p_ptr))).get_ref_ptr();
351 	}
352 
353 	_FORCE_INLINE_ static void encode(RefPtr p_val, const void *p_ptr) {
354 
355 		Ref<Reference> r = p_val;
356 		*(Ref<Reference> *)p_ptr = r;
357 	}
358 };
359 
360 template <>
361 struct PtrToArg<const RefPtr &> {
362 
363 	_FORCE_INLINE_ static RefPtr convert(const void *p_ptr) {
364 
365 		return Ref<Reference>(const_cast<Reference *>(reinterpret_cast<const Reference *>(p_ptr))).get_ref_ptr();
366 	}
367 };
368 
369 #endif // PTRCALL_ENABLED
370 
371 #ifdef DEBUG_METHODS_ENABLED
372 
373 template <class T>
374 struct GetTypeInfo<Ref<T> > {
375 	static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
376 	static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
377 
378 	static inline PropertyInfo get_class_info() {
379 		return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
380 	}
381 };
382 
383 template <class T>
384 struct GetTypeInfo<const Ref<T> &> {
385 	static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
386 	static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
387 
388 	static inline PropertyInfo get_class_info() {
389 		return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
390 	}
391 };
392 
393 #endif // DEBUG_METHODS_ENABLED
394 
395 #endif // REFERENCE_H
396