346 lines
7.6 KiB
C++
346 lines
7.6 KiB
C++
// vim:set ft=cpp: -*- Mode: C++ -*-
|
|
/*
|
|
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
|
|
* economic rights: Technische Universität Dresden (Germany)
|
|
*
|
|
* License: see LICENSE.spdx (in this directory or the directories above)
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "type_traits"
|
|
#include <stddef.h>
|
|
#include <l4/sys/compiler.h>
|
|
|
|
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<typename T, template< typename X > 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<T>
|
|
{
|
|
private:
|
|
typedef decltype(nullptr) Null_type;
|
|
typedef Weak_ptr<T, CNT> 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(reinterpret_cast<T*>(static_cast<unsigned long>(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<typename X>
|
|
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, [[maybe_unused]] bool d) noexcept : _p(o) { }
|
|
|
|
/**
|
|
* 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<typename OT>
|
|
Ref_ptr(Ref_ptr<OT, CNT> const &o) noexcept
|
|
{
|
|
_p = o.ptr();
|
|
__take_ref();
|
|
}
|
|
|
|
Ref_ptr(Ref_ptr<T> const &o) noexcept
|
|
{
|
|
_p = o._p;
|
|
__take_ref();
|
|
}
|
|
|
|
template< typename OT >
|
|
void operator = (Ref_ptr<OT> const &o) noexcept
|
|
{
|
|
__drop_ref();
|
|
_p = o.ptr();
|
|
__take_ref();
|
|
}
|
|
|
|
void operator = (Ref_ptr<T> const &o) noexcept
|
|
{
|
|
if (&o == this)
|
|
return;
|
|
|
|
__drop_ref();
|
|
_p = o._p;
|
|
__take_ref();
|
|
}
|
|
|
|
void operator = (Null_type) noexcept
|
|
{
|
|
__drop_ref();
|
|
_p = 0;
|
|
}
|
|
|
|
template<typename OT>
|
|
Ref_ptr(Ref_ptr<OT, CNT> &&o) noexcept
|
|
{ _p = o.release(); }
|
|
|
|
Ref_ptr(Ref_ptr<T> &&o) noexcept
|
|
{ _p = o.release(); }
|
|
|
|
template< typename OT >
|
|
void operator = (Ref_ptr<OT> &&o) noexcept
|
|
{
|
|
__drop_ref();
|
|
_p = o.release();
|
|
}
|
|
|
|
void operator = (Ref_ptr<T> &&o) noexcept
|
|
{
|
|
if (&o == this)
|
|
return;
|
|
|
|
__drop_ref();
|
|
_p = o.release();
|
|
}
|
|
|
|
[[nodiscard]] explicit operator bool () const noexcept { return _p; }
|
|
|
|
T *operator -> () const noexcept
|
|
{ return _p; }
|
|
|
|
[[nodiscard]] bool operator == (Ref_ptr const &o) const noexcept
|
|
{ return _p == o._p; }
|
|
|
|
[[nodiscard]] bool operator != (Ref_ptr const &o) const noexcept
|
|
{ return _p != o._p; }
|
|
|
|
[[nodiscard]] bool operator < (Ref_ptr const &o) const noexcept
|
|
{ return _p < o._p; }
|
|
|
|
[[nodiscard]] bool operator <= (Ref_ptr const &o) const noexcept
|
|
{ return _p <= o._p; }
|
|
|
|
[[nodiscard]] bool operator > (Ref_ptr const &o) const noexcept
|
|
{ return _p > o._p; }
|
|
|
|
[[nodiscard]] bool operator >= (Ref_ptr const &o) const noexcept
|
|
{ return _p >= o._p; }
|
|
|
|
[[nodiscard]] bool operator == (T const *o) const noexcept
|
|
{ return _p == o; }
|
|
|
|
[[nodiscard]] bool operator < (T const *o) const noexcept
|
|
{ return _p < o; }
|
|
|
|
[[nodiscard]] bool operator <= (T const *o) const noexcept
|
|
{ return _p <= o; }
|
|
|
|
[[nodiscard]] bool operator > (T const *o) const noexcept
|
|
{ return _p > o; }
|
|
|
|
[[nodiscard]] bool operator >= (T const *o) const noexcept
|
|
{ return _p >= o; }
|
|
|
|
private:
|
|
void __drop_ref() noexcept
|
|
{
|
|
if (_p)
|
|
static_cast<CNT<T>*>(this)->h_drop_ref(_p);
|
|
}
|
|
|
|
void __take_ref() noexcept
|
|
{
|
|
if (_p)
|
|
static_cast<CNT<T>*>(this)->h_take_ref(_p);
|
|
}
|
|
|
|
T *_p;
|
|
};
|
|
|
|
|
|
template<typename T, template< typename X > class CNT>
|
|
class Weak_ptr
|
|
{
|
|
private:
|
|
struct Null_type;
|
|
typedef Ref_ptr<T, CNT> 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<typename OT>
|
|
Weak_ptr(Weak_ptr<OT, CNT> const &o) noexcept : _p(o.ptr()) {}
|
|
|
|
Weak_ptr(Weak_ptr<T, CNT> const &o) noexcept : _p(o._p) {}
|
|
|
|
Weak_ptr<T, CNT> &operator = (const Weak_ptr<T, CNT> &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<Null_type const*>(_p); }
|
|
|
|
private:
|
|
T *_p;
|
|
};
|
|
|
|
template<typename OT, typename T> inline
|
|
Ref_ptr<OT> ref_ptr_static_cast(Ref_ptr<T> const &o)
|
|
{ return ref_ptr(static_cast<OT*>(o.ptr())); }
|
|
|
|
template< typename T >
|
|
inline Ref_ptr<T> ref_ptr(T *t)
|
|
{ return Ref_ptr<T>(t); }
|
|
|
|
template< typename T >
|
|
inline Weak_ptr<T> weak_ptr(T *t)
|
|
{ return Weak_ptr<T>(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<T>
|
|
make_ref_obj(Args &&... args)
|
|
{ return cxx::Ref_ptr<T>(new T(cxx::forward<Args>(args)...)); }
|
|
|
|
template<typename T, typename U>
|
|
Ref_ptr<T>
|
|
dynamic_pointer_cast(Ref_ptr<U> const &p) noexcept
|
|
{
|
|
// our constructor from a naked pointer increments the counter
|
|
return Ref_ptr<T>(dynamic_cast<T *>(p.get()));
|
|
}
|
|
|
|
template<typename T, typename U>
|
|
Ref_ptr<T>
|
|
static_pointer_cast(Ref_ptr<U> const &p) noexcept
|
|
{
|
|
// our constructor from a naked pointer increments the counter
|
|
return Ref_ptr<T>(static_cast<T *>(p.get()));
|
|
}
|
|
|
|
}
|