Files
moslab-code/src/l4/pkg/l4re-core/cxx/lib/tl/include/ref_ptr
2025-09-12 15:55:45 +02:00

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()));
}
}