[英]Encoding a long to a VLQ byte array and writing it to System.IO.BinaryWriter
這個問題是我最后一個問題的跟進: 鏈接
在該問題中,我詢問如何讀取特定的VLQ格式,不再贅述,但您可以從上一個問題中閱讀。
基本上,harold的結果是這樣的:
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會占用大量的if語句,並會大量使用Convert.To ...
再次感謝您的閱讀。
添加了對long.MinValue
支持(這有點復雜,因為abs(long.MinValue) > long.MaxValue
,因此需要特殊處理)。 添加了對int
單獨支持。 添加了對“非法”值的檢查(否則,您可以構建對於int
或long
而言太大的非法序列)。
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);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.