From e8ca41e5227e90027e8c83f3460943465f34db85 Mon Sep 17 00:00:00 2001 From: Pierre Fersing Date: Fri, 13 Mar 2020 10:35:35 +0100 Subject: [PATCH] Fix runCountRange when range start == interval start When the interval is a proper superset of the range with start equal to interval start, the range must be considered a superset or it will be completly ignored (since it neither a subset nor it overlaps) --- roaring/roaring.go | 8 ++++---- roaring/roaring_internal_test.go | 35 ++++++++++++++++++++++++++++++++ roaring/roaring_test.go | 6 ++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/roaring/roaring.go b/roaring/roaring.go index 86ee64fc5..ac49ee2f3 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -2033,18 +2033,18 @@ func (c *Container) runCountRange(start, end int32) (n int32) { break } // iv is superset of range - if int32(iv.start) < start && int32(iv.last) > end { + if int32(iv.start) <= start && int32(iv.last) >= end { return end - start } // iv is subset of range - if int32(iv.start) >= start && int32(iv.last) < end { + if int32(iv.start) >= start && int32(iv.last) <= end { n += iv.runlen() } - // iv overlaps beginning of range + // iv overlaps beginning of range without being a subset if int32(iv.start) < start && int32(iv.last) < end { n += int32(iv.last) - start + 1 } - // iv overlaps end of range + // iv overlaps end of range without being a subset if int32(iv.start) > start && int32(iv.last) >= end { n += end - int32(iv.start) } diff --git a/roaring/roaring_internal_test.go b/roaring/roaring_internal_test.go index 0ecd73021..27fbe8f29 100644 --- a/roaring/roaring_internal_test.go +++ b/roaring/roaring_internal_test.go @@ -147,6 +147,16 @@ func TestRunCountRange(t *testing.T) { c.add(10) c.add(11) + cnt = c.runCountRange(4, 8) + if cnt != 3 { + t.Fatalf("should get 3 from range overlaps front of interval, but got: %v", cnt) + } + + cnt = c.runCountRange(5, 8) + if cnt != 3 { + t.Fatalf("should get 3 from range within interval, but got: %v", cnt) + } + cnt = c.runCountRange(6, 8) if cnt != 2 { t.Fatalf("should get 2 from range within interval, but got: %v", cnt) @@ -162,6 +172,31 @@ func TestRunCountRange(t *testing.T) { t.Fatalf("should get 3 from range overlaps back of interval, but got: %v", cnt) } + cnt = c.runCountRange(8, 10) + if cnt != 2 { + t.Fatalf("should get 2 from range within interval, but got: %v", cnt) + } + + cnt = c.runCountRange(8, 11) + if cnt != 3 { + t.Fatalf("should get 3 from range within interval, but got: %v", cnt) + } + + cnt = c.runCountRange(8, 12) + if cnt != 4 { + t.Fatalf("should get 4 from range overlaps back of interval, but got: %v", cnt) + } + + cnt = c.runCountRange(5, 12) + if cnt != 7 { + t.Fatalf("should get 7 from interval within range, but got: %v", cnt) + } + + cnt = c.runCountRange(5, 11) + if cnt != 6 { + t.Fatalf("should get 6 from interval equal to range, but got: %v", cnt) + } + c.add(17) c.add(19) c.add(18) diff --git a/roaring/roaring_test.go b/roaring/roaring_test.go index 836fd8de3..fbe952737 100644 --- a/roaring/roaring_test.go +++ b/roaring/roaring_test.go @@ -457,6 +457,12 @@ func TestBitmap_RunCountRange(t *testing.T) { if n := bm2.CountRange(3, 2); n != 0 { t.Fatalf("unexpected n: %d", n) } + + bm3 := roaring.NewFileBitmap(1, 2, 3, 4) + bm3.Optimize() // convert to runs + if n := bm3.CountRange(1, 3); n != 2 { + t.Fatalf("unexpected n: %d", n) + } } func TestBitmap_Intersection(t *testing.T) {