Skip to content

Commit 34fc2bf

Browse files
lemireneena
andcommitted
faster faster iandNotRun16
Co-authored-by: Neena Dugar <[email protected]>
1 parent 5c4c97c commit 34fc2bf

File tree

1 file changed

+43
-14
lines changed

1 file changed

+43
-14
lines changed

arraycontainer.go

+43-14
Original file line numberDiff line numberDiff line change
@@ -664,25 +664,54 @@ func (ac *arrayContainer) iandNot(a container) container {
664664
}
665665

666666
func (ac *arrayContainer) iandNotRun16(rc *runContainer16) container {
667-
if len(ac.content) == 0 {
667+
// Fast path: if either the array container or the run container is empty, the result is the array.
668+
if ac.isEmpty() || rc.isEmpty() {
668669
// Empty
669670
return ac
670671
}
671-
672-
for _, run := range rc.iv {
673-
if run.start > ac.maximum() {
674-
// Since the runs are sorted, we can stop here. (No subsequent runs will
675-
// overlap with the array container.)
676-
break
677-
}
678-
if run.last() < ac.minimum() {
679-
// This run is entirely before the array container. We can skip it.
680-
continue
672+
// Fast path: if the run container is full, the result is empty.
673+
if rc.isFull() {
674+
ac.content = ac.content[:0]
675+
return ac
676+
}
677+
current_run := 0
678+
// All values in [start_run, end_end] are part of the run
679+
start_run := rc.iv[current_run].start
680+
end_end := start_run + rc.iv[current_run].length
681+
// We are going to read values in the array at index i, and we are
682+
// going to write them at index pos. So we do in-place processing.
683+
// We always have that pos <= i by construction. So we can either
684+
// overwrite a value just read, or a value that was previous read.
685+
pos := 0
686+
i := 0
687+
for ; i < len(ac.content); i++ {
688+
if ac.content[i] < start_run {
689+
// the value in the array appears before the run [start_run, end_end]
690+
ac.content[pos] = ac.content[i]
691+
pos++
692+
} else if ac.content[i] <= end_end {
693+
// nothing to do, the value is in the array but also in the run.
694+
} else {
695+
// We have the value in the array after the run. We cannot tell
696+
// whether we need to keep it or not. So let us move to another run.
697+
if current_run+1 < len(rc.iv) {
698+
current_run++
699+
start_run = rc.iv[current_run].start
700+
end_end = start_run + rc.iv[current_run].length
701+
i-- // retry with the same i
702+
} else {
703+
// We have exhausted the number of runs. We can keep the rest of the values
704+
// from i to len(ac.content) - 1 inclusively.
705+
break // We are done, the rest of the array will be kept
706+
}
681707
}
682-
683-
out := ac.iremoveRange(int(run.start), int(run.start)+int(run.length)+1).(*arrayContainer)
684-
*ac = *out
685708
}
709+
for ; i < len(ac.content); i++ {
710+
ac.content[pos] = ac.content[i]
711+
pos++
712+
}
713+
// We 'shink' the slice.
714+
ac.content = ac.content[:pos]
686715
return ac
687716
}
688717

0 commit comments

Comments
 (0)