L4Re - L4 Runtime Environment
ref_ptr
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 
25 namespace cxx {
26 
27 template< typename T >
28 struct Default_ref_counter
29 {
30  void h_drop_ref(T *p) throw()
31  {
32  if (p->remove_ref() == 0)
33  delete p;
34  }
35 
36  void h_take_ref(T *p) throw()
37  {
38  p->add_ref();
39  }
40 };
41 
42 struct Ref_ptr_base
43 {
44  enum Default_value
45  { Nil = 0 };
46 };
47 
48 template<typename T, template< typename X > class CNT = Default_ref_counter>
49 class Weak_ptr;
50 
51 /**
52  * A reference-counting pointer with automatic cleanup.
53  *
54  * \tparam T Type of object the pointer points to.
55  * \tparam CNT Type of management class that manages the life time of
56  * the object.
57  *
58  * This pointer is similar to the standard C++-11 shared_ptr but it does
59  * the reference counting directly in the object being pointed to, so that
60  * no additional management structures need to be allocated from the heap.
61  *
62  * Classes that use this pointer type must implement two functions:
63  *
64  * int remove_ref()
65  *
66  * is called when a reference is removed and must return 0 when there are no
67  * further references to the object.
68  *
69  * void add_ref()
70  *
71  * is called when another ref_ptr to the object is created.
72  *
73  * Ref_obj provides a simple implementation of this interface from which
74  * classes may inherit.
75  */
76 template <
77  typename T = void,
78  template< typename X > class CNT = Default_ref_counter
79 >
80 class Ref_ptr : public Ref_ptr_base, private CNT<T>
81 {
82 private:
83 #if __cplusplus >= 201103L
84  typedef decltype(nullptr) Null_type;
85 #else
86  typedef struct _Null_type const *Null_type;
87 #endif
88  typedef Weak_ptr<T, CNT> Wp;
89 
90 public:
91  /// Default constructor creates a pointer with no managed object.
92  Ref_ptr() throw() : _p(0) {}
93 
94  Ref_ptr(Ref_ptr_base::Default_value v) : _p((T*)v) {}
95 
96  /**
97  * Create a shared pointer from a weak pointer.
98  *
99  * Increases references.
100  */
101  Ref_ptr(Wp const &o) throw() : _p(o.ptr())
102  { __take_ref(); }
103 
104 #if __cplusplus >= 201103L
105  /// allow creation from `nullptr`
106  Ref_ptr(decltype(nullptr) n) noexcept : _p(n) {}
107 
108  /**
109  * Create a shared pointer from a raw pointer.
110  *
111  * In contrast to C++11 shared_ptr it is safe to use this constructor
112  * multiple times and have the same reference counter.
113  */
114  template<typename X>
115  explicit Ref_ptr(X *o) throw() : _p(o)
116  { __take_ref(); }
117 #else
118  /**
119  * Create a shared pointer from a raw pointer.
120  *
121  * In contrast to C++11 shared_ptr it is safe to use this constructor
122  * multiple times and have the same reference counter.
123  */
124  explicit Ref_ptr(T *o) throw() : _p(o)
125  { __take_ref(); }
126 #endif
127 
128  /**
129  * Create a shared pointer from a raw pointer without creating a new
130  * reference.
131  *
132  * \param o Pointer to the object.
133  * \param d Dummy parameter to select this constructor at compile time.
134  * The value may be true or false.
135  *
136  * This is the counterpart to release().
137  */
138  Ref_ptr(T *o, bool d) throw() : _p(o) { (void)d; }
139 
140  /**
141  * Return a raw pointer to the object this shared pointer points to.
142  *
143  * This does not release the pointer or decrease the reference count.
144  */
145  T *get() const throw()
146  {
147  return _p;
148  }
149 
150  /** \copydoc get() */
151  T *ptr() const throw()
152  {
153  return _p;
154  }
155 
156  /**
157  * Release the shared pointer without removing the reference.
158  *
159  * \return A raw pointer to the managed object.
160  *
161  */
162  T *release() throw()
163  {
164  T *p = _p;
165  _p = 0;
166  return p;
167  }
168 
169  ~Ref_ptr() throw()
170  { __drop_ref(); }
171 
172  template<typename OT>
173  Ref_ptr(Ref_ptr<OT, CNT> const &o) throw()
174  {
175  _p = o.ptr();
176  __take_ref();
177  }
178 
179  Ref_ptr(Ref_ptr<T> const &o) throw()
180  {
181  _p = o._p;
182  __take_ref();
183  }
184 
185  template< typename OT >
186  void operator = (Ref_ptr<OT> const &o) throw()
187  {
188  __drop_ref();
189  _p = o.ptr();
190  __take_ref();
191  }
192 
193  void operator = (Ref_ptr<T> const &o) throw()
194  {
195  if (&o == this)
196  return;
197 
198  __drop_ref();
199  _p = o._p;
200  __take_ref();
201  }
202 
203  void operator = (Null_type) throw()
204  {
205  __drop_ref();
206  _p = 0;
207  }
208 
209 #if __cplusplus >= 201103L
210  template<typename OT>
211  Ref_ptr(Ref_ptr<OT, CNT> &&o) throw()
212  { _p = o.release(); }
213 
214  Ref_ptr(Ref_ptr<T> &&o) throw()
215  { _p = o.release(); }
216 
217  template< typename OT >
218  void operator = (Ref_ptr<OT> &&o) throw()
219  {
220  __drop_ref();
221  _p = o.release();
222  }
223 
224  void operator = (Ref_ptr<T> &&o) throw()
225  {
226  if (&o == this)
227  return;
228 
229  __drop_ref();
230  _p = o.release();
231  }
232 
233  explicit operator bool () const throw() { return _p; }
234 #else
235  operator Null_type () const throw()
236  { return reinterpret_cast<Null_type>(_p); }
237 #endif
238 
239  T *operator -> () const throw ()
240  { return _p; }
241 
242  bool operator == (Ref_ptr const &o) const throw()
243  { return _p == o._p; }
244 
245  bool operator != (Ref_ptr const &o) const throw()
246  { return _p != o._p; }
247 
248  bool operator < (Ref_ptr const &o) const throw()
249  { return _p < o._p; }
250 
251  bool operator <= (Ref_ptr const &o) const throw()
252  { return _p <= o._p; }
253 
254  bool operator > (Ref_ptr const &o) const throw()
255  { return _p > o._p; }
256 
257  bool operator >= (Ref_ptr const &o) const throw()
258  { return _p >= o._p; }
259 
260  bool operator == (T const *o) const throw()
261  { return _p == o; }
262 
263  bool operator < (T const *o) const throw()
264  { return _p < o; }
265 
266  bool operator <= (T const *o) const throw()
267  { return _p <= o; }
268 
269  bool operator > (T const *o) const throw()
270  { return _p > o; }
271 
272  bool operator >= (T const *o) const throw()
273  { return _p >= o; }
274 
275 private:
276  void __drop_ref() throw()
277  {
278  if (_p)
279  static_cast<CNT<T>*>(this)->h_drop_ref(_p);
280  }
281 
282  void __take_ref() throw()
283  {
284  if (_p)
285  static_cast<CNT<T>*>(this)->h_take_ref(_p);
286  }
287 
288  T *_p;
289 };
290 
291 
292 template<typename T, template< typename X > class CNT>
293 class Weak_ptr
294 {
295 private:
296  struct Null_type;
297  typedef Ref_ptr<T, CNT> Rp;
298 
299 public:
300  Weak_ptr() throw() {}
301  Weak_ptr(Rp const &o) throw() : _p(o.ptr()) {}
302  explicit Weak_ptr(T *o) throw() : _p(o) {}
303 
304  T *get() const throw() { return _p; }
305  T *ptr() const throw() { return _p; }
306 
307  T *operator -> () const throw () { return _p; }
308  operator Null_type const * () const throw()
309  { return reinterpret_cast<Null_type const*>(_p); }
310 
311 private:
312  T *_p;
313 };
314 
315 template<typename OT, typename T> inline
316 Ref_ptr<OT> ref_ptr_static_cast(Ref_ptr<T> const &o)
317 { return ref_ptr(static_cast<OT*>(o.ptr())); }
318 
319 template< typename T >
320 inline Ref_ptr<T> ref_ptr(T *t)
321 { return Ref_ptr<T>(t); }
322 
323 template< typename T >
324 inline Weak_ptr<T> weak_ptr(T *t)
325 { return Weak_ptr<T>(t); }
326 
327 
328 class Ref_obj
329 {
330 private:
331  mutable int _ref_cnt;
332 
333 public:
334  Ref_obj() : _ref_cnt(0) {}
335  void add_ref() const throw() { ++_ref_cnt; }
336  int remove_ref() const throw() { return --_ref_cnt; }
337 };
338 
339 #if __cplusplus >= 201103L
340 
341 template< typename T, typename... Args >
342 Ref_ptr<T>
343 make_ref_obj(Args &&... args)
344 { return cxx::Ref_ptr<T>(new T(cxx::forward<Args>(args)...)); }
345 
346 template<typename T, typename U>
347 Ref_ptr<T>
348 dynamic_pointer_cast(Ref_ptr<U> const &p) noexcept
349 {
350  // our constructor from a naked pointer increments the counter
351  return Ref_ptr<T>(dynamic_cast<T *>(p.get()));
352 }
353 
354 template<typename T, typename U>
355 Ref_ptr<T>
356 static_pointer_cast(Ref_ptr<U> const &p) noexcept
357 {
358  // our constructor from a naked pointer increments the counter
359  return Ref_ptr<T>(static_cast<T *>(p.get()));
360 }
361 
362 #endif
363 
364 }