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