Skip to content

Commit 3e3e5c2

Browse files
committed
Added helpers for one-shot encoding and decoding
1 parent df8c9ae commit 3e3e5c2

File tree

3 files changed

+77
-7
lines changed

3 files changed

+77
-7
lines changed

src/DotNext.Tests/Buffers/Binary/Leb128Tests.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,13 @@ private static void EncodeDecode<T>(ReadOnlySpan<T> values)
88
where T : struct, IBinaryInteger<T>
99
{
1010
Span<byte> buffer = stackalloc byte[Leb128<T>.MaxSizeInBytes];
11-
var writer = new SpanWriter<byte>(buffer);
12-
var reader = new SpanReader<byte>(buffer);
1311

1412
foreach (var expected in values)
1513
{
16-
writer.Reset();
17-
reader.Reset();
18-
19-
True(writer.WriteLeb128(expected) > 0);
20-
Equal(expected, reader.ReadLeb128<T>());
14+
True(Leb128<T>.TryGetBytes(expected, buffer, out var bytesWritten));
15+
True(Leb128<T>.TryParse(buffer, out var actual, out var bytesConsumed));
16+
Equal(bytesWritten, bytesConsumed);
17+
Equal(expected, actual);
2118
}
2219
}
2320

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

27+
[Fact]
28+
public static void EncodeDecodeInt128() => EncodeDecode([0, Int128.MaxValue, Int128.MinValue, 0x80, Int128.NegativeOne]);
29+
3030
[Fact]
3131
public static void EncodeDecodeUInt32() => EncodeDecode([uint.MinValue, uint.MaxValue, 0x80U]);
3232
}

src/DotNext.Tests/Buffers/SpanReaderWriterTests.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,4 +452,27 @@ public static void WriteLengthPrefixedBytes(LengthFormat format)
452452
using var actual = reader.ReadBlock(format);
453453
Equal(expected, actual.Span);
454454
}
455+
456+
private static void EncodeDecodeLeb128<T>(ReadOnlySpan<T> values)
457+
where T : struct, IBinaryInteger<T>
458+
{
459+
Span<byte> buffer = stackalloc byte[Leb128<T>.MaxSizeInBytes];
460+
var writer = new SpanWriter<byte>(buffer);
461+
var reader = new SpanReader<byte>(buffer);
462+
463+
foreach (var expected in values)
464+
{
465+
writer.Reset();
466+
reader.Reset();
467+
468+
True(writer.WriteLeb128(expected) > 0);
469+
Equal(expected, reader.ReadLeb128<T>());
470+
}
471+
}
472+
473+
[Fact]
474+
public static void EncodeDecodeInt32() => EncodeDecodeLeb128([0, int.MaxValue, int.MinValue, 0x80, -1]);
475+
476+
[Fact]
477+
public static void EncodeDecodeInt64() => EncodeDecodeLeb128([0L, long.MaxValue, long.MinValue, 0x80L, -1L]);
455478
}

src/DotNext/Buffers/Binary/Leb128.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,53 @@ public T Value
9595
/// <returns></returns>
9696
public readonly Enumerator GetEnumerator() => new(value);
9797

98+
/// <summary>
99+
/// Tries to encode the value by using LEB128 binary format.
100+
/// </summary>
101+
/// <param name="value">The value to encode.</param>
102+
/// <param name="buffer">The output buffer.</param>
103+
/// <param name="bytesWritten">The number of bytes written.</param>
104+
/// <returns><see langword="true"/> if <paramref name="buffer"/> has enough space to save the encoded value; otherwise, <see langword="false"/>.</returns>
105+
public static bool TryGetBytes(T value, Span<byte> buffer, out int bytesWritten)
106+
{
107+
bytesWritten = 0;
108+
var index = 0;
109+
foreach (var octet in new Leb128<T> { Value = value })
110+
{
111+
if ((uint)index >= (uint)buffer.Length)
112+
return false;
113+
114+
buffer[index++] = octet;
115+
}
116+
117+
bytesWritten = index;
118+
return true;
119+
}
120+
121+
/// <summary>
122+
/// Decodes LEB128-encoded integer.
123+
/// </summary>
124+
/// <param name="buffer">The input buffer containing LEB128 octets.</param>
125+
/// <param name="result">The decoded value.</param>
126+
/// <param name="bytesConsumed">The number of bytes consumed from <paramref name="buffer"/>.</param>
127+
/// <returns><see langword="true"/> if operation is successful; otherwise, <see langword="false"/>.</returns>
128+
public static bool TryParse(ReadOnlySpan<byte> buffer, out T result, out int bytesConsumed)
129+
{
130+
bytesConsumed = 0;
131+
var decoder = new Leb128<T>();
132+
var successful = false;
133+
134+
foreach (var octet in buffer)
135+
{
136+
bytesConsumed += 1;
137+
if (successful = !decoder.Append(octet))
138+
break;
139+
}
140+
141+
result = decoder.Value;
142+
return successful;
143+
}
144+
98145
/// <summary>
99146
/// Represents an enumerator that produces 7-bit encoded integer as a sequence of octets.
100147
/// </summary>

0 commit comments

Comments
 (0)