Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Bencodex.Tests/EncoderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ public void EncodeInteger()
public void EncodeBinary()
{
var buffer = new byte[20];
long size = Encoder.EncodeBinary(new Binary("hello world", Encoding.ASCII), buffer, 2L);
long size = Encoder.EncodeBinary(new Binary("hello world", Encoding.ASCII).ByteArray.AsSpan(), buffer, 2L);
Assert.Equal(14L, size);
AssertEqual(
new byte[20]
Expand Down
29 changes: 14 additions & 15 deletions Bencodex/Decoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Globalization;
using System.IO;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
using Bencodex.Misc;
using Bencodex.Types;
Expand All @@ -12,7 +13,6 @@ namespace Bencodex
{
internal sealed class Decoder
{
private readonly byte[] _tinyBuffer = new byte[1];
private readonly Stream _stream;
private readonly IndirectValue.Loader? _indirectValueLoader;
private byte _lastRead;
Expand Down Expand Up @@ -74,7 +74,7 @@ private IValue DecodeValue()
return ReadTextAfterPrefix();

case 0x6c: // 'l'
var indirElements = new List<IndirectValue>();
var indirBuilder = ImmutableArray.CreateBuilder<IndirectValue>();
while (true)
{
byte b = ReadByte() ?? throw new DecodingException(
Expand All @@ -87,17 +87,17 @@ private IValue DecodeValue()
else if (b == indir)
{
Fingerprint fp = DecodeFingerprint();
indirElements.Add(new IndirectValue(fp));
indirBuilder.Add(new IndirectValue(fp));
continue;
}

Back();
IValue element = DecodeValue();
indirElements.Add(new IndirectValue(element));
indirBuilder.Add(new IndirectValue(element));
}

return new Bencodex.Types.List(
indirElements.ToImmutableArray(),
indirBuilder.MoveToImmutable().AsSpan(),
_indirectValueLoader
);

Expand Down Expand Up @@ -255,15 +255,15 @@ private byte[] Read(byte[] buffer)
return _lastRead;
}

int read = _stream.Read(_tinyBuffer, 0, 1);
int read = _stream.ReadByte();
if (read > 0)
{
_lastRead = _tinyBuffer[0];
_lastRead = (byte)read;
}

_offset++;
_didBack = false;
return read == 0 ? (byte?)null : _tinyBuffer[0];
return read == -1 ? (byte?)null : _lastRead;
}

private void Back()
Expand Down Expand Up @@ -363,12 +363,7 @@ Func<string, IFormatProvider, T> converter
)
{
byte[] buffer = ReadDigits(takeMinusSign, delimiter);
var digits = new char[buffer.Length];
for (int i = 0; i < buffer.Length; i++)
{
digits[i] = (char)buffer[i];
}

var digits = Unsafe.As<byte[], char[]>(ref buffer);
return converter(new string(digits), CultureInfo.InvariantCulture);
}

Expand Down Expand Up @@ -399,7 +394,7 @@ Func<string, IFormatProvider, T> converter
private Binary ReadBinary()
{
(byte[] bytes, _) = ReadByteArray();
return new Binary(bytes);
return new Binary(bytes.AsSpan());
}

private Text ReadTextAfterPrefix()
Expand All @@ -409,7 +404,11 @@ private Text ReadTextAfterPrefix()
string textContent;
try
{
#if NETSTANDARD2_0
textContent = Encoding.UTF8.GetString(bytes);
#else
textContent = Encoding.UTF8.GetString(bytes.AsSpan());
#endif
}
catch (ArgumentException e)
{
Expand Down
23 changes: 13 additions & 10 deletions Bencodex/Encoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ public static void Encode(IValue value, Stream output, IOffloadOptions? offloadO
}

byte[] buffer = Encode(value, offloadOptions);
#if NETSTANDARD2_0
output.Write(buffer, 0, buffer.Length);
#else
output.Write(buffer.AsSpan());
#endif
}

internal static long EstimateLength(IValue value, IOffloadOptions? offloadOptions)
Expand Down Expand Up @@ -145,23 +149,22 @@ internal static long EncodeInteger(in Integer value, byte[] buffer, long offset)
return 1L + digits.Length + 1L;
}

internal static long EncodeBinary(in Binary value, byte[] buffer, long offset)
internal static long EncodeBinary(in ReadOnlySpan<byte> bin, byte[] buffer, long offset)
{
long len = value.ByteArray.Length;
long len = bin.Length;
long lenStrLength = EncodeDigits(len, buffer, offset);
offset += lenStrLength;
buffer[offset] = 0x3a; // ':'
offset++;

if (offset + len <= int.MaxValue)
long ct = 0;
foreach (byte b in bin)
{
value.ByteArray.CopyTo(buffer, (int)offset);
return lenStrLength + 1L + len;
buffer[offset + ct] = b;
ct++;
}

byte[] b = value.ToByteArray();
Array.Copy(b, 0L, buffer, offset, b.LongLength);
return lenStrLength + 1L + b.LongLength;
return lenStrLength + 1L + ct;
}

internal static long EncodeText(in Text value, byte[] buffer, long offset)
Expand Down Expand Up @@ -240,7 +243,7 @@ long offset
actualBytes += pair.Key switch
{
Text tk => EncodeText(tk, buffer, offset + actualBytes),
Binary bk => EncodeBinary(bk, buffer, offset + actualBytes),
Binary bk => EncodeBinary(bk.ByteArray.AsSpan(), buffer, offset + actualBytes),
{ } k => Encode(k, offloadOptions, buffer, offset + actualBytes),
};
if (offloadOptions is { } oo && !oo.Embeds(pair.Value))
Expand Down Expand Up @@ -322,7 +325,7 @@ long offset
Null _ => EncodeNull(buffer, offset),
Types.Boolean b => EncodeBoolean(b, buffer, offset),
Integer i => EncodeInteger(i, buffer, offset),
Binary bin => EncodeBinary(bin, buffer, offset),
Binary bin => EncodeBinary(bin.ByteArray.AsSpan(), buffer, offset),
Text t => EncodeText(t, buffer, offset),
List l => EncodeList(l, offloadOptions, buffer, offset),
Dictionary d => EncodeDictionary(d, offloadOptions, buffer, offset),
Expand Down
26 changes: 18 additions & 8 deletions Bencodex/Types/Binary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,24 @@ namespace Bencodex.Types
private readonly int?[] _hashCode;
private readonly ImmutableArray<byte>?[] _digest;

public Binary(ImmutableArray<byte> value)
public Binary(ReadOnlySpan<byte> value)
{
_value = value;
var builder = ImmutableArray.CreateBuilder<byte>(value.Length);
foreach (byte b in value)
{
builder.Add(b);
}

_value = builder.MoveToImmutable();
_hashCode = new int?[1];
_digest = new[] { (ImmutableArray<byte>?)null };
}

public Binary(ImmutableArray<byte> value)
: this(value.AsSpan())
{
}

public Binary(params byte[] value)
: this(value is byte[] bytes
? ImmutableArray.Create(bytes)
Expand Down Expand Up @@ -90,7 +101,7 @@ public Fingerprint Fingerprint
public string Inspection => Inspect(true);

public static implicit operator Binary(ImmutableArray<byte> bytes) =>
new Binary(bytes);
new Binary(bytes.AsSpan());

public static implicit operator ImmutableArray<byte>(Binary binary) =>
binary.ByteArray;
Expand Down Expand Up @@ -179,7 +190,7 @@ byte ParseNibble(char hex)
bytes.Add((byte)(ParseNibble(upper) << 4 | ParseNibble(lower)));
}

return new Binary(bytes.MoveToImmutable());
return new Binary(bytes.MoveToImmutable().AsSpan());
}

#if !NETSTANDARD2_0
Expand Down Expand Up @@ -225,8 +236,7 @@ public static Binary FromBase64(ReadOnlySpan<char> base64)
public static Binary FromBase64(string base64)
{
byte[] bytes = Convert.FromBase64String(base64);
ImmutableArray<byte> moved = Unsafe.As<byte[], ImmutableArray<byte>>(ref bytes);
return new Binary(moved);
return new Binary(bytes.AsSpan());
}

bool IEquatable<ImmutableArray<byte>>.Equals(ImmutableArray<byte> other) =>
Expand Down Expand Up @@ -325,10 +335,10 @@ public byte[] ToByteArray()
{
if (ByteArray.IsDefaultOrEmpty)
{
return new byte[0];
return Array.Empty<byte>();
}

return ByteArray.ToBuilder().ToArray();
return ByteArray.ToArray();
}

/// <summary>
Expand Down
Loading