using System.Diagnostics;
using System.Threading;
namespace Dalamud.Utility;
///
/// Interface for reference counting.
///
internal interface IRefCountable : IDisposable
{
///
/// Result for .
///
public enum RefCountResult
{
///
/// The object still has remaining references. No futher action should be done.
///
StillAlive = 1,
///
/// The last reference to the object has been released. The object should be fully released.
///
FinalRelease = 2,
///
/// The object already has been disposed. may be thrown.
///
AlreadyDisposed = 3,
}
///
/// Adds a reference to this reference counted object.
///
/// The new number of references.
int AddRef();
///
/// Releases a reference from this reference counted object.
/// When all references are released, the object will be fully disposed.
///
/// The new number of references.
int Release();
///
/// Alias for .
///
void IDisposable.Dispose() => this.Release();
///
/// Alters by .
///
/// The delta to the reference count.
/// The reference to the reference count.
/// The new reference count.
/// The followup action that should be done.
public static RefCountResult AlterRefCount(int delta, ref int refCount, out int newRefCount)
{
Debug.Assert(delta is 1 or -1, "delta must be 1 or -1");
while (true)
{
var refCountCopy = refCount;
if (refCountCopy <= 0)
{
newRefCount = refCountCopy;
return RefCountResult.AlreadyDisposed;
}
newRefCount = refCountCopy + delta;
if (refCountCopy != Interlocked.CompareExchange(ref refCount, newRefCount, refCountCopy))
continue;
return newRefCount == 0 ? RefCountResult.FinalRelease : RefCountResult.StillAlive;
}
}
}