// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #pragma once //----------------------------------------------------------------------------- // SharedPtrTarget //----------------------------------------------------------------------------- class SharedPtrTarget { PROHIBIT_COPY(SharedPtrTarget) public: RefCount* GetRefCount() { return &m_RefCount; } protected: class AddRefScope final { PROHIBIT_COPY(AddRefScope) PROHIBIT_HEAP(AddRefScope) public: explicit AddRefScope(RefCount* pRefCount): m_pRefCount(pRefCount), m_RefCountValue(pRefCount->Increment()) { } size_t GetRefCountValue() const { return m_RefCountValue; } ~AddRefScope() { m_pRefCount->Decrement(); } private: RefCount* m_pRefCount; size_t m_RefCountValue; }; SharedPtrTarget(): m_RefCount(0) { } private: RefCount m_RefCount; }; //----------------------------------------------------------------------------- #define BEGIN_ADDREF_SCOPE \ { \ DISABLE_WARNING(4456) /* declaration hides previous local declaration */ \ AddRefScope t_AddRefScope(GetRefCount()); \ DEFAULT_WARNING(4456) #define END_ADDREF_SCOPE \ IGNORE_UNUSED(t_AddRefScope); \ } //----------------------------------------------------------------------------- // SharedPtrTraits //----------------------------------------------------------------------------- template struct SharedPtrTraits final: StaticBase { static void Destroy(T* pTarget) { delete pTarget; } }; //----------------------------------------------------------------------------- // SharedPtr //----------------------------------------------------------------------------- template class SharedPtr final { template friend class SharedPtr; public: SharedPtr() { Initialize(); } explicit SharedPtr(std::nullptr_t) { Initialize(); } explicit SharedPtr(T* pTarget) { Initialize(pTarget); } SharedPtr(const SharedPtr& that) { CopyInitialize(that); } SharedPtr(SharedPtr&& that) noexcept { MoveInitialize(that); } template explicit SharedPtr(const SharedPtr& that) { CopyInitialize(that); } template explicit SharedPtr(SharedPtr&& that) { MoveInitialize(that); } const SharedPtr& operator=(std::nullptr_t) { Empty(); return *this; } const SharedPtr& operator=(T* pTarget) { SharedPtr spHolder(m_pTarget, m_pRefCount); Initialize(pTarget); return *this; } const SharedPtr& operator=(const SharedPtr& that) { Copy(that); return *this; } const SharedPtr& operator=(SharedPtr&& that) noexcept { Move(that); return *this; } template const SharedPtr& operator=(const SharedPtr& that) { Copy(that); return *this; } template const SharedPtr& operator=(SharedPtr&& that) { Move(that); return *this; } T* operator->() const { _ASSERTE(m_pTarget != nullptr); return m_pTarget; } T& operator*() const { _ASSERTE(m_pTarget != nullptr); return *m_pTarget; } template TOther& DerefAs() const { _ASSERTE(m_pTarget != nullptr); return *static_cast(m_pTarget); } bool operator==(std::nullptr_t) const { return IsEmpty(); } bool operator==(T* pThat) const { return m_pTarget == pThat; } template bool operator==(const SharedPtr& that) const { return m_pTarget == that.m_pTarget; } bool operator!=(std::nullptr_t) const { return !operator==(nullptr); } bool operator!=(T* pThat) const { return !operator==(pThat); } template bool operator!=(const SharedPtr& that) const { return !operator==(that); } template SharedPtr CastTo() const { AddRef(); return SharedPtr(static_cast(m_pTarget), m_pRefCount); } bool IsEmpty() const { return m_pTarget == nullptr; } void Empty() { SharedPtr spHolder(std::move(*this)); } ~SharedPtr() { Release(); } private: SharedPtr(T* pTarget, RefCount* pRefCount) { Initialize(pTarget, pRefCount); } void Initialize() { m_pTarget = nullptr; m_pRefCount = nullptr; } void Initialize(T* pTarget) { m_pTarget = pTarget; m_pRefCount = (m_pTarget != nullptr) ? AttachRefCount(m_pTarget) : nullptr; } void Initialize(T* pTarget, RefCount* pRefCount) { m_pTarget = pTarget; m_pRefCount = pRefCount; } template void CopyInitialize(const SharedPtr& that) { Initialize(that.m_pTarget, that.m_pRefCount); AddRef(); } template void MoveInitialize(SharedPtr& that) { Initialize(that.m_pTarget, that.m_pRefCount); that.Initialize(); } template void Copy(const SharedPtr& that) { SharedPtr spHolder(m_pTarget, m_pRefCount); CopyInitialize(that); } template void Move(SharedPtr& that) { SharedPtr spHolder(m_pTarget, m_pRefCount); MoveInitialize(that); } void AddRef() const { if (m_pTarget != nullptr) { _ASSERTE(m_pRefCount); m_pRefCount->Increment(); } } void Release() { if (m_pTarget != nullptr) { T* pTarget = m_pTarget; m_pTarget = nullptr; RefCount* pRefCount = m_pRefCount; m_pRefCount = nullptr; _ASSERTE(pRefCount); if (pRefCount->Decrement() == 0) { DetachRefCount(pTarget, pRefCount); SharedPtrTraits::Destroy(pTarget); } } } static RefCount* AttachRefCount(SharedPtrTarget* pTarget) { RefCount* pRefCount = pTarget->GetRefCount(); pRefCount->Increment(); return pRefCount; } static void DetachRefCount(SharedPtrTarget* /*pTarget*/, RefCount* /*pRefCount*/) { } static RefCount* AttachRefCount(void* /*pvTarget*/) { return new RefCount(1); } static void DetachRefCount(void* /*pvTarget*/, RefCount* pRefCount) { delete pRefCount; } T* m_pTarget; RefCount* m_pRefCount; };