Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix SharedPtr block destruction #15

Merged
merged 1 commit into from
May 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 30 additions & 8 deletions radiant/SharedPtr.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ class _PtrBlockBase

RAD_NOT_COPYABLE(_PtrBlockBase);

virtual void Destroy() const noexcept = 0;
virtual void Delete() const noexcept = 0;
virtual void OnRefZero() const noexcept = 0;
virtual void OnWeakZero() const noexcept = 0;

const _PtrRefCount& RefCount() const noexcept
{
Expand All @@ -140,7 +140,7 @@ class _PtrBlockBase
{
if (RefCount().Decrement())
{
Destroy();
OnRefZero();
ReleaseWeak();
}
}
Expand All @@ -149,7 +149,7 @@ class _PtrBlockBase
{
if (RefCount().DecrementWeak())
{
Delete();
OnWeakZero();
}
}

Expand Down Expand Up @@ -188,22 +188,44 @@ class _PtrBlock final : public _PtrBlockBase
{
}

void Destroy() const noexcept override
void OnRefZero() const noexcept override
{
m_pair.~PairType();
//
// The strong reference count has dropped to zero, destruct the managed
// object now. Once the weak reference count drops to zero the rest of
// the block will be destructed and freed.
//
Value().~ValueType();
}

void Delete() const noexcept override
void OnWeakZero() const noexcept override
{
//
// Take a copy of the allocator first, this will be used to do the free.
// Then destruct the remaining parts of the block.
//
// N.B. The _PtrBlockBase and PairType destructors are not invoked
// directly because the base contains only atomics which do not need to
// be destructed and the PairType is destructed in parts. Perhaps there
// is a more correct way to handle this, but this seems to account for
// destructing the necessary parts as it is.
//
AllocatorType alloc(Allocator());
auto _this = const_cast<_PtrBlock*>(this);
_this->Allocator().Free(_this);
Allocator().~AllocatorType();
alloc.Free(_this);
}

AllocatorType& Allocator() noexcept
{
return m_pair.First();
}

const AllocatorType& Allocator() const noexcept
{
return m_pair.First();
}

ValueType& Value() noexcept
{
return m_pair.Second();
Expand Down
88 changes: 69 additions & 19 deletions test/TestAlloc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,48 +19,98 @@
namespace radtest
{

uint32_t StaticCountingAllocatorImpl::freeCount = 0;
uint32_t StaticCountingAllocatorImpl::allocCount = 0;
uint32_t StaticCountingAllocatorImpl::reallocCount = 0;
uint32_t StaticCountingAllocatorImpl::freeBytesCount = 0;
uint32_t StaticCountingAllocatorImpl::allocBytesCount = 0;
uint32_t StaticCountingAllocatorImpl::reallocBytesCount = 0;
uint32_t CountingAllocatorImpl::g_FreeCount = 0;
uint32_t CountingAllocatorImpl::g_AllocCount = 0;
uint32_t CountingAllocatorImpl::g_ReallocCount = 0;
uint32_t CountingAllocatorImpl::g_FreeBytesCount = 0;
uint32_t CountingAllocatorImpl::g_AllocBytesCount = 0;
uint32_t CountingAllocatorImpl::g_ReallocBytesCount = 0;

void StaticCountingAllocatorImpl::Free(void* ptr) noexcept
void CountingAllocatorImpl::Free(void* ptr) noexcept
{
++freeCount;
++g_FreeCount;
free(ptr);
}

void* StaticCountingAllocatorImpl::Alloc(uint32_t size) noexcept
void* CountingAllocatorImpl::Alloc(uint32_t size) noexcept
{
++allocCount;
++g_AllocCount;
return malloc(size);
}

void* StaticCountingAllocatorImpl::Realloc(void* ptr, uint32_t size) noexcept
void* CountingAllocatorImpl::Realloc(void* ptr, uint32_t size) noexcept
{
++reallocCount;
++g_ReallocCount;
return realloc(ptr, size);
}

void StaticCountingAllocatorImpl::FreeBytes(void* ptr) noexcept
void CountingAllocatorImpl::FreeBytes(void* ptr) noexcept
{
++freeBytesCount;
++g_FreeBytesCount;
free(ptr);
}

void* StaticCountingAllocatorImpl::AllocBytes(uint32_t size) noexcept
void* CountingAllocatorImpl::AllocBytes(uint32_t size) noexcept
{
++allocBytesCount;
++g_AllocBytesCount;
return malloc(size);
}

void* StaticCountingAllocatorImpl::ReallocBytes(void* ptr,
uint32_t size) noexcept
void* CountingAllocatorImpl::ReallocBytes(void* ptr, uint32_t size) noexcept
{
++reallocBytesCount;
++g_ReallocBytesCount;
return realloc(ptr, size);
}

uint32_t CountingAllocatorImpl::FreeCount() noexcept
{
return g_FreeCount;
}

uint32_t CountingAllocatorImpl::AllocCount() noexcept
{
return g_AllocCount;
}

uint32_t CountingAllocatorImpl::ReallocCount() noexcept
{
return g_ReallocCount;
}

uint32_t CountingAllocatorImpl::FreeBytesCount() noexcept
{
return g_FreeBytesCount;
}

uint32_t CountingAllocatorImpl::AllocBytesCount() noexcept
{
return g_AllocBytesCount;
}

uint32_t CountingAllocatorImpl::ReallocBytesCount() noexcept
{
return g_ReallocBytesCount;
}

void CountingAllocatorImpl::ResetCounts() noexcept
{
g_FreeCount = 0;
g_AllocCount = 0;
g_ReallocCount = 0;
g_FreeBytesCount = 0;
g_AllocBytesCount = 0;
g_ReallocBytesCount = 0;
}

bool CountingAllocatorImpl::VerifyCounts() noexcept
{
return (g_AllocCount == g_FreeCount);
}

bool CountingAllocatorImpl::VerifyCounts(uint32_t expectedAllocs,
uint32_t expectedFrees) noexcept
{
return (g_AllocCount == expectedAllocs) && (g_FreeCount == expectedFrees);
}

} // namespace radtest
Loading
Loading