将一个long编码为VLQ字节数组并将其写入系统.IO.BinaryWriter



这个问题是我最后一个问题的后续问题:链接

在那个问题中,我问我如何阅读特定的VLQ格式,我不会再描述了,但你可以从我之前的问题中阅读。

基本上哈罗德的结果是:

static int ReadVLQInt64(this BinaryReader r)
{
sbyte b0 = r.ReadSByte();
// the first byte has 6 bits of the raw value
int shift = 6;
long raw = b0 & 0x3FL;
// first continue flag is the second bit from the top, shift it into the sign
sbyte cont = (sbyte)(b0 << 1);
while (cont < 0)
{
sbyte b = r.ReadSByte();
// these bytes have 7 bits of the raw value
raw |= (b & 0x7F) << shift;
shift += 7;
// continue flag is already in the sign
cont = b;
}
return b0 < 0 ? -raw : raw;
}

(这只是它的int64版本(

这很好地解读了这样的价值观,但现在我需要能够写出这样的价值。简言之,我需要这个函数的反面。取一个int64值,并按上一个问题中描述的格式将其分解为可变长度的字节数组。

任何帮助都将不胜感激。

感谢阅读。

编辑:应评论的要求,我需要提供一些我自己的代码来构建。

public static void WriteVLQInt64(this BinaryWriter bw, long value)
{
var bytes = new List<byte>();
var i = 6;
var j = 0;
var shift = 0;
while (true)
{
var andvalue = Convert.ToInt64(Math.Pow(2, i) - Math.Pow(2, j));
j = i;
var b = Convert.ToByte((value & andvalue) >> shift);
if (b <= 0) break;
bytes.Add(b);
shift = i;
i += 7;
}
for (int k = 0; k < bytes.Count; k++)
{
if (bytes[k] == bytes.First())
{
if (value < 0)
{
bytes[k] |= 128;
}
if (bytes[k] != bytes.Last())
{
bytes[k] |= 64;
}
continue;
}
if (bytes[k] != bytes.Last())
{
bytes[k] |= 128;
}
}
bw.Write(bytes.ToArray());
/* - Just for debug
foreach (var item in bytes)
{
Console.Write(Convert.ToString(item, 2).PadLeft(8, '0'));
}
Console.WriteLine();
*/
}

我以前没有发布这篇文章,只是因为这是一个糟糕的解决方案,而且有太多的事情要做。所以我会重新表述我的问题。。。有没有可能有人能帮我压缩这个函数,并从中删除很多不必要的东西?例如Math。Pow-bit的大量if语句和Convert的大量使用。至…

再次感谢您的阅读。

增加了对long.MinValue的支持(它有点复杂,因为abs(long.MinValue) > long.MaxValue,所以需要特殊处理(。添加了对int的单独支持。增加了对"非法"值的检查(否则,您可能会构建对于intlong来说太大的非法序列(。

public static long ReadVlqInt64(this BinaryReader r)
{
byte b = r.ReadByte();
// the first byte has 6 bits of the raw value
ulong raw = (ulong)(b & 0x3F);
bool negative = (b & 0x80) != 0;
// first continue flag is the second bit from the top, shift it into the sign
bool cont = (b & 0x40) != 0;
if (cont)
{
int shift = 6;
while (true)
{
b = r.ReadByte();
cont = (b & 0x80) != 0;
b &= 0x7F;
if (shift == 62)
{
if (negative)
{
// minumum value abs(long.MinValue)
if (b > 0x2 || (b == 0x2 && raw != 0))
{
throw new Exception();
}
}
else
{
// maximum value long.MaxValue
if (b > 0x1)
{
throw new Exception();
}
}
}
// these bytes have 7 bits of the raw value
raw |= ((ulong)b) << shift;
if (!cont)
{
break;
}
if (shift == 62)
{
throw new Exception();
}
shift += 7;
}
}
// We use unchecked here to handle long.MinValue
return negative ? unchecked(-(long)raw) : (long)raw;
}
public static void WriteVlqInt64(this BinaryWriter r, long n)
{
bool negative = n < 0;
// We use unchecked here to handle long.MinValue
ulong raw = negative ? unchecked((ulong)-n) : (ulong)n;
byte b = (byte)(raw & 0x3F);
if (negative)
{
b |= 0x80;
}
raw >>= 6;
bool cont = raw != 0;
if (cont)
{
b |= 0x40;
}
r.Write(b);
while (cont)
{
b = (byte)(raw & 0x7F);
raw >>= 7;
cont = raw != 0;
if (cont)
{
b |= 0x80;
}
r.Write(b);
}
}
public static int ReadVlqInt32(this BinaryReader r)
{
byte b = r.ReadByte();
// the first byte has 6 bits of the raw value
uint raw = (uint)(b & 0x3F);
bool negative = (b & 0x80) != 0;
// first continue flag is the second bit from the top, shift it into the sign
bool cont = (b & 0x40) != 0;
if (cont)
{
int shift = 6;
while (true)
{
b = r.ReadByte();
cont = (b & 0x80) != 0;
b &= 0x7F;
if (shift == 27)
{
if (negative)
{
// minumum value abs(int.MinValue)
if (b > 0x10 || (b == 0x10 && raw != 0))
{
throw new Exception();
}
}
else
{
// maximum value int.MaxValue
if (b > 0xF)
{
throw new Exception();
}
}
}
// these bytes have 7 bits of the raw value
raw |= ((uint)b) << shift;
if (!cont)
{
break;
}
if (shift == 27)
{
throw new Exception();
}
shift += 7;
}
}
// We use unchecked here to handle int.MinValue
return negative ? unchecked(-(int)raw) : (int)raw;
}
public static void WriteVlqInt32(this BinaryWriter r, int n)
{
bool negative = n < 0;
// We use unchecked here to handle int.MinValue
uint raw = negative ? unchecked((uint)-n) : (uint)n;
byte b = (byte)(raw & 0x3F);
if (negative)
{
b |= 0x80;
}
raw >>= 6;
bool cont = raw != 0;
if (cont)
{
b |= 0x40;
}
r.Write(b);
while (cont)
{
b = (byte)(raw & 0x7F);
raw >>= 7;
cont = raw != 0;
if (cont)
{
b |= 0x80;
}
r.Write(b);
}
}

最新更新