簡體   English   中英

將long編碼為VLQ字節數組並將其寫入System.IO.BinaryWriter

[英]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單獨支持。 添加了對“非法”值的檢查(否則,您可以構建對於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);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM