Skip to content

Commit

Permalink
Added helpers for one-shot encoding and decoding
Browse files Browse the repository at this point in the history
  • Loading branch information
sakno committed Dec 5, 2024
1 parent df8c9ae commit 3e3e5c2
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 7 deletions.
14 changes: 7 additions & 7 deletions src/DotNext.Tests/Buffers/Binary/Leb128Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@ private static void EncodeDecode<T>(ReadOnlySpan<T> values)
where T : struct, IBinaryInteger<T>
{
Span<byte> buffer = stackalloc byte[Leb128<T>.MaxSizeInBytes];
var writer = new SpanWriter<byte>(buffer);
var reader = new SpanReader<byte>(buffer);

foreach (var expected in values)
{
writer.Reset();
reader.Reset();

True(writer.WriteLeb128(expected) > 0);
Equal(expected, reader.ReadLeb128<T>());
True(Leb128<T>.TryGetBytes(expected, buffer, out var bytesWritten));
True(Leb128<T>.TryParse(buffer, out var actual, out var bytesConsumed));
Equal(bytesWritten, bytesConsumed);
Equal(expected, actual);
}
}

Expand All @@ -27,6 +24,9 @@ private static void EncodeDecode<T>(ReadOnlySpan<T> values)
[Fact]
public static void EncodeDecodeInt64() => EncodeDecode([0L, long.MaxValue, long.MinValue, 0x80L, -1L]);

[Fact]
public static void EncodeDecodeInt128() => EncodeDecode([0, Int128.MaxValue, Int128.MinValue, 0x80, Int128.NegativeOne]);

[Fact]
public static void EncodeDecodeUInt32() => EncodeDecode([uint.MinValue, uint.MaxValue, 0x80U]);
}
23 changes: 23 additions & 0 deletions src/DotNext.Tests/Buffers/SpanReaderWriterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -452,4 +452,27 @@ public static void WriteLengthPrefixedBytes(LengthFormat format)
using var actual = reader.ReadBlock(format);
Equal(expected, actual.Span);
}

private static void EncodeDecodeLeb128<T>(ReadOnlySpan<T> values)
where T : struct, IBinaryInteger<T>
{
Span<byte> buffer = stackalloc byte[Leb128<T>.MaxSizeInBytes];
var writer = new SpanWriter<byte>(buffer);
var reader = new SpanReader<byte>(buffer);

foreach (var expected in values)
{
writer.Reset();
reader.Reset();

True(writer.WriteLeb128(expected) > 0);
Equal(expected, reader.ReadLeb128<T>());
}
}

[Fact]
public static void EncodeDecodeInt32() => EncodeDecodeLeb128([0, int.MaxValue, int.MinValue, 0x80, -1]);

[Fact]
public static void EncodeDecodeInt64() => EncodeDecodeLeb128([0L, long.MaxValue, long.MinValue, 0x80L, -1L]);
}
47 changes: 47 additions & 0 deletions src/DotNext/Buffers/Binary/Leb128.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,53 @@ public T Value
/// <returns></returns>
public readonly Enumerator GetEnumerator() => new(value);

/// <summary>
/// Tries to encode the value by using LEB128 binary format.
/// </summary>
/// <param name="value">The value to encode.</param>
/// <param name="buffer">The output buffer.</param>
/// <param name="bytesWritten">The number of bytes written.</param>
/// <returns><see langword="true"/> if <paramref name="buffer"/> has enough space to save the encoded value; otherwise, <see langword="false"/>.</returns>
public static bool TryGetBytes(T value, Span<byte> buffer, out int bytesWritten)
{
bytesWritten = 0;
var index = 0;
foreach (var octet in new Leb128<T> { Value = value })
{
if ((uint)index >= (uint)buffer.Length)
return false;

buffer[index++] = octet;
}

bytesWritten = index;
return true;
}

/// <summary>
/// Decodes LEB128-encoded integer.
/// </summary>
/// <param name="buffer">The input buffer containing LEB128 octets.</param>
/// <param name="result">The decoded value.</param>
/// <param name="bytesConsumed">The number of bytes consumed from <paramref name="buffer"/>.</param>
/// <returns><see langword="true"/> if operation is successful; otherwise, <see langword="false"/>.</returns>
public static bool TryParse(ReadOnlySpan<byte> buffer, out T result, out int bytesConsumed)
{
bytesConsumed = 0;
var decoder = new Leb128<T>();
var successful = false;

foreach (var octet in buffer)
{
bytesConsumed += 1;
if (successful = !decoder.Append(octet))
break;
}

result = decoder.Value;
return successful;
}

/// <summary>
/// Represents an enumerator that produces 7-bit encoded integer as a sequence of octets.
/// </summary>
Expand Down

0 comments on commit 3e3e5c2

Please sign in to comment.