The Wayback Machine - https://web.archive.org/web/20231226212304/https://github.com/RoaringBitmap/roaring/commit/ae4421a9c13668e1bd80f113314637d733ef7408
Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Optimized runIterator16.advanceIfNeeded by using binary search
* Added `hasNext` in condition `shortIterator.advanceIfNeeded`
* Fixed potential bug with moving `shortIterator`. Should be used
`shortIterator.hasNext` instead of `IntIterator.HasNext`
* Added tests to check `advanceIfNeeded` method with a value that is less
than the minimum element of a set
  • Loading branch information
alldroll committed Aug 3, 2019
1 parent 973271a commit ae4421a
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 6 deletions.
8 changes: 6 additions & 2 deletions container_test.go
Expand Up @@ -71,7 +71,7 @@ func testContainerIteratorPeekNext(t *testing.T, c container) {
}

func testContainerIteratorAdvance(t *testing.T, con container) {
values := []uint16{0, 2, 15, 16, 31, 32, 33, 9999}
values := []uint16{2, 15, 16, 31, 32, 33, 9999}
for _, v := range values {
con.iadd(v)
}
Expand All @@ -80,7 +80,7 @@ func testContainerIteratorAdvance(t *testing.T, con container) {
minval uint16
expected uint16
}{
{0, 0},
{0, 2},
{1, 2},
{2, 2},
{3, 15},
Expand Down Expand Up @@ -112,6 +112,10 @@ func testContainerIteratorAdvance(t *testing.T, con container) {

Convey("advance out of a container value", t, func() {
i := con.getShortIterator()

i.advanceIfNeeded(MaxUint16)
So(i.hasNext(), ShouldBeFalse)

i.advanceIfNeeded(MaxUint16)
So(i.hasNext(), ShouldBeFalse)
})
Expand Down
2 changes: 1 addition & 1 deletion roaring.go
Expand Up @@ -262,7 +262,7 @@ func (ii *intIterator) AdvanceIfNeeded(minval uint32) {
if ii.HasNext() && (ii.hs>>16) == to {
ii.iter.advanceIfNeeded(lowbits(minval))

if !ii.HasNext() {
if !ii.iter.hasNext() {
ii.pos++
ii.init()
}
Expand Down
8 changes: 6 additions & 2 deletions roaring_test.go
Expand Up @@ -2197,7 +2197,7 @@ func TestIteratorPeekNext(t *testing.T) {
}

func TestIteratorAdvance(t *testing.T) {
values := []uint32{0, 2, 15, 16, 31, 32, 33, 9999, MaxUint16}
values := []uint32{2, 15, 16, 31, 32, 33, 9999, MaxUint16}
bm := New()
for n := 0; n < len(values); n++ {
bm.Add(values[n])
Expand All @@ -2207,7 +2207,7 @@ func TestIteratorAdvance(t *testing.T) {
minval uint32
expected uint32
}{
{0, 0},
{0, 2},
{1, 2},
{2, 2},
{3, 15},
Expand Down Expand Up @@ -2240,6 +2240,10 @@ func TestIteratorAdvance(t *testing.T) {

Convey("advance out of a container value", t, func() {
i := bm.Iterator()

i.AdvanceIfNeeded(MaxUint32)
So(i.HasNext(), ShouldBeFalse)

i.AdvanceIfNeeded(MaxUint32)
So(i.HasNext(), ShouldBeFalse)
})
Expand Down
40 changes: 40 additions & 0 deletions runcontainer.go
Expand Up @@ -1213,6 +1213,46 @@ func (ri *runIterator16) peekNext() uint16 {
}

func (ri *runIterator16) advanceIfNeeded(minval uint16) {
if ri.hasNext() && ri.peekNext() < minval {
key := int64(minval)

opt := &searchOptions{
startIndex: ri.curIndex,
endxIndex: int64(len(ri.rc.iv)),
}

// first time is special
if opt.startIndex == -1 {
opt.startIndex = 0
}

interval, isPresent, _ := ri.rc.search(key, opt)

// interval == -1 means, that the key is before the pointed interval
if interval == -1 && !isPresent {
return
}

// actualize curSeq with the number of skipped elements
if ri.curIndex >= 0 && ri.rc.iv[ri.curIndex].length <= ri.curPosInIndex {
ri.curSeq += int64(ri.rc.iv[ri.curIndex].length - ri.curPosInIndex + 1)
}

for j := ri.curIndex + 1; j < interval; j++ {
ri.curSeq += int64(ri.rc.iv[j].length + 1)
}

// if isPresent, than we should use the previous interval
if isPresent {
ri.curIndex = interval - 1
} else {
// otherwise we have interval where the last value is less than minval
ri.curIndex = interval
}

ri.curPosInIndex = ri.rc.iv[ri.curIndex].length
}

for ri.hasNext() && ri.peekNext() < minval {
ri.next()
}
Expand Down
2 changes: 1 addition & 1 deletion shortiterator.go
Expand Up @@ -31,7 +31,7 @@ func (si *shortIterator) peekNext() uint16 {
}

func (si *shortIterator) advanceIfNeeded(minval uint16) {
if si.peekNext() < minval {
if si.hasNext() && si.peekNext() < minval {
si.loc = advanceUntil(si.slice, si.loc, len(si.slice), minval)
}
}
Expand Down

0 comments on commit ae4421a

Please sign in to comment.