gcroot.h
// gcroot.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2021
@import "IObject.h"
@import "WCSpace.h"
#include <atomic>
#include <type_traits>
namespace ceda
{
// See https://en.cppreference.com/w/cpp/types/is_convertible
// https://en.cppreference.com/w/cpp/types/enable_if
template<typename Tp>
class gcroot
{
public:
using pointer_type = Tp;
constexpr gcroot() noexcept {} // construct empty gcroot
constexpr gcroot(nullptr_t) noexcept {} // construct empty gcroot
template <class R, std::enable_if_t<std::is_convertible<R,pointer_type>::value, int> = 0>
explicit gcroot(R p) noexcept
{
if (p)
{
ptr_ = p;
ref_ = &p->GetIObjectSysState();
ref_->IncRef();
}
}
template <class R>
gcroot(R r, pointer_type p) noexcept
{
ptr_ = p;
if (r)
{
ref_ = &r->GetIObjectSysState();
ref_->IncRef();
}
}
~gcroot() noexcept
{
if (ref_)
{
ref_->DecRef();
}
}
template <class R>
gcroot(const gcroot<R>& right, pointer_type p) noexcept
{
// construct gcroot object that aliases right
this->_Alias_construct_from(right, p);
}
template <class R>
gcroot(gcroot<R>&& right, pointer_type p) noexcept
{
// move construct gcroot object that aliases right
this->_Alias_move_construct_from(std::move(right), p);
}
gcroot(const gcroot& right) noexcept
{
// construct gcroot object that owns same resource as right
this->_Copy_construct_from(right);
}
template <class R, std::enable_if_t<std::is_convertible<R,pointer_type>::value, int> = 0>
gcroot(const gcroot<R>& right) noexcept
{
// construct gcroot object that owns same resource as right
this->_Copy_construct_from(right);
}
gcroot(gcroot&& right) noexcept
{
// construct gcroot object that takes resource from right
this->_Move_construct_from(std::move(right));
}
template <class R, std::enable_if_t<std::is_convertible<R,pointer_type>::value, int> = 0>
gcroot(gcroot<R>&& right) noexcept
{
// construct gcroot object that takes resource from right
this->_Move_construct_from(std::move(right));
}
void swap(gcroot& right) noexcept
{
// swap pointers
using std::swap;
swap(ptr_, right.ptr_);
swap(ref_, right.ref_);
}
void reset() noexcept
{
// release resource and convert to empty gcroot object
gcroot().swap(*this);
}
template <class R>
void reset(R p)
{
// release, take ownership of p
gcroot(p).swap(*this);
}
gcroot& operator=(const gcroot& right) noexcept
{
gcroot(right).swap(*this);
return *this;
}
template <class R>
gcroot& operator=(const gcroot<R>& right) noexcept
{
gcroot(right).swap(*this);
return *this;
}
gcroot& operator=(gcroot&& right) noexcept
{
// take resource from right
gcroot(std::move(right)).swap(*this);
return *this;
}
template <class R>
gcroot& operator=(gcroot<R>&& right) noexcept
{
// take resource from right
gcroot(std::move(right)).swap(*this);
return *this;
}
[[nodiscard]] pointer_type get() const noexcept
{
return ptr_;
}
[[nodiscard]] auto& operator*() const noexcept
{
return *get();
}
[[nodiscard]] pointer_type operator->() const noexcept
{
return get();
}
explicit operator bool() const noexcept
{
return get() != nullptr;
}
private:
template <class S, class... Args>
friend gcroot<S*> make_gcroot(Args&&... args);
template <class R>
friend class gcroot;
template <class R>
void _Move_construct_from(gcroot<R>&& right) noexcept
{
ptr_ = right.ptr_;
ref_ = right.ref_;
right.ptr_ = nullptr;
right.ref_ = nullptr;
}
template <class R>
void _Copy_construct_from(const gcroot<R>& right) noexcept
{
if (right.ref_)
{
right.ref_->IncRef();
}
ptr_ = right.ptr_;
ref_ = right.ref_;
}
template <class R>
void _Alias_construct_from(const gcroot<R>& right, pointer_type p) noexcept
{
if (right.ref_)
{
right.ref_->IncRef();
}
ptr_ = p;
ref_ = right.ref_;
}
template <class R>
void _Alias_move_construct_from(gcroot<R>&& right, pointer_type p) noexcept
{
ptr_ = p;
ref_ = right.ref_;
right.ptr_ = nullptr;
right.ref_ = nullptr;
}
ObjSysState* ref_{nullptr};
pointer_type ptr_{nullptr};
};
template <class L, class R>
[[nodiscard]] bool operator==(const gcroot<L>& left, const gcroot<R>& right) noexcept
{
return left.get() == right.get();
}
template <class L, class R>
[[nodiscard]] bool operator!=(const gcroot<L>& left, const gcroot<R>& right) noexcept
{
return left.get() != right.get();
}
template <class L, class R>
[[nodiscard]] bool operator<(const gcroot<L>& left, const gcroot<R>& right) noexcept
{
return left.get() < right.get();
}
template <class L, class R>
[[nodiscard]] bool operator>=(const gcroot<L>& left, const gcroot<R>& right) noexcept
{
return left.get() >= right.get();
}
template <class L, class R>
[[nodiscard]] bool operator>(const gcroot<L>& left, const gcroot<R>& right) noexcept
{
return left.get() > right.get();
}
template <class L, class R>
[[nodiscard]] bool operator<=(const gcroot<L>& left, const gcroot<R>& right) noexcept
{
return left.get() <= right.get();
}
template <class T>
[[nodiscard]] bool operator==(const gcroot<T>& left, nullptr_t) noexcept
{
return left.get() == nullptr;
}
template <class T>
[[nodiscard]] bool operator==(nullptr_t, const gcroot<T>& right) noexcept
{
return nullptr == right.get();
}
template <class T>
[[nodiscard]] bool operator!=(const gcroot<T>& left, nullptr_t) noexcept
{
return left.get() != nullptr;
}
template <class T>
[[nodiscard]] bool operator!=(nullptr_t, const gcroot<T>& right) noexcept
{
return nullptr != right.get();
}
template <class T>
[[nodiscard]] bool operator<(const gcroot<T>& left, nullptr_t) noexcept
{
return left.get() < static_cast<T>(nullptr);
}
template <class T>
[[nodiscard]] bool operator<(nullptr_t, const gcroot<T>& right) noexcept
{
return static_cast<T>(nullptr) < right.get();
}
template <class T>
[[nodiscard]] bool operator>=(const gcroot<T>& left, nullptr_t) noexcept
{
return left.get() >= static_cast<T>(nullptr);
}
template <class T>
[[nodiscard]] bool operator>=(nullptr_t, const gcroot<T>& right) noexcept
{
return static_cast<T>(nullptr) >= right.get();
}
template <class T>
[[nodiscard]] bool operator>(const gcroot<T>& left, nullptr_t) noexcept
{
return left.get() > static_cast<T>(nullptr);
}
template <class T>
[[nodiscard]] bool operator>(nullptr_t, const gcroot<T>& right) noexcept
{
return static_cast<T>(nullptr) > right.get();
}
template <class T>
[[nodiscard]] bool operator<=(const gcroot<T>& left, nullptr_t) noexcept
{
return left.get() <= static_cast<T>(nullptr);
}
template <class T>
[[nodiscard]] bool operator<=(nullptr_t, const gcroot<T>& right) noexcept
{
return static_cast<T>(nullptr) <= right.get();
}
template <class _Elem, class _Traits, class T>
std::basic_ostream<_Elem, _Traits>& operator<<(std::basic_ostream<_Elem, _Traits>& os, const gcroot<T>& p)
{
// write contained pointer to stream
return os << p.get();
}
template <class T>
void swap(gcroot<T>& left, gcroot<T>& right) noexcept
{
left.swap(right);
}
template <class L, class R>
[[nodiscard]] gcroot<L> static_pointer_cast(const gcroot<R>& right) noexcept
{
const auto p = static_cast<L>(right.get());
return gcroot<L>(right, p);
}
template <class L, class R>
[[nodiscard]] gcroot<L> static_pointer_cast(gcroot<R>&& right) noexcept
{
const auto p = static_cast<L>(right.get());
return gcroot<L>(std::move(right), p);
}
template <class L, class R>
[[nodiscard]] gcroot<L> const_pointer_cast(const gcroot<R>& right) noexcept
{
const auto p = const_cast<L>(right.get());
return gcroot<L>(right, p);
}
template <class L, class R>
[[nodiscard]] gcroot<L> const_pointer_cast(gcroot<R>&& right) noexcept
{
const auto p = const_cast<L>(right.get());
return gcroot<L>(std::move(right), p);
}
template <class L, class R>
[[nodiscard]] gcroot<L> reinterpret_pointer_cast(const gcroot<R>& right) noexcept
{
const auto p = reinterpret_cast<L>(right.get());
return gcroot<L>(right, p);
}
template <class L, class R>
[[nodiscard]] gcroot<L> reinterpret_pointer_cast(gcroot<R>&& right) noexcept
{
const auto p = reinterpret_cast<L>(right.get());
return gcroot<L>(std::move(right), p);
}
template <class L, class R>
[[nodiscard]] gcroot<L> dynamic_pointer_cast(const gcroot<R>& right) noexcept
{
if (const auto p = dynamic_cast<L>(right.get()))
{
return gcroot<L>(right, p);
}
return gcroot<L>();
}
template <class L, class R>
[[nodiscard]] gcroot<L> dynamic_pointer_cast(gcroot<R>&& right) noexcept
{
if (const auto p = dynamic_cast<L>(right.get()))
{
return gcroot<L>(std::move(right), p);
}
return gcroot<L>();
}
// make a gcroot
template <class T, class... Args>
[[nodiscard]] gcroot<T*> make_gcroot(Args&&... args)
{
auto p = new T(std::forward<Args>(args)...);
RegisterGcObject(p);
return gcroot<T*>(p);
}
} // ceda