-
Notifications
You must be signed in to change notification settings - Fork 0
/
int.go
246 lines (206 loc) · 8.36 KB
/
int.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
package bitstring
/* unsigned integer get */
// Uint8 interprets the 8 bits at offset off as an uint8 in big endian and
// returns its value. Behavior is undefined if there aren't enough bits.
func (bs *Bitstring) Uint8(off int) uint8 {
bs.mustExist(off + 7)
return uint8(bs.uint(uint64(off), 7))
}
// Uint16 interprets the 16 bits at offset off as an uint16 in big endian and
// returns its value. Behavior is undefined if there aren't enough bits.
func (bs *Bitstring) Uint16(off int) uint16 {
bs.mustExist(off + 15)
return uint16(bs.uint(uint64(off), 15))
}
// Uint32 interprets the 32 bits at offset off as an uint32 in big endian and
// returns its value. Behavior is undefined if there aren't enough bits.
func (bs *Bitstring) Uint32(off int) uint32 {
bs.mustExist(off + 31)
return uint32(bs.uint(uint64(off), 31))
}
// Uint64 interprets the 64 bits at offset off as an uint64 in big endian and
// returns its value. Behavior is undefined if there aren't enough bits.
func (bs *Bitstring) Uint64(off int) uint64 {
bs.mustExist(off + 63)
if off&((1<<6)-1) == 0 {
// Fast path: off is a multiple of 64.
return uint64(bs.data[off>>6])
}
i := uint64(off)
w := wordoffset(i)
bit := bitoffset(i)
loword := bs.data[w] >> bit
hiword := bs.data[w+1] & ((1 << bit) - 1)
return uint64(loword | hiword<<(64-bit))
}
// Uintn interprets the n bits at offset off as an n-bit unsigned integer in big
// endian and returns its value. Behavior is undefined if there aren't enough
// bits. Panics if nbits is greater than 64.
func (bs *Bitstring) Uintn(off, n int) uint64 {
if n > 64 || n < 1 {
panic("Uintn supports unsigned integers from 1 to 64 bits long")
}
bs.mustExist(off + n - 1)
i, nbits := uint64(off), uint64(n)
j := wordoffset(i)
k := wordoffset(i + nbits - 1)
looff := bitoffset(i)
loword := bs.data[j]
if j == k {
// Fast path: value doesn't cross uint64 boundaries.
return (loword >> looff) & lomask(nbits)
}
hioff := bitoffset(i + nbits)
hiword := bs.data[k] & lomask(hioff)
loword = himask(looff) & loword >> looff
return loword | hiword<<(64-looff)
}
func (bs *Bitstring) uint(off, n uint64) uint64 {
bit := bitoffset(off)
loword := bs.data[wordoffset(off)] >> bit
hiword := bs.data[wordoffset(off+n)] & ((1 << bit) - 1)
return loword | hiword<<(64-bit)
}
/* unsigned integer set */
// SetUint8 sets the 8 bits at offset off with the given int8 value, in big
// endian. Behavior is undefined if there aren't enough bits.
func (bs *Bitstring) SetUint8(off int, val uint8) {
bs.mustExist(off + 7)
i := uint64(off)
lobit := bitoffset(i)
j := wordoffset(i)
k := wordoffset(i + 7)
if j == k {
// Fast path: value doesn't cross uint64 boundaries.
lobit := bitoffset(i)
neww := uint64(val) << lobit
msk := mask(lobit, lobit+8)
bs.data[j] = transferbits(bs.data[j], neww, msk)
return
}
// Transfer bits to low word.
bs.data[j] = transferbits(bs.data[j], uint64(val)<<lobit, himask(lobit))
// Transfer bits to high word.
lon := 64 - lobit
bs.data[k] = transferbits(bs.data[k], uint64(val)>>lon, lomask(8-lon))
}
// SetUint16 sets the 8 bits at offset off with the given int8 value, in big
// endian. Behavior is undefined if there aren't enough bits.
func (bs *Bitstring) SetUint16(off int, val uint16) {
bs.mustExist(off + 15)
i := uint64(off)
lobit := bitoffset(i)
j := wordoffset(i)
k := wordoffset(i + 15)
if j == k {
// Fast path: value doesn't cross uint64 boundaries.
neww := uint64(val) << lobit
msk := mask(lobit, lobit+16)
bs.data[j] = transferbits(bs.data[j], neww, msk)
return
}
// Transfer bits to low word.
bs.data[j] = transferbits(bs.data[j], uint64(val)<<lobit, himask(lobit))
// Transfer bits to high word.
lon := 64 - lobit
bs.data[k] = transferbits(bs.data[k], uint64(val)>>lon, lomask(16-lon))
}
// SetUint32 sets the 8 bits at offset off with the given int8 value, in big
// endian. Behavior is undefined if there aren't enough bits.
func (bs *Bitstring) SetUint32(off int, val uint32) {
bs.mustExist(off + 31)
i := uint64(off)
lobit := bitoffset(i)
j := wordoffset(i)
k := wordoffset(i + 31)
if j == k {
// Fast path: value doesn't cross uint64 boundaries.
neww := uint64(val) << lobit
msk := mask(lobit, lobit+32)
bs.data[j] = transferbits(bs.data[j], neww, msk)
return
}
// Transfer bits to low word.
bs.data[j] = transferbits(bs.data[j], uint64(val)<<lobit, himask(lobit))
// Transfer bits to high word.
lon := 64 - lobit
bs.data[k] = transferbits(bs.data[k], uint64(val)>>lon, lomask(32-lon))
}
// SetUint64 sets the 8 bits at offset off with the given int8 value, in big
// endian. Behavior is undefined if there aren't enough bits.
func (bs *Bitstring) SetUint64(off int, val uint64) {
bs.mustExist(off + 63)
i := uint64(off)
lobit := bitoffset(i)
j := wordoffset(i)
if off&((1<<6)-1) == 0 {
// Fast path: off is a multiple of 64.
bs.data[off>>6] = val
return
}
// Transfer bits to low word.
bs.data[j] = transferbits(bs.data[j], uint64(val)<<lobit, himask(lobit))
// Transfer bits to high word.
lon := (64 - lobit)
k := wordoffset(i + 63)
bs.data[k] = transferbits(bs.data[k], uint64(val)>>lon, lomask(64-lon))
}
// SetUintn sets the n bits at offset off with the given n-bit unsigned integer in
// big endian. Behavior is undefined if there aren't enough bits. Panics if
// nbits is greater than 64.
func (bs *Bitstring) SetUintn(off, n int, val uint64) {
if n > 64 || n < 1 {
panic("SetUintn supports unsigned integers from 1 to 64 bits long")
}
bs.mustExist(off + n - 1)
i, nbits := uint64(off), uint64(n)
lobit := bitoffset(i)
j := wordoffset(i)
k := wordoffset(i + nbits - 1)
if j == k {
// Fast path: value doesn't cross uint64 boundaries.
x := (val & lomask(nbits)) << lobit
bs.data[j] = transferbits(bs.data[j], x, mask(lobit, lobit+nbits))
return
}
// First and last bits are on different words.
// Transfer bits to low word.
lon := 64 - lobit // how many bits of n we transfer to loword
bs.data[j] = transferbits(bs.data[j], val<<lobit, himask(lon))
// Transfer bits to high word.
bs.data[k] = transferbits(bs.data[k], val>>lon, lomask(nbits-lon))
}
/* signed get */
// Int8 interprets the 8 bits at offset off as an int8 in big endian and
// returns its value. Behavior is undefined if there aren't enough bits.
func (bs *Bitstring) Int8(off int) int8 { return int8(bs.Uint8(off)) }
// Int16 interprets the 16 bits at offset off as an int16 in big endian and
// returns its value. Behavior is undefined if there aren't enough bits.
func (bs *Bitstring) Int16(off int) int16 { return int16(bs.Uint16(off)) }
// Int32 interprets the 32 bits at offset off as an int32 in big endian and
// returns its value. Behavior is undefined if there aren't enough bits.
func (bs *Bitstring) Int32(off int) int32 { return int32(bs.Uint32(off)) }
// Int64 interprets the 64 bits at offset off as an int64 in big endian and
// returns its value. Behavior is undefined if there aren't enough bits.
func (bs *Bitstring) Int64(off int) int64 { return int64(bs.Uint64(off)) }
// Intn interprets the n bits at offset off as an n-bit signed integer in big
// endian and returns its value. Behavior is undefined if there aren't enough
// bits. Panics if nbits is greater than 64.
func (bs *Bitstring) Intn(off, n int) int64 { return int64(bs.Uintn(off, n)) }
/* signed integer set */
// SetInt8 sets the 8 bits at offset off with the given int8 value, in big
// endian. Behavior is undefined if there aren't enough bits.
func (bs *Bitstring) SetInt8(off int, val int8) { bs.SetUint8(off, uint8(val)) }
// SetInt16 sets the 16 bits at offset off with the given int16 value, in big
// endian. Behavior is undefined if there aren't enough bits.
func (bs *Bitstring) SetInt16(off int, val int16) { bs.SetUint16(off, uint16(val)) }
// SetInt32 sets the 32 bits at offset off with the given int32 value, in big
// endian. Behavior is undefined if there aren't enough bits.
func (bs *Bitstring) SetInt32(off int, val int32) { bs.SetUint32(off, uint32(val)) }
// SetInt64 sets the 64 bits at offset off with the given int64 value, in big
// endian. Behavior is undefined if there aren't enough bits.
func (bs *Bitstring) SetInt64(off int, val int64) { bs.SetUint64(off, uint64(val)) }
// SetIntn sets the n bits at offset off with the given n-bit signed integer in
// big endian. Behavior is undefined if there aren't enough bits. Panics if
// nbits is greater than 64.
func (bs *Bitstring) SetIntn(off, n int, val int64) { bs.SetUintn(off, n, uint64(val)) }