AuROXTL/Include/auROXTL/STLShims/ExtendStlLikeSharedPtr.hpp

432 lines
11 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
{
namespace Memory
{
inline void ThrowNullException();
namespace _detail
{
struct IPtrGet
{
virtual void *Get() = 0;
};
struct IPtrNoOpGet : IPtrGet
{
inline virtual void *Get() override
{
ThrowNullException();
return {};
}
};
AU_INLINE_OR_STATIC_17 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;
#if defined(AU_LANG_CPP_17_)
using weak_type = typename Base_t::weak_type;
#else
using weak_type = std::weak_ptr<element_type>;
#endif
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(AuMove(in))
{
#if !defined(_AURORA_NULLEXPT_ENABLE_UB)
_cache();
#endif
}
ExSharedPtr(ExSharedPtr &&in) : Base_t(AuMove(in.BasePointerType()))
{
#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(AuMove(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)
{
if constexpr (AuIsFunction_v<Deleter>)
{
if (r.get_deleter())
{
this->~ExSharedPtr();
new (this) ExSharedPtr(r.release(), r.get_deleter());
}
else
{
this->~ExSharedPtr();
new (this) ExSharedPtr(r.release());
}
}
else
{
this->~ExSharedPtr();
new (this) ExSharedPtr(r.release(), r.get_deleter());
}
#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;
}
}
#elif defined(_AURORA_NULLEXPT_BRANCH_NO_BAD_SHARED_STRUCT)
auline void throwif() const
{
if (!Base_t::operator bool())
#if defined(AU_LANG_CPP_20_)
[[unlikely]]
#endif
{
AU_THROW_STRING("ExSharedPointer Null Access Violation");
}
}
auline void _cache()
{
}
#else
bool cached {};
auline void throwif() const
{
if (!cached) [[unlikely]]
{
#if defined(_AURORA_NULLEXPT_BRANCH_BUG_CHECK)
if (!Base_t::operator bool())
#if defined(AU_LANG_CPP_20_)
[[unlikely]]
#endif
#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();
}
};
}
}