// vim:set ft=cpp: -*- Mode: C++ -*- /* * (c) 2008-2009 Alexander Warg * economic rights: Technische Universität Dresden (Germany) * * This file is part of TUD:OS and distributed under the terms of the * GNU General Public License 2. * Please see the COPYING-GPL-2 file for details. * * As a special exception, you may use this file as part of a free software * library without restriction. Specifically, if other files instantiate * templates or use macros or inline functions from this file, or you compile * this file and link it with other files to produce an executable, this * file does not by itself cause the resulting executable to be covered by * the GNU General Public License. This exception does not however * invalidate any other reasons why the executable file might be covered by * the GNU General Public License. */ #pragma once #include "type_traits" #include #include namespace cxx { template< typename T > struct Default_ref_counter { void h_drop_ref(T *p) noexcept { if (p->remove_ref() == 0) delete p; } void h_take_ref(T *p) noexcept { p->add_ref(); } }; struct Ref_ptr_base { enum Default_value { Nil = 0 }; }; template class CNT = Default_ref_counter> class Weak_ptr; /** * A reference-counting pointer with automatic cleanup. * * \tparam T Type of object the pointer points to. * \tparam CNT Type of management class that manages the life time of * the object. * * This pointer is similar to the standard C++-11 shared_ptr but it does * the reference counting directly in the object being pointed to, so that * no additional management structures need to be allocated from the heap. * * Classes that use this pointer type must implement two functions: * * int remove_ref() * * is called when a reference is removed and must return 0 when there are no * further references to the object. * * void add_ref() * * is called when another ref_ptr to the object is created. * * Ref_obj provides a simple implementation of this interface from which * classes may inherit. */ template < typename T = void, template< typename X > class CNT = Default_ref_counter > class Ref_ptr : public Ref_ptr_base, private CNT { private: typedef decltype(nullptr) Null_type; typedef Weak_ptr Wp; public: /// Default constructor creates a pointer with no managed object. Ref_ptr() noexcept : _p(0) {} Ref_ptr(Ref_ptr_base::Default_value v) : _p((T*)v) {} /** * Create a shared pointer from a weak pointer. * * Increases references. */ Ref_ptr(Wp const &o) noexcept : _p(o.ptr()) { __take_ref(); } /// allow creation from `nullptr` Ref_ptr(decltype(nullptr) n) noexcept : _p(n) {} /** * Create a shared pointer from a raw pointer. * * In contrast to C++11 shared_ptr it is safe to use this constructor * multiple times and have the same reference counter. */ template explicit Ref_ptr(X *o) noexcept : _p(o) { __take_ref(); } /** * Create a shared pointer from a raw pointer without creating a new * reference. * * \param o Pointer to the object. * \param d Dummy parameter to select this constructor at compile time. * The value may be true or false. * * This is the counterpart to release(). */ Ref_ptr(T *o, bool d) noexcept : _p(o) { (void)d; } /** * Return a raw pointer to the object this shared pointer points to. * * This does not release the pointer or decrease the reference count. */ T *get() const noexcept { return _p; } /** \copydoc get() */ T *ptr() const noexcept { return _p; } /** * Release the shared pointer without removing the reference. * * \return A raw pointer to the managed object. * */ T *release() noexcept { T *p = _p; _p = 0; return p; } ~Ref_ptr() noexcept { __drop_ref(); } template Ref_ptr(Ref_ptr const &o) noexcept { _p = o.ptr(); __take_ref(); } Ref_ptr(Ref_ptr const &o) noexcept { _p = o._p; __take_ref(); } template< typename OT > void operator = (Ref_ptr const &o) noexcept { __drop_ref(); _p = o.ptr(); __take_ref(); } void operator = (Ref_ptr const &o) noexcept { if (&o == this) return; __drop_ref(); _p = o._p; __take_ref(); } void operator = (Null_type) noexcept { __drop_ref(); _p = 0; } template Ref_ptr(Ref_ptr &&o) noexcept { _p = o.release(); } Ref_ptr(Ref_ptr &&o) noexcept { _p = o.release(); } template< typename OT > void operator = (Ref_ptr &&o) noexcept { __drop_ref(); _p = o.release(); } void operator = (Ref_ptr &&o) noexcept { if (&o == this) return; __drop_ref(); _p = o.release(); } explicit operator bool () const noexcept { return _p; } T *operator -> () const noexcept { return _p; } bool operator == (Ref_ptr const &o) const noexcept { return _p == o._p; } bool operator != (Ref_ptr const &o) const noexcept { return _p != o._p; } bool operator < (Ref_ptr const &o) const noexcept { return _p < o._p; } bool operator <= (Ref_ptr const &o) const noexcept { return _p <= o._p; } bool operator > (Ref_ptr const &o) const noexcept { return _p > o._p; } bool operator >= (Ref_ptr const &o) const noexcept { return _p >= o._p; } bool operator == (T const *o) const noexcept { return _p == o; } bool operator < (T const *o) const noexcept { return _p < o; } bool operator <= (T const *o) const noexcept { return _p <= o; } bool operator > (T const *o) const noexcept { return _p > o; } bool operator >= (T const *o) const noexcept { return _p >= o; } private: void __drop_ref() noexcept { if (_p) static_cast*>(this)->h_drop_ref(_p); } void __take_ref() noexcept { if (_p) static_cast*>(this)->h_take_ref(_p); } T *_p; }; template class CNT> class Weak_ptr { private: struct Null_type; typedef Ref_ptr Rp; public: Weak_ptr() = default; Weak_ptr(decltype(nullptr)) : _p(nullptr) {} // backwards 0 ctor explicit Weak_ptr(int x) noexcept L4_DEPRECATED("Use initialization from 'nullptr'") : _p(nullptr) { if (x != 0) __builtin_trap(); } Weak_ptr(Rp const &o) noexcept : _p(o.ptr()) {} explicit Weak_ptr(T *o) noexcept : _p(o) {} template Weak_ptr(Weak_ptr const &o) noexcept : _p(o.ptr()) {} Weak_ptr(Weak_ptr const &o) noexcept : _p(o._p) {} Weak_ptr &operator = (const Weak_ptr &o) = default; T *get() const noexcept { return _p; } T *ptr() const noexcept { return _p; } T *operator -> () const noexcept { return _p; } operator Null_type const * () const noexcept { return reinterpret_cast(_p); } private: T *_p; }; template inline Ref_ptr ref_ptr_static_cast(Ref_ptr const &o) { return ref_ptr(static_cast(o.ptr())); } template< typename T > inline Ref_ptr ref_ptr(T *t) { return Ref_ptr(t); } template< typename T > inline Weak_ptr weak_ptr(T *t) { return Weak_ptr(t); } class Ref_obj { private: mutable int _ref_cnt; public: Ref_obj() : _ref_cnt(0) {} void add_ref() const noexcept { ++_ref_cnt; } int remove_ref() const noexcept { return --_ref_cnt; } }; template< typename T, typename... Args > Ref_ptr make_ref_obj(Args &&... args) { return cxx::Ref_ptr(new T(cxx::forward(args)...)); } template Ref_ptr dynamic_pointer_cast(Ref_ptr const &p) noexcept { // our constructor from a naked pointer increments the counter return Ref_ptr(dynamic_cast(p.get())); } template Ref_ptr static_pointer_cast(Ref_ptr const &p) noexcept { // our constructor from a naked pointer increments the counter return Ref_ptr(static_cast(p.get())); } }