401 lines
10 KiB
C++
401 lines
10 KiB
C++
/***
|
|
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: ExtendStlLikeSharedPtr.hpp
|
|
Date: 2022-1-25
|
|
Author: Reece
|
|
***/
|
|
#pragma once
|
|
|
|
//#include <auROXTL/auCastUtils.hpp>
|
|
#include <auROXTL/auCopyMoveUtils.hpp>
|
|
|
|
namespace Aurora::Memory
|
|
{
|
|
inline void ThrowNullException();
|
|
|
|
namespace _detail
|
|
{
|
|
struct IPtrGet
|
|
{
|
|
virtual void *Get() = 0;
|
|
};
|
|
|
|
struct IPtrNoOpGet : IPtrGet
|
|
{
|
|
inline virtual void *Get() override
|
|
{
|
|
ThrowNullException();
|
|
return {};
|
|
}
|
|
};
|
|
|
|
inline IPtrNoOpGet gNoop;
|
|
}
|
|
|
|
template <class TType_t, class Base_t>
|
|
struct ExSharedPtr : Base_t
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB) && !defined(_AURORA_NULLEXPT_BRANCH)
|
|
, private _detail::IPtrGet
|
|
#endif
|
|
{
|
|
using element_type = typename Base_t::element_type;
|
|
using weak_type = typename Base_t::weak_type;
|
|
using base_type = Base_t;
|
|
using Base_t::Base_t;
|
|
|
|
ExSharedPtr() : Base_t()
|
|
{
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
}
|
|
|
|
ExSharedPtr(Base_t &&in) : Base_t(in)
|
|
{
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
}
|
|
|
|
ExSharedPtr(ExSharedPtr &&in) : Base_t(in)
|
|
{
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
}
|
|
|
|
ExSharedPtr(const ExSharedPtr &in) : Base_t(in)
|
|
{
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
}
|
|
|
|
template <class T_t, typename B_t>
|
|
ExSharedPtr(const ExSharedPtr<T_t, B_t> &in) : Base_t(in.BasePointerType(), static_cast<T_t *>(in.get()))
|
|
{
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
}
|
|
|
|
template <class T_t, typename B_t>
|
|
ExSharedPtr(ExSharedPtr<T_t, B_t> &&in) : Base_t(in.BasePointerType(), static_cast<T_t *>(in.get()))
|
|
{
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
}
|
|
|
|
template <class T_t, typename B_t>
|
|
ExSharedPtr(ExSharedPtr<T_t, B_t> &&in, element_type *ptr) : Base_t(AuMove(in.BasePointerType()), ptr)
|
|
{
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
}
|
|
|
|
ExSharedPtr(Base_t &&in, element_type *ptr) : Base_t(in, ptr)
|
|
{
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
}
|
|
|
|
template <class T_t, typename B_t>
|
|
ExSharedPtr(const ExSharedPtr<T_t, B_t> &in, element_type *ptr) : Base_t(in.BasePointerType(), ptr)
|
|
{
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
}
|
|
|
|
ExSharedPtr(const Base_t &in, element_type *ptr) : Base_t(in, ptr)
|
|
{
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
}
|
|
|
|
ExSharedPtr(const Base_t &in) : Base_t(in)
|
|
{
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
}
|
|
|
|
template <class Y = element_type, class Deleter_t, class Alloc_t>
|
|
ExSharedPtr(Y *in, Deleter_t del, Alloc_t alloc) : Base_t(in, del, alloc)
|
|
{
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
}
|
|
|
|
template <class Y = element_type, class Deleter_t>
|
|
ExSharedPtr(Y *in, Deleter_t del) : Base_t(in, del)
|
|
{
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
}
|
|
|
|
template < class Y, class Deleter >
|
|
ExSharedPtr(AURORA_RUNTIME_AU_UNIQUE_PTR<Y, Deleter> &&r) : Base_t(r)
|
|
{
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
}
|
|
|
|
|
|
template <class T_t, typename B_t>
|
|
void swap(ExSharedPtr<T_t, B_t> &in)
|
|
{
|
|
Base_t::swap(in.BasePointerType());
|
|
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
}
|
|
|
|
void swap(Base_t &r)
|
|
{
|
|
Base_t::swap(r);
|
|
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
}
|
|
|
|
void reset()
|
|
{
|
|
Base_t::reset();
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
#if !defined(_AURORA_NULLEXPT_BRANCH)
|
|
ptr = &_detail::gNoop;
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
operator const Base_t &() const noexcept
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
// required for move casts
|
|
operator Base_t &() noexcept
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
const Base_t &BasePointerType() const noexcept
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
Base_t &BasePointerType() noexcept
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
operator bool() const noexcept
|
|
{
|
|
return Base_t::operator bool();
|
|
}
|
|
|
|
ExSharedPtr &operator =(const Base_t &in) noexcept
|
|
{
|
|
Base_t::operator=(in);
|
|
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
return *this;
|
|
}
|
|
|
|
template <class T_t, typename B_t>
|
|
ExSharedPtr &operator =(ExSharedPtr<T_t, B_t> &&in) noexcept
|
|
{
|
|
Base_t::operator=(AuMove(in.BasePointerType()));
|
|
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
return *this;
|
|
}
|
|
|
|
ExSharedPtr &operator =(Base_t &&in) noexcept
|
|
{
|
|
Base_t::operator=(in);
|
|
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
return *this;
|
|
}
|
|
|
|
ExSharedPtr &operator =(const ExSharedPtr &in) noexcept
|
|
{
|
|
Base_t::operator=(in);
|
|
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
return *this;
|
|
}
|
|
|
|
template <class T_t, typename B_t>
|
|
ExSharedPtr &operator =(const ExSharedPtr<T_t, B_t> &in) noexcept
|
|
{
|
|
Base_t::operator=(in.BasePointerType());
|
|
|
|
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
_cache();
|
|
#endif
|
|
return *this;
|
|
}
|
|
|
|
template <class TType2_t = TType_t>
|
|
TType2_t &operator*() const
|
|
{
|
|
return *operator->();
|
|
}
|
|
|
|
template <class TType2_t = TType_t>
|
|
TType2_t *operator->() const
|
|
{
|
|
#if defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
return Base_t::operator->();
|
|
#elif !defined(_AURORA_NULLEXPT_BRANCH)
|
|
return reinterpret_cast<TType2_t *>(ptr->Get());
|
|
#else
|
|
throwif();
|
|
return Base_t::operator->();
|
|
#endif
|
|
}
|
|
|
|
template <class TType2_t = TType_t>
|
|
TType2_t &operator*()
|
|
{
|
|
return *operator->();
|
|
}
|
|
|
|
template <class TType2_t = TType_t>
|
|
TType2_t *operator->()
|
|
{
|
|
#if defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
return Base_t::operator->();
|
|
#elif !defined(_AURORA_NULLEXPT_BRANCH)
|
|
return reinterpret_cast<TType2_t *>(ptr->Get());
|
|
#else
|
|
throwif();
|
|
return Base_t::operator->();
|
|
#endif
|
|
}
|
|
|
|
element_type *get() const
|
|
{
|
|
return Base_t::get();
|
|
}
|
|
|
|
#define ADD_OPERATOR(op) \
|
|
template <class T > \
|
|
bool operator op(const T &rhs) noexcept \
|
|
{ \
|
|
return static_cast<Base_t &>(*this) op(rhs); \
|
|
} \
|
|
\
|
|
template < class T > \
|
|
bool operator op(std::nullptr_t rhs) noexcept \
|
|
{ \
|
|
return static_cast<Base_t &>(*this) op(rhs); \
|
|
}
|
|
|
|
|
|
ADD_OPERATOR(==)
|
|
ADD_OPERATOR(!=)
|
|
#if defined(AU_LANG_CPP_20)
|
|
template < class T >
|
|
std::strong_ordering operator<=>(const T &rhs) noexcept
|
|
{
|
|
return Base_t::operator<=>(rhs);
|
|
}
|
|
#else
|
|
ADD_OPERATOR(>)
|
|
ADD_OPERATOR(<)
|
|
ADD_OPERATOR(<=)
|
|
ADD_OPERATOR(=>)
|
|
#endif
|
|
|
|
private:
|
|
|
|
#if defined(_AURORA_NULLEXPT_ENABLE_UB)
|
|
void _cache()
|
|
{}
|
|
#elif !defined(_AURORA_NULLEXPT_BRANCH)
|
|
_detail::IPtrGet * ptr;
|
|
|
|
inline virtual void *Get() override
|
|
{
|
|
return (void *)Base_t::operator->();
|
|
}
|
|
|
|
auline void _cache()
|
|
{
|
|
if (Base_t::operator bool())
|
|
{
|
|
ptr = this;
|
|
}
|
|
else
|
|
{
|
|
|
|
ptr = &_detail::gNoop;
|
|
}
|
|
}
|
|
#else
|
|
bool cached {};
|
|
auline void throwif() const
|
|
{
|
|
if (!cached) [[unlikely]]
|
|
{
|
|
#if defined(_AURORA_NULLEXPT_BRANCH_BUG_CHECK)
|
|
if (!Base_t::operator bool()) [[likely]]
|
|
#endif
|
|
{
|
|
AU_THROW_STRING("ExSharedPointer Null Access Violation");
|
|
}
|
|
}
|
|
}
|
|
|
|
auline void throwif()
|
|
{
|
|
if (!cached) [[unlikely]]
|
|
{
|
|
#if defined(_AURORA_NULLEXPT_BRANCH_BUG_CHECK)
|
|
cached = Base_t::operator bool();
|
|
if (!cached) [[likely]]
|
|
#endif
|
|
{
|
|
AU_THROW_STRING("ExSharedPointer Null Access Violation");
|
|
}
|
|
}
|
|
}
|
|
|
|
auline void _cache()
|
|
{
|
|
cached = Base_t::operator bool();
|
|
}
|
|
#endif
|
|
};
|
|
|
|
template <class TType_t, class Base_t>
|
|
struct ExSharedFromThis : Base_t
|
|
{
|
|
ExSharedPtr<TType_t, AURORA_RUNTIME_AU_SHARED_PTR<TType_t>> SharedFromThis()
|
|
{
|
|
return Base_t::shared_from_this();
|
|
}
|
|
};
|
|
} |