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