1// vi:set ft=cpp: -*- Mode: C++ -*- 2/* 3 * Copyright (C) 2015 Kernkonzept GmbH. 4 * Author(s): Sarah Hoffmann <sarah.hoffmann@kernkonzept.com> 5 * Alwexander Warg <alexander.warg@kernkonzept.com> 6 * 7 * This file is distributed under the terms of the GNU General Public 8 * License, version 2. Please see the COPYING-GPL-2 file for details. 9 */ 10#pragma once 11 12#include "hlist" 13 14namespace cxx { 15 16/** 17 * Generic (base) weak reference to some object. 18 * 19 * A weak reference is a reference that gets reset to NULL when the object 20 * shall be deleted. All weak references to the same object are kept in a 21 * linked list of weak references. 22 * 23 * For typed weak references see `cxx::Weak_ref`. 24 */ 25class Weak_ref_base : public H_list_item_t<Weak_ref_base> 26{ 27protected: 28 Weak_ref_base(void const *ptr = nullptr) : _obj(ptr) {} 29 void reset_hard() { _obj = nullptr; } 30 void const *_obj; 31 32public: 33 struct List : H_list_t<Weak_ref_base> 34 { 35 void reset() 36 { 37 while (!empty()) 38 pop_front()->reset_hard(); 39 } 40 41 ~List() 42 { reset(); } 43 }; 44 45 explicit operator bool () const 46 { return _obj ? true : false; } 47}; 48 49 50/** 51 * Typed weak reference to an object of type `T`. 52 * 53 * \tparam T The type of the referenced object. 54 * 55 * A weak reference is a reference that is invalidated when the referenced 56 * object is about to be deleted. All weak references to an object are kept in 57 * a linked list and all the weak references are iterated and reset by the 58 * Weak_ref_base::List destructor or Weak_ref_base::reset(). 59 * 60 * The type `T` must provide two methods that handle the housekeeping of weak 61 * references: remove_weak_ref(Weak_ref_base *) and add_weak_ref(Weak_ref_base *). 62 * These functions must handle the insertion and removal of the weak reference 63 * into the respective Weak_ref_base::List object. For convenience one can use the 64 * cxx::Weak_ref_obj as a base class that handles weak references for you. 65 */ 66template <typename T> 67class Weak_ref : public Weak_ref_base 68{ 69public: 70 T *get() const 71 { return reinterpret_cast<T*>(const_cast<void *>(_obj)); } 72 73 T *reset(T *n) 74 { 75 T *r = get(); 76 if (r) 77 r->remove_weak_ref(this); 78 79 _obj = n; 80 if (n) 81 n->add_weak_ref(this); 82 83 return r; 84 } 85 86 Weak_ref(T *s = nullptr) : Weak_ref_base(s) 87 { 88 if (s) 89 s->add_weak_ref(this); 90 } 91 92 ~Weak_ref() { reset(0); } 93 94 void operator = (T *n) 95 { reset(n); } 96 97 Weak_ref(Weak_ref const &o) : Weak_ref_base(o._obj) 98 { 99 if (T *x = get()) 100 x->add_weak_ref(this); 101 } 102 103 Weak_ref &operator = (Weak_ref const &o) 104 { 105 if (&o == this) 106 return *this; 107 108 reset(o.get()); 109 return *this; 110 } 111 112 T &operator * () const { return get(); } 113 T *operator -> () const { return get(); } 114}; 115 116class Weak_ref_obj 117{ 118protected: 119 template <typename T> friend class Weak_ref; 120 mutable Weak_ref_base::List weak_references; 121 122 void add_weak_ref(Weak_ref_base *ref) const 123 { weak_references.push_front(ref); } 124 125 void remove_weak_ref(Weak_ref_base *ref) const 126 { weak_references.remove(ref); } 127}; 128 129} 130