@@ -42,30 +42,34 @@ namespace godot {
4242
4343// Helper class for RefCounted objects, same as Godot one.
4444
45- class RefCounted ;
46-
4745template <typename T>
4846class Ref {
4947 T *reference = nullptr ;
5048
51- void ref (const Ref &p_from) {
52- if (p_from.reference == reference) {
49+ _FORCE_INLINE_ void ref (const Ref &p_from) {
50+ ref_pointer<false >(p_from.reference );
51+ }
52+
53+ template <bool Init>
54+ _FORCE_INLINE_ void ref_pointer (T *p_refcounted) {
55+ if (p_refcounted == reference) {
5356 return ;
5457 }
5558
56- unref ();
57-
58- reference = p_from.reference ;
59+ // This will go out of scope and get unref'd.
60+ Ref cleanup_ref;
61+ cleanup_ref.reference = reference;
62+ reference = p_refcounted;
5963 if (reference) {
60- reference-> reference ();
61- }
62- }
63-
64- void ref_pointer (T *p_ref) {
65- ERR_FAIL_NULL (p_ref);
66-
67- if (p_ref-> init_ref ()) {
68- reference = p_ref;
64+ if constexpr (Init) {
65+ if (!reference-> init_ref ()) {
66+ reference = nullptr ;
67+ }
68+ } else {
69+ if (!reference-> reference ()) {
70+ reference = nullptr ;
71+ }
72+ }
6973 }
7074 }
7175
@@ -111,110 +115,88 @@ class Ref {
111115 ref (p_from);
112116 }
113117
114- template <typename T_Other>
115- void operator =(const Ref<T_Other> &p_from) {
116- RefCounted *refb = const_cast <RefCounted *>(static_cast <const RefCounted *>(p_from.ptr ()));
117- if (!refb) {
118- unref ();
118+ void operator =(Ref &&p_from) {
119+ if (reference == p_from.reference ) {
119120 return ;
120121 }
122+ unref ();
123+ reference = p_from.reference ;
124+ p_from.reference = nullptr ;
125+ }
121126
122- Ref r;
123- r.reference = Object::cast_to<T>(refb);
124- ref (r);
125- r.reference = nullptr ;
127+ template <typename T_Other>
128+ void operator =(const Ref<T_Other> &p_from) {
129+ ref_pointer<false >(Object::cast_to<T>(p_from.ptr ()));
126130 }
127131
128- void operator =(const Variant &p_variant) {
129- // Needs testing, Variant has a cast to Object * here.
132+ void operator =(T *p_from) {
133+ ref_pointer<true >(p_from);
134+ }
130135
131- // Object *object = p_variant.get_validated_object();
132- Object *object = p_variant;
136+ void operator =( const Variant & p_variant) {
137+ Object *object = p_variant. get_validated_object () ;
133138
134139 if (object == reference) {
135140 return ;
136141 }
137142
138- unref ();
139-
140- if (!object) {
141- return ;
142- }
143-
144- T *r = Object::cast_to<T>(object);
145- if (r && r->reference ()) {
146- reference = r;
147- }
143+ ref_pointer<false >(Object::cast_to<T>(object));
148144 }
149145
150146 template <typename T_Other>
151147 void reference_ptr (T_Other *p_ptr) {
152148 if (reference == p_ptr) {
153149 return ;
154150 }
155- unref ();
156151
157- T *r = Object::cast_to<T>(p_ptr);
158- if (r) {
159- ref_pointer (r);
160- }
152+ ref_pointer<true >(Object::cast_to<T>(p_ptr));
161153 }
162154
163155 Ref (const Ref &p_from) {
164- ref (p_from);
156+ this ->operator =(p_from);
157+ }
158+
159+ Ref (Ref &&p_from) {
160+ reference = p_from.reference ;
161+ p_from.reference = nullptr ;
165162 }
166163
167164 template <typename T_Other>
168165 Ref (const Ref<T_Other> &p_from) {
169- RefCounted *refb = const_cast <RefCounted *>(static_cast <const RefCounted *>(p_from.ptr ()));
170- if (!refb) {
171- unref ();
172- return ;
173- }
174-
175- Ref r;
176- r.reference = Object::cast_to<T>(refb);
177- ref (r);
178- r.reference = nullptr ;
166+ this ->operator =(p_from);
179167 }
180168
181- Ref (T *p_reference) {
182- if (p_reference) {
183- ref_pointer (p_reference);
184- }
169+ Ref (T *p_from) {
170+ this ->operator =(p_from);
185171 }
186172
187- Ref (const Variant &p_variant) {
188- // Needs testing, Variant has a cast to Object * here.
189-
190- // Object *object = p_variant.get_validated_object();
191- Object *object = p_variant;
192-
193- if (!object) {
194- return ;
195- }
196-
197- T *r = Object::cast_to<T>(object);
198- if (r && r->reference ()) {
199- reference = r;
200- }
173+ Ref (const Variant &p_from) {
174+ this ->operator =(p_from);
201175 }
202176
203177 inline bool is_valid () const { return reference != nullptr ; }
204178 inline bool is_null () const { return reference == nullptr ; }
205179
206180 void unref () {
207- if (reference && reference->unreference ()) {
208- memdelete (reference);
181+ if (reference) {
182+ // NOTE: `reinterpret_cast` is "safe" here because we know `T` has simple linear
183+ // inheritance to `RefCounted`. This guarantees that `T * == `RefCounted *`, which
184+ // allows us to declare `Ref<T>` with forward declared `T` types.
185+ if (reinterpret_cast <RefCounted *>(reference)->unreference ()) {
186+ memdelete (reinterpret_cast <RefCounted *>(reference));
187+ }
188+ reference = nullptr ;
209189 }
210- reference = nullptr ;
211190 }
212191
213- void instantiate () {
214- ref (memnew (T ()));
192+ template <typename ... VarArgs>
193+ void instantiate (VarArgs... p_params) {
194+ ref (memnew (T (p_params...)));
215195 }
216196
217- Ref () {}
197+ uint32_t hash () const { return HashMapHasherDefault::hash (reference); }
198+
199+ Ref () = default ;
218200
219201 ~Ref () {
220202 unref ();
@@ -224,7 +206,7 @@ class Ref {
224206 // without adding to the refcount.
225207 inline static Ref<T> _gde_internal_constructor (Object *obj) {
226208 Ref<T> r;
227- r.reference = ( T *) obj;
209+ r.reference = reinterpret_cast < T *>( obj) ;
228210 return r;
229211 }
230212};
0 commit comments