#pragma once
#include "NSDefines.hpp"
namespace NS
{
template <class _Class>
class SharedPtr
{
public:
SharedPtr();
~SharedPtr();
SharedPtr(const SharedPtr<_Class>& other) noexcept;
template <class _OtherClass>
SharedPtr(const SharedPtr<_OtherClass>& other, typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>> * = nullptr) noexcept;
SharedPtr(SharedPtr<_Class>&& other) noexcept;
template <class _OtherClass>
SharedPtr(SharedPtr<_OtherClass>&& other, typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>> * = nullptr) noexcept;
SharedPtr& operator=(const SharedPtr<_Class>& other);
template <class _OtherClass>
typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>, SharedPtr &>
operator=(const SharedPtr<_OtherClass>& other);
SharedPtr& operator=(SharedPtr<_Class>&& other);
template <class _OtherClass>
typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>, SharedPtr &>
operator=(SharedPtr<_OtherClass>&& other);
_Class* get() const;
_Class* operator->() const;
explicit operator bool() const;
void reset();
void detach();
template <class _OtherClass>
friend SharedPtr<_OtherClass> RetainPtr(_OtherClass* ptr);
template <class _OtherClass>
friend SharedPtr<_OtherClass> TransferPtr(_OtherClass* ptr);
private:
_Class* m_pObject;
};
template <class _Class>
_NS_INLINE NS::SharedPtr<_Class> RetainPtr(_Class* pObject)
{
NS::SharedPtr<_Class> ret;
ret.m_pObject = pObject->retain();
return ret;
}
template <class _Class>
_NS_INLINE NS::SharedPtr<_Class> TransferPtr(_Class* pObject)
{
NS::SharedPtr<_Class> ret;
ret.m_pObject = pObject;
return ret;
}
}
template <class _Class>
_NS_INLINE NS::SharedPtr<_Class>::SharedPtr()
: m_pObject(nullptr)
{
}
template <class _Class>
_NS_INLINE NS::SharedPtr<_Class>::~SharedPtr()
{
if (m_pObject)
{
m_pObject->release();
}
}
template <class _Class>
_NS_INLINE NS::SharedPtr<_Class>::SharedPtr(const NS::SharedPtr<_Class>& other) noexcept
: m_pObject(other.m_pObject->retain())
{
}
template <class _Class>
template <class _OtherClass>
_NS_INLINE NS::SharedPtr<_Class>::SharedPtr(const NS::SharedPtr<_OtherClass>& other, typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>> *) noexcept
: m_pObject(reinterpret_cast<_Class*>(other.get()->retain()))
{
}
template <class _Class>
_NS_INLINE NS::SharedPtr<_Class>::SharedPtr(NS::SharedPtr<_Class>&& other) noexcept
: m_pObject(other.m_pObject)
{
other.m_pObject = nullptr;
}
template <class _Class>
template <class _OtherClass>
_NS_INLINE NS::SharedPtr<_Class>::SharedPtr(NS::SharedPtr<_OtherClass>&& other, typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>> *) noexcept
: m_pObject(reinterpret_cast<_Class*>(other.get()))
{
other.detach();
}
template <class _Class>
_NS_INLINE _Class* NS::SharedPtr<_Class>::get() const
{
return m_pObject;
}
template <class _Class>
_NS_INLINE _Class* NS::SharedPtr<_Class>::operator->() const
{
return m_pObject;
}
template <class _Class>
_NS_INLINE NS::SharedPtr<_Class>::operator bool() const
{
return nullptr != m_pObject;
}
template <class _Class>
_NS_INLINE void NS::SharedPtr<_Class>::reset()
{
m_pObject->release();
m_pObject = nullptr;
}
template <class _Class>
_NS_INLINE void NS::SharedPtr<_Class>::detach()
{
m_pObject = nullptr;
}
template <class _Class>
_NS_INLINE NS::SharedPtr<_Class>& NS::SharedPtr<_Class>::operator=(const SharedPtr<_Class>& other)
{
if (m_pObject != other.m_pObject)
{
if (m_pObject)
{
m_pObject->release();
}
m_pObject = other.m_pObject->retain();
}
return *this;
}
template <class _Class>
template <class _OtherClass>
typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>, NS::SharedPtr<_Class> &>
_NS_INLINE NS::SharedPtr<_Class>::operator=(const SharedPtr<_OtherClass>& other)
{
if (m_pObject != other.get())
{
if (m_pObject)
{
m_pObject->release();
}
m_pObject = reinterpret_cast<_Class*>(other.get()->retain());
}
return *this;
}
template <class _Class>
_NS_INLINE NS::SharedPtr<_Class>& NS::SharedPtr<_Class>::operator=(SharedPtr<_Class>&& other)
{
if (m_pObject != other.m_pObject)
{
if (m_pObject)
{
m_pObject->release();
}
m_pObject = other.m_pObject;
}
else
{
m_pObject = other.m_pObject;
other.m_pObject->release();
}
other.m_pObject = nullptr;
return *this;
}
template <class _Class>
template <class _OtherClass>
typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>, NS::SharedPtr<_Class> &>
_NS_INLINE NS::SharedPtr<_Class>::operator=(SharedPtr<_OtherClass>&& other)
{
if (m_pObject != other.get())
{
if (m_pObject)
{
m_pObject->release();
}
m_pObject = reinterpret_cast<_Class*>(other.get());
other.detach();
}
else
{
m_pObject = other.get();
other.reset();
}
return *this;
}
template <class _ClassLhs, class _ClassRhs>
_NS_INLINE bool operator==(const NS::SharedPtr<_ClassLhs>& lhs, const NS::SharedPtr<_ClassRhs>& rhs)
{
return lhs.get() == rhs.get();
}
template <class _ClassLhs, class _ClassRhs>
_NS_INLINE bool operator!=(const NS::SharedPtr<_ClassLhs>& lhs, const NS::SharedPtr<_ClassRhs>& rhs)
{
return lhs.get() != rhs.get();
}