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
37class RefCounted : public Object {
38 GDCLASS(RefCounted, Object);
39 SafeRefCount refcount;
40 SafeRefCount refcount_init;
41
42protected:
43 static void _bind_methods();
44
45public:
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
56template <class T>
57class 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; }
82public:
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
226class WeakRef : public RefCounted {
227 GDCLASS(WeakRef, RefCounted);
228
229 ObjectID ref;
230
231protected:
232 static void _bind_methods();
233
234public:
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
242template <class T>
243struct 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
260template <class T>
261struct 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
273template <class T>
274struct 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
283template <class T>
284struct 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
293template <class T>
294struct 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
299template <class T>
300struct 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