mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-10-07 03:17:50 +00:00
There was a case where the Bitmap iterator logic could skip over a bit in a run container if 1. the run container was not the first container in the bitmap, and 2. The first run in the run container had only one bit. The bug was due to how the iterator was initialized with iterator.Seek(0) which sets up the initial values of itr.i,j,k based on the type of the first container. It was failing to set itr.k to -1 unless the first container was an RLE container. itr.k is only used by RLE containers in the iterator, and must be set to -1 when an RLE container is encountered. When Iterator.Next() encountered the run container and itr.k was set to 0, it checked to see if itr.k <= run.last - run.first, and if so it assumes that it was finished with the run and moved to the next one. run.last - run.first is 0 in the case of a single bit run, so that bit was skipped. After this, itr.k is set to -1 and all further iteration proceeds as expected.
2671 lines
71 KiB
Go
2671 lines
71 KiB
Go
// Copyright 2017 Pilosa Corp.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package roaring
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
// String produces a human viewable string of the contents.
|
|
func (iv interval16) String() string {
|
|
return fmt.Sprintf("[%d, %d]", iv.start, iv.last)
|
|
}
|
|
|
|
func (c *container) String() string {
|
|
return fmt.Sprintf("<%s container n=%d, array[%d], runs[%d], bitmap[%d]> type:%d", c.info().Type, c.n, len(c.array), len(c.runs), len(c.bitmap), c.containerType)
|
|
}
|
|
|
|
func TestRunAppendInterval(t *testing.T) {
|
|
a := container{containerType: ContainerRun}
|
|
tests := []struct {
|
|
base []interval16
|
|
app interval16
|
|
exp int
|
|
}{
|
|
{
|
|
base: []interval16{},
|
|
app: interval16{start: 22, last: 25},
|
|
exp: 4,
|
|
},
|
|
{
|
|
base: []interval16{{start: 20, last: 23}},
|
|
app: interval16{start: 22, last: 25},
|
|
exp: 2,
|
|
},
|
|
{
|
|
base: []interval16{{start: 20, last: 23}},
|
|
app: interval16{start: 21, last: 22},
|
|
exp: 0,
|
|
},
|
|
{
|
|
base: []interval16{{start: 20, last: 23}},
|
|
app: interval16{start: 19, last: 25},
|
|
exp: 2, // runAppendInterval explicitly does not support intervals whose start is < c.runs[-1].start
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
a.runs = test.base
|
|
if n := a.runAppendInterval(test.app); n != test.exp {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, n)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func TestInterval16RunLen(t *testing.T) {
|
|
iv := interval16{start: 7, last: 9}
|
|
if iv.runlen() != 3 {
|
|
t.Fatalf("should be 3")
|
|
}
|
|
iv = interval16{start: 7, last: 7}
|
|
if iv.runlen() != 1 {
|
|
t.Fatalf("should be 1")
|
|
}
|
|
}
|
|
|
|
func TestContainerRunAdd(t *testing.T) {
|
|
c := container{runs: make([]interval16, 0), containerType: ContainerRun}
|
|
tests := []struct {
|
|
op uint16
|
|
exp []interval16
|
|
}{
|
|
{1, []interval16{{start: 1, last: 1}}},
|
|
{2, []interval16{{start: 1, last: 2}}},
|
|
{4, []interval16{{start: 1, last: 2}, {start: 4, last: 4}}},
|
|
{3, []interval16{{start: 1, last: 4}}},
|
|
{10, []interval16{{start: 1, last: 4}, {start: 10, last: 10}}},
|
|
{7, []interval16{{start: 1, last: 4}, {start: 7, last: 7}, {start: 10, last: 10}}},
|
|
{6, []interval16{{start: 1, last: 4}, {start: 6, last: 7}, {start: 10, last: 10}}},
|
|
{0, []interval16{{start: 0, last: 4}, {start: 6, last: 7}, {start: 10, last: 10}}},
|
|
{8, []interval16{{start: 0, last: 4}, {start: 6, last: 8}, {start: 10, last: 10}}},
|
|
}
|
|
for _, test := range tests {
|
|
c.mapped = true
|
|
ret := c.add(test.op)
|
|
if !ret {
|
|
t.Fatalf("result of adding new bit should be true: %v", c.runs)
|
|
}
|
|
if !reflect.DeepEqual(c.runs, test.exp) {
|
|
t.Fatalf("Should have %v, but got %v after adding %v", test.exp, c.runs, test.op)
|
|
}
|
|
if c.mapped {
|
|
t.Fatalf("container should not be mapped after adding bit %v", test.op)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestContainerRunAdd2(t *testing.T) {
|
|
c := container{runs: make([]interval16, 0), containerType: ContainerRun}
|
|
ret := c.add(0)
|
|
if !ret {
|
|
t.Fatalf("result of adding new bit should be true: %v", c.runs)
|
|
}
|
|
if !reflect.DeepEqual(c.runs, []interval16{{start: 0, last: 0}}) {
|
|
t.Fatalf("should have 1 run of length 1, but have %v", c.runs)
|
|
}
|
|
ret = c.add(0)
|
|
if ret {
|
|
t.Fatalf("result of adding existing bit should be false: %v", c.runs)
|
|
}
|
|
}
|
|
|
|
func TestRunCountRange(t *testing.T) {
|
|
c := container{runs: make([]interval16, 0), containerType: ContainerRun}
|
|
cnt := c.runCountRange(2, 9)
|
|
if cnt != 0 {
|
|
t.Fatalf("should get 0 from empty container, but got: %v", cnt)
|
|
}
|
|
c.add(5)
|
|
c.add(6)
|
|
c.add(7)
|
|
|
|
cnt = c.runCountRange(2, 9)
|
|
if cnt != 3 {
|
|
t.Fatalf("should get 3 from interval within range, but got: %v", cnt)
|
|
}
|
|
|
|
c.add(8)
|
|
c.add(9)
|
|
c.add(10)
|
|
c.add(11)
|
|
|
|
cnt = c.runCountRange(6, 8)
|
|
if cnt != 2 {
|
|
t.Fatalf("should get 2 from range within interval, but got: %v", cnt)
|
|
}
|
|
|
|
cnt = c.runCountRange(3, 9)
|
|
if cnt != 4 {
|
|
t.Fatalf("should get 4 from range overlaps front of interval, but got: %v", cnt)
|
|
}
|
|
|
|
cnt = c.runCountRange(9, 14)
|
|
if cnt != 3 {
|
|
t.Fatalf("should get 3 from range overlaps back of interval, but got: %v", cnt)
|
|
}
|
|
|
|
c.add(17)
|
|
c.add(18)
|
|
c.add(19)
|
|
|
|
cnt = c.runCountRange(1, 22)
|
|
if cnt != 10 {
|
|
t.Fatalf("should get 10 from multiple ranges in interval, but got: %v", cnt)
|
|
}
|
|
|
|
c.add(13)
|
|
c.add(14)
|
|
|
|
cnt = c.runCountRange(6, 18)
|
|
if cnt != 9 {
|
|
t.Fatalf("should get 9 from multiple ranges overlapping both sides, but got: %v", cnt)
|
|
}
|
|
}
|
|
|
|
func TestRunContains(t *testing.T) {
|
|
c := container{runs: make([]interval16, 0), containerType: ContainerRun}
|
|
if c.runContains(5) {
|
|
t.Fatalf("empty run container should not contain 5")
|
|
}
|
|
c.add(5)
|
|
if !c.runContains(5) {
|
|
t.Fatalf("run container with 5 should contain 5")
|
|
}
|
|
|
|
c.add(6)
|
|
c.add(7)
|
|
|
|
c.add(9)
|
|
c.add(10)
|
|
c.add(11)
|
|
|
|
if !c.runContains(10) {
|
|
t.Fatalf("run container with 10 in second run should contain 10")
|
|
}
|
|
}
|
|
|
|
func TestBitmapCountRange(t *testing.T) {
|
|
c := container{containerType: ContainerBitmap}
|
|
tests := []struct {
|
|
start int
|
|
end int
|
|
bitmap []uint64
|
|
exp int
|
|
}{
|
|
{start: 0, end: 1, bitmap: []uint64{1}, exp: 1},
|
|
{start: 2, end: 7, bitmap: []uint64{0xFFFFFFFFFFFFFF18}, exp: 2},
|
|
{start: 67, end: 68, bitmap: []uint64{0, 0x8}, exp: 1},
|
|
{start: 1, end: 68, bitmap: []uint64{0x3, 0x8, 0xF}, exp: 2},
|
|
{start: 1, end: 258, bitmap: []uint64{0xF, 0x8, 0xA, 0x4, 0xFFFFFFFFFFFFFFFF}, exp: 9},
|
|
{start: 66, end: 71, bitmap: []uint64{0xF, 0xFFFFFFFFFFFFFF18}, exp: 2},
|
|
{start: 63, end: 64, bitmap: []uint64{0x8000000000000000}, exp: 1},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
c.bitmap = test.bitmap
|
|
if ret := c.bitmapCountRange(test.start, test.end); ret != test.exp {
|
|
t.Fatalf("test #%v count of %v from %v to %v should be %v but got %v", i, test.bitmap, test.start, test.end, test.exp, ret)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIntersectionCountArrayBitmap3(t *testing.T) {
|
|
a, b := &container{}, &container{}
|
|
a.containerType = ContainerBitmap
|
|
a.bitmap = getFullBitmap()
|
|
a.n = maxContainerVal + 1
|
|
|
|
b.containerType = ContainerBitmap
|
|
b.bitmap = getFullBitmap()
|
|
b.n = maxContainerVal + 1
|
|
res := intersectBitmapBitmap(a, b)
|
|
if res.n != res.count() || res.n != maxContainerVal+1 {
|
|
t.Fatalf("test #1 intersectCountBitmapBitmap fail orig: %v new: %v exp: %v", res.n, res.count(), maxContainerVal+1)
|
|
}
|
|
|
|
a.bitmapToRun()
|
|
res = intersectBitmapRun(b, a)
|
|
if res.n != res.count() || res.n != maxContainerVal+1 {
|
|
t.Fatalf("test #2 intersectCountBitmapRun fail orig: %v new: %v exp: %v", res.n, res.count(), maxContainerVal+1)
|
|
}
|
|
b.bitmapToRun()
|
|
res = intersectRunRun(a, b)
|
|
n := intersectionCountRunRun(a, b)
|
|
if res.n != res.count() || res.n != maxContainerVal+1 || res.n != int(n) {
|
|
t.Fatalf("test #3 intersectCountRunRun fail orig: %v new: %v exp: %v", res.n, res.count(), maxContainerVal+1)
|
|
}
|
|
}
|
|
|
|
func TestIntersectionCountArrayBitmap2(t *testing.T) {
|
|
a, b := &container{}, &container{}
|
|
tests := []struct {
|
|
array []uint16
|
|
bitmap []uint64
|
|
exp int
|
|
}{
|
|
{
|
|
array: []uint16{0},
|
|
bitmap: []uint64{1},
|
|
exp: 1,
|
|
},
|
|
{
|
|
array: []uint16{0, 1},
|
|
bitmap: []uint64{3},
|
|
exp: 2,
|
|
},
|
|
{
|
|
array: []uint16{64, 128, 129, 2000},
|
|
bitmap: []uint64{932421, 2},
|
|
exp: 0,
|
|
},
|
|
{
|
|
array: []uint16{0, 65, 130, 195},
|
|
bitmap: []uint64{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
|
exp: 4,
|
|
},
|
|
{
|
|
array: []uint16{63, 120, 543, 639, 12000},
|
|
bitmap: []uint64{0x8000000000000000, 0, 0, 0, 0, 0, 0, 0, 0, 0x8000000000000000},
|
|
exp: 2,
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
a.array = test.array
|
|
a.containerType = ContainerArray
|
|
b.bitmap = test.bitmap
|
|
b.containerType = ContainerBitmap
|
|
ret := intersectionCountArrayBitmap(a, b)
|
|
if ret != test.exp {
|
|
t.Fatalf("test #%v intersectCountArrayBitmap fail received: %v exp: %v", i, ret, test.exp)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRunRemove(t *testing.T) {
|
|
c := container{runs: []interval16{{start: 2, last: 10}, {start: 12, last: 13}, {start: 15, last: 16}}, containerType: ContainerRun}
|
|
tests := []struct {
|
|
op uint16
|
|
exp []interval16
|
|
expRet bool
|
|
}{
|
|
{2, []interval16{{start: 3, last: 10}, {start: 12, last: 13}, {start: 15, last: 16}}, true},
|
|
{10, []interval16{{start: 3, last: 9}, {start: 12, last: 13}, {start: 15, last: 16}}, true},
|
|
{12, []interval16{{start: 3, last: 9}, {start: 13, last: 13}, {start: 15, last: 16}}, true},
|
|
{13, []interval16{{start: 3, last: 9}, {start: 15, last: 16}}, true},
|
|
{16, []interval16{{start: 3, last: 9}, {start: 15, last: 15}}, true},
|
|
{6, []interval16{{start: 3, last: 5}, {start: 7, last: 9}, {start: 15, last: 15}}, true},
|
|
{8, []interval16{{start: 3, last: 5}, {start: 7, last: 7}, {start: 9, last: 9}, {start: 15, last: 15}}, true},
|
|
{8, []interval16{{start: 3, last: 5}, {start: 7, last: 7}, {start: 9, last: 9}, {start: 15, last: 15}}, false},
|
|
{1, []interval16{{start: 3, last: 5}, {start: 7, last: 7}, {start: 9, last: 9}, {start: 15, last: 15}}, false},
|
|
{44, []interval16{{start: 3, last: 5}, {start: 7, last: 7}, {start: 9, last: 9}, {start: 15, last: 15}}, false},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
c.mapped = true
|
|
ret := c.remove(test.op)
|
|
if ret != test.expRet || !reflect.DeepEqual(c.runs, test.exp) {
|
|
t.Fatalf("test #%v Unexpected result removing %v from runs. Expected %v, got %v. Expected %v, got %v", i, test.op, test.expRet, ret, test.exp, c.runs)
|
|
}
|
|
if ret && c.mapped {
|
|
t.Fatalf("test #%v container was not unmapped although bit %v was removed", i, test.op)
|
|
}
|
|
if !ret && !c.mapped {
|
|
t.Fatalf("test #%v container was unmapped although bit %v was not removed", i, test.op)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRunMax(t *testing.T) {
|
|
c := container{runs: []interval16{{start: 2, last: 10}, {start: 12, last: 13}, {start: 15, last: 16}}, containerType: ContainerRun}
|
|
max := c.max()
|
|
if max != 16 {
|
|
t.Fatalf("max for %v should be 16", c.runs)
|
|
}
|
|
|
|
c = container{runs: []interval16{}}
|
|
max = c.max()
|
|
if max != 0 {
|
|
t.Fatalf("max for %v should be 0", c.runs)
|
|
}
|
|
}
|
|
|
|
func TestIntersectionCountArrayRun(t *testing.T) {
|
|
a := &container{containerType: ContainerArray, array: []uint16{1, 5, 10, 11, 12}}
|
|
b := &container{containerType: ContainerRun, runs: []interval16{{start: 2, last: 10}, {start: 12, last: 13}, {start: 15, last: 16}}}
|
|
|
|
ret := intersectionCountArrayRun(a, b)
|
|
if ret != 3 {
|
|
t.Fatalf("count of %v with %v should be 3, but got %v", a.array, b.runs, ret)
|
|
}
|
|
}
|
|
|
|
func TestIntersectionCountBitmapRun(t *testing.T) {
|
|
a := &container{containerType: ContainerBitmap, bitmap: []uint64{0x8000000000000000}}
|
|
b := &container{containerType: ContainerRun, runs: []interval16{{start: 63, last: 64}}}
|
|
|
|
ret := intersectionCountBitmapRun(a, b)
|
|
if ret != 1 {
|
|
t.Fatalf("count of %v with %v should be 1, but got %v", a.bitmap, b.runs, ret)
|
|
}
|
|
|
|
a = &container{containerType: ContainerBitmap, bitmap: []uint64{0xF0000001, 0xFF00000000000000, 0xFF000000000000F0, 0x0F0000}}
|
|
b = &container{containerType: ContainerRun, runs: []interval16{{start: 29, last: 31}, {start: 125, last: 134}, {start: 191, last: 197}, {start: 200, last: 300}}}
|
|
|
|
ret = intersectionCountBitmapRun(a, b)
|
|
if ret != 14 {
|
|
t.Fatalf("count of %v with %v should be 14, but got %v", a.bitmap, b.runs, ret)
|
|
}
|
|
}
|
|
|
|
func TestIntersectionCountRunRun(t *testing.T) {
|
|
a := &container{}
|
|
b := &container{}
|
|
tests := []struct {
|
|
aruns []interval16
|
|
bruns []interval16
|
|
exp int
|
|
}{
|
|
{
|
|
aruns: []interval16{},
|
|
bruns: []interval16{{start: 3, last: 8}}, exp: 0},
|
|
{
|
|
aruns: []interval16{{start: 2, last: 10}},
|
|
bruns: []interval16{{start: 3, last: 8}}, exp: 6},
|
|
{
|
|
aruns: []interval16{{start: 2, last: 10}},
|
|
bruns: []interval16{{start: 1, last: 11}}, exp: 9},
|
|
{
|
|
aruns: []interval16{{start: 2, last: 10}},
|
|
bruns: []interval16{{start: 0, last: 2}}, exp: 1},
|
|
{
|
|
aruns: []interval16{{start: 2, last: 10}},
|
|
bruns: []interval16{{start: 1, last: 10}}, exp: 9},
|
|
{
|
|
aruns: []interval16{{start: 2, last: 10}},
|
|
bruns: []interval16{{start: 5, last: 12}}, exp: 6},
|
|
{
|
|
aruns: []interval16{{start: 2, last: 10}},
|
|
bruns: []interval16{{start: 10, last: 99}}, exp: 1},
|
|
{
|
|
aruns: []interval16{{start: 2, last: 10}, {start: 44, last: 99}},
|
|
bruns: []interval16{{start: 12, last: 14}}, exp: 0},
|
|
{
|
|
aruns: []interval16{{start: 2, last: 10}, {start: 12, last: 13}},
|
|
bruns: []interval16{{start: 2, last: 10}, {start: 12, last: 13}}, exp: 11},
|
|
{
|
|
aruns: []interval16{{start: 8, last: 12}, {start: 15, last: 19}},
|
|
bruns: []interval16{{start: 9, last: 9}, {start: 11, last: 17}}, exp: 6},
|
|
}
|
|
for i, test := range tests {
|
|
a.containerType = ContainerRun
|
|
b.containerType = ContainerRun
|
|
a.runs = test.aruns
|
|
b.runs = test.bruns
|
|
ret := intersectionCountRunRun(a, b)
|
|
if ret != test.exp {
|
|
t.Fatalf("test #%v failed intersecting %v with %v should be %v, but got %v", i, test.aruns, test.bruns, test.exp, ret)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIntersectArrayRun(t *testing.T) {
|
|
a := &container{}
|
|
b := &container{}
|
|
tests := []struct {
|
|
array []uint16
|
|
runs []interval16
|
|
exp []uint16
|
|
}{
|
|
{
|
|
array: []uint16{1, 4, 5, 7, 10, 11, 12},
|
|
runs: []interval16{{start: 5, last: 10}},
|
|
exp: []uint16{5, 7, 10},
|
|
},
|
|
{
|
|
array: []uint16{},
|
|
runs: []interval16{{start: 5, last: 10}},
|
|
exp: []uint16(nil),
|
|
},
|
|
{
|
|
array: []uint16{1, 4, 5, 7, 10, 11, 12},
|
|
runs: []interval16{},
|
|
exp: []uint16(nil),
|
|
},
|
|
{
|
|
array: []uint16{0, 1, 4, 5, 7, 10, 11, 12},
|
|
runs: []interval16{{start: 0, last: 5}, {start: 7, last: 7}},
|
|
exp: []uint16{0, 1, 4, 5, 7},
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
a.containerType = ContainerArray
|
|
b.containerType = ContainerRun
|
|
a.array = test.array
|
|
b.runs = test.runs
|
|
ret := intersectArrayRun(a, b)
|
|
if !reflect.DeepEqual(ret.array, test.exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.array)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIntersectRunRun(t *testing.T) {
|
|
a := &container{}
|
|
b := &container{}
|
|
tests := []struct {
|
|
aruns []interval16
|
|
bruns []interval16
|
|
exp []interval16
|
|
expN int
|
|
}{
|
|
{
|
|
aruns: []interval16{},
|
|
bruns: []interval16{{start: 5, last: 10}},
|
|
exp: []interval16(nil),
|
|
expN: 0,
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 5, last: 12}},
|
|
bruns: []interval16{{start: 5, last: 10}},
|
|
exp: []interval16{{start: 5, last: 10}},
|
|
expN: 6,
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 1, last: 3}, {start: 5, last: 5}, {start: 7, last: 8}, {start: 9, last: 12}},
|
|
bruns: []interval16{{start: 5, last: 10}},
|
|
exp: []interval16{{start: 5, last: 5}, {start: 7, last: 10}},
|
|
expN: 5,
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 20, last: 30}},
|
|
bruns: []interval16{{start: 5, last: 10}, {start: 19, last: 21}},
|
|
exp: []interval16{{start: 20, last: 21}},
|
|
expN: 2,
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 5, last: 10}},
|
|
bruns: []interval16{{start: 7, last: 12}},
|
|
exp: []interval16{{start: 7, last: 10}},
|
|
expN: 4,
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 5, last: 12}},
|
|
bruns: []interval16{{start: 7, last: 10}},
|
|
exp: []interval16{{start: 7, last: 10}},
|
|
expN: 4,
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
a.containerType = ContainerRun
|
|
b.containerType = ContainerRun
|
|
a.runs = test.aruns
|
|
b.runs = test.bruns
|
|
ret := intersectRunRun(a, b)
|
|
if ret.n != test.expN {
|
|
t.Fatalf("test #%v expected n to be %v, but got %v", i, test.expN, ret.n)
|
|
}
|
|
if !reflect.DeepEqual(ret.runs, test.exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.runs)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func TestIntersectBitmapRunBitmap(t *testing.T) {
|
|
a := &container{bitmap: make([]uint64, bitmapN)}
|
|
b := &container{}
|
|
tests := []struct {
|
|
bitmap []uint64
|
|
runs []interval16
|
|
exp []uint64
|
|
expN int
|
|
}{
|
|
{
|
|
bitmap: []uint64{1},
|
|
runs: []interval16{{start: 0, last: 0}, {start: 2, last: 5}, {start: 62, last: 71}, {start: 77, last: 4096}},
|
|
exp: []uint64{1},
|
|
expN: 1,
|
|
},
|
|
{
|
|
bitmap: []uint64{0xFFFFFFFFFFFFFFFF},
|
|
runs: []interval16{{start: 1, last: 1}},
|
|
exp: []uint64{2},
|
|
expN: 1,
|
|
},
|
|
{
|
|
bitmap: []uint64{0xFFFFFFFFFFFFFFFF},
|
|
runs: []interval16{{start: 1, last: 1}, {start: 10, last: 12}, {start: 61, last: 77}},
|
|
exp: []uint64{0xe000000000001C02},
|
|
expN: 7,
|
|
},
|
|
{
|
|
bitmap: []uint64{0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF},
|
|
runs: []interval16{{start: 1, last: 1}, {start: 61, last: 77}},
|
|
exp: []uint64{0xE000000000000002, 0x00000000000003FFF},
|
|
expN: 18,
|
|
},
|
|
{
|
|
bitmap: []uint64{0xFFFFFFFFFFFFFFFF, 1, 1, 1, 0xA, 1, 1, 0, 1},
|
|
runs: []interval16{{start: 63, last: 10000}},
|
|
exp: []uint64{0x8000000000000000, 1, 1, 1, 0xA, 1, 1, 0, 1},
|
|
expN: 9,
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
for i, v := range test.bitmap {
|
|
a.bitmap[i] = v
|
|
}
|
|
b.runs = test.runs
|
|
b.n = 4097 // ;)
|
|
exp := make([]uint64, bitmapN)
|
|
for i, v := range test.exp {
|
|
exp[i] = v
|
|
}
|
|
a.containerType = ContainerBitmap
|
|
b.containerType = ContainerRun
|
|
ret := intersectBitmapRun(a, b)
|
|
if ret.isArray() {
|
|
ret.arrayToBitmap()
|
|
}
|
|
if !reflect.DeepEqual(ret.bitmap, exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, exp, ret.bitmap)
|
|
}
|
|
if ret.n != test.expN {
|
|
t.Fatalf("test #%v expected n to be %v, but got %v", i, test.expN, ret.n)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func TestIntersectBitmapRunArray(t *testing.T) {
|
|
a := &container{bitmap: make([]uint64, bitmapN)}
|
|
b := &container{}
|
|
tests := []struct {
|
|
bitmap []uint64
|
|
runs []interval16
|
|
exp []uint16
|
|
expN int
|
|
}{
|
|
{
|
|
bitmap: []uint64{1},
|
|
runs: []interval16{{start: 0, last: 0}, {start: 2, last: 5}, {start: 62, last: 71}, {start: 77, last: 4096}},
|
|
exp: []uint16{0},
|
|
expN: 1,
|
|
},
|
|
{
|
|
bitmap: []uint64{0xFFFFFFFFFFFFFFFF},
|
|
runs: []interval16{{start: 1, last: 1}},
|
|
exp: []uint16{1},
|
|
expN: 1,
|
|
},
|
|
{
|
|
bitmap: []uint64{0xFFFFFFFFFFFFFFFF},
|
|
runs: []interval16{{start: 1, last: 1}, {start: 10, last: 12}, {start: 61, last: 77}},
|
|
exp: []uint16{1, 10, 11, 12, 61, 62, 63},
|
|
expN: 7,
|
|
},
|
|
{
|
|
bitmap: []uint64{0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF},
|
|
runs: []interval16{{start: 1, last: 1}, {start: 61, last: 68}},
|
|
exp: []uint16{1, 61, 62, 63, 64, 65, 66, 67, 68},
|
|
expN: 9,
|
|
},
|
|
{
|
|
bitmap: []uint64{0xFFFFFFFFFFFFFFFF, 1, 1, 1, 0xA, 1, 1, 0, 1},
|
|
runs: []interval16{{start: 63, last: 10000}, {start: 65000, last: 65535}},
|
|
exp: []uint16{63, 64, 128, 192, 257, 259, 320, 384, 512},
|
|
expN: 9,
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
for i, v := range test.bitmap {
|
|
a.bitmap[i] = v
|
|
}
|
|
b.runs = test.runs
|
|
a.containerType = ContainerBitmap
|
|
b.containerType = ContainerRun
|
|
ret := intersectBitmapRun(a, b)
|
|
if !reflect.DeepEqual(ret.array, test.exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.array)
|
|
}
|
|
if ret.n != test.expN {
|
|
t.Fatalf("test #%v expected n to be %v, but got %v", i, test.expN, ret.n)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func TestUnionMixed(t *testing.T) {
|
|
|
|
// array container
|
|
a := &container{}
|
|
a.array = []uint16{1, 4, 5, 7, 10, 11, 12}
|
|
a.containerType = ContainerArray
|
|
a.n = 7
|
|
|
|
// bitmap container
|
|
b := &container{bitmap: make([]uint64, bitmapN)}
|
|
b.bitmap[0] = uint64(0x3)
|
|
b.n = 2
|
|
b.containerType = ContainerBitmap
|
|
|
|
// run container
|
|
r := &container{}
|
|
r.runs = []interval16{{start: 5, last: 10}}
|
|
r.containerType = ContainerRun
|
|
r.n = 6
|
|
|
|
t.Run("various container Unions", func(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
c1 *container
|
|
c2 *container
|
|
exp []uint16
|
|
}{
|
|
{name: "run-array", c1: r, c2: a, exp: []uint16{1, 4, 5, 6, 7, 8, 9, 10, 11, 12}},
|
|
{name: "array-run", c1: a, c2: r, exp: []uint16{1, 4, 5, 6, 7, 8, 9, 10, 11, 12}},
|
|
{name: "run-run", c1: r, c2: r, exp: []uint16{5, 6, 7, 8, 9, 10}},
|
|
|
|
{name: "bitmap-run", c1: b, c2: r, exp: []uint16{0, 1, 5, 6, 7, 8, 9, 10}},
|
|
{name: "run-bitmap", c1: r, c2: b, exp: []uint16{0, 1, 5, 6, 7, 8, 9, 10}},
|
|
{name: "array-bitmap", c1: a, c2: b, exp: []uint16{0, 1, 4, 5, 7, 10, 11, 12}},
|
|
{name: "bitmap-array", c1: a, c2: b, exp: []uint16{0, 1, 4, 5, 7, 10, 11, 12}},
|
|
}
|
|
for _, tt := range tests {
|
|
res := union(tt.c1, tt.c2)
|
|
// convert to array for comparison
|
|
if res.isBitmap() {
|
|
res.bitmapToArray()
|
|
} else if res.isRun() {
|
|
res.runToArray()
|
|
}
|
|
if !reflect.DeepEqual(res.array, tt.exp) {
|
|
t.Fatalf("test %s expected %v, but got %v", tt.name, tt.exp, res.array)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestIntersectMixed(t *testing.T) {
|
|
a := &container{}
|
|
b := &container{}
|
|
c := &container{}
|
|
|
|
a.runs = []interval16{{start: 5, last: 10}}
|
|
a.n = 6
|
|
a.containerType = ContainerRun
|
|
b.array = []uint16{1, 4, 5, 7, 10, 11, 12}
|
|
b.n = 7
|
|
b.containerType = ContainerArray
|
|
res := intersect(a, b)
|
|
if !reflect.DeepEqual(res.array, []uint16{5, 7, 10}) {
|
|
t.Fatalf("test #1 expected %v, but got %v", []uint16{5, 7, 10}, res.array)
|
|
}
|
|
res = intersect(b, a)
|
|
if !reflect.DeepEqual(res.array, []uint16{5, 7, 10}) {
|
|
t.Fatalf("test #1 expected %v, but got %v", []uint16{5, 7, 10}, res.array)
|
|
}
|
|
|
|
res = intersect(a, a)
|
|
if !reflect.DeepEqual(res.runs, []interval16{{start: 5, last: 10}}) {
|
|
t.Fatalf("test #3 expected %v, but got %v", []interval16{{start: 5, last: 10}}, res.runs)
|
|
}
|
|
c.bitmap = []uint64{0x60}
|
|
c.n = 2
|
|
c.containerType = ContainerBitmap
|
|
|
|
res = intersect(c, a)
|
|
if !reflect.DeepEqual(res.array, []uint16{5, 6}) {
|
|
t.Fatalf("test #4 expected %v, but got %v", []uint16{6}, res.array)
|
|
}
|
|
|
|
res = intersect(a, c)
|
|
if !reflect.DeepEqual(res.array, []uint16{5, 6}) {
|
|
t.Fatalf("test #5 expected %v, but got %v", []uint16{6}, res.array)
|
|
}
|
|
|
|
res = intersect(b, c)
|
|
if !reflect.DeepEqual(res.array, []uint16{5}) {
|
|
t.Fatalf("test #6 expected %v, but got %v", []uint16{5}, res.array)
|
|
}
|
|
res = intersect(c, b)
|
|
if !reflect.DeepEqual(res.array, []uint16{5}) {
|
|
t.Fatalf("test #7 expected %v, but got %v", []uint16{5}, res.array)
|
|
}
|
|
|
|
}
|
|
func TestDifferenceMixed(t *testing.T) {
|
|
a := &container{}
|
|
b := &container{}
|
|
c := &container{}
|
|
d := &container{}
|
|
|
|
a.runs = []interval16{{start: 5, last: 10}}
|
|
a.n = a.runCountRange(0, 100)
|
|
a.containerType = ContainerRun
|
|
|
|
b.array = []uint16{0, 2, 4, 6, 8, 10, 12}
|
|
b.n = len(b.array)
|
|
b.containerType = ContainerArray
|
|
|
|
d.array = []uint16{1, 3, 5, 7, 9, 11, 12}
|
|
d.n = len(d.array)
|
|
d.containerType = ContainerArray
|
|
|
|
res := difference(a, b)
|
|
|
|
if !reflect.DeepEqual(res.array, []uint16{5, 7, 9}) {
|
|
t.Fatalf("test #1 expected %v, but got %#v", []uint16{5, 7, 9}, res)
|
|
}
|
|
|
|
res = difference(b, a)
|
|
if !reflect.DeepEqual(res.array, []uint16{0, 2, 4, 12}) {
|
|
t.Fatalf("test #2 expected %v, but got %v", []uint16{0, 2, 4, 12}, res.array)
|
|
}
|
|
|
|
res = difference(a, a)
|
|
if !reflect.DeepEqual(res.runs, []interval16{}) {
|
|
t.Fatalf("test #3 expected empty but got %v", res.runs)
|
|
}
|
|
|
|
c.bitmap = []uint64{0x64}
|
|
c.n = c.countRange(0, 100)
|
|
c.containerType = ContainerBitmap
|
|
res = difference(c, a)
|
|
if !reflect.DeepEqual(res.bitmap, []uint64{0x4}) {
|
|
t.Fatalf("test #4 expected %v, but got %v", []uint16{4}, res.bitmap)
|
|
}
|
|
|
|
res = difference(a, c)
|
|
if !reflect.DeepEqual(res.runs, []interval16{{start: 7, last: 10}}) {
|
|
t.Fatalf("test #5 expected %v, but got %v", []interval16{{start: 7, last: 10}}, res.runs)
|
|
}
|
|
|
|
res = difference(b, c)
|
|
if !reflect.DeepEqual(res.array, []uint16{0, 4, 8, 10, 12}) {
|
|
t.Fatalf("test #6 expected %v, but got %v", []uint16{0, 4, 8, 10, 12}, res.array)
|
|
}
|
|
|
|
res = difference(c, b)
|
|
if !reflect.DeepEqual(res.array, []uint16{5}) {
|
|
t.Fatalf("test #7 expected %v, but got %v", []uint16{5}, res.array)
|
|
}
|
|
|
|
res = difference(b, b)
|
|
if res.n != 0 {
|
|
t.Fatalf("test #8 expected 0, but got %d", res.n)
|
|
}
|
|
|
|
res = difference(c, c)
|
|
if res.n != 0 {
|
|
t.Fatalf("test #9 expected 0, but got %d", res.n)
|
|
}
|
|
|
|
res = difference(d, b)
|
|
if !reflect.DeepEqual(res.array, []uint16{1, 3, 5, 7, 9, 11}) {
|
|
t.Fatalf("test #10 expected %v, but got %d", []uint16{1, 3, 5, 7, 9, 11}, res.array)
|
|
}
|
|
|
|
res = difference(b, d)
|
|
if !reflect.DeepEqual(res.array, []uint16{0, 2, 4, 6, 8, 10}) {
|
|
t.Fatalf("test #11 expected %v, but got %d", []uint16{0, 2, 4, 6, 8, 10}, res.array)
|
|
}
|
|
|
|
}
|
|
|
|
func TestUnionRunRun(t *testing.T) {
|
|
a := &container{}
|
|
b := &container{}
|
|
tests := []struct {
|
|
aruns []interval16
|
|
bruns []interval16
|
|
exp []interval16
|
|
}{
|
|
{
|
|
aruns: []interval16{},
|
|
bruns: []interval16{{start: 5, last: 10}},
|
|
exp: []interval16{{start: 5, last: 10}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 5, last: 12}},
|
|
bruns: []interval16{{start: 5, last: 10}},
|
|
exp: []interval16{{start: 5, last: 12}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 1, last: 3}, {start: 5, last: 5}, {start: 7, last: 8}, {start: 9, last: 12}},
|
|
bruns: []interval16{{start: 5, last: 10}},
|
|
exp: []interval16{{start: 1, last: 3}, {start: 5, last: 12}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 1, last: 3}, {start: 5, last: 5}, {start: 7, last: 8}, {start: 9, last: 12}},
|
|
bruns: []interval16{{start: 2, last: 65535}},
|
|
exp: []interval16{{start: 1, last: 65535}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 2, last: 65535}},
|
|
bruns: []interval16{{start: 1, last: 3}, {start: 5, last: 5}, {start: 7, last: 8}, {start: 9, last: 12}},
|
|
exp: []interval16{{start: 1, last: 65535}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 1, last: 3}, {start: 5, last: 5}, {start: 7, last: 8}, {start: 9, last: 12}},
|
|
bruns: []interval16{{start: 0, last: 65535}},
|
|
exp: []interval16{{start: 0, last: 65535}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 0, last: 65535}},
|
|
bruns: []interval16{{start: 1, last: 3}, {start: 5, last: 5}, {start: 7, last: 8}, {start: 9, last: 12}},
|
|
exp: []interval16{{start: 0, last: 65535}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 1, last: 3}, {start: 5, last: 5}, {start: 7, last: 9}, {start: 12, last: 22}},
|
|
bruns: []interval16{{start: 2, last: 8}, {start: 16, last: 27}, {start: 33, last: 34}},
|
|
exp: []interval16{{start: 1, last: 9}, {start: 12, last: 27}, {start: 33, last: 34}},
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
a.runs = test.aruns
|
|
b.runs = test.bruns
|
|
a.containerType = ContainerRun
|
|
b.containerType = ContainerRun
|
|
ret := unionRunRun(a, b)
|
|
if !reflect.DeepEqual(ret.runs, test.exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.runs)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUnionArrayRun(t *testing.T) {
|
|
a := &container{}
|
|
b := &container{}
|
|
tests := []struct {
|
|
array []uint16
|
|
runs []interval16
|
|
exp []uint16
|
|
}{
|
|
{
|
|
array: []uint16{1, 4, 5, 7, 10, 11, 12},
|
|
runs: []interval16{{start: 5, last: 10}},
|
|
exp: []uint16{1, 4, 5, 6, 7, 8, 9, 10, 11, 12},
|
|
},
|
|
{
|
|
array: []uint16{},
|
|
runs: []interval16{{start: 5, last: 10}},
|
|
exp: []uint16{5, 6, 7, 8, 9, 10},
|
|
},
|
|
{
|
|
array: []uint16{1, 4, 5, 7, 10, 11, 12},
|
|
runs: []interval16{},
|
|
exp: []uint16{1, 4, 5, 7, 10, 11, 12},
|
|
},
|
|
{
|
|
array: []uint16{0, 1, 4, 5, 7, 10, 11, 12},
|
|
runs: []interval16{{start: 0, last: 5}, {start: 7, last: 7}},
|
|
exp: []uint16{0, 1, 2, 3, 4, 5, 7, 10, 11, 12},
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
a.array = test.array
|
|
b.runs = test.runs
|
|
a.containerType = ContainerArray
|
|
b.containerType = ContainerRun
|
|
ret := unionArrayRun(a, b)
|
|
if !reflect.DeepEqual(ret.array, test.exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.array)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBitmapSetRange(t *testing.T) {
|
|
c := &container{containerType: ContainerBitmap, bitmap: make([]uint64, bitmapN)}
|
|
tests := []struct {
|
|
bitmap []uint64
|
|
start uint64
|
|
last uint64
|
|
exp []uint64
|
|
expN int
|
|
}{
|
|
{
|
|
bitmap: []uint64{0x0000000000FFF900},
|
|
start: 9,
|
|
last: 10,
|
|
exp: []uint64{0x0000000000FFFF00},
|
|
expN: 16,
|
|
},
|
|
{
|
|
bitmap: []uint64{0xFF0, 0xFF, 0xFF},
|
|
start: 60,
|
|
last: 130,
|
|
exp: []uint64{0xF000000000000FF0, 0xFFFFFFFFFFFFFFFF, 0xFF},
|
|
expN: 84,
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
for i, v := range test.bitmap {
|
|
c.bitmap[i] = v
|
|
}
|
|
c.n = c.countRange(0, 65535)
|
|
c.bitmapSetRange(test.start, test.last+1)
|
|
if !reflect.DeepEqual(c.bitmap[:len(test.exp)], test.exp) {
|
|
t.Fatalf("test %#v expected %x, got %x", i, test.exp, c.bitmap[:len(test.bitmap)])
|
|
}
|
|
if test.expN != c.n {
|
|
t.Fatalf("test #%v expected n to be %v, but got %v", i, test.expN, c.n)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestArrayToBitmap(t *testing.T) {
|
|
a := &container{containerType: ContainerArray}
|
|
tests := []struct {
|
|
array []uint16
|
|
exp []uint64
|
|
}{
|
|
{
|
|
array: []uint16{},
|
|
exp: []uint64{},
|
|
},
|
|
{
|
|
array: []uint16{0, 1, 2, 3},
|
|
exp: []uint64{0xF},
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
exp := make([]uint64, bitmapN)
|
|
for i, v := range test.exp {
|
|
exp[i] = v
|
|
}
|
|
|
|
a.array = test.array
|
|
a.n = len(test.array)
|
|
a.arrayToBitmap()
|
|
if !reflect.DeepEqual(a.bitmap, exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, exp, a.bitmap)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBitmapToArray(t *testing.T) {
|
|
a := &container{containerType: ContainerBitmap}
|
|
tests := []struct {
|
|
bitmap []uint64
|
|
exp []uint16
|
|
}{
|
|
{
|
|
bitmap: []uint64{},
|
|
exp: []uint16{},
|
|
},
|
|
{
|
|
bitmap: []uint64{0xF},
|
|
exp: []uint16{0, 1, 2, 3},
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
a.bitmap = make([]uint64, bitmapN)
|
|
n := 0
|
|
for i, v := range test.bitmap {
|
|
a.bitmap[i] = v
|
|
n += int(popcount(v))
|
|
}
|
|
a.n = n
|
|
|
|
a.bitmapToArray()
|
|
if !reflect.DeepEqual(a.array, test.exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, a.array)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRunToBitmap(t *testing.T) {
|
|
a := &container{containerType: ContainerRun}
|
|
tests := []struct {
|
|
runs []interval16
|
|
exp []uint64
|
|
}{
|
|
{
|
|
runs: []interval16{},
|
|
exp: []uint64{},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 0, last: 0}},
|
|
exp: []uint64{1},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 0, last: 4}},
|
|
exp: []uint64{31},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 2, last: 2}, {start: 5, last: 7}, {start: 13, last: 14}, {start: 17, last: 17}},
|
|
exp: []uint64{155876},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 0, last: 3}, {start: 60, last: 67}},
|
|
exp: []uint64{0xF00000000000000F, 0x000000000000000F},
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
exp := make([]uint64, bitmapN)
|
|
n := 0
|
|
for i, v := range test.exp {
|
|
exp[i] = v
|
|
n += int(popcount(v))
|
|
}
|
|
|
|
a.runs = test.runs
|
|
a.n = n
|
|
a.runToBitmap()
|
|
if !reflect.DeepEqual(a.bitmap, exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, exp, a.bitmap)
|
|
}
|
|
}
|
|
}
|
|
|
|
func getFullBitmap() []uint64 {
|
|
x := make([]uint64, 1024, 1024)
|
|
for i := range x {
|
|
x[i] = uint64(0xFFFFFFFFFFFFFFFF)
|
|
}
|
|
return x
|
|
|
|
}
|
|
|
|
func TestBitmapToRun(t *testing.T) {
|
|
a := &container{containerType: ContainerBitmap}
|
|
tests := []struct {
|
|
bitmap []uint64
|
|
exp []interval16
|
|
}{
|
|
{
|
|
// empty run
|
|
bitmap: []uint64{},
|
|
exp: []interval16{},
|
|
},
|
|
{
|
|
// single-bit run
|
|
bitmap: []uint64{1},
|
|
exp: []interval16{{start: 0, last: 0}},
|
|
},
|
|
{
|
|
// single multi-bit run in one word
|
|
bitmap: []uint64{31},
|
|
exp: []interval16{{start: 0, last: 4}},
|
|
},
|
|
{
|
|
// multiple runs in one word
|
|
bitmap: []uint64{155876},
|
|
exp: []interval16{{start: 2, last: 2}, {start: 5, last: 7}, {start: 13, last: 14}, {start: 17, last: 17}},
|
|
},
|
|
{
|
|
// span two words, both mixed
|
|
bitmap: []uint64{0xF00000000000000F, 0x000000000000000F},
|
|
exp: []interval16{{start: 0, last: 3}, {start: 60, last: 67}},
|
|
},
|
|
{
|
|
// span two words, first = maxBitmap
|
|
bitmap: []uint64{0xFFFFFFFFFFFFFFFF, 0xF},
|
|
exp: []interval16{{start: 0, last: 67}},
|
|
},
|
|
{
|
|
// span two words, second = maxBitmap
|
|
bitmap: []uint64{0xF000000000000000, 0xFFFFFFFFFFFFFFFF},
|
|
exp: []interval16{{start: 60, last: 127}},
|
|
},
|
|
{
|
|
// span three words
|
|
bitmap: []uint64{0xF000000000000000, 0xFFFFFFFFFFFFFFFF, 0xF},
|
|
exp: []interval16{{start: 60, last: 131}},
|
|
},
|
|
{
|
|
bitmap: make([]uint64, bitmapN),
|
|
exp: []interval16{{start: 65408, last: 65535}},
|
|
},
|
|
{
|
|
bitmap: getFullBitmap(),
|
|
exp: []interval16{{start: 0, last: 65535}},
|
|
},
|
|
}
|
|
tests[8].bitmap[1022] = 0xFFFFFFFFFFFFFFFF
|
|
tests[8].bitmap[1023] = 0xFFFFFFFFFFFFFFFF
|
|
|
|
for i, test := range tests {
|
|
a.bitmap = make([]uint64, bitmapN)
|
|
n := 0
|
|
for i, v := range test.bitmap {
|
|
a.bitmap[i] = v
|
|
n += int(popcount(v))
|
|
}
|
|
a.n = n
|
|
x := a.bitmap
|
|
a.bitmapToRun()
|
|
if !reflect.DeepEqual(a.runs, test.exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, a.runs)
|
|
}
|
|
a.runToBitmap()
|
|
if !reflect.DeepEqual(a.bitmap, x) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, a.bitmap, x)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestArrayToRun(t *testing.T) {
|
|
a := &container{containerType: ContainerArray}
|
|
tests := []struct {
|
|
array []uint16
|
|
exp []interval16
|
|
}{
|
|
{
|
|
array: []uint16{},
|
|
exp: []interval16{},
|
|
},
|
|
{
|
|
array: []uint16{0},
|
|
exp: []interval16{{start: 0, last: 0}},
|
|
},
|
|
{
|
|
array: []uint16{0, 1, 2, 3, 4},
|
|
exp: []interval16{{start: 0, last: 4}},
|
|
},
|
|
{
|
|
array: []uint16{2, 5, 6, 7, 13, 14, 17},
|
|
exp: []interval16{{start: 2, last: 2}, {start: 5, last: 7}, {start: 13, last: 14}, {start: 17, last: 17}},
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
a.array = test.array
|
|
a.n = int(len(test.array))
|
|
a.arrayToRun()
|
|
if !reflect.DeepEqual(a.runs, test.exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, a.runs)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRunToArray(t *testing.T) {
|
|
a := &container{containerType: ContainerRun}
|
|
tests := []struct {
|
|
runs []interval16
|
|
exp []uint16
|
|
}{
|
|
{
|
|
runs: []interval16{},
|
|
exp: []uint16{},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 0, last: 0}},
|
|
exp: []uint16{0},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 0, last: 4}},
|
|
exp: []uint16{0, 1, 2, 3, 4},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 2, last: 2}, {start: 5, last: 7}, {start: 13, last: 14}, {start: 17, last: 17}},
|
|
exp: []uint16{2, 5, 6, 7, 13, 14, 17},
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
a.runs = test.runs
|
|
a.n = len(test.exp)
|
|
a.runToArray()
|
|
if !reflect.DeepEqual(a.array, test.exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, a.array)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBitmapZeroRange(t *testing.T) {
|
|
c := &container{containerType: ContainerBitmap, bitmap: make([]uint64, bitmapN)}
|
|
tests := []struct {
|
|
bitmap []uint64
|
|
start uint64
|
|
last uint64
|
|
exp []uint64
|
|
expN int
|
|
}{
|
|
{
|
|
bitmap: []uint64{0x0000000000FFFF00},
|
|
start: 9,
|
|
last: 10,
|
|
exp: []uint64{0x0000000000FFF900},
|
|
expN: 14,
|
|
},
|
|
{
|
|
bitmap: []uint64{0xFF0, 0xFF, 0xFF},
|
|
start: 60,
|
|
last: 130,
|
|
exp: []uint64{0xFF0, 0, 0xF8},
|
|
expN: 13,
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
for i, v := range test.bitmap {
|
|
c.bitmap[i] = v
|
|
}
|
|
c.n = c.countRange(0, 65535)
|
|
c.bitmapZeroRange(test.start, test.last+1)
|
|
if !reflect.DeepEqual(c.bitmap[:len(test.exp)], test.exp) {
|
|
t.Fatalf("test %#v expected %x, got %x", i, test.exp, c.bitmap[:len(test.bitmap)])
|
|
}
|
|
if test.expN != c.n {
|
|
t.Fatalf("test #%v expected n to be %v, but got %v", i, test.expN, c.n)
|
|
}
|
|
for i := range test.bitmap {
|
|
c.bitmap[i] = 0
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func TestUnionBitmapRun(t *testing.T) {
|
|
a := &container{containerType: ContainerBitmap, bitmap: make([]uint64, bitmapN)}
|
|
b := &container{containerType: ContainerRun}
|
|
tests := []struct {
|
|
bitmap []uint64
|
|
runs []interval16
|
|
exp []uint64
|
|
expN int
|
|
}{
|
|
{
|
|
bitmap: []uint64{2},
|
|
runs: []interval16{{start: 0, last: 0}, {start: 2, last: 5}, {start: 62, last: 71}, {start: 77, last: 78}},
|
|
exp: []uint64{0xC00000000000003F, 0x60FF},
|
|
expN: 18,
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
for i, v := range test.bitmap {
|
|
a.bitmap[i] = v
|
|
}
|
|
a.n = a.bitmapCountRange(0, 65535)
|
|
b.runs = test.runs
|
|
b.n = b.runCountRange(0, 65535)
|
|
ret := unionBitmapRun(a, b)
|
|
if ret.isArray() {
|
|
ret.arrayToBitmap()
|
|
}
|
|
if !reflect.DeepEqual(ret.bitmap[:len(test.exp)], test.exp) {
|
|
t.Fatalf("test #%v expected %x, but got %x", i, test.exp, ret.bitmap[:len(test.exp)])
|
|
}
|
|
if ret.n != test.expN {
|
|
t.Fatalf("test #%v expected n to be %v, but got %v", i, test.expN, ret.n)
|
|
}
|
|
for i := range test.bitmap {
|
|
a.bitmap[i] = 0
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBitmapCountRuns(t *testing.T) {
|
|
c := &container{containerType: ContainerBitmap, bitmap: make([]uint64, bitmapN)}
|
|
tests := []struct {
|
|
bitmap []uint64
|
|
exp int
|
|
}{
|
|
{
|
|
bitmap: []uint64{0xFF00FF00},
|
|
exp: 2,
|
|
},
|
|
{
|
|
bitmap: []uint64{0xFF00FF0000000000, 0x1},
|
|
exp: 2,
|
|
},
|
|
{
|
|
bitmap: []uint64{0xFF00FF0000000000, 0x2, 0x100},
|
|
exp: 4,
|
|
},
|
|
{
|
|
bitmap: []uint64{0xFF00FF0000000000, 0x1010101FF0101010, 0x100},
|
|
exp: 10,
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
for j, v := range test.bitmap {
|
|
c.bitmap[j] = v
|
|
}
|
|
|
|
ret := c.bitmapCountRuns()
|
|
if ret != test.exp {
|
|
t.Fatalf("test #%v expected %v but got %v", i, test.exp, ret)
|
|
}
|
|
|
|
for j := range test.bitmap {
|
|
c.bitmap[j] = 0
|
|
}
|
|
}
|
|
|
|
test := tests[3]
|
|
for j, v := range test.bitmap {
|
|
c.bitmap[1024-len(test.bitmap)+j] = v
|
|
|
|
}
|
|
ret := c.bitmapCountRuns()
|
|
if ret != test.exp {
|
|
t.Fatalf("test at end expected %v but got %v", test.exp, ret)
|
|
}
|
|
}
|
|
|
|
func TestArrayCountRuns(t *testing.T) {
|
|
c := &container{containerType: ContainerArray}
|
|
tests := []struct {
|
|
array []uint16
|
|
exp int
|
|
}{
|
|
{
|
|
array: []uint16{},
|
|
exp: 0,
|
|
},
|
|
{
|
|
array: []uint16{0},
|
|
exp: 1,
|
|
},
|
|
{
|
|
array: []uint16{1},
|
|
exp: 1,
|
|
},
|
|
{
|
|
array: []uint16{1, 2, 3, 5},
|
|
exp: 2,
|
|
},
|
|
{
|
|
array: []uint16{0, 1, 3, 9, 2048, 4096, 4097, 65534, 65535},
|
|
exp: 6,
|
|
},
|
|
{
|
|
array: []uint16{0, 10, 11, 12},
|
|
exp: 2,
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
c.array = test.array
|
|
ret := c.arrayCountRuns()
|
|
if ret != test.exp {
|
|
t.Fatalf("test #%v expected %v but got %v", i, test.exp, ret)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDifferenceArrayRun(t *testing.T) {
|
|
a := &container{containerType: ContainerArray}
|
|
b := &container{containerType: ContainerRun}
|
|
tests := []struct {
|
|
array []uint16
|
|
runs []interval16
|
|
exp []uint16
|
|
}{
|
|
{
|
|
array: []uint16{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
|
|
runs: []interval16{{start: 5, last: 10}},
|
|
exp: []uint16{0, 1, 2, 3, 4, 11, 12},
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
a.array = test.array
|
|
a.n = len(a.array)
|
|
b.runs = test.runs
|
|
b.n = b.runCountRange(0, 100)
|
|
ret := differenceArrayRun(a, b)
|
|
if !reflect.DeepEqual(ret.array, test.exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.array)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDifferenceRunArray(t *testing.T) {
|
|
a := &container{containerType: ContainerRun}
|
|
b := &container{containerType: ContainerArray}
|
|
tests := []struct {
|
|
runs []interval16
|
|
array []uint16
|
|
exp []interval16
|
|
}{
|
|
{
|
|
runs: []interval16{{start: 0, last: 12}},
|
|
array: []uint16{5, 6, 7, 8, 9, 10},
|
|
exp: []interval16{{start: 0, last: 4}, {start: 11, last: 12}},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 0, last: 12}},
|
|
array: []uint16{0, 1, 2, 3},
|
|
exp: []interval16{{start: 4, last: 12}},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 0, last: 12}},
|
|
array: []uint16{9, 10, 11, 12, 13},
|
|
exp: []interval16{{start: 0, last: 8}},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 1, last: 12}},
|
|
array: []uint16{0, 9, 10, 11, 12, 13},
|
|
exp: []interval16{{start: 1, last: 8}},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 1, last: 12}, {start: 14, last: 14}, {start: 18, last: 18}},
|
|
array: []uint16{0, 9, 10, 11, 12, 13, 14, 17},
|
|
exp: []interval16{{start: 1, last: 8}, {start: 18, last: 18}},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 1, last: 12}, {start: 14, last: 14}, {start: 18, last: 18}},
|
|
array: []uint16{0, 9, 10, 11, 12, 13, 14, 17, 19},
|
|
exp: []interval16{{start: 1, last: 8}, {start: 18, last: 18}},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 1, last: 12}, {start: 14, last: 17}, {start: 19, last: 28}},
|
|
array: []uint16{0, 9, 10, 11, 12, 13, 14, 17, 19, 25, 27},
|
|
exp: []interval16{{start: 1, last: 8}, {start: 15, last: 16}, {start: 20, last: 24}, {start: 26, last: 26}, {start: 28, last: 28}},
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
a.runs = test.runs
|
|
a.n = a.runCountRange(0, 100)
|
|
b.array = test.array
|
|
b.n = len(b.array)
|
|
ret := differenceRunArray(a, b)
|
|
if !reflect.DeepEqual(ret.runs, test.exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.runs)
|
|
}
|
|
}
|
|
}
|
|
func MakeBitmap(start []uint64) []uint64 {
|
|
|
|
b := make([]uint64, bitmapN)
|
|
for i, v := range start {
|
|
b[i] = v
|
|
|
|
}
|
|
return b
|
|
}
|
|
func MakeLastBitSet() []uint64 {
|
|
obj := NewBitmap(65535)
|
|
c := obj.container(0)
|
|
c.arrayToBitmap()
|
|
return c.bitmap
|
|
}
|
|
|
|
func TestDifferenceRunBitmap(t *testing.T) {
|
|
a := &container{containerType: ContainerRun}
|
|
b := &container{containerType: ContainerBitmap, bitmap: make([]uint64, bitmapN)}
|
|
tests := []struct {
|
|
runs []interval16
|
|
bitmap []uint64
|
|
exp []interval16
|
|
}{
|
|
{
|
|
runs: []interval16{{start: 0, last: 63}},
|
|
bitmap: MakeBitmap([]uint64{0x0000FFFF000000F0}),
|
|
exp: []interval16{{start: 0, last: 3}, {start: 8, last: 31}, {start: 48, last: 63}},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 0, last: 63}},
|
|
bitmap: MakeBitmap([]uint64{0x8000000000000000}),
|
|
exp: []interval16{{start: 0, last: 62}},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 0, last: 63}},
|
|
bitmap: MakeBitmap([]uint64{0x0000000000000001}),
|
|
exp: []interval16{{start: 1, last: 63}},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 0, last: 63}},
|
|
bitmap: MakeBitmap([]uint64{0x0, 0x0000000000000001}),
|
|
exp: []interval16{{start: 0, last: 63}},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 0, last: 65}},
|
|
bitmap: MakeBitmap([]uint64{0x0, 0x0000000000000001}),
|
|
exp: []interval16{{start: 0, last: 63}, {start: 65, last: 65}},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 0, last: 65}},
|
|
bitmap: MakeBitmap([]uint64{0x0, 0x8000000000000000}),
|
|
exp: []interval16{{start: 0, last: 65}},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 1, last: 65535}},
|
|
bitmap: MakeBitmap([]uint64{0x0000000000000001}),
|
|
exp: []interval16{{start: 1, last: 65535}},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 0, last: 65533}, {start: 65535, last: 65535}},
|
|
bitmap: MakeLastBitSet(),
|
|
exp: []interval16{{start: 0, last: 65533}},
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
a.runs = test.runs
|
|
a.n = a.runCountRange(0, 65536)
|
|
for i, v := range test.bitmap {
|
|
b.bitmap[i] = v
|
|
}
|
|
b.n = b.bitmapCountRange(0, 65536)
|
|
ret := differenceRunBitmap(a, b)
|
|
if !reflect.DeepEqual(ret.runs, test.exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.runs)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDifferenceBitmapRun(t *testing.T) {
|
|
a := &container{containerType: ContainerBitmap, bitmap: make([]uint64, bitmapN)}
|
|
b := &container{containerType: ContainerRun}
|
|
tests := []struct {
|
|
bitmap []uint64
|
|
runs []interval16
|
|
exp []uint64
|
|
}{
|
|
{
|
|
bitmap: []uint64{0xFFFFFFFFFFFFFFFF},
|
|
runs: []interval16{{start: 4, last: 7}, {start: 32, last: 47}},
|
|
exp: []uint64{0xFFFF0000FFFFFF0F},
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
for i, v := range test.bitmap {
|
|
a.bitmap[i] = v
|
|
}
|
|
a.n = a.bitmapCountRange(0, 100)
|
|
b.runs = test.runs
|
|
b.n = b.runCountRange(0, 100)
|
|
ret := differenceBitmapRun(a, b)
|
|
if !reflect.DeepEqual(ret.bitmap[:len(test.exp)], test.exp) {
|
|
t.Fatalf("test #%v expected \n%X, but got \n%X", i, test.exp, ret.bitmap[:len(test.exp)])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDifferenceBitmapArray(t *testing.T) {
|
|
b := &container{containerType: ContainerBitmap, bitmap: make([]uint64, bitmapN)}
|
|
a := &container{containerType: ContainerArray}
|
|
tests := []struct {
|
|
bitmap []uint64
|
|
array []uint16
|
|
exp []uint16
|
|
}{
|
|
{
|
|
bitmap: MakeBitmap([]uint64{0xFF0F}),
|
|
array: []uint16{0, 1, 2, 3, 4, 5, 6, 7, 10},
|
|
exp: []uint16{8, 9, 11, 12, 13, 14, 15},
|
|
},
|
|
{
|
|
bitmap: []uint64{0x0000},
|
|
array: []uint16{0, 1, 2, 3, 4, 5, 6, 7, 10},
|
|
exp: []uint16{},
|
|
},
|
|
{
|
|
bitmap: []uint64{0xFFFF},
|
|
array: []uint16{0, 1, 2, 3, 4, 5, 6, 7, 10},
|
|
exp: []uint16{8, 9, 11, 12, 13, 14, 15},
|
|
},
|
|
{
|
|
bitmap: bitmapOdds(),
|
|
array: []uint16{0, 1, 2, 3, 4, 5, 6, 7, 10},
|
|
exp: []uint16{9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63},
|
|
},
|
|
{
|
|
bitmap: bitmapOdds(),
|
|
array: []uint16{63},
|
|
exp: []uint16{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61},
|
|
},
|
|
{
|
|
bitmap: MakeBitmap([]uint64{0x0000FFFF000000F0}),
|
|
array: []uint16{4, 5, 6, 7, 20, 21, 22, 23, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47},
|
|
exp: []uint16{},
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
b.bitmap[0] = test.bitmap[0]
|
|
b.n = b.count()
|
|
a.array = test.array
|
|
ret := differenceBitmapArray(b, a)
|
|
if !reflect.DeepEqual(ret.array, test.exp) {
|
|
t.Fatalf("test #%v expected %X, but got %X", i, test.exp, ret.array)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDifferenceBitmapBitmap(t *testing.T) {
|
|
a := &container{bitmap: make([]uint64, bitmapN), containerType: ContainerBitmap}
|
|
b := &container{bitmap: make([]uint64, bitmapN), containerType: ContainerBitmap}
|
|
tests := []struct {
|
|
abitmap []uint64
|
|
bbitmap []uint64
|
|
exp []uint16
|
|
}{
|
|
{
|
|
abitmap: []uint64{0xFF00FFFFFFFFFFFF},
|
|
bbitmap: []uint64{0xFFFFFFFFFFFFF000},
|
|
exp: []uint16{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
|
|
},
|
|
{
|
|
abitmap: []uint64{0xF},
|
|
bbitmap: []uint64{0},
|
|
exp: []uint16{0, 1, 2, 3},
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
a.bitmap[0] = test.abitmap[0]
|
|
b.bitmap[0] = test.bbitmap[0]
|
|
|
|
ret := differenceBitmapBitmap(a, b)
|
|
if !reflect.DeepEqual(ret.array, test.exp) {
|
|
t.Fatalf("test #%v expected \n%X, but got \n%X", i, test.exp, ret.array)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDifferenceRunRun(t *testing.T) {
|
|
a := &container{containerType: ContainerRun}
|
|
b := &container{containerType: ContainerRun}
|
|
tests := []struct {
|
|
aruns []interval16
|
|
bruns []interval16
|
|
exp []interval16
|
|
expn int
|
|
}{
|
|
{
|
|
// this tests all six overlap combinations
|
|
// A [ ] [ ] [ ] [ ] [ ] [ ]
|
|
// B [ ] [ ] [ ] [ ] [ ] [ ]
|
|
aruns: []interval16{{start: 3, last: 6}, {start: 13, last: 16}, {start: 24, last: 26}, {start: 33, last: 38}, {start: 43, last: 46}, {start: 53, last: 56}},
|
|
bruns: []interval16{{start: 1, last: 8}, {start: 11, last: 14}, {start: 21, last: 23}, {start: 35, last: 37}, {start: 44, last: 48}, {start: 57, last: 59}},
|
|
exp: []interval16{{start: 15, last: 16}, {start: 24, last: 26}, {start: 33, last: 34}, {start: 38, last: 38}, {start: 43, last: 43}, {start: 53, last: 56}},
|
|
expn: 13,
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
a.runs = test.aruns
|
|
a.n = a.runCountRange(0, 100)
|
|
b.runs = test.bruns
|
|
b.n = b.runCountRange(0, 100)
|
|
ret := differenceRunRun(a, b)
|
|
if !reflect.DeepEqual(ret.runs, test.exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.runs)
|
|
}
|
|
if ret.n != test.expn {
|
|
t.Fatalf("test #%v expected n=%v, but got n=%v", i, test.expn, ret.n)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWriteReadArray(t *testing.T) {
|
|
ca := &container{array: []uint16{1, 10, 100, 1000}, n: 4, containerType: ContainerArray}
|
|
ba := &Bitmap{keys: []uint64{0}, containers: []*container{ca}}
|
|
ba2 := &Bitmap{}
|
|
var buf bytes.Buffer
|
|
_, err := ba.WriteTo(&buf)
|
|
if err != nil {
|
|
t.Fatalf("error writing: %v", err)
|
|
}
|
|
err = ba2.UnmarshalBinary(buf.Bytes())
|
|
if err != nil {
|
|
t.Fatalf("error unmarshaling: %v", err)
|
|
}
|
|
if !reflect.DeepEqual(ba2.containers[0].array, ca.array) {
|
|
t.Fatalf("array test expected %x, but got %x", ca.array, ba2.containers[0].array)
|
|
}
|
|
}
|
|
|
|
func TestWriteReadBitmap(t *testing.T) {
|
|
// create bitmap containing > 4096 bits
|
|
cb := &container{bitmap: make([]uint64, bitmapN), n: 129 * 32, containerType: ContainerBitmap}
|
|
for i := 0; i < 129; i++ {
|
|
cb.bitmap[i] = 0x5555555555555555
|
|
}
|
|
bb := &Bitmap{keys: []uint64{0}, containers: []*container{cb}}
|
|
bb2 := &Bitmap{}
|
|
var buf bytes.Buffer
|
|
_, err := bb.WriteTo(&buf)
|
|
if err != nil {
|
|
t.Fatalf("error writing: %v", err)
|
|
}
|
|
err = bb2.UnmarshalBinary(buf.Bytes())
|
|
if err != nil {
|
|
t.Fatalf("error unmarshaling: %v", err)
|
|
}
|
|
if !reflect.DeepEqual(bb2.containers[0].bitmap, cb.bitmap) {
|
|
t.Fatalf("bitmap test expected %x, but got %x", cb.bitmap, bb2.containers[0].bitmap)
|
|
}
|
|
}
|
|
|
|
func TestWriteReadFullBitmap(t *testing.T) {
|
|
// create bitmap containing > 4096 bits
|
|
cb := &container{bitmap: make([]uint64, bitmapN), n: 65536, containerType: ContainerBitmap}
|
|
for i := 0; i < bitmapN; i++ {
|
|
cb.bitmap[i] = 0xffffffffffffffff
|
|
}
|
|
bb := &Bitmap{keys: []uint64{0}, containers: []*container{cb}}
|
|
bb2 := &Bitmap{}
|
|
var buf bytes.Buffer
|
|
_, err := bb.WriteTo(&buf)
|
|
if err != nil {
|
|
t.Fatalf("error writing: %v", err)
|
|
}
|
|
err = bb2.UnmarshalBinary(buf.Bytes())
|
|
if err != nil {
|
|
t.Fatalf("error unmarshaling: %v", err)
|
|
}
|
|
if !reflect.DeepEqual(bb2.containers[0].bitmap, cb.bitmap) {
|
|
t.Fatalf("bitmap test expected %x, but got %x", cb.bitmap, bb2.containers[0].bitmap)
|
|
}
|
|
|
|
if bb2.containers[0].n != cb.n {
|
|
t.Fatalf("bitmap test expected count %x, but got %x", cb.n, bb2.containers[0].n)
|
|
}
|
|
if bb2.containers[0].count() != cb.count() {
|
|
t.Fatalf("bitmap test expected count %x, but got %x", cb.n, bb2.containers[0].n)
|
|
}
|
|
}
|
|
|
|
func TestWriteReadRun(t *testing.T) {
|
|
cr := &container{runs: []interval16{{start: 3, last: 13}, {start: 100, last: 109}}, n: 21, containerType: ContainerRun}
|
|
br := &Bitmap{keys: []uint64{0}, containers: []*container{cr}}
|
|
br2 := &Bitmap{}
|
|
var buf bytes.Buffer
|
|
_, err := br.WriteTo(&buf)
|
|
if err != nil {
|
|
t.Fatalf("error writing: %v", err)
|
|
}
|
|
err = br2.UnmarshalBinary(buf.Bytes())
|
|
if err != nil {
|
|
t.Fatalf("error unmarshaling: %v", err)
|
|
}
|
|
if !reflect.DeepEqual(br2.containers[0].runs, cr.runs) {
|
|
t.Fatalf("run test expected %x, but got %x", cr.runs, br2.containers[0].runs)
|
|
}
|
|
}
|
|
|
|
func TestXorArrayRun(t *testing.T) {
|
|
tests := []struct {
|
|
a *container
|
|
b *container
|
|
exp *container
|
|
}{
|
|
{
|
|
a: &container{array: []uint16{1, 5, 10, 11, 12}, containerType: ContainerArray},
|
|
b: &container{runs: []interval16{{start: 2, last: 10}, {start: 12, last: 13}, {start: 15, last: 16}}, containerType: ContainerRun},
|
|
exp: &container{array: []uint16{1, 2, 3, 4, 6, 7, 8, 9, 11, 13, 15, 16}, containerType: ContainerArray, n: 12},
|
|
}, {
|
|
a: &container{array: []uint16{1, 5, 10, 11, 12, 13, 14}, containerType: ContainerArray},
|
|
b: &container{runs: []interval16{{start: 2, last: 10}, {start: 12, last: 13}, {start: 15, last: 16}}, containerType: ContainerRun},
|
|
exp: &container{array: []uint16{1, 2, 3, 4, 6, 7, 8, 9, 11, 14, 15, 16}, containerType: ContainerArray, n: 12},
|
|
}, {
|
|
a: &container{array: []uint16{65535}, containerType: ContainerArray},
|
|
b: &container{runs: []interval16{{start: 65534, last: 65535}}, containerType: ContainerRun},
|
|
exp: &container{array: []uint16{65534}, containerType: ContainerArray, n: 1},
|
|
}, {
|
|
a: &container{array: []uint16{65535}, containerType: ContainerArray},
|
|
b: &container{runs: []interval16{{start: 65535, last: 65535}}, containerType: ContainerRun},
|
|
exp: &container{array: []uint16{}, containerType: ContainerArray, n: 0},
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
test.a.n = test.a.count()
|
|
test.b.n = test.b.count()
|
|
ret := xor(test.a, test.b)
|
|
if !reflect.DeepEqual(ret, test.exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret)
|
|
}
|
|
ret = xor(test.b, test.a)
|
|
if !reflect.DeepEqual(ret, test.exp) {
|
|
t.Fatalf("test #%v.1 expected %v, but got %v", i, test.exp, ret)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//special case that didn't fit the xorrunrun table testing below.
|
|
func TestXorRunRun1(t *testing.T) {
|
|
a := &container{containerType: ContainerRun}
|
|
b := &container{containerType: ContainerRun}
|
|
a.runs = []interval16{{start: 4, last: 10}}
|
|
b.runs = []interval16{{start: 5, last: 10}}
|
|
ret := xorRunRun(a, b)
|
|
if !reflect.DeepEqual(ret.array, []uint16{4}) {
|
|
t.Fatalf("test #1 expected %v, but got %v", []uint16{4}, ret.array)
|
|
}
|
|
ret = xorRunRun(b, a)
|
|
if !reflect.DeepEqual(ret.array, []uint16{4}) {
|
|
t.Fatalf("test #1 expected %v, but got %v", []uint16{4}, ret.array)
|
|
}
|
|
}
|
|
|
|
func TestXorRunRun(t *testing.T) {
|
|
a := &container{containerType: ContainerRun}
|
|
b := &container{containerType: ContainerRun}
|
|
tests := []struct {
|
|
aruns []interval16
|
|
bruns []interval16
|
|
exp []interval16
|
|
}{
|
|
{
|
|
aruns: []interval16{},
|
|
bruns: []interval16{{start: 5, last: 10}},
|
|
exp: []interval16{{start: 5, last: 10}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 0, last: 4}},
|
|
bruns: []interval16{{start: 6, last: 10}},
|
|
exp: []interval16{{start: 0, last: 4}, {start: 6, last: 10}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 0, last: 6}},
|
|
bruns: []interval16{{start: 4, last: 10}},
|
|
exp: []interval16{{start: 0, last: 3}, {start: 7, last: 10}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 4, last: 10}},
|
|
bruns: []interval16{{start: 0, last: 6}},
|
|
exp: []interval16{{start: 0, last: 3}, {start: 7, last: 10}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 0, last: 10}},
|
|
bruns: []interval16{{start: 0, last: 6}},
|
|
exp: []interval16{{start: 7, last: 10}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 0, last: 6}},
|
|
bruns: []interval16{{start: 0, last: 10}},
|
|
exp: []interval16{{start: 7, last: 10}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 0, last: 6}},
|
|
bruns: []interval16{{start: 0, last: 10}},
|
|
exp: []interval16{{start: 7, last: 10}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 5, last: 12}},
|
|
bruns: []interval16{{start: 5, last: 10}},
|
|
exp: []interval16{{start: 11, last: 12}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 1, last: 3}, {start: 5, last: 5}, {start: 7, last: 12}},
|
|
bruns: []interval16{{start: 5, last: 10}},
|
|
exp: []interval16{{start: 1, last: 3}, {start: 6, last: 6}, {start: 11, last: 12}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 1, last: 3}, {start: 5, last: 5}, {start: 7, last: 12}},
|
|
bruns: []interval16{{start: 2, last: 65535}},
|
|
exp: []interval16{{start: 1, last: 1}, {start: 4, last: 4}, {start: 6, last: 6}, {start: 13, last: 65535}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 2, last: 65535}},
|
|
bruns: []interval16{{start: 1, last: 3}, {start: 5, last: 5}, {start: 7, last: 12}},
|
|
exp: []interval16{{start: 1, last: 1}, {start: 4, last: 4}, {start: 6, last: 6}, {start: 13, last: 65535}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 1, last: 3}, {start: 5, last: 5}, {start: 7, last: 12}},
|
|
bruns: []interval16{{start: 0, last: 65535}},
|
|
exp: []interval16{{start: 0, last: 0}, {start: 4, last: 4}, {start: 6, last: 6}, {start: 13, last: 65535}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 0, last: 65535}},
|
|
bruns: []interval16{{start: 1, last: 3}, {start: 5, last: 5}, {start: 7, last: 12}},
|
|
exp: []interval16{{start: 0, last: 0}, {start: 4, last: 4}, {start: 6, last: 6}, {start: 13, last: 65535}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 1, last: 3}, {start: 5, last: 5}, {start: 7, last: 9}, {start: 12, last: 22}},
|
|
bruns: []interval16{{start: 2, last: 8}, {start: 16, last: 27}, {start: 33, last: 34}},
|
|
exp: []interval16{{start: 1, last: 1}, {start: 4, last: 4}, {start: 6, last: 6}, {start: 9, last: 9}, {start: 12, last: 15}, {start: 23, last: 27}, {start: 33, last: 34}},
|
|
},
|
|
{
|
|
aruns: []interval16{{start: 65530, last: 65535}},
|
|
bruns: []interval16{{start: 65532, last: 65535}},
|
|
exp: []interval16{{start: 65530, last: 65531}},
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
a.runs = test.aruns
|
|
b.runs = test.bruns
|
|
ret := xorRunRun(a, b)
|
|
if !reflect.DeepEqual(ret.runs, test.exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.runs)
|
|
}
|
|
ret = xorRunRun(b, a)
|
|
if !reflect.DeepEqual(ret.runs, test.exp) {
|
|
t.Fatalf("test #%v.1 expected %v, but got %v", i, test.exp, ret.runs)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBitmapFlip(t *testing.T) {
|
|
c := &container{bitmap: make([]uint64, bitmapN), containerType: ContainerBitmap}
|
|
|
|
ttable := []struct {
|
|
original uint64
|
|
flipped uint64
|
|
}{
|
|
{0x0000000000000000, 0xFFFFFFFFFFFFFFFF},
|
|
{0xFFFFFFFFFFFFFFFF, 0x0000000000000000},
|
|
{0xFFFFFFFFFFFFFFF0, 0x000000000000000F},
|
|
{0xFFFFFFEFFFFFFFFF, 0x0000001000000000},
|
|
{0x0000001000000000, 0xFFFFFFEFFFFFFFFF},
|
|
}
|
|
|
|
expectedN := int(65536)
|
|
for i, tt := range ttable {
|
|
c.bitmap[i] = tt.original
|
|
expectedN -= int(popcount(tt.original))
|
|
}
|
|
|
|
o := c.flipBitmap()
|
|
|
|
for i, tt := range ttable {
|
|
if o.bitmap[i] != tt.flipped {
|
|
t.Fatalf("bitmapFlip calculation. expected %v, got %v", tt.flipped, o.bitmap[i])
|
|
}
|
|
}
|
|
if o.n != expectedN {
|
|
t.Fatalf("bitmapFlip calculation. expected count %v, got %v", expectedN, o.n)
|
|
}
|
|
}
|
|
|
|
func TestBitmapXorRange(t *testing.T) {
|
|
c := &container{bitmap: make([]uint64, bitmapN), containerType: ContainerBitmap}
|
|
tests := []struct {
|
|
bitmap []uint64
|
|
start uint64
|
|
last uint64
|
|
exp []uint64
|
|
expN int
|
|
}{
|
|
{
|
|
bitmap: []uint64{0x0000000000000000},
|
|
start: 0,
|
|
last: 2,
|
|
exp: []uint64{0x0000000000000007},
|
|
expN: 3,
|
|
},
|
|
{
|
|
bitmap: []uint64{0xF1},
|
|
start: 4,
|
|
last: 8,
|
|
exp: []uint64{0x101},
|
|
expN: 2,
|
|
},
|
|
{
|
|
bitmap: []uint64{0xAA},
|
|
start: 0,
|
|
last: 7,
|
|
exp: []uint64{0x55},
|
|
expN: 4,
|
|
},
|
|
{
|
|
bitmap: []uint64{0x0, 0x0000000000000000, 0x0000000000000000},
|
|
start: 63,
|
|
last: 128,
|
|
exp: []uint64{0x8000000000000000, 0xFFFFFFFFFFFFFFFF, 0x000000000000001},
|
|
expN: 66,
|
|
},
|
|
{
|
|
bitmap: []uint64{0x0, 0x00000000000000FF, 0x0000000000000000},
|
|
start: 63,
|
|
last: 128,
|
|
exp: []uint64{0x8000000000000000, 0xFFFFFFFFFFFFFF00, 0x000000000000001},
|
|
expN: 58,
|
|
},
|
|
{
|
|
bitmap: []uint64{0x0, 0x0, 0x0},
|
|
start: 129,
|
|
last: 131,
|
|
exp: []uint64{0x0000000000000000, 0x0000000000000000, 0x00000000000000E},
|
|
expN: 3,
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
for i, v := range test.bitmap {
|
|
c.bitmap[i] = v
|
|
}
|
|
c.n = c.countRange(0, 65535)
|
|
c.bitmapXorRange(test.start, test.last+1)
|
|
if !reflect.DeepEqual(c.bitmap[:len(test.exp)], test.exp) {
|
|
t.Fatalf("test %#v expected %x, got %x", i, test.exp, c.bitmap[:len(test.bitmap)])
|
|
}
|
|
if test.expN != c.n {
|
|
t.Fatalf("test #%v expected n to be %v, but got %v", i, test.expN, c.n)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestXorBitmapRun(t *testing.T) {
|
|
a := &container{containerType: ContainerBitmap}
|
|
b := &container{containerType: ContainerRun}
|
|
tests := []struct {
|
|
bitmap []uint64
|
|
runs []interval16
|
|
exp []uint64
|
|
}{
|
|
{
|
|
bitmap: []uint64{0x0, 0x0, 0x0},
|
|
runs: []interval16{{start: 129, last: 131}},
|
|
exp: []uint64{0x0, 0x0, 0x00000000000000E},
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
a.bitmap = test.bitmap
|
|
b.runs = test.runs
|
|
//xorBitmapRun
|
|
ret := xor(a, b)
|
|
if !reflect.DeepEqual(ret.bitmap, test.exp) {
|
|
t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.bitmap)
|
|
}
|
|
ret = xor(b, a)
|
|
if !reflect.DeepEqual(ret.bitmap, test.exp) {
|
|
t.Fatalf("test #%v.1 expected %v, but got %v", i, test.exp, ret.bitmap)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func TestIteratorArray(t *testing.T) {
|
|
// use values that span two containers
|
|
b := NewBitmap(0, 1, 10, 100, 1000, 10000, 90000, 100000)
|
|
if !b.containers[0].isArray() {
|
|
t.Fatalf("wrong container type")
|
|
}
|
|
|
|
itr := b.Iterator()
|
|
if !(itr.i == 0 && itr.j == -1) {
|
|
t.Fatalf("iterator did not zero correctly: %v\n", itr)
|
|
}
|
|
|
|
itr.Seek(1000)
|
|
if !(itr.i == 0 && itr.j == 3) {
|
|
t.Fatalf("iterator did not seek correctly: %v\n", itr)
|
|
}
|
|
|
|
itr.Seek(10000)
|
|
itr.Next()
|
|
val, eof := itr.Next()
|
|
if !(itr.i == 1 && itr.j == 0 && val == 90000 && !eof) {
|
|
t.Fatalf("iterator did not next correctly across containers: %v\n", itr)
|
|
}
|
|
|
|
itr.Seek(80000)
|
|
if !(itr.i == 1 && itr.j == -1) {
|
|
t.Fatalf("iterator did not seek missing value correctly: %v\n", itr)
|
|
}
|
|
|
|
itr.Seek(100000)
|
|
if !(itr.i == 1 && itr.j == 0) {
|
|
t.Fatalf("iterator did not seek correctly in multiple containers: %v\n", itr)
|
|
}
|
|
|
|
val, eof = itr.Next()
|
|
if !(val == 100000 && !eof) {
|
|
t.Fatalf("iterator did not next correctly: %d, %v\n", val, eof)
|
|
}
|
|
|
|
val, eof = itr.Next()
|
|
if !(val == 0 && eof) {
|
|
t.Fatalf("iterator did not eof correctly: %d, %v\n", val, eof)
|
|
}
|
|
}
|
|
|
|
func TestIteratorBitmap(t *testing.T) {
|
|
// use values that span two containers
|
|
// this dataset will update to bitmap after enough Adds,
|
|
// but won't update to RLE until Optimize() is called
|
|
b := NewBitmap()
|
|
for i := uint64(61000); i < 71000; i++ {
|
|
b.Add(i)
|
|
}
|
|
for i := uint64(75000); i < 75100; i++ {
|
|
b.Add(i)
|
|
}
|
|
if !b.containers[0].isBitmap() {
|
|
t.Fatalf("wrong container type")
|
|
}
|
|
|
|
itr := b.Iterator()
|
|
if !(itr.i == 0 && itr.j == -1) {
|
|
t.Fatalf("iterator did not zero correctly: %v\n", itr)
|
|
}
|
|
|
|
itr.Seek(65000)
|
|
if !(itr.i == 0 && itr.j == 64999) {
|
|
t.Fatalf("iterator did not seek correctly: %v\n", itr)
|
|
}
|
|
|
|
itr.Seek(65535)
|
|
itr.Next()
|
|
val, eof := itr.Next()
|
|
if !(itr.i == 1 && itr.j == 0 && val == 65536 && !eof) {
|
|
t.Fatalf("iterator did not next correctly across containers: %v\n", itr)
|
|
}
|
|
|
|
itr.Seek(74000)
|
|
if !(itr.i == 1 && itr.j == 8463) {
|
|
t.Fatalf("iterator did not seek missing value correctly: %v\n", itr)
|
|
}
|
|
|
|
itr.Seek(70999)
|
|
if !(itr.i == 1 && itr.j == 5462) {
|
|
t.Fatalf("iterator did not seek correctly in multiple containers: %v\n", itr)
|
|
}
|
|
|
|
val, eof = itr.Next()
|
|
if !(val == 70999 && !eof) {
|
|
t.Fatalf("iterator did not next correctly: %d, %v\n", val, eof)
|
|
}
|
|
|
|
itr.Seek(75100)
|
|
val, eof = itr.Next()
|
|
if !(val == 0 && eof) {
|
|
t.Fatalf("iterator did not eof correctly: %d, %v\n", val, eof)
|
|
}
|
|
}
|
|
|
|
func TestIteratorRuns(t *testing.T) {
|
|
b := NewBitmap(0, 1, 2, 3, 4, 5, 1000, 1001, 1002, 1003, 1004, 1005, 100000, 100001, 100002, 100003, 100004, 100005)
|
|
b.Optimize()
|
|
if !b.containers[0].isRun() {
|
|
t.Fatalf("wrong container type")
|
|
}
|
|
|
|
itr := b.Iterator()
|
|
if !(itr.i == 0 && itr.j == 0 && itr.k == -1) {
|
|
t.Fatalf("iterator did not zero correctly: %v\n", itr)
|
|
}
|
|
|
|
itr.Seek(4)
|
|
if !(itr.i == 0 && itr.j == 0 && itr.k == 3) {
|
|
t.Fatalf("iterator did not seek correctly: %v\n", itr)
|
|
}
|
|
itr.Next()
|
|
itr.Next()
|
|
val, eof := itr.Next()
|
|
if !(val == 1000 && !eof) {
|
|
t.Fatalf("iterator did not next correctly across runs: %v, %v", val, itr)
|
|
}
|
|
itr.Next()
|
|
val, eof = itr.Next()
|
|
if !(val == 1002 && !eof) {
|
|
t.Fatalf("iterator did not next correctly within a run: %v, %v", val, itr)
|
|
}
|
|
itr.Next()
|
|
itr.Next()
|
|
itr.Next()
|
|
val, eof = itr.Next()
|
|
if !(val == 100000 && !eof) {
|
|
t.Fatalf("iterator did not next correctly across containers: %v, %v", val, itr)
|
|
}
|
|
|
|
itr.Seek(500)
|
|
if !(itr.i == 0 && itr.j == 1 && itr.k == -1) {
|
|
t.Fatalf("iterator did not seek missing value correctly: %v\n", itr)
|
|
}
|
|
|
|
itr.Seek(1004)
|
|
if !(itr.i == 0 && itr.j == 1 && itr.k == 3) {
|
|
t.Fatalf("iterator did not seek correctly in multiple runs: %v\n", itr)
|
|
}
|
|
|
|
itr.Seek(1005)
|
|
if !(itr.i == 0 && itr.j == 1 && itr.k == 4) {
|
|
t.Fatalf("iterator did not seek correctly to end of run: %v\n", itr)
|
|
}
|
|
|
|
itr.Seek(100005)
|
|
if !(itr.i == 1 && itr.j == 0 && itr.k == 4) {
|
|
t.Fatalf("iterator did not seek correctly in multiple containers: %v\n", itr)
|
|
}
|
|
|
|
val, eof = itr.Next()
|
|
val, eof = itr.Next()
|
|
if !(val == 0 && eof) {
|
|
t.Fatalf("iterator did not eof correctly: %d, %v\n", val, eof)
|
|
}
|
|
}
|
|
|
|
func TestIteratorVarious(t *testing.T) {
|
|
tests := []struct {
|
|
bm *Bitmap
|
|
exp uint64
|
|
}{
|
|
{
|
|
bm: NewBitmap(3, 4, 5),
|
|
exp: 3,
|
|
},
|
|
{
|
|
bm: bitmapVariousContainers(),
|
|
exp: 61221,
|
|
},
|
|
{
|
|
bm: NewBitmap(2, 66000, 70000, 70001, 70002, 70003, 70004),
|
|
exp: 7,
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
test.bm.Optimize()
|
|
t.Run(fmt.Sprintf("#%d:", i), func(t *testing.T) {
|
|
if cnt := test.bm.Count(); cnt != test.exp {
|
|
t.Fatalf("merged count %d is not %d", cnt, test.exp)
|
|
}
|
|
iter := test.bm.Iterator()
|
|
bits := make([]uint64, 0, test.bm.Count())
|
|
for v, eof := iter.Next(); !eof; v, eof = iter.Next() {
|
|
bits = append(bits, v)
|
|
}
|
|
if length := len(bits); uint64(length) != test.exp {
|
|
t.Fatalf("length %d is not %d", length, test.exp)
|
|
}
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
func TestRunBinSearchContains(t *testing.T) {
|
|
tests := []struct {
|
|
runs []interval16
|
|
index uint16
|
|
exp struct {
|
|
index int
|
|
found bool
|
|
}
|
|
}{
|
|
{
|
|
runs: []interval16{{start: 0, last: 10}},
|
|
index: uint16(3),
|
|
exp: struct {
|
|
index int
|
|
found bool
|
|
}{index: 0, found: true},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 0, last: 10}},
|
|
index: uint16(13),
|
|
exp: struct {
|
|
index int
|
|
found bool
|
|
}{index: 0, found: false},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 0, last: 10}, {start: 20, last: 30}},
|
|
index: uint16(13),
|
|
exp: struct {
|
|
index int
|
|
found bool
|
|
}{index: 0, found: false},
|
|
},
|
|
{
|
|
runs: []interval16{{start: 0, last: 10}, {start: 20, last: 30}},
|
|
index: uint16(36),
|
|
exp: struct {
|
|
index int
|
|
found bool
|
|
}{index: 1, found: false},
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
index := test.index
|
|
runs := test.runs
|
|
idx, found := binSearchRuns(index, runs)
|
|
|
|
if test.exp.index != idx && test.exp.found != found {
|
|
t.Fatalf("test #%v expected %v , but got %v %v", i, test.exp, idx, found)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRunBinSearch(t *testing.T) {
|
|
tests := []struct {
|
|
runs []interval16
|
|
search uint16
|
|
exp bool
|
|
expi int
|
|
}{
|
|
{
|
|
runs: []interval16{{2, 10}, {50, 60}, {80, 90}},
|
|
search: 1,
|
|
exp: false,
|
|
expi: 0,
|
|
},
|
|
{
|
|
runs: []interval16{{2, 10}, {50, 60}, {80, 90}},
|
|
search: 2,
|
|
exp: true,
|
|
expi: 0,
|
|
},
|
|
{
|
|
runs: []interval16{{2, 10}, {50, 60}, {80, 90}},
|
|
search: 5,
|
|
exp: true,
|
|
expi: 0,
|
|
},
|
|
{
|
|
runs: []interval16{{2, 10}, {50, 60}, {80, 90}},
|
|
search: 10,
|
|
exp: true,
|
|
expi: 0,
|
|
},
|
|
{
|
|
runs: []interval16{{2, 10}, {50, 60}, {80, 90}},
|
|
search: 20,
|
|
exp: false,
|
|
expi: 1,
|
|
},
|
|
{
|
|
runs: []interval16{{2, 10}, {50, 60}, {80, 90}},
|
|
search: 55,
|
|
exp: true,
|
|
expi: 1,
|
|
},
|
|
{
|
|
runs: []interval16{{2, 10}, {50, 60}, {80, 90}},
|
|
search: 70,
|
|
exp: false,
|
|
expi: 2,
|
|
},
|
|
{
|
|
runs: []interval16{{2, 10}, {50, 60}, {80, 90}},
|
|
search: 100,
|
|
exp: false,
|
|
expi: 3,
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
idx, contains := binSearchRuns(test.search, test.runs)
|
|
if !(test.exp == contains && test.expi == idx) {
|
|
t.Fatalf("test #%v expected (%v, %v) but got (%v, %v)", i, test.exp, test.expi, contains, idx)
|
|
}
|
|
}
|
|
}
|
|
func TestBitmap_RemoveEmptyContainers(t *testing.T) {
|
|
bm1 := NewBitmap(1<<16, 2<<16, 3<<16)
|
|
bm1.Remove(2 << 16)
|
|
if bm1.countEmptyContainers() != 1 {
|
|
t.Fatalf("Should be 1 empty container ")
|
|
}
|
|
bm1.removeEmptyContainers()
|
|
|
|
if bm1.countEmptyContainers() != 0 {
|
|
t.Fatalf("Should be no empty containers ")
|
|
}
|
|
}
|
|
|
|
func TestBitmap_BitmapWriteToWithEmpty(t *testing.T) {
|
|
bm1 := NewBitmap(1<<16, 2<<16, 3<<16)
|
|
bm1.Remove(2 << 16)
|
|
var buf bytes.Buffer
|
|
if _, err := bm1.WriteTo(&buf); err != nil {
|
|
t.Fatalf("Failure to write to bitmap buffer. ")
|
|
}
|
|
bm0 := NewBitmap()
|
|
bm0.UnmarshalBinary(buf.Bytes())
|
|
if bm0.countEmptyContainers() != 0 {
|
|
t.Fatalf("Should be no empty containers ")
|
|
}
|
|
if bm0.Count() != bm1.Count() {
|
|
t.Fatalf("Counts do not match after a marshal %d %d", bm0.Count(), bm1.Count())
|
|
}
|
|
}
|
|
|
|
func TestSearc64(t *testing.T) {
|
|
tests := []struct {
|
|
a []uint64
|
|
value uint64
|
|
exp int
|
|
}{
|
|
{
|
|
a: []uint64{1, 5, 10, 12},
|
|
value: 5,
|
|
exp: 1,
|
|
},
|
|
{
|
|
a: []uint64{1, 5, 10, 12},
|
|
value: 1,
|
|
exp: 0,
|
|
},
|
|
{
|
|
a: []uint64{1, 5, 10, 12},
|
|
value: 0,
|
|
exp: -1,
|
|
},
|
|
{
|
|
a: []uint64{1, 5, 10, 12},
|
|
value: 2,
|
|
exp: -2,
|
|
},
|
|
{
|
|
a: []uint64{1, 5, 10, 12},
|
|
value: 7,
|
|
exp: -3,
|
|
},
|
|
{
|
|
a: []uint64{1, 5, 10, 12},
|
|
value: 11,
|
|
exp: -4,
|
|
},
|
|
{
|
|
a: []uint64{1, 5, 10, 12},
|
|
value: 13,
|
|
exp: -5,
|
|
},
|
|
{
|
|
a: []uint64{1, 5, 10, 12},
|
|
value: 3843534,
|
|
exp: -5,
|
|
},
|
|
{
|
|
a: []uint64{},
|
|
value: 3843534,
|
|
exp: -1,
|
|
},
|
|
{
|
|
a: []uint64{},
|
|
value: 0,
|
|
exp: -1,
|
|
},
|
|
{
|
|
a: []uint64{0},
|
|
value: 0,
|
|
exp: 0,
|
|
},
|
|
{
|
|
a: []uint64{0},
|
|
value: 1,
|
|
exp: -2,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("%d in %v", test.value, test.a), func(t *testing.T) {
|
|
actual := search64(test.a, test.value)
|
|
if actual != test.exp {
|
|
t.Errorf("got: %d, exp: %d", actual, test.exp)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIntersectArrayBitmap(t *testing.T) {
|
|
a, b := &container{containerType: ContainerArray}, &container{
|
|
containerType: ContainerBitmap,
|
|
bitmap: make([]uint64, bitmapN),
|
|
}
|
|
tests := []struct {
|
|
array []uint16
|
|
bitmap []uint64
|
|
exp []uint16
|
|
}{
|
|
{
|
|
array: []uint16{0},
|
|
bitmap: []uint64{1},
|
|
exp: []uint16{0},
|
|
},
|
|
{
|
|
array: []uint16{0, 1},
|
|
bitmap: []uint64{3},
|
|
exp: []uint16{0, 1},
|
|
},
|
|
{
|
|
array: []uint16{64, 128, 129, 2000},
|
|
bitmap: []uint64{932421, 2},
|
|
exp: []uint16{},
|
|
},
|
|
{
|
|
array: []uint16{0, 65, 130, 195},
|
|
bitmap: []uint64{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
|
exp: []uint16{0, 65, 130, 195},
|
|
},
|
|
{
|
|
array: []uint16{63, 120, 543, 639, 12000},
|
|
bitmap: []uint64{0x8000000000000000, 0, 0, 0, 0, 0, 0, 0, 0, 0x8000000000000000},
|
|
exp: []uint16{63, 639},
|
|
},
|
|
{
|
|
array: []uint16{0, 1, 63, 120, 543, 639, 12000, 65534, 65535},
|
|
bitmap: bitmapOdds(),
|
|
exp: []uint16{1, 63, 543, 639, 65535},
|
|
},
|
|
{
|
|
array: []uint16{0, 1, 63, 120, 543, 639, 12000, 65534, 65535},
|
|
bitmap: bitmapEvens(),
|
|
exp: []uint16{0, 120, 12000, 65534},
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
a.array = test.array
|
|
a.containerType = ContainerArray
|
|
for i, bmval := range test.bitmap {
|
|
b.bitmap[i] = bmval
|
|
}
|
|
b.containerType = ContainerBitmap
|
|
ret := intersectArrayBitmap(a, b).array
|
|
if len(ret) == 0 && len(test.exp) == 0 {
|
|
continue
|
|
}
|
|
if !reflect.DeepEqual(ret, test.exp) {
|
|
t.Fatalf("test #%v intersectArrayBitmap received: %v exp: %v", i, ret, test.exp)
|
|
}
|
|
}
|
|
}
|
|
|
|
func bitmapOdds() []uint64 {
|
|
bitmap := make([]uint64, bitmapN)
|
|
for i := 0; i < bitmapN; i++ {
|
|
bitmap[i] = 0xAAAAAAAAAAAAAAAA
|
|
}
|
|
return bitmap
|
|
}
|
|
|
|
func bitmapEvens() []uint64 {
|
|
bitmap := make([]uint64, bitmapN)
|
|
for i := 0; i < bitmapN; i++ {
|
|
bitmap[i] = 0x5555555555555555
|
|
}
|
|
return bitmap
|
|
}
|
|
|
|
var containerWidth uint64 = 65536
|
|
|
|
// rleCont returns a slice of numbers all in the range starting from
|
|
// container_width*num, and ending at container_width*(num+1)-1. If left is
|
|
// true, then the first 100 bits will be set, if mid is true, 100 bits in the
|
|
// middle will be set, if right is true, the last 100 bits will be set.
|
|
// sets 100 bits per true
|
|
func rleCont(num int, left, mid, right bool) []uint64 {
|
|
ret := make([]uint64, 0)
|
|
base := containerWidth * uint64(num)
|
|
if left {
|
|
for i := uint64(0); i < 100; i++ {
|
|
ret = append(ret, base+i)
|
|
}
|
|
}
|
|
if mid {
|
|
for i := containerWidth / 2; i < containerWidth/2+100; i++ {
|
|
ret = append(ret, base+i)
|
|
}
|
|
}
|
|
if right {
|
|
for i := containerWidth - 100; i < containerWidth; i++ {
|
|
ret = append(ret, base+i)
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// sets 2 bits per true.
|
|
func arrCont(num int, left, mid, right bool) []uint64 {
|
|
ret := make([]uint64, 0)
|
|
base := containerWidth * uint64(num)
|
|
if left {
|
|
ret = append(ret, base+0, base+2)
|
|
}
|
|
if mid {
|
|
half := containerWidth / 2
|
|
ret = append(ret, base+half, base+half+2)
|
|
}
|
|
if right {
|
|
ret = append(ret, base+containerWidth-3, base+containerWidth-1)
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// sets 6667 bits per true.
|
|
func bitCont(num int, left, mid, right bool) []uint64 {
|
|
ret := make([]uint64, 0)
|
|
base := containerWidth * uint64(num)
|
|
if left {
|
|
for i := uint64(0); i < 20001; i += 3 {
|
|
ret = append(ret, base+i)
|
|
}
|
|
}
|
|
if mid {
|
|
for i := uint64(21000); i < 41001; i += 3 {
|
|
ret = append(ret, base+i)
|
|
}
|
|
}
|
|
if right {
|
|
for i := uint64(45537); i <= 65535; i += 3 {
|
|
ret = append(ret, base+i)
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func bitmapVariousContainers() *Bitmap {
|
|
bits := make([]uint64, 0)
|
|
bits = append(bits, rleCont(0, true, true, true)...)
|
|
bits = append(bits, rleCont(1, true, true, true)...)
|
|
bits = append(bits, arrCont(2, true, true, true)...)
|
|
bits = append(bits, arrCont(3, true, true, true)...)
|
|
bits = append(bits, bitCont(4, true, true, true)...)
|
|
bits = append(bits, bitCont(5, true, true, true)...)
|
|
bits = append(bits, rleCont(6, true, true, true)...)
|
|
bits = append(bits, bitCont(7, true, true, true)...)
|
|
bits = append(bits, arrCont(8, true, true, true)...)
|
|
bits = append(bits, rleCont(9, true, true, true)...)
|
|
bm := NewBitmap(bits...)
|
|
bm.Optimize()
|
|
return bm
|
|
}
|