Last active
April 6, 2026 06:22
-
-
Save ruccho/253fc9f52a6ede8c58c51e9c025d621a to your computer and use it in GitHub Desktop.
An utility to get Action<T> which is automatically pooled after called once.
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
| using System; | |
| using System.Threading; | |
| using System.Collections.Concurrent; | |
| namespace PooledActions | |
| { | |
| internal readonly struct PooledActionOnce<TContext> : IDisposable | |
| { | |
| private static int _poolCapacity = 32; | |
| public static int PoolCapacity | |
| { | |
| get => _poolCapacity; | |
| set | |
| { | |
| if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Pool capacity must be non-negative."); | |
| _poolCapacity = value; | |
| while (Volatile.Read(ref _poolCount) > _poolCapacity) | |
| { | |
| if (!Pool.TryDequeue(out _)) | |
| { | |
| break; | |
| } | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| } | |
| } | |
| private static int _poolCount = 0; | |
| private static readonly ConcurrentQueue<Core> Pool = new(); | |
| private readonly ushort _version; | |
| private readonly Core _core; | |
| public Action Wrapper | |
| { | |
| get | |
| { | |
| if (_core._version != _version) throw new InvalidOperationException(); | |
| return _core.Wrapper; | |
| } | |
| } | |
| public static PooledActionOnce<TContext> Get( | |
| Action<TContext, Action> callback, TContext context) | |
| { | |
| if (callback == null) throw new ArgumentNullException(nameof(callback)); | |
| if (Pool.TryDequeue(out var pooled)) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| else | |
| { | |
| pooled = new Core(); | |
| } | |
| pooled.Set(callback, context); | |
| return new PooledActionOnce<TContext>(pooled); | |
| } | |
| public void Dispose() | |
| { | |
| if (_core._version != _version) return; | |
| _core.Release(); | |
| } | |
| private PooledActionOnce(Core core) | |
| { | |
| _version = core._version; | |
| _core = core; | |
| } | |
| private class Core | |
| { | |
| private Action<TContext, Action> _callback; | |
| private TContext _context; | |
| public ushort _version; | |
| public Core() | |
| { | |
| Wrapper = () => | |
| { | |
| _callback!(_context, Wrapper); | |
| Release(); | |
| }; | |
| } | |
| public Action Wrapper { get; } | |
| public void Set(Action<TContext, Action> callback, TContext context) | |
| { | |
| _callback = callback; | |
| _context = context; | |
| } | |
| public void Release() | |
| { | |
| _callback = null; | |
| _context = default; | |
| if (++_version == ushort.MaxValue) return; | |
| var reservedCount = Interlocked.Increment(ref _poolCount); | |
| if (reservedCount > PoolCapacity) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| return; | |
| } | |
| Pool.Enqueue(this); | |
| } | |
| } | |
| } | |
| internal readonly struct PooledActionOnce<TContext, T1> : IDisposable | |
| { | |
| private static int _poolCapacity = 32; | |
| public static int PoolCapacity | |
| { | |
| get => _poolCapacity; | |
| set | |
| { | |
| if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Pool capacity must be non-negative."); | |
| _poolCapacity = value; | |
| while (Volatile.Read(ref _poolCount) > _poolCapacity) | |
| { | |
| if (!Pool.TryDequeue(out _)) | |
| { | |
| break; | |
| } | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| } | |
| } | |
| private static int _poolCount = 0; | |
| private static readonly ConcurrentQueue<Core> Pool = new(); | |
| private readonly ushort _version; | |
| private readonly Core _core; | |
| public Action<T1> Wrapper | |
| { | |
| get | |
| { | |
| if (_core._version != _version) throw new InvalidOperationException(); | |
| return _core.Wrapper; | |
| } | |
| } | |
| public static PooledActionOnce<TContext, T1> Get( | |
| Action<TContext, Action<T1>, T1> callback, TContext context) | |
| { | |
| if (callback == null) throw new ArgumentNullException(nameof(callback)); | |
| if (Pool.TryDequeue(out var pooled)) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| else | |
| { | |
| pooled = new Core(); | |
| } | |
| pooled.Set(callback, context); | |
| return new PooledActionOnce<TContext, T1>(pooled); | |
| } | |
| public void Dispose() | |
| { | |
| if (_core._version != _version) return; | |
| _core.Release(); | |
| } | |
| private PooledActionOnce(Core core) | |
| { | |
| _version = core._version; | |
| _core = core; | |
| } | |
| private class Core | |
| { | |
| private Action<TContext, Action<T1>, T1> _callback; | |
| private TContext _context; | |
| public ushort _version; | |
| public Core() | |
| { | |
| Wrapper = (arg1) => | |
| { | |
| _callback!(_context, Wrapper, arg1); | |
| Release(); | |
| }; | |
| } | |
| public Action<T1> Wrapper { get; } | |
| public void Set(Action<TContext, Action<T1>, T1> callback, TContext context) | |
| { | |
| _callback = callback; | |
| _context = context; | |
| } | |
| public void Release() | |
| { | |
| _callback = null; | |
| _context = default; | |
| if (++_version == ushort.MaxValue) return; | |
| var reservedCount = Interlocked.Increment(ref _poolCount); | |
| if (reservedCount > PoolCapacity) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| return; | |
| } | |
| Pool.Enqueue(this); | |
| } | |
| } | |
| } | |
| internal readonly struct PooledActionOnce<TContext, T1, T2> : IDisposable | |
| { | |
| private static int _poolCapacity = 32; | |
| public static int PoolCapacity | |
| { | |
| get => _poolCapacity; | |
| set | |
| { | |
| if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Pool capacity must be non-negative."); | |
| _poolCapacity = value; | |
| while (Volatile.Read(ref _poolCount) > _poolCapacity) | |
| { | |
| if (!Pool.TryDequeue(out _)) | |
| { | |
| break; | |
| } | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| } | |
| } | |
| private static int _poolCount = 0; | |
| private static readonly ConcurrentQueue<Core> Pool = new(); | |
| private readonly ushort _version; | |
| private readonly Core _core; | |
| public Action<T1, T2> Wrapper | |
| { | |
| get | |
| { | |
| if (_core._version != _version) throw new InvalidOperationException(); | |
| return _core.Wrapper; | |
| } | |
| } | |
| public static PooledActionOnce<TContext, T1, T2> Get( | |
| Action<TContext, Action<T1, T2>, T1, T2> callback, TContext context) | |
| { | |
| if (callback == null) throw new ArgumentNullException(nameof(callback)); | |
| if (Pool.TryDequeue(out var pooled)) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| else | |
| { | |
| pooled = new Core(); | |
| } | |
| pooled.Set(callback, context); | |
| return new PooledActionOnce<TContext, T1, T2>(pooled); | |
| } | |
| public void Dispose() | |
| { | |
| if (_core._version != _version) return; | |
| _core.Release(); | |
| } | |
| private PooledActionOnce(Core core) | |
| { | |
| _version = core._version; | |
| _core = core; | |
| } | |
| private class Core | |
| { | |
| private Action<TContext, Action<T1, T2>, T1, T2> _callback; | |
| private TContext _context; | |
| public ushort _version; | |
| public Core() | |
| { | |
| Wrapper = (arg1, arg2) => | |
| { | |
| _callback!(_context, Wrapper, arg1, arg2); | |
| Release(); | |
| }; | |
| } | |
| public Action<T1, T2> Wrapper { get; } | |
| public void Set(Action<TContext, Action<T1, T2>, T1, T2> callback, TContext context) | |
| { | |
| _callback = callback; | |
| _context = context; | |
| } | |
| public void Release() | |
| { | |
| _callback = null; | |
| _context = default; | |
| if (++_version == ushort.MaxValue) return; | |
| var reservedCount = Interlocked.Increment(ref _poolCount); | |
| if (reservedCount > PoolCapacity) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| return; | |
| } | |
| Pool.Enqueue(this); | |
| } | |
| } | |
| } | |
| internal readonly struct PooledActionOnce<TContext, T1, T2, T3> : IDisposable | |
| { | |
| private static int _poolCapacity = 32; | |
| public static int PoolCapacity | |
| { | |
| get => _poolCapacity; | |
| set | |
| { | |
| if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Pool capacity must be non-negative."); | |
| _poolCapacity = value; | |
| while (Volatile.Read(ref _poolCount) > _poolCapacity) | |
| { | |
| if (!Pool.TryDequeue(out _)) | |
| { | |
| break; | |
| } | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| } | |
| } | |
| private static int _poolCount = 0; | |
| private static readonly ConcurrentQueue<Core> Pool = new(); | |
| private readonly ushort _version; | |
| private readonly Core _core; | |
| public Action<T1, T2, T3> Wrapper | |
| { | |
| get | |
| { | |
| if (_core._version != _version) throw new InvalidOperationException(); | |
| return _core.Wrapper; | |
| } | |
| } | |
| public static PooledActionOnce<TContext, T1, T2, T3> Get( | |
| Action<TContext, Action<T1, T2, T3>, T1, T2, T3> callback, TContext context) | |
| { | |
| if (callback == null) throw new ArgumentNullException(nameof(callback)); | |
| if (Pool.TryDequeue(out var pooled)) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| else | |
| { | |
| pooled = new Core(); | |
| } | |
| pooled.Set(callback, context); | |
| return new PooledActionOnce<TContext, T1, T2, T3>(pooled); | |
| } | |
| public void Dispose() | |
| { | |
| if (_core._version != _version) return; | |
| _core.Release(); | |
| } | |
| private PooledActionOnce(Core core) | |
| { | |
| _version = core._version; | |
| _core = core; | |
| } | |
| private class Core | |
| { | |
| private Action<TContext, Action<T1, T2, T3>, T1, T2, T3> _callback; | |
| private TContext _context; | |
| public ushort _version; | |
| public Core() | |
| { | |
| Wrapper = (arg1, arg2, arg3) => | |
| { | |
| _callback!(_context, Wrapper, arg1, arg2, arg3); | |
| Release(); | |
| }; | |
| } | |
| public Action<T1, T2, T3> Wrapper { get; } | |
| public void Set(Action<TContext, Action<T1, T2, T3>, T1, T2, T3> callback, TContext context) | |
| { | |
| _callback = callback; | |
| _context = context; | |
| } | |
| public void Release() | |
| { | |
| _callback = null; | |
| _context = default; | |
| if (++_version == ushort.MaxValue) return; | |
| var reservedCount = Interlocked.Increment(ref _poolCount); | |
| if (reservedCount > PoolCapacity) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| return; | |
| } | |
| Pool.Enqueue(this); | |
| } | |
| } | |
| } | |
| internal readonly struct PooledActionOnce<TContext, T1, T2, T3, T4> : IDisposable | |
| { | |
| private static int _poolCapacity = 32; | |
| public static int PoolCapacity | |
| { | |
| get => _poolCapacity; | |
| set | |
| { | |
| if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Pool capacity must be non-negative."); | |
| _poolCapacity = value; | |
| while (Volatile.Read(ref _poolCount) > _poolCapacity) | |
| { | |
| if (!Pool.TryDequeue(out _)) | |
| { | |
| break; | |
| } | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| } | |
| } | |
| private static int _poolCount = 0; | |
| private static readonly ConcurrentQueue<Core> Pool = new(); | |
| private readonly ushort _version; | |
| private readonly Core _core; | |
| public Action<T1, T2, T3, T4> Wrapper | |
| { | |
| get | |
| { | |
| if (_core._version != _version) throw new InvalidOperationException(); | |
| return _core.Wrapper; | |
| } | |
| } | |
| public static PooledActionOnce<TContext, T1, T2, T3, T4> Get( | |
| Action<TContext, Action<T1, T2, T3, T4>, T1, T2, T3, T4> callback, TContext context) | |
| { | |
| if (callback == null) throw new ArgumentNullException(nameof(callback)); | |
| if (Pool.TryDequeue(out var pooled)) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| else | |
| { | |
| pooled = new Core(); | |
| } | |
| pooled.Set(callback, context); | |
| return new PooledActionOnce<TContext, T1, T2, T3, T4>(pooled); | |
| } | |
| public void Dispose() | |
| { | |
| if (_core._version != _version) return; | |
| _core.Release(); | |
| } | |
| private PooledActionOnce(Core core) | |
| { | |
| _version = core._version; | |
| _core = core; | |
| } | |
| private class Core | |
| { | |
| private Action<TContext, Action<T1, T2, T3, T4>, T1, T2, T3, T4> _callback; | |
| private TContext _context; | |
| public ushort _version; | |
| public Core() | |
| { | |
| Wrapper = (arg1, arg2, arg3, arg4) => | |
| { | |
| _callback!(_context, Wrapper, arg1, arg2, arg3, arg4); | |
| Release(); | |
| }; | |
| } | |
| public Action<T1, T2, T3, T4> Wrapper { get; } | |
| public void Set(Action<TContext, Action<T1, T2, T3, T4>, T1, T2, T3, T4> callback, TContext context) | |
| { | |
| _callback = callback; | |
| _context = context; | |
| } | |
| public void Release() | |
| { | |
| _callback = null; | |
| _context = default; | |
| if (++_version == ushort.MaxValue) return; | |
| var reservedCount = Interlocked.Increment(ref _poolCount); | |
| if (reservedCount > PoolCapacity) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| return; | |
| } | |
| Pool.Enqueue(this); | |
| } | |
| } | |
| } | |
| internal readonly struct PooledActionOnce<TContext, T1, T2, T3, T4, T5> : IDisposable | |
| { | |
| private static int _poolCapacity = 32; | |
| public static int PoolCapacity | |
| { | |
| get => _poolCapacity; | |
| set | |
| { | |
| if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Pool capacity must be non-negative."); | |
| _poolCapacity = value; | |
| while (Volatile.Read(ref _poolCount) > _poolCapacity) | |
| { | |
| if (!Pool.TryDequeue(out _)) | |
| { | |
| break; | |
| } | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| } | |
| } | |
| private static int _poolCount = 0; | |
| private static readonly ConcurrentQueue<Core> Pool = new(); | |
| private readonly ushort _version; | |
| private readonly Core _core; | |
| public Action<T1, T2, T3, T4, T5> Wrapper | |
| { | |
| get | |
| { | |
| if (_core._version != _version) throw new InvalidOperationException(); | |
| return _core.Wrapper; | |
| } | |
| } | |
| public static PooledActionOnce<TContext, T1, T2, T3, T4, T5> Get( | |
| Action<TContext, Action<T1, T2, T3, T4, T5>, T1, T2, T3, T4, T5> callback, TContext context) | |
| { | |
| if (callback == null) throw new ArgumentNullException(nameof(callback)); | |
| if (Pool.TryDequeue(out var pooled)) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| else | |
| { | |
| pooled = new Core(); | |
| } | |
| pooled.Set(callback, context); | |
| return new PooledActionOnce<TContext, T1, T2, T3, T4, T5>(pooled); | |
| } | |
| public void Dispose() | |
| { | |
| if (_core._version != _version) return; | |
| _core.Release(); | |
| } | |
| private PooledActionOnce(Core core) | |
| { | |
| _version = core._version; | |
| _core = core; | |
| } | |
| private class Core | |
| { | |
| private Action<TContext, Action<T1, T2, T3, T4, T5>, T1, T2, T3, T4, T5> _callback; | |
| private TContext _context; | |
| public ushort _version; | |
| public Core() | |
| { | |
| Wrapper = (arg1, arg2, arg3, arg4, arg5) => | |
| { | |
| _callback!(_context, Wrapper, arg1, arg2, arg3, arg4, arg5); | |
| Release(); | |
| }; | |
| } | |
| public Action<T1, T2, T3, T4, T5> Wrapper { get; } | |
| public void Set(Action<TContext, Action<T1, T2, T3, T4, T5>, T1, T2, T3, T4, T5> callback, TContext context) | |
| { | |
| _callback = callback; | |
| _context = context; | |
| } | |
| public void Release() | |
| { | |
| _callback = null; | |
| _context = default; | |
| if (++_version == ushort.MaxValue) return; | |
| var reservedCount = Interlocked.Increment(ref _poolCount); | |
| if (reservedCount > PoolCapacity) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| return; | |
| } | |
| Pool.Enqueue(this); | |
| } | |
| } | |
| } | |
| internal readonly struct PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6> : IDisposable | |
| { | |
| private static int _poolCapacity = 32; | |
| public static int PoolCapacity | |
| { | |
| get => _poolCapacity; | |
| set | |
| { | |
| if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Pool capacity must be non-negative."); | |
| _poolCapacity = value; | |
| while (Volatile.Read(ref _poolCount) > _poolCapacity) | |
| { | |
| if (!Pool.TryDequeue(out _)) | |
| { | |
| break; | |
| } | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| } | |
| } | |
| private static int _poolCount = 0; | |
| private static readonly ConcurrentQueue<Core> Pool = new(); | |
| private readonly ushort _version; | |
| private readonly Core _core; | |
| public Action<T1, T2, T3, T4, T5, T6> Wrapper | |
| { | |
| get | |
| { | |
| if (_core._version != _version) throw new InvalidOperationException(); | |
| return _core.Wrapper; | |
| } | |
| } | |
| public static PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6> Get( | |
| Action<TContext, Action<T1, T2, T3, T4, T5, T6>, T1, T2, T3, T4, T5, T6> callback, TContext context) | |
| { | |
| if (callback == null) throw new ArgumentNullException(nameof(callback)); | |
| if (Pool.TryDequeue(out var pooled)) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| else | |
| { | |
| pooled = new Core(); | |
| } | |
| pooled.Set(callback, context); | |
| return new PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6>(pooled); | |
| } | |
| public void Dispose() | |
| { | |
| if (_core._version != _version) return; | |
| _core.Release(); | |
| } | |
| private PooledActionOnce(Core core) | |
| { | |
| _version = core._version; | |
| _core = core; | |
| } | |
| private class Core | |
| { | |
| private Action<TContext, Action<T1, T2, T3, T4, T5, T6>, T1, T2, T3, T4, T5, T6> _callback; | |
| private TContext _context; | |
| public ushort _version; | |
| public Core() | |
| { | |
| Wrapper = (arg1, arg2, arg3, arg4, arg5, arg6) => | |
| { | |
| _callback!(_context, Wrapper, arg1, arg2, arg3, arg4, arg5, arg6); | |
| Release(); | |
| }; | |
| } | |
| public Action<T1, T2, T3, T4, T5, T6> Wrapper { get; } | |
| public void Set(Action<TContext, Action<T1, T2, T3, T4, T5, T6>, T1, T2, T3, T4, T5, T6> callback, TContext context) | |
| { | |
| _callback = callback; | |
| _context = context; | |
| } | |
| public void Release() | |
| { | |
| _callback = null; | |
| _context = default; | |
| if (++_version == ushort.MaxValue) return; | |
| var reservedCount = Interlocked.Increment(ref _poolCount); | |
| if (reservedCount > PoolCapacity) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| return; | |
| } | |
| Pool.Enqueue(this); | |
| } | |
| } | |
| } | |
| internal readonly struct PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7> : IDisposable | |
| { | |
| private static int _poolCapacity = 32; | |
| public static int PoolCapacity | |
| { | |
| get => _poolCapacity; | |
| set | |
| { | |
| if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Pool capacity must be non-negative."); | |
| _poolCapacity = value; | |
| while (Volatile.Read(ref _poolCount) > _poolCapacity) | |
| { | |
| if (!Pool.TryDequeue(out _)) | |
| { | |
| break; | |
| } | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| } | |
| } | |
| private static int _poolCount = 0; | |
| private static readonly ConcurrentQueue<Core> Pool = new(); | |
| private readonly ushort _version; | |
| private readonly Core _core; | |
| public Action<T1, T2, T3, T4, T5, T6, T7> Wrapper | |
| { | |
| get | |
| { | |
| if (_core._version != _version) throw new InvalidOperationException(); | |
| return _core.Wrapper; | |
| } | |
| } | |
| public static PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7> Get( | |
| Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7>, T1, T2, T3, T4, T5, T6, T7> callback, TContext context) | |
| { | |
| if (callback == null) throw new ArgumentNullException(nameof(callback)); | |
| if (Pool.TryDequeue(out var pooled)) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| else | |
| { | |
| pooled = new Core(); | |
| } | |
| pooled.Set(callback, context); | |
| return new PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7>(pooled); | |
| } | |
| public void Dispose() | |
| { | |
| if (_core._version != _version) return; | |
| _core.Release(); | |
| } | |
| private PooledActionOnce(Core core) | |
| { | |
| _version = core._version; | |
| _core = core; | |
| } | |
| private class Core | |
| { | |
| private Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7>, T1, T2, T3, T4, T5, T6, T7> _callback; | |
| private TContext _context; | |
| public ushort _version; | |
| public Core() | |
| { | |
| Wrapper = (arg1, arg2, arg3, arg4, arg5, arg6, arg7) => | |
| { | |
| _callback!(_context, Wrapper, arg1, arg2, arg3, arg4, arg5, arg6, arg7); | |
| Release(); | |
| }; | |
| } | |
| public Action<T1, T2, T3, T4, T5, T6, T7> Wrapper { get; } | |
| public void Set(Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7>, T1, T2, T3, T4, T5, T6, T7> callback, TContext context) | |
| { | |
| _callback = callback; | |
| _context = context; | |
| } | |
| public void Release() | |
| { | |
| _callback = null; | |
| _context = default; | |
| if (++_version == ushort.MaxValue) return; | |
| var reservedCount = Interlocked.Increment(ref _poolCount); | |
| if (reservedCount > PoolCapacity) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| return; | |
| } | |
| Pool.Enqueue(this); | |
| } | |
| } | |
| } | |
| internal readonly struct PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8> : IDisposable | |
| { | |
| private static int _poolCapacity = 32; | |
| public static int PoolCapacity | |
| { | |
| get => _poolCapacity; | |
| set | |
| { | |
| if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Pool capacity must be non-negative."); | |
| _poolCapacity = value; | |
| while (Volatile.Read(ref _poolCount) > _poolCapacity) | |
| { | |
| if (!Pool.TryDequeue(out _)) | |
| { | |
| break; | |
| } | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| } | |
| } | |
| private static int _poolCount = 0; | |
| private static readonly ConcurrentQueue<Core> Pool = new(); | |
| private readonly ushort _version; | |
| private readonly Core _core; | |
| public Action<T1, T2, T3, T4, T5, T6, T7, T8> Wrapper | |
| { | |
| get | |
| { | |
| if (_core._version != _version) throw new InvalidOperationException(); | |
| return _core.Wrapper; | |
| } | |
| } | |
| public static PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8> Get( | |
| Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8>, T1, T2, T3, T4, T5, T6, T7, T8> callback, TContext context) | |
| { | |
| if (callback == null) throw new ArgumentNullException(nameof(callback)); | |
| if (Pool.TryDequeue(out var pooled)) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| else | |
| { | |
| pooled = new Core(); | |
| } | |
| pooled.Set(callback, context); | |
| return new PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8>(pooled); | |
| } | |
| public void Dispose() | |
| { | |
| if (_core._version != _version) return; | |
| _core.Release(); | |
| } | |
| private PooledActionOnce(Core core) | |
| { | |
| _version = core._version; | |
| _core = core; | |
| } | |
| private class Core | |
| { | |
| private Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8>, T1, T2, T3, T4, T5, T6, T7, T8> _callback; | |
| private TContext _context; | |
| public ushort _version; | |
| public Core() | |
| { | |
| Wrapper = (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) => | |
| { | |
| _callback!(_context, Wrapper, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); | |
| Release(); | |
| }; | |
| } | |
| public Action<T1, T2, T3, T4, T5, T6, T7, T8> Wrapper { get; } | |
| public void Set(Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8>, T1, T2, T3, T4, T5, T6, T7, T8> callback, TContext context) | |
| { | |
| _callback = callback; | |
| _context = context; | |
| } | |
| public void Release() | |
| { | |
| _callback = null; | |
| _context = default; | |
| if (++_version == ushort.MaxValue) return; | |
| var reservedCount = Interlocked.Increment(ref _poolCount); | |
| if (reservedCount > PoolCapacity) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| return; | |
| } | |
| Pool.Enqueue(this); | |
| } | |
| } | |
| } | |
| internal readonly struct PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9> : IDisposable | |
| { | |
| private static int _poolCapacity = 32; | |
| public static int PoolCapacity | |
| { | |
| get => _poolCapacity; | |
| set | |
| { | |
| if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Pool capacity must be non-negative."); | |
| _poolCapacity = value; | |
| while (Volatile.Read(ref _poolCount) > _poolCapacity) | |
| { | |
| if (!Pool.TryDequeue(out _)) | |
| { | |
| break; | |
| } | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| } | |
| } | |
| private static int _poolCount = 0; | |
| private static readonly ConcurrentQueue<Core> Pool = new(); | |
| private readonly ushort _version; | |
| private readonly Core _core; | |
| public Action<T1, T2, T3, T4, T5, T6, T7, T8, T9> Wrapper | |
| { | |
| get | |
| { | |
| if (_core._version != _version) throw new InvalidOperationException(); | |
| return _core.Wrapper; | |
| } | |
| } | |
| public static PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9> Get( | |
| Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9>, T1, T2, T3, T4, T5, T6, T7, T8, T9> callback, TContext context) | |
| { | |
| if (callback == null) throw new ArgumentNullException(nameof(callback)); | |
| if (Pool.TryDequeue(out var pooled)) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| else | |
| { | |
| pooled = new Core(); | |
| } | |
| pooled.Set(callback, context); | |
| return new PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9>(pooled); | |
| } | |
| public void Dispose() | |
| { | |
| if (_core._version != _version) return; | |
| _core.Release(); | |
| } | |
| private PooledActionOnce(Core core) | |
| { | |
| _version = core._version; | |
| _core = core; | |
| } | |
| private class Core | |
| { | |
| private Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9>, T1, T2, T3, T4, T5, T6, T7, T8, T9> _callback; | |
| private TContext _context; | |
| public ushort _version; | |
| public Core() | |
| { | |
| Wrapper = (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) => | |
| { | |
| _callback!(_context, Wrapper, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); | |
| Release(); | |
| }; | |
| } | |
| public Action<T1, T2, T3, T4, T5, T6, T7, T8, T9> Wrapper { get; } | |
| public void Set(Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9>, T1, T2, T3, T4, T5, T6, T7, T8, T9> callback, TContext context) | |
| { | |
| _callback = callback; | |
| _context = context; | |
| } | |
| public void Release() | |
| { | |
| _callback = null; | |
| _context = default; | |
| if (++_version == ushort.MaxValue) return; | |
| var reservedCount = Interlocked.Increment(ref _poolCount); | |
| if (reservedCount > PoolCapacity) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| return; | |
| } | |
| Pool.Enqueue(this); | |
| } | |
| } | |
| } | |
| internal readonly struct PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : IDisposable | |
| { | |
| private static int _poolCapacity = 32; | |
| public static int PoolCapacity | |
| { | |
| get => _poolCapacity; | |
| set | |
| { | |
| if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Pool capacity must be non-negative."); | |
| _poolCapacity = value; | |
| while (Volatile.Read(ref _poolCount) > _poolCapacity) | |
| { | |
| if (!Pool.TryDequeue(out _)) | |
| { | |
| break; | |
| } | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| } | |
| } | |
| private static int _poolCount = 0; | |
| private static readonly ConcurrentQueue<Core> Pool = new(); | |
| private readonly ushort _version; | |
| private readonly Core _core; | |
| public Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Wrapper | |
| { | |
| get | |
| { | |
| if (_core._version != _version) throw new InvalidOperationException(); | |
| return _core.Wrapper; | |
| } | |
| } | |
| public static PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Get( | |
| Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> callback, TContext context) | |
| { | |
| if (callback == null) throw new ArgumentNullException(nameof(callback)); | |
| if (Pool.TryDequeue(out var pooled)) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| else | |
| { | |
| pooled = new Core(); | |
| } | |
| pooled.Set(callback, context); | |
| return new PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(pooled); | |
| } | |
| public void Dispose() | |
| { | |
| if (_core._version != _version) return; | |
| _core.Release(); | |
| } | |
| private PooledActionOnce(Core core) | |
| { | |
| _version = core._version; | |
| _core = core; | |
| } | |
| private class Core | |
| { | |
| private Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> _callback; | |
| private TContext _context; | |
| public ushort _version; | |
| public Core() | |
| { | |
| Wrapper = (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) => | |
| { | |
| _callback!(_context, Wrapper, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); | |
| Release(); | |
| }; | |
| } | |
| public Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Wrapper { get; } | |
| public void Set(Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> callback, TContext context) | |
| { | |
| _callback = callback; | |
| _context = context; | |
| } | |
| public void Release() | |
| { | |
| _callback = null; | |
| _context = default; | |
| if (++_version == ushort.MaxValue) return; | |
| var reservedCount = Interlocked.Increment(ref _poolCount); | |
| if (reservedCount > PoolCapacity) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| return; | |
| } | |
| Pool.Enqueue(this); | |
| } | |
| } | |
| } | |
| internal readonly struct PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> : IDisposable | |
| { | |
| private static int _poolCapacity = 32; | |
| public static int PoolCapacity | |
| { | |
| get => _poolCapacity; | |
| set | |
| { | |
| if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Pool capacity must be non-negative."); | |
| _poolCapacity = value; | |
| while (Volatile.Read(ref _poolCount) > _poolCapacity) | |
| { | |
| if (!Pool.TryDequeue(out _)) | |
| { | |
| break; | |
| } | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| } | |
| } | |
| private static int _poolCount = 0; | |
| private static readonly ConcurrentQueue<Core> Pool = new(); | |
| private readonly ushort _version; | |
| private readonly Core _core; | |
| public Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Wrapper | |
| { | |
| get | |
| { | |
| if (_core._version != _version) throw new InvalidOperationException(); | |
| return _core.Wrapper; | |
| } | |
| } | |
| public static PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Get( | |
| Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> callback, TContext context) | |
| { | |
| if (callback == null) throw new ArgumentNullException(nameof(callback)); | |
| if (Pool.TryDequeue(out var pooled)) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| else | |
| { | |
| pooled = new Core(); | |
| } | |
| pooled.Set(callback, context); | |
| return new PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(pooled); | |
| } | |
| public void Dispose() | |
| { | |
| if (_core._version != _version) return; | |
| _core.Release(); | |
| } | |
| private PooledActionOnce(Core core) | |
| { | |
| _version = core._version; | |
| _core = core; | |
| } | |
| private class Core | |
| { | |
| private Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> _callback; | |
| private TContext _context; | |
| public ushort _version; | |
| public Core() | |
| { | |
| Wrapper = (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11) => | |
| { | |
| _callback!(_context, Wrapper, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); | |
| Release(); | |
| }; | |
| } | |
| public Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Wrapper { get; } | |
| public void Set(Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> callback, TContext context) | |
| { | |
| _callback = callback; | |
| _context = context; | |
| } | |
| public void Release() | |
| { | |
| _callback = null; | |
| _context = default; | |
| if (++_version == ushort.MaxValue) return; | |
| var reservedCount = Interlocked.Increment(ref _poolCount); | |
| if (reservedCount > PoolCapacity) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| return; | |
| } | |
| Pool.Enqueue(this); | |
| } | |
| } | |
| } | |
| internal readonly struct PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> : IDisposable | |
| { | |
| private static int _poolCapacity = 32; | |
| public static int PoolCapacity | |
| { | |
| get => _poolCapacity; | |
| set | |
| { | |
| if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Pool capacity must be non-negative."); | |
| _poolCapacity = value; | |
| while (Volatile.Read(ref _poolCount) > _poolCapacity) | |
| { | |
| if (!Pool.TryDequeue(out _)) | |
| { | |
| break; | |
| } | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| } | |
| } | |
| private static int _poolCount = 0; | |
| private static readonly ConcurrentQueue<Core> Pool = new(); | |
| private readonly ushort _version; | |
| private readonly Core _core; | |
| public Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Wrapper | |
| { | |
| get | |
| { | |
| if (_core._version != _version) throw new InvalidOperationException(); | |
| return _core.Wrapper; | |
| } | |
| } | |
| public static PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Get( | |
| Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> callback, TContext context) | |
| { | |
| if (callback == null) throw new ArgumentNullException(nameof(callback)); | |
| if (Pool.TryDequeue(out var pooled)) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| else | |
| { | |
| pooled = new Core(); | |
| } | |
| pooled.Set(callback, context); | |
| return new PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(pooled); | |
| } | |
| public void Dispose() | |
| { | |
| if (_core._version != _version) return; | |
| _core.Release(); | |
| } | |
| private PooledActionOnce(Core core) | |
| { | |
| _version = core._version; | |
| _core = core; | |
| } | |
| private class Core | |
| { | |
| private Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> _callback; | |
| private TContext _context; | |
| public ushort _version; | |
| public Core() | |
| { | |
| Wrapper = (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12) => | |
| { | |
| _callback!(_context, Wrapper, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); | |
| Release(); | |
| }; | |
| } | |
| public Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Wrapper { get; } | |
| public void Set(Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> callback, TContext context) | |
| { | |
| _callback = callback; | |
| _context = context; | |
| } | |
| public void Release() | |
| { | |
| _callback = null; | |
| _context = default; | |
| if (++_version == ushort.MaxValue) return; | |
| var reservedCount = Interlocked.Increment(ref _poolCount); | |
| if (reservedCount > PoolCapacity) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| return; | |
| } | |
| Pool.Enqueue(this); | |
| } | |
| } | |
| } | |
| internal readonly struct PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> : IDisposable | |
| { | |
| private static int _poolCapacity = 32; | |
| public static int PoolCapacity | |
| { | |
| get => _poolCapacity; | |
| set | |
| { | |
| if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Pool capacity must be non-negative."); | |
| _poolCapacity = value; | |
| while (Volatile.Read(ref _poolCount) > _poolCapacity) | |
| { | |
| if (!Pool.TryDequeue(out _)) | |
| { | |
| break; | |
| } | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| } | |
| } | |
| private static int _poolCount = 0; | |
| private static readonly ConcurrentQueue<Core> Pool = new(); | |
| private readonly ushort _version; | |
| private readonly Core _core; | |
| public Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Wrapper | |
| { | |
| get | |
| { | |
| if (_core._version != _version) throw new InvalidOperationException(); | |
| return _core.Wrapper; | |
| } | |
| } | |
| public static PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Get( | |
| Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> callback, TContext context) | |
| { | |
| if (callback == null) throw new ArgumentNullException(nameof(callback)); | |
| if (Pool.TryDequeue(out var pooled)) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| else | |
| { | |
| pooled = new Core(); | |
| } | |
| pooled.Set(callback, context); | |
| return new PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(pooled); | |
| } | |
| public void Dispose() | |
| { | |
| if (_core._version != _version) return; | |
| _core.Release(); | |
| } | |
| private PooledActionOnce(Core core) | |
| { | |
| _version = core._version; | |
| _core = core; | |
| } | |
| private class Core | |
| { | |
| private Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> _callback; | |
| private TContext _context; | |
| public ushort _version; | |
| public Core() | |
| { | |
| Wrapper = (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13) => | |
| { | |
| _callback!(_context, Wrapper, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); | |
| Release(); | |
| }; | |
| } | |
| public Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Wrapper { get; } | |
| public void Set(Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> callback, TContext context) | |
| { | |
| _callback = callback; | |
| _context = context; | |
| } | |
| public void Release() | |
| { | |
| _callback = null; | |
| _context = default; | |
| if (++_version == ushort.MaxValue) return; | |
| var reservedCount = Interlocked.Increment(ref _poolCount); | |
| if (reservedCount > PoolCapacity) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| return; | |
| } | |
| Pool.Enqueue(this); | |
| } | |
| } | |
| } | |
| internal readonly struct PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> : IDisposable | |
| { | |
| private static int _poolCapacity = 32; | |
| public static int PoolCapacity | |
| { | |
| get => _poolCapacity; | |
| set | |
| { | |
| if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Pool capacity must be non-negative."); | |
| _poolCapacity = value; | |
| while (Volatile.Read(ref _poolCount) > _poolCapacity) | |
| { | |
| if (!Pool.TryDequeue(out _)) | |
| { | |
| break; | |
| } | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| } | |
| } | |
| private static int _poolCount = 0; | |
| private static readonly ConcurrentQueue<Core> Pool = new(); | |
| private readonly ushort _version; | |
| private readonly Core _core; | |
| public Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> Wrapper | |
| { | |
| get | |
| { | |
| if (_core._version != _version) throw new InvalidOperationException(); | |
| return _core.Wrapper; | |
| } | |
| } | |
| public static PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> Get( | |
| Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> callback, TContext context) | |
| { | |
| if (callback == null) throw new ArgumentNullException(nameof(callback)); | |
| if (Pool.TryDequeue(out var pooled)) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| else | |
| { | |
| pooled = new Core(); | |
| } | |
| pooled.Set(callback, context); | |
| return new PooledActionOnce<TContext, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(pooled); | |
| } | |
| public void Dispose() | |
| { | |
| if (_core._version != _version) return; | |
| _core.Release(); | |
| } | |
| private PooledActionOnce(Core core) | |
| { | |
| _version = core._version; | |
| _core = core; | |
| } | |
| private class Core | |
| { | |
| private Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> _callback; | |
| private TContext _context; | |
| public ushort _version; | |
| public Core() | |
| { | |
| Wrapper = (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14) => | |
| { | |
| _callback!(_context, Wrapper, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); | |
| Release(); | |
| }; | |
| } | |
| public Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> Wrapper { get; } | |
| public void Set(Action<TContext, Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> callback, TContext context) | |
| { | |
| _callback = callback; | |
| _context = context; | |
| } | |
| public void Release() | |
| { | |
| _callback = null; | |
| _context = default; | |
| if (++_version == ushort.MaxValue) return; | |
| var reservedCount = Interlocked.Increment(ref _poolCount); | |
| if (reservedCount > PoolCapacity) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| return; | |
| } | |
| Pool.Enqueue(this); | |
| } | |
| } | |
| } | |
| } |
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
| <#@ template language="C#" #> | |
| <#@ import namespace="System.Linq" #> | |
| using System; | |
| using System.Threading; | |
| using System.Collections.Concurrent; | |
| namespace PooledActions | |
| { | |
| <# | |
| const int MaxArgs = 14; | |
| for (var i = 0; i <= MaxArgs; i++) | |
| { | |
| var typeParams = Enumerable.Range(1, i).Select(n => $"T{n}"); | |
| var typeParamListWithBrackets = typeParams.Any() ? $"<{string.Join(", ", typeParams)}>" : string.Empty; | |
| var typeParamListWithPrecedingComma = typeParams.Any() ? $", {string.Join(", ", typeParams)}" : string.Empty; | |
| var lambdaParams = Enumerable.Range(1, i).Select(n => $"arg{n}").ToArray(); | |
| var lambdaParamList = lambdaParams.Any() ? string.Join(", ", lambdaParams) : string.Empty; | |
| var lambdaParamListWithPrecedingComma = lambdaParams.Any() ? $", {lambdaParamList}" : string.Empty; | |
| #> | |
| internal readonly struct PooledActionOnce<TContext<#= typeParamListWithPrecedingComma #>> : IDisposable | |
| { | |
| private static int _poolCapacity = 32; | |
| public static int PoolCapacity | |
| { | |
| get => _poolCapacity; | |
| set | |
| { | |
| if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Pool capacity must be non-negative."); | |
| _poolCapacity = value; | |
| while (Volatile.Read(ref _poolCount) > _poolCapacity) | |
| { | |
| if (!Pool.TryDequeue(out _)) | |
| { | |
| break; | |
| } | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| } | |
| } | |
| private static int _poolCount = 0; | |
| private static readonly ConcurrentQueue<Core> Pool = new(); | |
| private readonly ushort _version; | |
| private readonly Core _core; | |
| public Action<#= typeParamListWithBrackets #> Wrapper | |
| { | |
| get | |
| { | |
| if (_core._version != _version) throw new InvalidOperationException(); | |
| return _core.Wrapper; | |
| } | |
| } | |
| public static PooledActionOnce<TContext<#= typeParamListWithPrecedingComma #>> Get( | |
| Action<TContext, Action<#= typeParamListWithBrackets #><#= typeParamListWithPrecedingComma #>> callback, TContext context) | |
| { | |
| if (callback == null) throw new ArgumentNullException(nameof(callback)); | |
| if (Pool.TryDequeue(out var pooled)) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| } | |
| else | |
| { | |
| pooled = new Core(); | |
| } | |
| pooled.Set(callback, context); | |
| return new PooledActionOnce<TContext<#= typeParamListWithPrecedingComma #>>(pooled); | |
| } | |
| public void Dispose() | |
| { | |
| if (_core._version != _version) return; | |
| _core.Release(); | |
| } | |
| private PooledActionOnce(Core core) | |
| { | |
| _version = core._version; | |
| _core = core; | |
| } | |
| private class Core | |
| { | |
| private Action<TContext, Action<#= typeParamListWithBrackets #><#= typeParamListWithPrecedingComma #>> _callback; | |
| private TContext _context; | |
| public ushort _version; | |
| public Core() | |
| { | |
| Wrapper = (<#= lambdaParamList #>) => | |
| { | |
| _callback!(_context, Wrapper<#= lambdaParamListWithPrecedingComma #>); | |
| Release(); | |
| }; | |
| } | |
| public Action<#= typeParamListWithBrackets #> Wrapper { get; } | |
| public void Set(Action<TContext, Action<#= typeParamListWithBrackets #><#= typeParamListWithPrecedingComma #>> callback, TContext context) | |
| { | |
| _callback = callback; | |
| _context = context; | |
| } | |
| public void Release() | |
| { | |
| _callback = null; | |
| _context = default; | |
| if (++_version == ushort.MaxValue) return; | |
| var reservedCount = Interlocked.Increment(ref _poolCount); | |
| if (reservedCount > PoolCapacity) | |
| { | |
| Interlocked.Decrement(ref _poolCount); | |
| return; | |
| } | |
| Pool.Enqueue(this); | |
| } | |
| } | |
| } | |
| <# | |
| } | |
| #> | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment