| // Copyright 2011 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package binary | |
| // This file implements "varint" encoding of 64-bit integers. | |
| // The encoding is: | |
| // - unsigned integers are serialized 7 bits at a time, starting with the | |
| // least significant bits | |
| // - the most significant bit (msb) in each output byte indicates if there | |
| // is a continuation byte (msb = 1) | |
| // - signed integers are mapped to unsigned integers using "zig-zag" | |
| // encoding: Positive values x are written as 2*x + 0, negative values | |
| // are written as 2*(^x) + 1; that is, negative numbers are complemented | |
| // and whether to complement is encoded in bit 0. | |
| // | |
| // Design note: | |
| // At most 10 bytes are needed for 64-bit values. The encoding could | |
| // be more dense: a full 64-bit value needs an extra byte just to hold bit 63. | |
| // Instead, the msb of the previous byte could be used to hold bit 63 since we | |
| // know there can't be more than 64 bits. This is a trivial improvement and | |
| // would reduce the maximum encoding length to 9 bytes. However, it breaks the | |
| // invariant that the msb is always the "continuation bit" and thus makes the | |
| // format incompatible with a varint encoding for larger numbers (say 128-bit). | |
| import ( | |
| "errors" | |
| "io" | |
| ) | |
| // MaxVarintLenN is the maximum length of a varint-encoded N-bit integer. | |
| const ( | |
| MaxVarintLen16 = 3 | |
| MaxVarintLen32 = 5 | |
| MaxVarintLen64 = 10 | |
| ) | |
| // AppendUvarint appends the varint-encoded form of x, | |
| // as generated by [PutUvarint], to buf and returns the extended buffer. | |
| func AppendUvarint(buf []byte, x uint64) []byte { | |
| for x >= 0x80 { | |
| buf = append(buf, byte(x)|0x80) | |
| x >>= 7 | |
| } | |
| return append(buf, byte(x)) | |
| } | |
| // PutUvarint encodes a uint64 into buf and returns the number of bytes written. | |
| // If the buffer is too small, PutUvarint will panic. | |
| func PutUvarint(buf []byte, x uint64) int { | |
| i := 0 | |
| for x >= 0x80 { | |
| buf[i] = byte(x) | 0x80 | |
| x >>= 7 | |
| i++ | |
| } | |
| buf[i] = byte(x) | |
| return i + 1 | |
| } | |
| // Uvarint decodes a uint64 from buf and returns that value and the | |
| // number of bytes read (> 0). If an error occurred, the value is 0 | |
| // and the number of bytes n is <= 0 meaning: | |
| // - n == 0: buf too small; | |
| // - n < 0: value larger than 64 bits (overflow) and -n is the number of | |
| // bytes read. | |
| func Uvarint(buf []byte) (uint64, int) { | |
| var x uint64 | |
| var s uint | |
| for i, b := range buf { | |
| if i == MaxVarintLen64 { | |
| // Catch byte reads past MaxVarintLen64. | |
| // See issue https://golang.org/issues/41185 | |
| return 0, -(i + 1) // overflow | |
| } | |
| if b < 0x80 { | |
| if i == MaxVarintLen64-1 && b > 1 { | |
| return 0, -(i + 1) // overflow | |
| } | |
| return x | uint64(b)<<s, i + 1 | |
| } | |
| x |= uint64(b&0x7f) << s | |
| s += 7 | |
| } | |
| return 0, 0 | |
| } | |
| // AppendVarint appends the varint-encoded form of x, | |
| // as generated by [PutVarint], to buf and returns the extended buffer. | |
| func AppendVarint(buf []byte, x int64) []byte { | |
| ux := uint64(x) << 1 | |
| if x < 0 { | |
| ux = ^ux | |
| } | |
| return AppendUvarint(buf, ux) | |
| } | |
| // PutVarint encodes an int64 into buf and returns the number of bytes written. | |
| // If the buffer is too small, PutVarint will panic. | |
| func PutVarint(buf []byte, x int64) int { | |
| ux := uint64(x) << 1 | |
| if x < 0 { | |
| ux = ^ux | |
| } | |
| return PutUvarint(buf, ux) | |
| } | |
| // Varint decodes an int64 from buf and returns that value and the | |
| // number of bytes read (> 0). If an error occurred, the value is 0 | |
| // and the number of bytes n is <= 0 with the following meaning: | |
| // - n == 0: buf too small; | |
| // - n < 0: value larger than 64 bits (overflow) | |
| // and -n is the number of bytes read. | |
| func Varint(buf []byte) (int64, int) { | |
| ux, n := Uvarint(buf) // ok to continue in presence of error | |
| x := int64(ux >> 1) | |
| if ux&1 != 0 { | |
| x = ^x | |
| } | |
| return x, n | |
| } | |
| var errOverflow = errors.New("binary: varint overflows a 64-bit integer") | |
| // ReadUvarint reads an encoded unsigned integer from r and returns it as a uint64. | |
| // The error is [io.EOF] only if no bytes were read. | |
| // If an [io.EOF] happens after reading some but not all the bytes, | |
| // ReadUvarint returns [io.ErrUnexpectedEOF]. | |
| func ReadUvarint(r io.ByteReader) (uint64, error) { | |
| var x uint64 | |
| var s uint | |
| for i := 0; i < MaxVarintLen64; i++ { | |
| b, err := r.ReadByte() | |
| if err != nil { | |
| if i > 0 && err == io.EOF { | |
| err = io.ErrUnexpectedEOF | |
| } | |
| return x, err | |
| } | |
| if b < 0x80 { | |
| if i == MaxVarintLen64-1 && b > 1 { | |
| return x, errOverflow | |
| } | |
| return x | uint64(b)<<s, nil | |
| } | |
| x |= uint64(b&0x7f) << s | |
| s += 7 | |
| } | |
| return x, errOverflow | |
| } | |
| // ReadVarint reads an encoded signed integer from r and returns it as an int64. | |
| // The error is [io.EOF] only if no bytes were read. | |
| // If an [io.EOF] happens after reading some but not all the bytes, | |
| // ReadVarint returns [io.ErrUnexpectedEOF]. | |
| func ReadVarint(r io.ByteReader) (int64, error) { | |
| ux, err := ReadUvarint(r) // ok to continue in presence of error | |
| x := int64(ux >> 1) | |
| if ux&1 != 0 { | |
| x = ^x | |
| } | |
| return x, err | |
| } | |