Search code examples
gobinaryvarint

How to write LEB128 in Go


How do you write an integer to LEB128 format in Go? I'm trying to encode an int32 to a Minecraft VarInt, so far I've tried importing the example on the wiki to Go. I get the wrong results when testing though, wiki says -1 should equal [255 255 255 255 15], but I get [255 255 255 255 255] instead. What I'm I doing wrong here?

func WriteVarInt2(v int32) []byte{
   var out []byte
   c := 0
   for{
       currentByte := byte(v & 0b01111111)
       v >>= 7
       if v != 0 {
           currentByte |= 0b10000000
       }
       out = append(out, currentByte)
       c++

       if c >= 5 || v == 0{
           return out
       }
    }
}

Solution

  • The problem is with the shifting operation.

    >> is arithmetic shift right, >>> is logical shift right. The difference is that >> brings in the sign bit (on the left), while >>> brings in zeros (whatever the sign bit was).

    The algorithm of LEB128's Varint uses logical shift, and Go's >> is arithmetic shift.

    There is no distinct logical shift in Go, but if you treat the number as unsigned, you'll get exactly that:

    func WriteVarInt2(v_ int32) []byte {
        v := uint32(v_)
    
        // rest of your function unchanged
        // ...
    }
    

    Testing it:

    fmt.Println(WriteVarInt2(-1))
    

    Output is as expected (try it on the Go Playground):

    [255 255 255 255 15]