67 lines
1.9 KiB
C#
67 lines
1.9 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
|
|
namespace RTCSync.Utils;
|
|
|
|
public readonly struct BitIndex
|
|
{
|
|
private readonly ushort _byteIdx;
|
|
private readonly byte _startBitIdx0;
|
|
private readonly byte _endBitIdx0;
|
|
|
|
// порядок указывания байт в структуре
|
|
// сначала старший, потом младше
|
|
// 1<-------------------------------41
|
|
// порядок указывания бит в структуре
|
|
// сначала младший, потом старше
|
|
// 7<------0
|
|
// таким образом все биты вписываются по порядку справа налево
|
|
// BitIndex[new(3, 0..7), new(2, 0..7), new(1, 0..6)]
|
|
public BitIndex(int byteIdx1, Range bits)
|
|
{
|
|
_byteIdx = (ushort)(byteIdx1 - 1);
|
|
Debug.Assert(!bits.Start.IsFromEnd);
|
|
Debug.Assert(!bits.End.IsFromEnd);
|
|
_startBitIdx0 = (byte)bits.Start.Value;
|
|
_endBitIdx0 = (byte)bits.End.Value;
|
|
}
|
|
|
|
public int Length => _endBitIdx0 - _startBitIdx0 + 1;
|
|
|
|
public int Take(ReadOnlySpan<byte> bytes)
|
|
{
|
|
// example: Len=3, 0b00001000 - 1 = 0b00000111
|
|
var mask = (1U << (_endBitIdx0 - _startBitIdx0 + 1)) - 1U;
|
|
return (int)((bytes[_byteIdx] >> _startBitIdx0) & mask);
|
|
}
|
|
|
|
public static int Take(BitIndex[] bis, ReadOnlySpan<byte> bytes)
|
|
{
|
|
var shift = 0;
|
|
var result = 0;
|
|
foreach (var bi in bis)
|
|
{
|
|
result |= (bi.Take(bytes) << shift);
|
|
shift += bi.Length;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
}
|
|
|
|
public static class BitIndexV2Extensions
|
|
{
|
|
public static int Take(this BitIndex[] bis, ReadOnlySpan<byte> bytes)
|
|
{
|
|
var shift = 0;
|
|
var result = 0;
|
|
foreach (var bi in bis)
|
|
{
|
|
result |= (bi.Take(bytes) << shift);
|
|
shift += bi.Length;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
} |