151 lines
3.1 KiB
C++
151 lines
3.1 KiB
C++
|
/***
|
||
|
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||
|
|
||
|
File: DestructionWatch.hpp
|
||
|
Date: 2024-01-22
|
||
|
Author: Reece
|
||
|
***/
|
||
|
#pragma once
|
||
|
|
||
|
namespace Aurora::Utility
|
||
|
{
|
||
|
struct ADestructionWatcher;
|
||
|
|
||
|
struct DestructionWatch
|
||
|
{
|
||
|
inline DestructionWatch();
|
||
|
inline ~DestructionWatch();
|
||
|
|
||
|
inline void RemoveAll();
|
||
|
|
||
|
private:
|
||
|
friend struct ADestructionWatcher;
|
||
|
|
||
|
Threading::Waitables::FutexWaitable mutex;
|
||
|
ADestructionWatcher *pFirstWatcher {};
|
||
|
AuList<ADestructionWatcher *> listpWatches;
|
||
|
|
||
|
inline void RemoveWatcher(ADestructionWatcher *pWatcher);
|
||
|
inline void RemoveWatcherCall(ADestructionWatcher *pWatcher);
|
||
|
};
|
||
|
|
||
|
struct ADestructionWatcher
|
||
|
{
|
||
|
inline ADestructionWatcher();
|
||
|
inline ~ADestructionWatcher();
|
||
|
|
||
|
inline void Observe(DestructionWatch *pWatch);
|
||
|
inline bool IsObservedAlive();
|
||
|
inline bool IsObservedDead();
|
||
|
|
||
|
protected:
|
||
|
inline virtual void OnDestroyedChild()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
friend struct DestructionWatch;
|
||
|
|
||
|
inline void OnSelfDTOR();
|
||
|
inline void OnDTOR();
|
||
|
|
||
|
DestructionWatch *pParent {};
|
||
|
bool bWasCalled {};
|
||
|
};
|
||
|
|
||
|
DestructionWatch::DestructionWatch()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
DestructionWatch::~DestructionWatch()
|
||
|
{
|
||
|
this->RemoveAll();
|
||
|
}
|
||
|
|
||
|
void DestructionWatch::RemoveAll()
|
||
|
{
|
||
|
AU_LOCK_GUARD(this->mutex);
|
||
|
|
||
|
if (auto pWatcher = AuExchange(this->pFirstWatcher, nullptr))
|
||
|
{
|
||
|
this->RemoveWatcherCall(pWatcher);
|
||
|
}
|
||
|
|
||
|
for (const auto pWatcher : AuExchange(this->listpWatches, {}))
|
||
|
{
|
||
|
this->RemoveWatcherCall(pWatcher);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void DestructionWatch::RemoveWatcher(ADestructionWatcher *pWatcher)
|
||
|
{
|
||
|
AU_LOCK_GUARD(this->mutex);
|
||
|
if (this->pFirstWatcher == pWatcher)
|
||
|
{
|
||
|
this->pFirstWatcher = nullptr;
|
||
|
}
|
||
|
AuTryRemove(this->listpWatches, pWatcher);
|
||
|
}
|
||
|
|
||
|
void DestructionWatch::RemoveWatcherCall(ADestructionWatcher *pWatcher)
|
||
|
{
|
||
|
pWatcher->OnDTOR();
|
||
|
}
|
||
|
|
||
|
ADestructionWatcher::ADestructionWatcher()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
ADestructionWatcher::~ADestructionWatcher()
|
||
|
{
|
||
|
this->OnSelfDTOR();
|
||
|
}
|
||
|
|
||
|
void ADestructionWatcher::Observe(DestructionWatch *pWatch)
|
||
|
{
|
||
|
AU_LOCK_GUARD(pWatch->mutex);
|
||
|
if (!pWatch->pFirstWatcher)
|
||
|
{
|
||
|
pWatch->pFirstWatcher = this;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pWatch->listpWatches.push_back(this);
|
||
|
}
|
||
|
this->pParent = pWatch;
|
||
|
}
|
||
|
|
||
|
bool ADestructionWatcher::IsObservedAlive()
|
||
|
{
|
||
|
return !this->bWasCalled;
|
||
|
}
|
||
|
|
||
|
bool ADestructionWatcher::IsObservedDead()
|
||
|
{
|
||
|
return this->bWasCalled;
|
||
|
}
|
||
|
|
||
|
void ADestructionWatcher::OnSelfDTOR()
|
||
|
{
|
||
|
if (auto pParent = AuExchange(this->pParent, nullptr))
|
||
|
{
|
||
|
pParent->RemoveWatcher(this);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ADestructionWatcher::OnDTOR()
|
||
|
{
|
||
|
this->pParent = nullptr;
|
||
|
|
||
|
if (AuExchange(this->bWasCalled, true))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this->OnDestroyedChild();
|
||
|
}
|
||
|
}
|