-
Notifications
You must be signed in to change notification settings - Fork 3
/
encoding.go
129 lines (104 loc) · 4.51 KB
/
encoding.go
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package varint
import (
"github.com/golang-infrastructure/go-gtypes"
)
// 这个文件中存放的是比较靠底层的方法实现,上层的API都是对这些底层方法的进一步封装
// 约定:
// 1. varint编码的字节数组约定以字节的最高位的值来表示某个无符号整数对应的多个字节是否结束,
// 如果传入的要解码的字节数组没有正确设置结束标志位的话,会一直读取到字节数组结束位置都认为是当前数字的值的一部分,这可能会发生溢出
// ---------------------------------------------------------------------------------------------------------------------
const (
// VarIntEndByteHighestBitValue 对varint字节数组而言,如果某个字节的最高位的值是0表示这是当前数字variant编码字节数组的最后一个字节
VarIntEndByteHighestBitValue = 0x0
// VarIntNotEndByteHighestBitValue 对varint字节数组而言,如果某个字节的最高位的值是1表示这不是当前数字varint编码字节数组的最后一个字节,后面至少还有一个字节
VarIntNotEndByteHighestBitValue = 0x1
)
// ByteHighestBit 获取byte的最高位
const ByteHighestBit = 0x80
// 0对应的varint编码
var ZeroVarIntBytes = []byte{VarIntNotEndByteHighestBitValue << 7}
// ---------------------------------------------------------------------------------------------------------------------
// Encode 对无符号类型进行编码,注意,如果被编码的数字位数较小可能会越编码越大
func Encode[T gtypes.Unsigned](value T) []byte {
bytes := make([]byte, 0)
// 只要不是读取到了最后一个字节就一直读取
for value > 127 {
bit := (value & 0x7F) | (VarIntNotEndByteHighestBitValue << 7)
value >>= 7
bytes = append(bytes, uint8(bit))
}
// 设置结束标志位,结束标志位是强制必须设置的
v := uint8(value&0x7F) | (VarIntEndByteHighestBitValue << 7)
bytes = append(bytes, v)
return bytes
}
// EncodeSlice 对无符号切片编码,切片中的无符号数字会被挨个存储在返回的字节切片中
func EncodeSlice[T gtypes.Unsigned](valueSlice []T) []byte {
slice := make([]byte, 0)
for _, value := range valueSlice {
slice = append(slice, Encode(value)...)
}
return slice
}
// EncodeChannel 从无符号整数channel中读取数据,varint编码之后发送到字节channel
func EncodeChannel[T gtypes.Unsigned](valueChannel <-chan T, outputByteChannel chan<- byte) {
for v := range valueChannel {
varintBytes := Encode[T](v)
for _, b := range varintBytes {
outputByteChannel <- b
}
}
close(outputByteChannel)
}
// ---------------------------------------------------------------------------------------------------------------------
// Decode 对varint编码的无符号整数进行解码,一次解码一个
func Decode[T gtypes.Unsigned](bytes []byte) T {
var r T
weight := 0
for _, b := range bytes {
r = r | (T(b&0x7F) << weight)
weight += 7
// 判断是否是最后一个字节,如果是最后一个字节说明当前这个数字读取完毕了
if b&ByteHighestBit == VarIntEndByteHighestBitValue {
break
}
}
return r
}
// DecodeSlice 当多个无符号整数放在同一个字节切片中时,可以调用这个方法解码
func DecodeSlice[T gtypes.Unsigned](bytes []byte) []T {
slice := make([]T, 0)
lastIndex := 0
for index, b := range bytes {
// 当读取到当前无符号整数的最后一个字节的时候,截取当前无符号整数的全部字节传进去解码
if b&ByteHighestBit == VarIntEndByteHighestBitValue {
value := Decode[T](bytes[lastIndex : index+1])
slice = append(slice, value)
lastIndex = index + 1
}
}
// 说明有未读取处理完的内容,将剩下的内容一股脑儿的当做一个数字解码
if lastIndex < len(bytes) {
value := Decode[T](bytes[lastIndex:len(bytes)])
slice = append(slice, value)
}
return slice
}
// DecodeChannel 通过channel流式解码
func DecodeChannel[T gtypes.Unsigned](varintBytesChannel <-chan byte, outputChannel chan<- T) {
nowBytes := make([]byte, 0)
for b := range varintBytesChannel {
// 长度限制,避免畸形数据打爆内存
if len(nowBytes) <= 64 {
nowBytes = append(nowBytes, b)
}
// 读取完一个无符号整数的时候就解码发送一次
if b&ByteHighestBit == VarIntEndByteHighestBitValue {
v := Decode[T](nowBytes)
outputChannel <- v
nowBytes = make([]byte, 0)
}
}
close(outputChannel)
}
// ---------------------------------------------------------------------------------------------------------------------