Skip to content

Commit 948df24

Browse files
committed
Optimized token attachment
1 parent 8e390bb commit 948df24

File tree

1 file changed

+25
-17
lines changed

1 file changed

+25
-17
lines changed

src/DotNext.Threading/Threading/CancellationTokenMultiplexer.CTS.cs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,59 @@
1+
using System.Diagnostics;
2+
using System.Runtime.CompilerServices;
13
using System.Runtime.InteropServices;
24

35
namespace DotNext.Threading;
46

7+
using InlinedTokenList = ValueTuple<CancellationTokenRegistration, CancellationTokenRegistration, CancellationTokenRegistration>;
8+
59
partial class CancellationTokenMultiplexer
610
{
711
private sealed class PooledCancellationTokenSource : LinkedCancellationTokenSource, IResettable
812
{
9-
private const int Capacity = 3;
10-
private (CancellationTokenRegistration, CancellationTokenRegistration, CancellationTokenRegistration) inlinedList;
11-
private byte inlinedTokenCount;
13+
private static readonly int InlinedListCapacity = GetCapacity<InlinedTokenList>();
14+
15+
private InlinedTokenList inlinedList;
16+
private int inlinedTokenCount;
1217
private List<CancellationTokenRegistration>? extraTokens;
1318
internal PooledCancellationTokenSource? Next;
1419

1520
public void Add(CancellationToken token)
16-
=> Add() = Attach(token);
21+
=> Add(Attach(token));
1722

18-
private ref CancellationTokenRegistration Add()
23+
private void Add(CancellationTokenRegistration registration)
1924
{
20-
Span<CancellationTokenRegistration> registrations;
21-
int index;
22-
if (inlinedTokenCount < Capacity)
25+
if (inlinedTokenCount < InlinedListCapacity)
2326
{
24-
index = inlinedTokenCount++;
25-
registrations = inlinedList.AsSpan();
27+
Unsafe.Add(ref FirstInlinedRegistration, inlinedTokenCount++) = registration;
2628
}
2729
else
2830
{
2931
extraTokens ??= new();
30-
index = extraTokens.Count;
31-
extraTokens.Add(default);
32-
registrations = CollectionsMarshal.AsSpan(extraTokens);
32+
extraTokens.Add(registration);
3333
}
34-
35-
return ref registrations[index];
3634
}
3735

36+
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
37+
private ref CancellationTokenRegistration FirstInlinedRegistration
38+
=> ref Unsafe.As<InlinedTokenList, CancellationTokenRegistration>(ref inlinedList);
39+
3840
public int Count => inlinedTokenCount + extraTokens?.Count ?? 0;
3941

4042
public ref CancellationTokenRegistration this[int index]
4143
{
4244
get
4345
{
46+
Debug.Assert((uint)index < (uint)Count);
47+
4448
Span<CancellationTokenRegistration> registrations;
45-
if (index < Capacity)
49+
if (index < InlinedListCapacity)
4650
{
4751
registrations = inlinedList.AsSpan();
4852
}
4953
else
5054
{
5155
registrations = CollectionsMarshal.AsSpan(extraTokens);
52-
index -= Capacity;
56+
index -= InlinedListCapacity;
5357
}
5458

5559
return ref registrations[index];
@@ -63,6 +67,10 @@ public void Reset()
6367
extraTokens?.Clear();
6468
}
6569

70+
private static int GetCapacity<T>()
71+
where T : struct, ITuple
72+
=> default(T).Length;
73+
6674
protected override void Dispose(bool disposing)
6775
{
6876
if (disposing)

0 commit comments

Comments
 (0)