Last active
October 1, 2024 09:03
-
-
Save ruccho/e2b5ca51d5af8a65441c5cd4f5af5678 to your computer and use it in GitHub Desktop.
The minimal implementation of pooled IDisposable.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 | |
{ | |
#if THREADSAFE | |
[ThreadStatic] | |
private static Stack<Core> Pool; | |
#else | |
private static readonly Stack<Core> Pool = new(); | |
#endif | |
public static Core Get(Action<T> dispose, T state) | |
{ | |
#if THREADSAFE | |
Pool ??= new(); | |
#endif | |
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 | |
{ | |
#if THREADSAFE | |
Pool ??= new(); | |
#endif | |
Pool.Push(this); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment