-
Notifications
You must be signed in to change notification settings - Fork 0
/
range.go
214 lines (184 loc) · 4.49 KB
/
range.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
package bitarray
// A Range represents a span over a certain number of bits in a BitArray starting
// at specific position.
type Range struct {
*BitArray
b, n int
}
// Range creates a Range object representing `n` bits starting at `b`.
func (ba *BitArray) Range(b, n int) Range {
if (b < ba.n) && (b+n-1 < ba.n) {
return Range{ba, b, n}
}
panic("index out of bounds")
}
// CopyRange copies bits from `src` into `dst` specified by the ranges.
// The procedure copies number of bits equal to the the minimum of the two ranges.
// It is undefined behavior to copy overlapping ranges.
func CopyRange(dst, src Range) {
nb := min(dst.n, src.n) // no. of bits to get
dbi, dsi := biandsi(dst.b)
sbi, ssi := biandsi(src.b)
if dsi == 0 && ssi == 0 {
m, n := biandsi(nb) // nb/64, nb%64
copy(dst.bits[dbi:dbi+m], src.bits[sbi:sbi+m])
if n != 0 {
// copy remaining < 64 bits, one bit at a time
copyu64bits(n, &dst.bits[dbi+m], src.bits[sbi+m])
}
return
}
if dst.b == src.b {
bi, si := biandsi(dst.b)
// wind the first block till the next boundary
for ; si < 64; si++ {
if nb != 0 {
setbit(&dst.bits[bi], si, getbit(src.bits[bi], si))
} else {
return
}
}
// we've wound up to the next boundary
// so we'll copy blocks up until the last-but-one block
bi++
m, n := biandsi(nb) // nb/64, nb%64
copy(dst.bits[bi:bi+m], src.bits[bi:bi+m])
if n != 0 {
// copy the remaining bits from the last block
copyu64bits(n, &dst.bits[bi+m], src.bits[bi+m])
}
return
}
unalignedCopy(nb, dst.bits, dbi, dsi, src.bits, sbi, ssi)
}
func copyu64bits(n uint64, d *uint64, s uint64) {
for i := uint64(0); n != 0; i++ {
setbit(d, i, getbit(s, i))
n--
}
}
// SwapRange swaps the bits of two ranges `a` and `b`.
// The procedure copies number of bits equal to the the minimum of the two ranges.
// It is undefined behavior to swap overlapping ranges.
func SwapRange(a, b Range) {
nb := min(a.n, b.n) // no. of bits to swap
abi, asi := biandsi(a.b)
bbi, bsi := biandsi(b.b)
if asi == 0 && bsi == 0 {
m, n := biandsi(nb) // nb/64, nb%64
// swap the aligned blocks first
for m != 0 {
a.bits[abi], b.bits[bbi] = b.bits[bbi], a.bits[abi]
abi++
bbi++
m--
}
if n != 0 {
// swap the bits of the last block, bit-by-bit
swapu64bits(n, &a.bits[abi], &b.bits[bbi])
}
return
}
// starting point is same
if a.b == b.b {
bi, si := biandsi(a.b)
// process the first block
anum, bnum := &a.bits[bi], &b.bits[bi]
for ; si < 64; si++ {
if nb != 0 {
abit := getbit(*anum, si)
bbit := getbit(*bnum, si)
setbit(anum, si, bbit)
setbit(bnum, si, abit)
nb--
} else {
return
}
}
// we've wound up to the beginning of the next boundary
// process from the second till the last-but-one block
bi++
m, n := biandsi(nb) // nb/64, nb%64
// swap until the last block
for m != 0 {
a.bits[bi], b.bits[bi] = b.bits[bi], a.bits[bi]
bi++
m--
}
if n != 0 {
// swap the remaining bits, if any, in the last block bitwise
swapu64bits(n, &a.bits[bi], &b.bits[bi])
}
return
}
// general case
unalignedSwap(nb, a.bits, abi, asi, b.bits, bbi, bsi)
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func getbit(u uint64, i uint64) Bit { return (u >> i) & 1 }
func setbit(u *uint64, i uint64, b Bit) { *u = (*u & ^(1 << i)) | (b << i) }
func alignedcopy(nb int, dst []Bit, di uint64, src []Bit, si uint64) (int, uint64, uint64) {
m := uint64(nb / 64) // no. of blocks to copy
copy(dst[di:di+m], src[si:si+m])
// for nb != 0 {
// dst[di] = src[si]
// di++
// si++
// nb -= 64
// }
return nb, di + m, si + m
}
func unalignedCopy(nb int, d []Bit, dbi, dsi uint64, s []Bit, sbi, ssi uint64) {
for nb != 0 {
// dst[dbi][dsi] <- src[sbi][ssi]
setbit(&d[dbi], dsi, getbit(s[sbi], ssi))
// move to the next src bit
ssi++
if ssi >= 64 {
sbi++
ssi = 0
}
// move to the next dst bit
dsi++
if dsi >= 64 {
dbi++
dsi = 0
}
// one less bit to process
nb--
}
}
func swapu64bits(n uint64, a, b *uint64) {
for i := uint64(0); n != 0; i++ {
abit := getbit(*a, i)
bbit := getbit(*b, i)
setbit(a, i, bbit)
setbit(b, i, abit)
n--
}
}
func unalignedSwap(nb int, a []Bit, abi, asi uint64, b []Bit, bbi, bsi uint64) {
for nb != 0 {
anum, bnum := &a[abi], &b[bbi]
abit := getbit(*anum, asi)
bbit := getbit(*bnum, bsi)
setbit(anum, asi, bbit)
setbit(bnum, bsi, abit)
asi++
if asi >= 64 {
abi++
asi = 0
}
bsi++
if bsi >= 64 {
bbi++
bsi = 0
}
nb--
}
}