-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathvlq.go
More file actions
87 lines (69 loc) · 1.98 KB
/
vlq.go
File metadata and controls
87 lines (69 loc) · 1.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package fwt
import (
"errors"
)
// See https://github.com/git/git/blob/master/varint.c to original Git's VLQ implementation
var (
ErrEmptyBuffer = errors.New("empty buffer")
ErrIncompleteNumber = errors.New("incomplete VLQ number")
ErrBufferTooSmall = errors.New("buffer too small")
ErrValueTooLarge = errors.New("value too large to encode")
)
// decodeVLQ decodes a variable-length quantity from the given buffer.
// It returns the decoded value, the number of bytes read, and an error if any.
func decodeVLQ(buffer []byte) (uint64, int, error) {
if len(buffer) == 0 {
return 0, 0, ErrEmptyBuffer
}
var val uint64
var bytesRead int
// Read first byte
c := buffer[bytesRead]
bytesRead++
val = uint64(c & 0x7F)
// Continue reading while the continuation bit is set
for c&0x80 != 0 {
if bytesRead >= len(buffer) {
return 0, bytesRead, ErrIncompleteNumber
}
val++
// Check for overflow
//if val == 0 || (val & ^uint64(0x7F)) != 0 {
// return 0, bytesRead, ErrOverflow
//}
c = buffer[bytesRead]
bytesRead++
val = (val << 7) + uint64(c&0x7F)
}
return val, bytesRead, nil
}
// encodeVLQ encodes a variable-length quantity to the given buffer.
// It returns the number of bytes written and an error if any.
func encodeVLQ(buffer []byte, value uint64) (int, error) {
if len(buffer) == 0 {
return 0, ErrBufferTooSmall
}
var varint [16]byte
pos := len(varint) - 1
// Encode the least significant 7 bits
varint[pos] = byte(value & 0x7F)
// Continue encoding while there are more bits
// while (value >>= 7)
// varint[--pos] = 128 | (--value & 127);
for value >>= 7; value > 0; value >>= 7 {
pos--
if pos < 0 {
return 0, ErrValueTooLarge
}
value--
varint[pos] = byte(0x80 | (value & 0x7F))
}
// Check if the target buffer is large enough
bytesToWrite := len(varint) - pos
if len(buffer) < bytesToWrite {
return 0, ErrBufferTooSmall
}
// Copy the encoded bytes to the target buffer
copy(buffer, varint[pos:])
return bytesToWrite, nil
}