Skip to content

Commit 9f229fd

Browse files
committed
perf: unroll And, Or and AndNot operations
1 parent 0911e70 commit 9f229fd

2 files changed

Lines changed: 74 additions & 11 deletions

File tree

bitset.go

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ import (
88
)
99

1010
const (
11-
bpw = 64 // bits per word
12-
maxw = 1<<bpw - 1 // maximum value of a word
13-
shift = 6 // 1<<6 == 64, to be used as multiplier/divisor by 64
14-
div64rem = 63 // remainder of division by 64 when n&div64rem is used
11+
bpw = 64 // bits per word
12+
maxw uint64 = 1<<bpw - 1 // maximum value of a word
13+
shift = 6 // 1<<6 == 64, to be used as multiplier/divisor by 64
14+
div64rem = 63 // remainder of division by 64 when n&div64rem is used
1515
)
1616

1717
// Word is a convenience alias.
@@ -374,8 +374,31 @@ func And(s1, s2 BitSet) BitSet {
374374
// And keeps only bits set in both *bs and other.
375375
func (bs *BitSet) And(other BitSet) {
376376
minLen := min(len(*bs), len(other))
377-
for i := 0; i < minLen; i++ {
378-
(*bs)[i] &= other[i]
377+
if minLen < 8 {
378+
for i := 0; i < minLen; i++ {
379+
(*bs)[i] &= other[i]
380+
}
381+
for i := minLen; i < len(*bs); i++ {
382+
(*bs)[i] = 0
383+
}
384+
bs.trim()
385+
return
386+
}
387+
388+
b := (*bs)[:minLen]
389+
o := other[:minLen]
390+
for ; len(o) > 7; b, o = b[8:], o[8:] {
391+
b[0] &= o[0]
392+
b[1] &= o[1]
393+
b[2] &= o[2]
394+
b[3] &= o[3]
395+
b[4] &= o[4]
396+
b[5] &= o[5]
397+
b[6] &= o[6]
398+
b[7] &= o[7]
399+
}
400+
for i := range o {
401+
b[i] &= o[i]
379402
}
380403
for i := minLen; i < len(*bs); i++ {
381404
(*bs)[i] = 0
@@ -430,8 +453,28 @@ func (bs *BitSet) Or(other BitSet) {
430453
if len(other) > len(*bs) {
431454
bs.resize(len(other))
432455
}
433-
for i := 0; i < len(other); i++ {
434-
(*bs)[i] |= other[i]
456+
if len(other) < 8 {
457+
for i := range other {
458+
(*bs)[i] |= other[i]
459+
}
460+
bs.trim()
461+
return
462+
}
463+
464+
b := *bs
465+
o := other
466+
for ; len(o) > 7; b, o = b[8:], o[8:] {
467+
b[0] |= o[0]
468+
b[1] |= o[1]
469+
b[2] |= o[2]
470+
b[3] |= o[3]
471+
b[4] |= o[4]
472+
b[5] |= o[5]
473+
b[6] |= o[6]
474+
b[7] |= o[7]
475+
}
476+
for i := range o {
477+
b[i] |= o[i]
435478
}
436479
bs.trim()
437480
}
@@ -520,8 +563,28 @@ func AndNot(s1, s2 BitSet) BitSet {
520563
// AndNot removes bits that are set in other from *bs.
521564
func (bs *BitSet) AndNot(other BitSet) {
522565
minLen := min(len(*bs), len(other))
523-
for i := 0; i < minLen; i++ {
524-
(*bs)[i] &^= other[i]
566+
if minLen < 8 {
567+
for i := 0; i < minLen; i++ {
568+
(*bs)[i] &^= other[i]
569+
}
570+
bs.trim()
571+
return
572+
}
573+
574+
b := (*bs)[:minLen]
575+
o := other[:minLen]
576+
for ; len(o) > 7; b, o = b[8:], o[8:] {
577+
b[0] &^= o[0]
578+
b[1] &^= o[1]
579+
b[2] &^= o[2]
580+
b[3] &^= o[3]
581+
b[4] &^= o[4]
582+
b[5] &^= o[5]
583+
b[6] &^= o[6]
584+
b[7] &^= o[7]
585+
}
586+
for i := range o {
587+
b[i] &^= o[i]
525588
}
526589
bs.trim()
527590
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/KernelPryanic/bitmask
22

3-
go 1.24.0
3+
go 1.25
44

55
require github.com/stretchr/testify v1.10.0
66

0 commit comments

Comments
 (0)