1 #ifndef _GLIBMM_WEAKREF_H
2 #define _GLIBMM_WEAKREF_H
3 
4 /* Copyright (C) 2015 The glibmm Development Team
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <glib-object.h>
21 #include <glibmm/refptr.h>
22 #include <glibmm/objectbase.h>
23 #include <type_traits> // std::is_base_of<>
24 #include <utility> // std::swap<>, std::forward<>
25 
26 namespace Glib
27 {
28 
29 /** WeakRef<> is a weak reference smartpointer.
30  *
31  * WeakRef can store a pointer to any class that is derived from Glib::ObjectBase,
32  * and whose reference() method is noexcept.
33  * In glibmm and gtkmm, that is anything derived from Glib::ObjectBase.
34  *
35  * Unlike a RefPtr, a WeakRef does not contribute to the reference counting of
36  * the underlying object.
37  *
38  * @newin{2,46}
39  */
40 template <typename T_CppObject>
41 class WeakRef
42 {
43   static_assert(std::is_base_of<Glib::ObjectBase, T_CppObject>::value,
44     "Glib::WeakRef can be used only for classes derived from Glib::ObjectBase.");
45 
46 public:
47   /** Default constructor.
48    *
49    * Create an empty weak reference.
50    */
51   inline WeakRef() noexcept;
52 
53   /// Copy constructor.
54   inline WeakRef(const WeakRef& src) noexcept;
55 
56   /// Move constructor.
57   inline WeakRef(WeakRef&& src) noexcept;
58 
59   /// Copy constructor from different, but castable type.
60   template <typename T_CastFrom>
61   inline WeakRef(const WeakRef<T_CastFrom>& src) noexcept;
62 
63   /// Move constructor from different, but castable type.
64   template <typename T_CastFrom>
65   inline WeakRef(WeakRef<T_CastFrom>&& src) noexcept;
66 
67   /** Constructor from a RefPtr of the same or a castable type.
68    *
69    * Create a weak reference from a RefPtr of the same or a castable type.
70    * If the RefPtr references nothing, an empty weak reference will be constructed.
71    */
72   template <typename T_CastFrom>
73   inline WeakRef(const RefPtr<T_CastFrom>& src) noexcept;
74 
75   /// Destructor.
76   inline ~WeakRef() noexcept;
77 
78   /// Swap the contents of two WeakRef<>.
79   inline void swap(WeakRef& other) noexcept;
80 
81   /// Copy assignment operator.
82   inline WeakRef& operator=(const WeakRef& src) noexcept;
83 
84   /// Move assignment operator.
85   inline WeakRef& operator=(WeakRef&& src) noexcept;
86 
87   /// Copy assignment from different, but castable type.
88   template <typename T_CastFrom>
89   inline WeakRef& operator=(const WeakRef<T_CastFrom>& src) noexcept;
90 
91   /// Move assignment from different, but castable type.
92   template <typename T_CastFrom>
93   inline WeakRef& operator=(WeakRef<T_CastFrom>&& src) noexcept;
94 
95   /// Assignment from a RefPtr of the same or a castable type.
96   template <typename T_CastFrom>
97   inline WeakRef& operator=(const RefPtr<T_CastFrom>& src) noexcept;
98 
99   /** Test whether the WeakRef<> points to any underlying instance.
100    *
101    * Mimics usage of ordinary pointers:
102    * @code
103    * if (ptr)
104    *   do_something();
105    * @endcode
106    *
107    * In a multi-threaded program a <tt>true</tt> return value can become
108    * obsolete at any time, even before the caller has a chance to test it,
109    * because the underlying instance may lose its last reference in another
110    * thread. Use get() if this is not acceptable.
111    */
112   inline explicit operator bool() const noexcept;
113 
114   /** Create a strong reference to the underlying object.
115    *
116    * This is a thread-safe way to acquire a strong reference to the underlying
117    * object. If the WeakRef is empty, the returned RefPtr will reference nothing.
118    */
119   inline RefPtr<T_CppObject> get() const noexcept;
120 
121   /// Make this WeakRef empty.
122   inline void reset() noexcept;
123 
124   /** Dynamic cast to derived class.
125    *
126    * The WeakRef can't be cast with the usual notation so instead you can use
127    * @code
128    * ptr_derived = Glib::WeakRef<Derived>::cast_dynamic(ptr_base);
129    * @endcode
130    */
131   template <typename T_CastFrom>
132   static inline WeakRef cast_dynamic(const WeakRef<T_CastFrom>& src) noexcept;
133 
134   /** Static cast to derived class.
135    *
136    * The WeakRef can't be cast with the usual notation so instead you can use
137    * @code
138    * ptr_derived = Glib::WeakRef<Derived>::cast_static(ptr_base);
139    * @endcode
140    */
141   template <typename T_CastFrom>
142   static inline WeakRef cast_static(const WeakRef<T_CastFrom>& src) noexcept;
143 
144   /** Cast to non-const.
145    *
146    * The WeakRef can't be cast with the usual notation so instead you can use
147    * @code
148    * ptr_nonconst = Glib::WeakRef<NonConstType>::cast_const(ptr_const);
149    * @endcode
150    */
151   template <typename T_CastFrom>
152   static inline WeakRef cast_const(const WeakRef<T_CastFrom>& src) noexcept;
153 
154 private:
155   // Let all instantiations of WeakRef access private data.
156   template <typename T_CastFrom>
157   friend class WeakRef;
158 
159   // If pCppObject != nullptr && gobject == nullptr,
160   // then the caller holds a strong reference.
161   void set(T_CppObject* pCppObject, GWeakRef* gobject) noexcept;
162 
163   // WeakRef owns *gobject_, but it does not own *pCppObject_.
164   // Invariant: (!pCppObject_ || gobject_),
165   // i.e. if pCppObject_ != nullptr then also gobject_ != nullptr.
166   T_CppObject* pCppObject_;
167   GWeakRef* gobject_;
168 
169   // Some methods would be simpler if gobject_ were a GWeakRef instead of
170   // a GWeakRef*, but then the move constructor and the move assignment
171   // operation would not be efficient.
172 
173 }; // end class WeakRef
174 
175 #ifndef DOXYGEN_SHOULD_SKIP_THIS
176 
177 template <typename T_CppObject>
WeakRef()178 WeakRef<T_CppObject>::WeakRef() noexcept : pCppObject_(nullptr), gobject_(nullptr)
179 {
180 }
181 
182 template <typename T_CppObject>
WeakRef(const WeakRef & src)183 WeakRef<T_CppObject>::WeakRef(const WeakRef& src) noexcept : pCppObject_(src.pCppObject_),
184                                                              gobject_(nullptr)
185 {
186   if (pCppObject_)
187   {
188     // We must own a strong reference to the underlying GObject while
189     // calling g_weak_ref_init().
190     gpointer ptr = g_weak_ref_get(src.gobject_);
191     if (ptr)
192     {
193       gobject_ = new GWeakRef;
194       g_weak_ref_init(gobject_, pCppObject_->gobj());
195       g_object_unref(ptr);
196     }
197     else
198       pCppObject_ = nullptr;
199   }
200 }
201 
202 template <typename T_CppObject>
WeakRef(WeakRef && src)203 WeakRef<T_CppObject>::WeakRef(WeakRef&& src) noexcept : pCppObject_(src.pCppObject_),
204                                                         gobject_(src.gobject_)
205 {
206   src.pCppObject_ = nullptr;
207   src.gobject_ = nullptr;
208 }
209 
210 // The templated ctor allows copy construction from any object that's
211 // castable. Thus, it does downcasts:
212 //   base_ref = derived_ref
213 template <typename T_CppObject>
214 template <typename T_CastFrom>
WeakRef(const WeakRef<T_CastFrom> & src)215 WeakRef<T_CppObject>::WeakRef(const WeakRef<T_CastFrom>& src) noexcept
216   : pCppObject_(src.pCppObject_),
217     gobject_(nullptr)
218 {
219   if (pCppObject_)
220   {
221     // We must own a strong reference to the underlying GObject while
222     // calling g_weak_ref_init().
223     gpointer ptr = g_weak_ref_get(src.gobject_);
224     if (ptr)
225     {
226       gobject_ = new GWeakRef;
227       g_weak_ref_init(gobject_, pCppObject_->gobj());
228       g_object_unref(ptr);
229     }
230     else
231       pCppObject_ = nullptr;
232   }
233 }
234 
235 // The templated ctor allows move construction from any object that's
236 // castable. Thus, it does downcasts:
237 //   base_ref = std::move(derived_ref)
238 template <typename T_CppObject>
239 template <typename T_CastFrom>
WeakRef(WeakRef<T_CastFrom> && src)240 WeakRef<T_CppObject>::WeakRef(WeakRef<T_CastFrom>&& src) noexcept : pCppObject_(src.pCppObject_),
241                                                                     gobject_(src.gobject_)
242 {
243   src.pCppObject_ = nullptr;
244   src.gobject_ = nullptr;
245 }
246 
247 template <typename T_CppObject>
248 template <typename T_CastFrom>
WeakRef(const RefPtr<T_CastFrom> & src)249 WeakRef<T_CppObject>::WeakRef(const RefPtr<T_CastFrom>& src) noexcept
250   : pCppObject_(src.operator->()),
251     gobject_(nullptr)
252 {
253   if (pCppObject_)
254   {
255     gobject_ = new GWeakRef;
256     g_weak_ref_init(gobject_, pCppObject_->gobj());
257   }
258 }
259 
260 template <typename T_CppObject>
~WeakRef()261 WeakRef<T_CppObject>::~WeakRef() noexcept
262 {
263   if (gobject_)
264   {
265     g_weak_ref_clear(gobject_);
266     delete gobject_;
267   }
268 }
269 
270 template <class T_CppObject>
271 void
swap(WeakRef & other)272 WeakRef<T_CppObject>::swap(WeakRef& other) noexcept
273 {
274   std::swap(pCppObject_, other.pCppObject_);
275   std::swap(gobject_, other.gobject_);
276 }
277 
278 template <typename T_CppObject>
279 WeakRef<T_CppObject>&
280 WeakRef<T_CppObject>::operator=(const WeakRef& src) noexcept
281 {
282   set(src.pCppObject_, src.gobject_);
283   return *this;
284 }
285 
286 template <typename T_CppObject>
287 WeakRef<T_CppObject>&
288 WeakRef<T_CppObject>::operator=(WeakRef&& src) noexcept
289 {
290   // See RefPtr for an explanation of the swap() technique to implement
291   // copy assignment and move assignment.
292   // This technique is inefficient for copy assignment of WeakRef,
293   // because it involves copy construction + destruction, i.e. in a typical
294   // case g_weak_ref_init() + g_weak_ref_clear(), when a g_weak_ref_set()
295   // would be enough. For move assignment, the swap technique is fine.
296   WeakRef<T_CppObject> temp(std::forward<WeakRef<T_CppObject>>(src));
297   this->swap(temp);
298   return *this;
299 }
300 
301 template <typename T_CppObject>
302 template <typename T_CastFrom>
303 WeakRef<T_CppObject>&
304 WeakRef<T_CppObject>::operator=(const WeakRef<T_CastFrom>& src) noexcept
305 {
306   set(src.pCppObject_, src.gobject_);
307   return *this;
308 }
309 
310 template <typename T_CppObject>
311 template <typename T_CastFrom>
312 WeakRef<T_CppObject>&
313 WeakRef<T_CppObject>::operator=(WeakRef<T_CastFrom>&& src) noexcept
314 {
315   WeakRef<T_CppObject> temp(std::forward<WeakRef<T_CastFrom>>(src));
316   this->swap(temp);
317   return *this;
318 }
319 
320 template <typename T_CppObject>
321 template <typename T_CastFrom>
322 WeakRef<T_CppObject>&
323 WeakRef<T_CppObject>::operator=(const RefPtr<T_CastFrom>& src) noexcept
324 {
325   T_CppObject* pCppObject = src.operator->();
326   set(pCppObject, nullptr);
327   return *this;
328 }
329 
330 template <class T_CppObject>
331 WeakRef<T_CppObject>::operator bool() const noexcept
332 {
333   if (!pCppObject_)
334     return false;
335 
336   gpointer ptr = g_weak_ref_get(gobject_);
337   if (!ptr)
338     return false;
339 
340   g_object_unref(ptr);
341   return true;
342 }
343 
344 template <typename T_CppObject>
345 RefPtr<T_CppObject>
get()346 WeakRef<T_CppObject>::get() const noexcept
347 {
348   RefPtr<T_CppObject> ret;
349 
350   if (!pCppObject_)
351     return ret;
352 
353   gpointer ptr = g_weak_ref_get(gobject_);
354   if (!ptr)
355     return ret;
356 
357   // A RefPtr constructed from pointer expects reference to be done externally.
358   pCppObject_->reference();
359   ret = RefPtr<T_CppObject>(pCppObject_);
360 
361   g_object_unref(ptr);
362 
363   return ret;
364 }
365 
366 template <typename T_CppObject>
367 void
reset()368 WeakRef<T_CppObject>::reset() noexcept
369 {
370   set(nullptr, nullptr);
371 }
372 
373 template <typename T_CppObject>
374 template <typename T_CastFrom>
375 WeakRef<T_CppObject>
cast_dynamic(const WeakRef<T_CastFrom> & src)376 WeakRef<T_CppObject>::cast_dynamic(const WeakRef<T_CastFrom>& src) noexcept
377 {
378   WeakRef<T_CppObject> ret;
379 
380   if (!src.pCppObject_)
381     return ret;
382 
383   gpointer ptr = g_weak_ref_get(src.gobject_);
384   if (!ptr)
385     return ret;
386 
387   // Don't call dynamic_cast<>() unless we know that the referenced object
388   // still exists.
389   T_CppObject* const pCppObject = dynamic_cast<T_CppObject*>(src.pCppObject_);
390   ret.set(pCppObject, nullptr);
391   g_object_unref(ptr);
392 
393   return ret;
394 }
395 
396 template <typename T_CppObject>
397 template <typename T_CastFrom>
398 WeakRef<T_CppObject>
cast_static(const WeakRef<T_CastFrom> & src)399 WeakRef<T_CppObject>::cast_static(const WeakRef<T_CastFrom>& src) noexcept
400 {
401   T_CppObject* const pCppObject = static_cast<T_CppObject*>(src.pCppObject_);
402 
403   WeakRef<T_CppObject> ret;
404   ret.set(pCppObject, src.gobject_);
405   return ret;
406 }
407 
408 template <typename T_CppObject>
409 template <typename T_CastFrom>
410 WeakRef<T_CppObject>
cast_const(const WeakRef<T_CastFrom> & src)411 WeakRef<T_CppObject>::cast_const(const WeakRef<T_CastFrom>& src) noexcept
412 {
413   T_CppObject* const pCppObject = const_cast<T_CppObject*>(src.pCppObject_);
414 
415   WeakRef<T_CppObject> ret;
416   ret.set(pCppObject, src.gobject_);
417   return ret;
418 }
419 
420 template <typename T_CppObject>
421 void
set(T_CppObject * pCppObject,GWeakRef * gobject)422 WeakRef<T_CppObject>::set(T_CppObject* pCppObject, GWeakRef* gobject) noexcept
423 {
424   // We must own a strong reference to the underlying GObject while
425   // calling g_weak_ref_init() or g_weak_ref_set().
426   // If pCppObject != nullptr && gobject == nullptr,
427   // then the caller holds a strong reference.
428 
429   // An aim with this moderately complicated method is to keep the same
430   // GWeakRef, calling g_weak_ref_set() when possible, instead of using swap(),
431   // which implies creating a new WeakRef, swapping with *this, and deleting
432   // the new WeakRef.
433 
434   gpointer ptr = nullptr;
435   if (pCppObject && gobject)
436     ptr = g_weak_ref_get(gobject);
437 
438   pCppObject_ = (ptr || !gobject) ? pCppObject : nullptr;
439   if (pCppObject_ && !gobject_)
440   {
441     gobject_ = new GWeakRef;
442     g_weak_ref_init(gobject_, pCppObject_->gobj());
443   }
444   else if (gobject_)
445     g_weak_ref_set(gobject_, pCppObject_ ? pCppObject_->gobj() : nullptr);
446 
447   if (ptr)
448     g_object_unref(ptr);
449 }
450 
451 #endif // DOXYGEN_SHOULD_SKIP_THIS
452 
453 /** Swap the contents of two WeakRef<>.
454  * @relates Glib::WeakRef
455  */
456 template <class T_CppObject>
457 inline void
swap(WeakRef<T_CppObject> & lhs,WeakRef<T_CppObject> & rhs)458 swap(WeakRef<T_CppObject>& lhs, WeakRef<T_CppObject>& rhs) noexcept
459 {
460   lhs.swap(rhs);
461 }
462 
463 } // namespace Glib
464 
465 #endif // _GLIBMM_WEAKREF_H
466