Skip to content

Instantly share code, notes, and snippets.

@ruccho
Last active September 9, 2024 00:18
Show Gist options
  • Save ruccho/e2b5ca51d5af8a65441c5cd4f5af5678 to your computer and use it in GitHub Desktop.
Save ruccho/e2b5ca51d5af8a65441c5cd4f5af5678 to your computer and use it in GitHub Desktop.
The minimal implementation of pooled IDisposable.
#define THREADSAFE
using System;
using System.Collections.Generic;
using System.Threading;
public static class Disposable
{
public static Disposable<T> Create<T>(Action<T> dispose, T state)
{
return Disposable<T>.Create(dispose, state);
}
}
public readonly struct Disposable<T> : IDisposable
{
public static Disposable<T> Create(Action<T> dispose, T state)
{
return new Disposable<T>(Core.Get(dispose, state));
}
private readonly int version;
private readonly Core core;
private Disposable(Core core)
{
this.version = core.Version;
this.core = core;
}
public void Dispose()
{
core.Dispose(version);
}
private class Core
{
private static readonly
#if THREADSAFE
ConcurrentStack<Core>
#else
Stack<Core>
#endif
Pool = new();
public static Core Get(Action<T> dispose, T state)
{
if (!Pool.TryPop(out var pooled))
{
pooled = new();
}
pooled.dispose = dispose;
pooled.state = state;
return pooled;
}
public int Version => version;
private int version;
private Action<T> dispose;
private T state;
public void Dispose(int version)
{
if (version != this.version) return;
#if THREADSAFE
if (Interlocked.CompareExchange(ref this.version, unchecked(version + 1), version) != version) return;
#else
this.version = unchecked(version + 1);
#endif
try
{
dispose(state);
}
finally
{
if (version == -2)
{
// collected by GC
}
else
{
Pool.Push(this);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment