L4Re - L4 Runtime Environment
weak_ref
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 
14 namespace 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  */
25 class Weak_ref_base : public H_list_item_t<Weak_ref_base>
26 {
27 protected:
28  Weak_ref_base(void const *ptr = nullptr) : _obj(ptr) {}
29  void reset_hard() { _obj = nullptr; }
30  void const *_obj;
31 
32 public:
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  */
66 template <typename T>
67 class Weak_ref : public Weak_ref_base
68 {
69 public:
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 
116 class Weak_ref_obj
117 {
118 protected:
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 }