Skip to content

Commit 43802aa

Browse files
NightOwl888paulirwin
authored andcommitted
PERFORMANCE: Lucene.Net.Store.DataOutput::WriteString(): Added WriteChars() method that accepts a span and moved allocations to the stack or array pool for buffer reuse.
1 parent 4ad19ff commit 43802aa

1 file changed

Lines changed: 44 additions & 4 deletions

File tree

src/Lucene.Net/Store/DataOutput.cs

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,12 +260,52 @@ public void WriteVInt64(long i)
260260
/// <seealso cref="DataInput.ReadString()"/>
261261
public virtual void WriteString(string s)
262262
{
263-
var utf8Result = new BytesRef(10);
264-
UnicodeUtil.UTF16toUTF8(s, 0, s.Length, utf8Result);
265-
WriteVInt32(utf8Result.Length);
266-
WriteBytes(utf8Result.Bytes, 0, utf8Result.Length);
263+
if (s is null)
264+
throw new ArgumentNullException(nameof(s));
265+
WriteChars(s.AsSpan());
267266
}
268267

268+
#nullable enable
269+
270+
/// <summary>
271+
/// Writes a character span.
272+
/// <para/>
273+
/// Writes chars as UTF-8 encoded bytes. First the length, in bytes, is
274+
/// written as a <see cref="WriteVInt32"/>, followed by the bytes.
275+
/// </summary>
276+
/// <param name="chars">The chars to write.</param>
277+
// LUCENENET specific
278+
public virtual void WriteChars(ReadOnlySpan<char> chars)
279+
{
280+
if (chars.IsEmpty)
281+
{
282+
// Fast path - don't allocate if we don't need to
283+
WriteVInt32(0);
284+
WriteBytes(Array.Empty<byte>());
285+
return;
286+
}
287+
288+
int bufferLength = UnicodeUtil.GetMaxByteCount(chars.Length);
289+
byte[]? arrayToReturnToPool = null;
290+
Span<byte> utf8Result = bufferLength > Constants.MaxStackByteLimit
291+
? (arrayToReturnToPool = ArrayPool<byte>.Shared.Rent(bufferLength))
292+
: stackalloc byte[bufferLength];
293+
try
294+
{
295+
// We are calculating the size up front, so this will always succeed.
296+
bool success = UnicodeUtil.TryUTF16toUTF8(chars, utf8Result, out int bytesLength);
297+
Debug.Assert(success, "There wasn't enough memory allocated for all of the bytes.");
298+
WriteVInt32(bytesLength);
299+
WriteBytes(utf8Result.Slice(0, bytesLength));
300+
}
301+
finally
302+
{
303+
ArrayPool<byte>.Shared.ReturnIfNotNull(arrayToReturnToPool);
304+
}
305+
}
306+
307+
#nullable restore
308+
269309
private const int COPY_BUFFER_SIZE = 16384;
270310
private byte[] copyBuffer;
271311

0 commit comments

Comments
 (0)