Skip to content

Commit 47ff9c3

Browse files
committed
Blazor scenarios
1 parent 9334c3e commit 47ff9c3

File tree

1 file changed

+26
-20
lines changed

1 file changed

+26
-20
lines changed

src/PooledStringBuilder.cs

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@ public PooledStringBuilder(int capacity = _defaultCapacity)
2424
_disposed = false;
2525
}
2626

27+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
28+
private void EnsureInitialized()
29+
{
30+
// If never constructed but not disposed, lazily initialize.
31+
if (_buffer is null)
32+
{
33+
if (_disposed) ThrowDisposed();
34+
_buffer = ArrayPool<char>.Shared.Rent(_defaultCapacity);
35+
_pos = 0;
36+
}
37+
}
38+
2739
public int Length
2840
{
2941
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -36,6 +48,7 @@ public int Capacity
3648
get
3749
{
3850
ThrowIfDisposed();
51+
EnsureInitialized();
3952
return _buffer!.Length;
4053
}
4154
}
@@ -44,23 +57,25 @@ public int Capacity
4457
public void Clear()
4558
{
4659
ThrowIfDisposed();
60+
EnsureInitialized();
4761
_pos = 0;
4862
}
4963

5064
[MethodImpl(MethodImplOptions.AggressiveInlining)]
5165
public ReadOnlySpan<char> AsSpan()
5266
{
5367
ThrowIfDisposed();
68+
EnsureInitialized();
5469
return _buffer!.AsSpan(0, _pos);
5570
}
5671

5772
[MethodImpl(MethodImplOptions.AggressiveInlining)]
5873
public void EnsureCapacity(int required)
5974
{
6075
ThrowIfDisposed();
76+
EnsureInitialized();
6177
if ((uint)required <= (uint)_buffer!.Length) return;
6278

63-
// Round up to next power of two to keep rent/copy count low.
6479
int newSize = RoundUpPow2(required);
6580
char[] newBuf = ArrayPool<char>.Shared.Rent(newSize);
6681
_buffer.AsSpan(0, _pos)
@@ -74,8 +89,7 @@ public void EnsureCapacity(int required)
7489
public Span<char> AppendSpan(int length)
7590
{
7691
ThrowIfDisposed();
77-
if (length <= 0)
78-
return Span<char>.Empty;
92+
if (length <= 0) return Span<char>.Empty;
7993

8094
int newPos = _pos + length;
8195
EnsureCapacity(newPos);
@@ -88,6 +102,7 @@ public Span<char> AppendSpan(int length)
88102
public void Append(char c)
89103
{
90104
ThrowIfDisposed();
105+
EnsureInitialized();
91106
int i = _pos;
92107
if ((uint)i >= (uint)_buffer!.Length)
93108
{
@@ -103,8 +118,7 @@ public void Append(char c)
103118
public void Append(string? value)
104119
{
105120
ThrowIfDisposed();
106-
if (string.IsNullOrEmpty(value))
107-
return;
121+
if (string.IsNullOrEmpty(value)) return;
108122

109123
ReadOnlySpan<char> src = value.AsSpan();
110124
Span<char> dest = AppendSpan(src.Length);
@@ -143,20 +157,17 @@ public void Append(char c1, char c2, char c3)
143157
public void Append<T>(T value, ReadOnlySpan<char> format = default, IFormatProvider? provider = null) where T : ISpanFormattable
144158
{
145159
ThrowIfDisposed();
146-
// Worst-case length guess to reduce retries (32 covers most primitives; dates may need more).
147160
var hint = 32;
148161

149162
while (true)
150163
{
151164
Span<char> span = AppendSpan(hint);
152165
if (value.TryFormat(span, out int written, format, provider))
153166
{
154-
// Adjust back if our hint was larger than actually written
155167
_pos -= (hint - written);
156168
return;
157169
}
158170

159-
// Not enough; roll back and grow, then retry.
160171
_pos -= hint;
161172
hint <<= 1;
162173
EnsureCapacity(_pos + hint);
@@ -171,14 +182,14 @@ public void Append<T>(T value, ReadOnlySpan<char> format = default, IFormatProvi
171182
public void AppendSeparatorIfNotEmpty(char separator)
172183
{
173184
ThrowIfDisposed();
174-
if (_pos != 0)
175-
Append(separator);
185+
if (_pos != 0) Append(separator);
176186
}
177187

178188
[MethodImpl(MethodImplOptions.AggressiveInlining)]
179189
public override string ToString()
180190
{
181191
ThrowIfDisposed();
192+
EnsureInitialized();
182193
return new string(_buffer!, 0, _pos);
183194
}
184195

@@ -187,7 +198,8 @@ public override string ToString()
187198
public string ToStringAndDispose(bool clear = false)
188199
{
189200
ThrowIfDisposed();
190-
var s = new string(_buffer!, 0, _pos);
201+
EnsureInitialized();
202+
string s = new string(_buffer!, 0, _pos);
191203
Dispose(clear);
192204
return s;
193205
}
@@ -210,29 +222,23 @@ public void Dispose(bool clear)
210222
[MethodImpl(MethodImplOptions.AggressiveInlining)]
211223
private static int RoundUpPow2(int v)
212224
{
213-
// clamp to positive
214-
if (v <= 0)
215-
return _defaultCapacity;
225+
if (v <= 0) return _defaultCapacity;
216226

217-
// next power-of-two (cap at Array.MaxLength-ish range)
218-
var x = (uint)(v - 1);
227+
uint x = (uint)(v - 1);
219228
x |= x >> 1;
220229
x |= x >> 2;
221230
x |= x >> 4;
222231
x |= x >> 8;
223232
x |= x >> 16;
224233
x++;
225-
// Avoid excessively huge rents; ArrayPool may throw if extreme.
226234
const int max = 0x3FFFFFE0; // approx Array.MaxLength for char[]
227235
return (int)Math.Min(x, max);
228236
}
229237

230238
[MethodImpl(MethodImplOptions.AggressiveInlining)]
231239
private void ThrowIfDisposed()
232240
{
233-
// Catch both: disposed and default-constructed
234-
if (_disposed || _buffer is null)
235-
ThrowDisposed();
241+
if (_disposed) ThrowDisposed();
236242
}
237243

238244
[MethodImpl(MethodImplOptions.NoInlining)]

0 commit comments

Comments
 (0)