-
Notifications
You must be signed in to change notification settings - Fork 0
/
bits.go
130 lines (115 loc) · 2.49 KB
/
bits.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
130
package bits
type (
// Array is a bitmap array
Array struct {
Bytes []byte
}
// Writer of numbers to Array.
Writer struct {
*Array
bitOffset int
}
// Reader of numbers from Array.
Reader struct {
*Array
byteOffset int
bitOffset int
}
)
// NewWriter is a bitmap writer
func NewWriter(arr *Array) *Writer {
return &Writer{
Array: arr,
}
}
// NewReader is a bitmap reader
func NewReader(arr *Array) *Reader {
return &Reader{
Array: arr,
}
}
func (a *Writer) byteBitsFree() int {
return 8 - a.bitOffset
}
func (a *Writer) writeIntoLastByte(v uint) {
a.Bytes[len(a.Bytes)-1] |= byte(v << a.bitOffset)
}
func zeroTopByteBits(v uint, bits int) uint {
mask := uint(0xff) >> bits
return v & mask
}
// Write bits of a number into array.
func (a *Writer) Write(bits int, v uint) {
if a.bitOffset == 0 {
a.Bytes = append(a.Bytes, byte(0))
}
free := a.byteBitsFree()
if bits <= free {
toWrite := bits
// appending v to the bit array
a.writeIntoLastByte(v)
// increment offsets
if toWrite == free {
a.bitOffset = 0
} else {
a.bitOffset += toWrite
}
} else {
toWrite := free
clear := a.bitOffset // 8 - free
// zeroing top `clear` bits and appending result to the bit array
a.writeIntoLastByte(zeroTopByteBits(v, clear))
// increment offsets
a.bitOffset = 0
a.Write(bits-toWrite, v>>toWrite)
}
}
func (a *Reader) byteBitsFree() int {
return 8 - a.bitOffset
}
func (a *Reader) Read(bits int) (v uint) {
// perform all the checks in the same function to make CPU branch predictor work better
if bits == 0 {
return 0
}
/*if bits > a.NonReadBits() {
panic(io.ErrUnexpectedEOF)
}*/
free := a.byteBitsFree()
if bits <= free {
toRead := bits
clear := 8 - (a.bitOffset + toRead)
v = zeroTopByteBits(uint(a.Bytes[a.byteOffset]), clear) >> a.bitOffset
// increment offsets
if toRead == free {
a.bitOffset = 0
a.byteOffset++
} else {
a.bitOffset += toRead
}
} else {
toRead := free
v = uint(a.Bytes[a.byteOffset]) >> a.bitOffset
// increment offsets
a.bitOffset = 0
a.byteOffset++
// read rest
rest := a.Read(bits - toRead)
v |= rest << toRead
}
return
}
func (a *Reader) View(bits int) (v uint) {
cp := *a
cpp := &cp
return cpp.Read(bits)
}
// NonReadBytes returns a number of non-consumed bytes
func (a *Reader) NonReadBytes() int {
return len(a.Bytes) - a.byteOffset
}
// NonReadBytes returns a number of non-consumed bits
func (a *Reader) NonReadBits() int {
//return a.nonReadBits
return a.NonReadBytes()*8 - a.bitOffset
}