Leb128<T>
public struct Leb128<T> : ISupplier<T>, IFunctional<Func<T>>, IResettable where T : struct, IBinaryInteger<T>
Represents encoder and decoder for 7-bit encoded integers.
using DotNext.Numerics;
using DotNext.Runtime.CompilerServices;
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DotNext.Buffers.Binary
{
[StructLayout(LayoutKind.Auto)]
public struct Leb128<T> : ISupplier<T>, IFunctional<Func<T>>, IResettable where T : struct, IBinaryInteger<T>
{
[StructLayout(LayoutKind.Auto)]
public struct Enumerator
{
private T value;
private byte current;
private bool completed;
public byte Current {
[IsReadOnly]
get {
return current;
}
}
internal Enumerator(T value)
{
current = 0;
completed = false;
this.value = value;
}
public bool MoveNext()
{
if (completed)
return false;
if (Number.IsSigned<T>())
MoveNextSigned();
else
MoveNextUnsigned();
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void MoveNextSigned()
{
T val = value & T.CreateTruncating<byte>((byte)127);
value >>= 7;
byte b = byte.CreateTruncating<T>(val);
if (value == -T.CreateTruncating<int>((int)(((uint)b >> 6) & 1)))
completed = true;
else
b = (byte)(b | 128);
current = b;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void MoveNextUnsigned()
{
if (value > T.CreateTruncating<byte>((byte)127)) {
current = (byte)(byte.CreateTruncating<T>(value) | 128);
value = T.op_UnsignedRightShift(value, 7);
} else {
current = byte.CreateTruncating<T>(value);
completed = true;
}
}
}
private static readonly int MaxSizeInBits;
private const byte BitMask = 127;
private const byte CarryBit = 128;
private ushort shift;
private T value;
public static int MaxSizeInBytes { get; }
public T Value {
[IsReadOnly]
get {
return value;
}
set {
shift = 0;
this.value = value;
}
}
static Leb128()
{
MaxSizeInBits = (MaxSizeInBytes = Math.DivRem(Number.GetMaxByteCount<T>() * 8, 7, out int result) + Unsafe.BitCast<bool, byte>(result != 0)) * 7;
}
public bool Append(byte b)
{
if (shift == MaxSizeInBits)
<Append>g__ThrowInvalidDataException|9_0();
value |= (T.CreateTruncating<byte>(b) & T.CreateTruncating<byte>((byte)127)) << (int)shift;
shift += 7;
bool flag = Unsafe.BitCast<byte, bool>((byte)(b >> 7));
if (Number.IsSigned<T>() && !flag && shift < MaxSizeInBits && (b & 64) != 0)
value |= T.get_AllBitsSet() << (int)shift;
return flag;
}
public void Reset()
{
Value = default(T);
}
[IsReadOnly]
T ISupplier<T>.Invoke()
{
return value;
}
[IsReadOnly]
public Enumerator GetEnumerator()
{
return new Enumerator(value);
}
public static bool TryGetBytes(T value, Span<byte> buffer, out int bytesWritten)
{
bytesWritten = 0;
int num = 0;
Leb128<T> leb = default(Leb128<T>);
leb.Value = value;
Enumerator enumerator = leb.GetEnumerator();
while (enumerator.MoveNext()) {
byte current = enumerator.Current;
if ((uint)num >= (uint)buffer.Length)
return false;
buffer[num++] = current;
}
bytesWritten = num;
return true;
}
public static bool TryParse(ReadOnlySpan<byte> buffer, out T result, out int bytesConsumed)
{
bytesConsumed = 0;
Leb128<T> leb = default(Leb128<T>);
bool result2 = false;
ReadOnlySpan<byte> readOnlySpan = buffer;
foreach (byte b in readOnlySpan) {
bytesConsumed++;
if (result2 = !leb.Append(b))
break;
}
result = leb.Value;
return result2;
}
}
}