// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #pragma once //----------------------------------------------------------------------------- // forward declarations //----------------------------------------------------------------------------- template class WeakRefTarget; template class WeakRefImpl; //----------------------------------------------------------------------------- // WeakRef //----------------------------------------------------------------------------- template class WeakRef final { friend class WeakRefTarget; public: WeakRef(const WeakRef& that): m_spImpl(that.m_spImpl) { } WeakRef(WeakRef&& that) noexcept: m_spImpl(std::move(that.m_spImpl)) { } const WeakRef& operator=(const WeakRef& that) { m_spImpl = that.m_spImpl; return *this; } const WeakRef& operator=(WeakRef&& that) noexcept { m_spImpl = std::move(that.m_spImpl); return *this; } SharedPtr GetTarget() const { return m_spImpl->GetTarget(); } private: explicit WeakRef(const SharedPtr>& spImpl): m_spImpl(spImpl) { } SharedPtr> m_spImpl; }; //----------------------------------------------------------------------------- // WeakRefTarget //----------------------------------------------------------------------------- template class WeakRefTarget: public SharedPtrTarget { public: WeakRefTarget(): m_spWeakRefImpl(new WeakRefImpl(static_cast(this))) { } WeakRef CreateWeakRef() const { return WeakRef(m_spWeakRefImpl); } protected: ~WeakRefTarget() { m_spWeakRefImpl->OnTargetDeleted(); } private: SharedPtr> m_spWeakRefImpl; }; //----------------------------------------------------------------------------- // WeakRefImpl //----------------------------------------------------------------------------- template class WeakRefImpl final: public SharedPtrTarget { friend class WeakRef; friend class WeakRefTarget; private: explicit WeakRefImpl(T* pTarget): m_pTarget(pTarget) { } SharedPtr GetTarget() { SharedPtr spTarget; BEGIN_MUTEX_SCOPE(m_Mutex) if (m_pTarget != nullptr) { AddRefScope addRefScope(m_pTarget->GetRefCount()); if (addRefScope.GetRefCountValue() > 1) { spTarget = m_pTarget; } } END_MUTEX_SCOPE return spTarget; } void OnTargetDeleted() { BEGIN_MUTEX_SCOPE(m_Mutex) m_pTarget = nullptr; END_MUTEX_SCOPE } SimpleMutex m_Mutex; T* m_pTarget; };