-
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathStringBuilderPool.cs
More file actions
87 lines (76 loc) · 2.5 KB
/
Copy pathStringBuilderPool.cs
File metadata and controls
87 lines (76 loc) · 2.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
using System.Text;
namespace NpgsqlRest;
/// <summary>
/// A simple thread-safe StringBuilder pool to reduce allocations in high-throughput scenarios.
/// Uses a lock-free stack-based approach for fast rent/return operations.
/// </summary>
internal static class StringBuilderPool
{
private const int MaxPoolSize = 64;
private const int DefaultCapacity = 256;
private const int MaxCapacity = 8192;
private static readonly StringBuilder?[] _pool = new StringBuilder?[MaxPoolSize];
private static int _index = -1;
/// <summary>
/// Rents a StringBuilder from the pool. Returns a new instance if the pool is empty.
/// </summary>
public static StringBuilder Rent()
{
StringBuilder? sb = null;
int currentIndex = Interlocked.Decrement(ref _index);
if (currentIndex >= 0 && currentIndex < MaxPoolSize)
{
sb = Interlocked.Exchange(ref _pool[currentIndex], null);
}
else
{
// Pool was empty or index went negative, restore it
Interlocked.Increment(ref _index);
}
return sb ?? new StringBuilder(DefaultCapacity);
}
/// <summary>
/// Rents a StringBuilder from the pool with a minimum capacity.
/// </summary>
public static StringBuilder Rent(int minimumCapacity)
{
var sb = Rent();
if (sb.Capacity < minimumCapacity)
{
sb.EnsureCapacity(minimumCapacity);
}
return sb;
}
/// <summary>
/// Returns a StringBuilder to the pool. The StringBuilder is cleared before being pooled.
/// Large StringBuilders (capacity > MaxCapacity) are not pooled to avoid memory bloat.
/// </summary>
public static void Return(StringBuilder sb)
{
if (sb.Capacity > MaxCapacity)
{
// Don't pool oversized builders - let GC collect them
return;
}
sb.Clear();
int currentIndex = Interlocked.Increment(ref _index);
if (currentIndex >= 0 && currentIndex < MaxPoolSize)
{
_pool[currentIndex] = sb;
}
else
{
// Pool is full, decrement index back and let the StringBuilder be collected
Interlocked.Decrement(ref _index);
}
}
/// <summary>
/// Gets the string value and returns the StringBuilder to the pool.
/// </summary>
public static string ToStringAndReturn(StringBuilder sb)
{
var result = sb.ToString();
Return(sb);
return result;
}
}