rcp/include/rcp.h

124 lines
2.0 KiB
C++

#pragma once
#include <atomic>
namespace rcp_internal
{
class root
{
private:
mutable std::atomic<int> ref_count{0};
rcp<root> root_rcp;
protected:
root()
{
root_rcp = rcp<root>(this);
}
virtual ~root() = default;
public:
void add_ref() const
{
ref_count.fetch_add(1, std::memory_order_relaxed);
}
void release_ref() const
{
if (ref_count.fetch_sub(1, std::memory_order_acq_rel) == 0)
{
delete this;
}
}
rcp<root> & get_root_rcp()
{
return root_rcp;
}
}
template <typename T>
class managed
{
public:
static_assert(std::is_base_of<root, T>::value,
"T must inherit from rcp::root to use rcp::managed<T>");
rcp<T> get_rcp()
{
root * r = (root *)this;
return rcp<T>(r->get_root_ref());
}
}
}
/**
* Reference-counting pointer.
*/
template <typename T>
class rcp
{
private:
T * ptr = nullptr;
explicit rcp(T * p) : ptr(p)
{
if (p)
{
ptr->add_ref();
}
}
friend T;
public:
rcp() = default;
rcp(const rcp & other) : ptr(other.ptr)
{
if (ptr)
{
ptr->add_ref();
}
}
~rcp()
{
if (ptr)
{
ptr->release_ref();
}
}
/* Casting constructor: allows rcp<Base> -> rcp<Derived> */
template <typename U>
rcp(const rcp<U> & other) : ptr(static_cast<T *>(other.get_raw()))
{
if (ptr)
{
ptr->add_ref();
}
}
T * get_raw() const
{
return ptr;
}
T * operator->() const
{
return ptr;
}
bool operator!() const
{
return !ptr;
}
using root = rcp_internal::root;
using managed = rcp_internal::managed;
}