// 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;
};