-
-
Notifications
You must be signed in to change notification settings - Fork 203
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
GetChars(Encoding,byte[],StringBuilder) helper
- encode ReadOnlySpan<byte> without allocs into StringBuilder + tests
- Loading branch information
1 parent
9e77131
commit d935e45
Showing
2 changed files
with
103 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
using System; | ||
using System.Buffers; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Runtime.InteropServices; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Pchp.Core.Utilities | ||
{ | ||
public static class EncodingExtensions | ||
{ | ||
const int MaxBytesAtOnce = 1 * 1024 * 1024; // 1M | ||
|
||
/// <summary> | ||
/// Encodes byte array using <paramref name="encoding"/> into given <paramref name="builder"/>. | ||
/// </summary> | ||
/// <returns>Number of characters encoded.</returns> | ||
public static int GetChars(this Encoding encoding, ReadOnlySpan<byte> bytes, StringBuilder builder) | ||
{ | ||
ArgumentNullException.ThrowIfNull(encoding, nameof(encoding)); | ||
ArgumentNullException.ThrowIfNull(builder, nameof(builder)); | ||
|
||
if (bytes.IsEmpty) | ||
{ | ||
return 0; | ||
} | ||
|
||
if (bytes.Length <= MaxBytesAtOnce) | ||
{ | ||
|
||
var maxCharCount = encoding.GetCharCount(bytes); | ||
|
||
var span = ArrayPool<char>.Shared.Rent(maxCharCount); | ||
var chars = encoding.GetChars(bytes, span.AsSpan()); | ||
|
||
// | ||
builder.Append(span.AsSpan(0, chars)); | ||
|
||
// | ||
ArrayPool<char>.Shared.Return(span); | ||
|
||
return chars; | ||
} | ||
|
||
// | ||
|
||
var decoder = encoding.GetDecoder(); // we need to encode in chunks, preserve state between chunks | ||
int charsCount = 0; | ||
|
||
while (bytes.Length > 0) | ||
{ | ||
var segment = bytes.Slice(0, Math.Min(MaxBytesAtOnce, bytes.Length)); | ||
|
||
bytes = bytes.Slice(segment.Length); | ||
|
||
var maxCharCount = decoder.GetCharCount(segment, flush: bytes.IsEmpty); | ||
var span = ArrayPool<char>.Shared.Rent(maxCharCount); | ||
var chars = decoder.GetChars(segment, span.AsSpan(), flush: bytes.IsEmpty); | ||
|
||
// | ||
builder.Append(span.AsSpan(0, chars)); | ||
charsCount += chars; | ||
|
||
// | ||
ArrayPool<char>.Shared.Return(span); | ||
} | ||
|
||
// | ||
return charsCount; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters