suyu/externals/metal-cpp/Foundation/NSSharedPtr.hpp
2024-04-06 20:33:10 +02:00

311 lines
8.3 KiB
C++

//-------------------------------------------------------------------------------------------------------------------------------------------------------------
//
// Foundation/NSSharedPtr.hpp
//
// Copyright 2020-2023 Apple Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
#pragma once
#include "NSDefines.hpp"
namespace NS
{
template <class _Class>
class SharedPtr
{
public:
/**
* Create a new null pointer.
*/
SharedPtr();
/**
* Destroy this SharedPtr, decreasing the reference count.
*/
~SharedPtr();
/**
* SharedPtr copy constructor.
*/
SharedPtr(const SharedPtr<_Class>& other) noexcept;
/**
* Construction from another pointee type.
*/
template <class _OtherClass>
SharedPtr(const SharedPtr<_OtherClass>& other, typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>> * = nullptr) noexcept;
/**
* SharedPtr move constructor.
*/
SharedPtr(SharedPtr<_Class>&& other) noexcept;
/**
* Move from another pointee type.
*/
template <class _OtherClass>
SharedPtr(SharedPtr<_OtherClass>&& other, typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>> * = nullptr) noexcept;
/**
* Copy assignment operator.
* Copying increases reference count. Only releases previous pointee if objects are different.
*/
SharedPtr& operator=(const SharedPtr<_Class>& other);
/**
* Copy-assignment from different pointee.
* Copying increases reference count. Only releases previous pointee if objects are different.
*/
template <class _OtherClass>
typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>, SharedPtr &>
operator=(const SharedPtr<_OtherClass>& other);
/**
* Move assignment operator.
* Move without affecting reference counts, unless pointees are equal. Moved-from object is reset to nullptr.
*/
SharedPtr& operator=(SharedPtr<_Class>&& other);
/**
* Move-asignment from different pointee.
* Move without affecting reference counts, unless pointees are equal. Moved-from object is reset to nullptr.
*/
template <class _OtherClass>
typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>, SharedPtr &>
operator=(SharedPtr<_OtherClass>&& other);
/**
* Access raw pointee.
* @warning Avoid wrapping the returned value again, as it may lead double frees unless this object becomes detached.
*/
_Class* get() const;
/**
* Call operations directly on the pointee.
*/
_Class* operator->() const;
/**
* Implicit cast to bool.
*/
explicit operator bool() const;
/**
* Reset this SharedPtr to null, decreasing the reference count.
*/
void reset();
/**
* Detach the SharedPtr from the pointee, without decreasing the reference count.
*/
void detach();
template <class _OtherClass>
friend SharedPtr<_OtherClass> RetainPtr(_OtherClass* ptr);
template <class _OtherClass>
friend SharedPtr<_OtherClass> TransferPtr(_OtherClass* ptr);
private:
_Class* m_pObject;
};
/**
* Create a SharedPtr by retaining an existing raw pointer.
* Increases the reference count of the passed-in object.
* If the passed-in object was in an AutoreleasePool, it will be removed from it.
*/
template <class _Class>
_NS_INLINE NS::SharedPtr<_Class> RetainPtr(_Class* pObject)
{
NS::SharedPtr<_Class> ret;
ret.m_pObject = pObject->retain();
return ret;
}
/*
* Create a SharedPtr by transfering the ownership of an existing raw pointer to SharedPtr.
* Does not increase the reference count of the passed-in pointer, it is assumed to be >= 1.
* This method does not remove objects from an AutoreleasePool.
*/
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<_Class>()
{
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();
}