forked from Taritsyn/JavaScriptEngineSwitcher
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStringBuilderPool.cs
More file actions
142 lines (123 loc) · 3.47 KB
/
StringBuilderPool.cs
File metadata and controls
142 lines (123 loc) · 3.47 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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
using System;
using System.Text;
using System.Threading;
namespace JavaScriptEngineSwitcher.Core.Utilities
{
/// <summary>
/// Pool of string builders
/// </summary>
public static class StringBuilderPool
{
/// <summary>
/// Maximum capacity of builder
/// </summary>
const int MAX_BUILDER_CAPACITY = 8 * 1024;
/// <summary>
/// Number of builders per processor
/// </summary>
const int BUILDER_COUNT_PER_PROCESSOR = 4;
/// <summary>
/// First builder
/// </summary>
/// <remarks>The first builder is stored in a dedicated field, because we expect
/// to be able to satisfy most requests from it.</remarks>
private static StringBuilder _firstBuilder;
/// <summary>
/// List of the remaining builders
/// </summary>
private static readonly StringBuilder[] _builders;
/// <summary>
/// Static constructor
/// </summary>
static StringBuilderPool()
{
int builderCount = Environment.ProcessorCount * BUILDER_COUNT_PER_PROCESSOR;
if (builderCount < 5)
{
builderCount = 5;
}
_builders = new StringBuilder[builderCount - 1];
}
/// <summary>
/// Gets a instance of string builder from the pool
/// </summary>
/// <returns>Instance of string builder</returns>
public static StringBuilder GetBuilder()
{
// Examine the first builder.
// If that fails, then `GetBuilderSlow` method will look at the remaining builders.
StringBuilder builder = _firstBuilder;
if (builder == null || builder != Interlocked.CompareExchange(ref _firstBuilder, null, builder))
{
builder = GetBuilderSlow();
}
return builder;
}
/// <summary>
/// Gets a instance of string builder with at least the given capacity from the pool
/// </summary>
/// <remarks>If the capacity is less than or equal to our maximum capacity, then return builder from the pool.
/// Otherwise create a new string builder, that will just get discarded when released.</remarks>
/// <param name="capacity">Capacity of string builder</param>
/// <returns>Instance of string builder</returns>
public static StringBuilder GetBuilder(int capacity)
{
if (capacity <= MAX_BUILDER_CAPACITY)
{
return GetBuilder();
}
return new StringBuilder(capacity);
}
private static StringBuilder GetBuilderSlow()
{
StringBuilder[] builders = _builders;
int builderCount = builders.Length;
for (int builderIndex = 0; builderIndex < builderCount; builderIndex++)
{
StringBuilder builder = builders[builderIndex];
if (builder != null)
{
if (builder == Interlocked.CompareExchange(ref builders[builderIndex], null, builder))
{
return builder;
}
}
}
return new StringBuilder(MAX_BUILDER_CAPACITY);
}
/// <summary>
/// Returns a instance of string builder to the pool
/// </summary>
/// <param name="builder">Instance of string builder</param>
public static void ReleaseBuilder(StringBuilder builder)
{
if (builder == null || builder.Capacity > MAX_BUILDER_CAPACITY)
{
return;
}
if (_firstBuilder == null)
{
builder.Clear();
_firstBuilder = builder;
}
else
{
ReleaseBuilderSlow(builder);
}
}
private static void ReleaseBuilderSlow(StringBuilder builder)
{
StringBuilder[] builders = _builders;
int builderCount = builders.Length;
for (int builderIndex = 0; builderIndex < builderCount; builderIndex++)
{
if (builders[builderIndex] == null)
{
builder.Clear();
builders[builderIndex] = builder;
break;
}
}
}
}
}