1// vim:set ft=cpp: -*- Mode: C++ -*-
2/*
3 * (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
4 *     economic rights: Technische Universität Dresden (Germany)
5 *
6 * This file is part of TUD:OS and distributed under the terms of the
7 * GNU General Public License 2.
8 * Please see the COPYING-GPL-2 file for details.
9 *
10 * As a special exception, you may use this file as part of a free software
11 * library without restriction.  Specifically, if other files instantiate
12 * templates or use macros or inline functions from this file, or you compile
13 * this file and link it with other files to produce an executable, this
14 * file does not by itself cause the resulting executable to be covered by
15 * the GNU General Public License.  This exception does not however
16 * invalidate any other reasons why the executable file might be covered by
17 * the GNU General Public License.
18 */
19
20#pragma once
21
22#include "type_traits"
23#include <cstddef>
24#include <l4/sys/compiler.h>
25
26namespace cxx {
27
28template< typename T >
29struct Default_ref_counter
30{
31  void h_drop_ref(T *p) noexcept
32  {
33    if (p->remove_ref() == 0)
34      delete p;
35  }
36
37  void h_take_ref(T *p) noexcept
38  {
39    p->add_ref();
40  }
41};
42
43struct Ref_ptr_base
44{
45  enum Default_value
46  { Nil = 0 };
47};
48
49template<typename T, template< typename X > class CNT = Default_ref_counter>
50class Weak_ptr;
51
52/**
53 * A reference-counting pointer with automatic cleanup.
54 *
55 * \tparam T   Type of object the pointer points to.
56 * \tparam CNT Type of management class that manages the life time of
57 *             the object.
58 *
59 * This pointer is similar to the standard C++-11 shared_ptr but it does
60 * the reference counting directly in the object being pointed to, so that
61 * no additional management structures need to be allocated from the heap.
62 *
63 * Classes that use this pointer type must implement two functions:
64 *
65 *     int remove_ref()
66 *
67 * is called when a reference is removed and must return 0 when there are no
68 * further references to the object.
69 *
70 *     void add_ref()
71 *
72 * is called when another ref_ptr to the object is created.
73 *
74 * Ref_obj provides a simple implementation of this interface from which
75 * classes may inherit.
76 */
77template <
78  typename T = void,
79  template< typename X > class CNT = Default_ref_counter
80>
81class Ref_ptr : public Ref_ptr_base, private CNT<T>
82{
83private:
84  typedef decltype(nullptr) Null_type;
85  typedef Weak_ptr<T, CNT> Wp;
86
87public:
88  /// Default constructor creates a pointer with no managed object.
89  Ref_ptr() noexcept : _p(0) {}
90
91  Ref_ptr(Ref_ptr_base::Default_value v) : _p((T*)v) {}
92
93  /**
94   * Create a shared pointer from a weak pointer.
95   *
96   * Increases references.
97   */
98  Ref_ptr(Wp const &o) noexcept : _p(o.ptr())
99  { __take_ref(); }
100
101  /// allow creation from `nullptr`
102  Ref_ptr(decltype(nullptr) n) noexcept : _p(n) {}
103
104  /**
105   * Create a shared pointer from a raw pointer.
106   *
107   * In contrast to C++11 shared_ptr it is safe to use this constructor
108   * multiple times and have the same reference counter.
109   */
110  template<typename X>
111  explicit Ref_ptr(X *o) noexcept : _p(o)
112  { __take_ref(); }
113
114  /**
115   * Create a shared pointer from a raw pointer without creating a new
116   * reference.
117   *
118   * \param o  Pointer to the object.
119   * \param d  Dummy parameter to select this constructor at compile time.
120   *           The value may be true or false.
121   *
122   * This is the counterpart to release().
123   */
124  Ref_ptr(T *o, bool d) noexcept : _p(o) { (void)d; }
125
126  /**
127   * Return a raw pointer to the object this shared pointer points to.
128   *
129   * This does not release the pointer or decrease the reference count.
130   */
131  T *get() const noexcept
132  {
133    return _p;
134  }
135
136  /** \copydoc get() */
137  T *ptr() const noexcept
138  {
139    return _p;
140  }
141
142  /**
143   * Release the shared pointer without removing the reference.
144   *
145   * \return A raw pointer to the managed object.
146   *
147   */
148  T *release() noexcept
149  {
150    T *p = _p;
151    _p = 0;
152    return p;
153  }
154
155  ~Ref_ptr() noexcept
156  { __drop_ref(); }
157
158  template<typename OT>
159  Ref_ptr(Ref_ptr<OT, CNT> const &o) noexcept
160  {
161    _p = o.ptr();
162    __take_ref();
163  }
164
165  Ref_ptr(Ref_ptr<T> const &o) noexcept
166  {
167    _p = o._p;
168    __take_ref();
169  }
170
171  template< typename OT >
172  void operator = (Ref_ptr<OT> const &o) noexcept
173  {
174    __drop_ref();
175    _p = o.ptr();
176    __take_ref();
177  }
178
179  void operator = (Ref_ptr<T> const &o) noexcept
180  {
181    if (&o == this)
182      return;
183
184    __drop_ref();
185    _p = o._p;
186    __take_ref();
187  }
188
189  void operator = (Null_type) noexcept
190  {
191    __drop_ref();
192    _p = 0;
193  }
194
195  template<typename OT>
196  Ref_ptr(Ref_ptr<OT, CNT> &&o) noexcept
197  { _p = o.release(); }
198
199  Ref_ptr(Ref_ptr<T> &&o) noexcept
200  { _p = o.release(); }
201
202  template< typename OT >
203  void operator = (Ref_ptr<OT> &&o) noexcept
204  {
205    __drop_ref();
206    _p = o.release();
207  }
208
209  void operator = (Ref_ptr<T> &&o) noexcept
210  {
211    if (&o == this)
212      return;
213
214    __drop_ref();
215    _p = o.release();
216  }
217
218  explicit operator bool () const noexcept { return _p; }
219
220  T *operator -> () const noexcept
221  { return _p; }
222
223  bool operator == (Ref_ptr const &o) const noexcept
224  { return _p == o._p; }
225
226  bool operator != (Ref_ptr const &o) const noexcept
227  { return _p != o._p; }
228
229  bool operator < (Ref_ptr const &o) const noexcept
230  { return _p < o._p; }
231
232  bool operator <= (Ref_ptr const &o) const noexcept
233  { return _p <= o._p; }
234
235  bool operator > (Ref_ptr const &o) const noexcept
236  { return _p > o._p; }
237
238  bool operator >= (Ref_ptr const &o) const noexcept
239  { return _p >= o._p; }
240
241  bool operator == (T const *o) const noexcept
242  { return _p == o; }
243
244  bool operator < (T const *o) const noexcept
245  { return _p < o; }
246
247  bool operator <= (T const *o) const noexcept
248  { return _p <= o; }
249
250  bool operator > (T const *o) const noexcept
251  { return _p > o; }
252
253  bool operator >= (T const *o) const noexcept
254  { return _p >= o; }
255
256private:
257  void __drop_ref() noexcept
258  {
259    if (_p)
260      static_cast<CNT<T>*>(this)->h_drop_ref(_p);
261  }
262
263  void __take_ref() noexcept
264  {
265    if (_p)
266      static_cast<CNT<T>*>(this)->h_take_ref(_p);
267  }
268
269  T *_p;
270};
271
272
273template<typename T, template< typename X > class CNT>
274class Weak_ptr
275{
276private:
277  struct Null_type;
278  typedef Ref_ptr<T, CNT> Rp;
279
280public:
281  Weak_ptr() = default;
282  Weak_ptr(decltype(nullptr)) : _p(nullptr) {}
283  // backwards 0 ctor
284  explicit Weak_ptr(int x) noexcept
285  L4_DEPRECATED("Use initialization from 'nullptr'")
286  : _p(nullptr)
287  { if (x != 0) __builtin_trap(); }
288
289  Weak_ptr(Rp const &o) noexcept : _p(o.ptr()) {}
290  explicit Weak_ptr(T *o) noexcept : _p(o) {}
291
292  template<typename OT>
293  Weak_ptr(Weak_ptr<OT, CNT> const &o) noexcept : _p(o.ptr()) {}
294
295  Weak_ptr(Weak_ptr<T, CNT> const &o) noexcept : _p(o._p) {}
296
297  Weak_ptr<T, CNT> &operator = (const Weak_ptr<T, CNT> &o) = default;
298
299  T *get() const noexcept { return _p; }
300  T *ptr() const noexcept { return _p; }
301
302  T *operator -> () const noexcept { return _p; }
303  operator Null_type const * () const noexcept
304  { return reinterpret_cast<Null_type const*>(_p); }
305
306private:
307  T *_p;
308};
309
310template<typename OT, typename T> inline
311Ref_ptr<OT> ref_ptr_static_cast(Ref_ptr<T> const &o)
312{ return ref_ptr(static_cast<OT*>(o.ptr())); }
313
314template< typename T >
315inline Ref_ptr<T> ref_ptr(T *t)
316{ return Ref_ptr<T>(t); }
317
318template< typename T >
319inline Weak_ptr<T> weak_ptr(T *t)
320{ return Weak_ptr<T>(t); }
321
322
323class Ref_obj
324{
325private:
326  mutable int _ref_cnt;
327
328public:
329  Ref_obj() : _ref_cnt(0)  {}
330  void add_ref() const noexcept { ++_ref_cnt; }
331  int remove_ref() const noexcept { return --_ref_cnt; }
332};
333
334template< typename T, typename... Args >
335Ref_ptr<T>
336make_ref_obj(Args &&... args)
337{ return cxx::Ref_ptr<T>(new T(cxx::forward<Args>(args)...)); }
338
339template<typename T, typename U>
340Ref_ptr<T>
341dynamic_pointer_cast(Ref_ptr<U> const &p) noexcept
342{
343  // our constructor from a naked pointer increments the counter
344  return Ref_ptr<T>(dynamic_cast<T *>(p.get()));
345}
346
347template<typename T, typename U>
348Ref_ptr<T>
349static_pointer_cast(Ref_ptr<U> const &p) noexcept
350{
351  // our constructor from a naked pointer increments the counter
352  return Ref_ptr<T>(static_cast<T *>(p.get()));
353}
354
355}
356