Path: blob/master/thirdparty/metal-cpp/Foundation/NSSharedPtr.hpp
21066 views
//-------------------------------------------------------------------------------------------------------------------------------------------------------------1//2// Foundation/NSSharedPtr.hpp3//4// Copyright 2020-2024 Apple Inc.5//6// Licensed under the Apache License, Version 2.0 (the "License");7// you may not use this file except in compliance with the License.8// You may obtain a copy of the License at9//10// http://www.apache.org/licenses/LICENSE-2.011//12// Unless required by applicable law or agreed to in writing, software13// distributed under the License is distributed on an "AS IS" BASIS,14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.15// See the License for the specific language governing permissions and16// limitations under the License.17//18//-------------------------------------------------------------------------------------------------------------------------------------------------------------1920#pragma once2122#include <cstddef>23#include "NSDefines.hpp"2425namespace NS26{27template <class _Class>28class SharedPtr29{30public:31/**32* Create a new null pointer.33*/34SharedPtr();3536/**37* Destroy this SharedPtr, decreasing the reference count.38*/39~SharedPtr();4041/**42* Create a new null pointer.43*/44SharedPtr(std::nullptr_t) noexcept;4546/**47* SharedPtr copy constructor.48*/49SharedPtr(const SharedPtr<_Class>& other) noexcept;5051/**52* Construction from another pointee type.53*/54template <class _OtherClass>55SharedPtr(const SharedPtr<_OtherClass>& other, typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>> * = nullptr) noexcept;5657/**58* SharedPtr move constructor.59*/60SharedPtr(SharedPtr<_Class>&& other) noexcept;6162/**63* Move from another pointee type.64*/65template <class _OtherClass>66SharedPtr(SharedPtr<_OtherClass>&& other, typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>> * = nullptr) noexcept;6768/**69* Copy assignment operator.70* Copying increases reference count. Only releases previous pointee if objects are different.71*/72SharedPtr& operator=(const SharedPtr<_Class>& other);7374/**75* Copy-assignment from different pointee.76* Copying increases reference count. Only releases previous pointee if objects are different.77*/78template <class _OtherClass>79typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>, SharedPtr &>80operator=(const SharedPtr<_OtherClass>& other);8182/**83* Move assignment operator.84* Move without affecting reference counts, unless pointees are equal. Moved-from object is reset to nullptr.85*/86SharedPtr& operator=(SharedPtr<_Class>&& other);8788/**89* Move-asignment from different pointee.90* Move without affecting reference counts, unless pointees are equal. Moved-from object is reset to nullptr.91*/92template <class _OtherClass>93typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>, SharedPtr &>94operator=(SharedPtr<_OtherClass>&& other);9596/**97* Access raw pointee.98* @warning Avoid wrapping the returned value again, as it may lead double frees unless this object becomes detached.99*/100_Class* get() const;101102/**103* Call operations directly on the pointee.104*/105_Class* operator->() const;106107/**108* Implicit cast to bool.109*/110explicit operator bool() const;111112/**113* Reset this SharedPtr to null, decreasing the reference count.114*/115void reset();116117/**118* Detach the SharedPtr from the pointee, without decreasing the reference count.119*/120void detach();121122template <class _OtherClass>123friend SharedPtr<_OtherClass> RetainPtr(_OtherClass* ptr);124125template <class _OtherClass>126friend SharedPtr<_OtherClass> TransferPtr(_OtherClass* ptr);127128private:129_Class* m_pObject;130};131132/**133* Create a SharedPtr by retaining an existing raw pointer.134* Increases the reference count of the passed-in object.135* If the passed-in object was in an AutoreleasePool, it will be removed from it.136*/137template <class _Class>138_NS_INLINE NS::SharedPtr<_Class> RetainPtr(_Class* pObject)139{140NS::SharedPtr<_Class> ret;141ret.m_pObject = pObject->retain();142return ret;143}144145/*146* Create a SharedPtr by transfering the ownership of an existing raw pointer to SharedPtr.147* Does not increase the reference count of the passed-in pointer, it is assumed to be >= 1.148* This method does not remove objects from an AutoreleasePool.149*/150template <class _Class>151_NS_INLINE NS::SharedPtr<_Class> TransferPtr(_Class* pObject)152{153NS::SharedPtr<_Class> ret;154ret.m_pObject = pObject;155return ret;156}157158}159160template <class _Class>161_NS_INLINE NS::SharedPtr<_Class>::SharedPtr()162: m_pObject(nullptr)163{164}165166template <class _Class>167_NS_INLINE NS::SharedPtr<_Class>::~SharedPtr<_Class>() __attribute__((no_sanitize("undefined")))168{169m_pObject->release();170}171172template <class _Class>173_NS_INLINE NS::SharedPtr<_Class>::SharedPtr(std::nullptr_t) noexcept174: m_pObject(nullptr)175{176}177178template <class _Class>179_NS_INLINE NS::SharedPtr<_Class>::SharedPtr(const SharedPtr<_Class>& other) noexcept180: m_pObject(other.m_pObject->retain())181{182}183184template <class _Class>185template <class _OtherClass>186_NS_INLINE NS::SharedPtr<_Class>::SharedPtr(const SharedPtr<_OtherClass>& other, typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>> *) noexcept187: m_pObject(reinterpret_cast<_Class*>(other.get()->retain()))188{189}190191template <class _Class>192_NS_INLINE NS::SharedPtr<_Class>::SharedPtr(SharedPtr<_Class>&& other) noexcept193: m_pObject(other.m_pObject)194{195other.m_pObject = nullptr;196}197198template <class _Class>199template <class _OtherClass>200_NS_INLINE NS::SharedPtr<_Class>::SharedPtr(SharedPtr<_OtherClass>&& other, typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>> *) noexcept201: m_pObject(reinterpret_cast<_Class*>(other.get()))202{203other.detach();204}205206template <class _Class>207_NS_INLINE _Class* NS::SharedPtr<_Class>::get() const208{209return m_pObject;210}211212template <class _Class>213_NS_INLINE _Class* NS::SharedPtr<_Class>::operator->() const214{215return m_pObject;216}217218template <class _Class>219_NS_INLINE NS::SharedPtr<_Class>::operator bool() const220{221return nullptr != m_pObject;222}223224template <class _Class>225_NS_INLINE void NS::SharedPtr<_Class>::reset() __attribute__((no_sanitize("undefined")))226{227m_pObject->release();228m_pObject = nullptr;229}230231template <class _Class>232_NS_INLINE void NS::SharedPtr<_Class>::detach()233{234m_pObject = nullptr;235}236237template <class _Class>238_NS_INLINE NS::SharedPtr<_Class>& NS::SharedPtr<_Class>::operator=(const SharedPtr<_Class>& other) __attribute__((no_sanitize("undefined")))239{240_Class* pOldObject = m_pObject;241242m_pObject = other.m_pObject->retain();243244pOldObject->release();245246return *this;247}248249template <class _Class>250template <class _OtherClass>251typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>, NS::SharedPtr<_Class> &>252_NS_INLINE NS::SharedPtr<_Class>::operator=(const SharedPtr<_OtherClass>& other) __attribute__((no_sanitize("undefined")))253{254_Class* pOldObject = m_pObject;255256m_pObject = reinterpret_cast<_Class*>(other.get()->retain());257258pOldObject->release();259260return *this;261}262263template <class _Class>264_NS_INLINE NS::SharedPtr<_Class>& NS::SharedPtr<_Class>::operator=(SharedPtr<_Class>&& other) __attribute__((no_sanitize("undefined")))265{266if (m_pObject != other.m_pObject)267{268m_pObject->release();269m_pObject = other.m_pObject;270}271else272{273m_pObject = other.m_pObject;274other.m_pObject->release();275}276other.m_pObject = nullptr;277return *this;278}279280template <class _Class>281template <class _OtherClass>282typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>, NS::SharedPtr<_Class> &>283_NS_INLINE NS::SharedPtr<_Class>::operator=(SharedPtr<_OtherClass>&& other) __attribute__((no_sanitize("undefined")))284{285if (m_pObject != other.get())286{287m_pObject->release();288m_pObject = reinterpret_cast<_Class*>(other.get());289other.detach();290}291else292{293m_pObject = other.get();294other.reset();295}296return *this;297}298299template <class _ClassLhs, class _ClassRhs>300_NS_INLINE bool operator==(const NS::SharedPtr<_ClassLhs>& lhs, const NS::SharedPtr<_ClassRhs>& rhs)301{302return lhs.get() == rhs.get();303}304305template <class _ClassLhs, class _ClassRhs>306_NS_INLINE bool operator!=(const NS::SharedPtr<_ClassLhs>& lhs, const NS::SharedPtr<_ClassRhs>& rhs)307{308return lhs.get() != rhs.get();309}310311312