DotNext by .NET Foundation and Contributors

<PackageReference Include="DotNext" Version="5.16.1" />

 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; } } }