mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-10-07 11:27:50 +00:00
On a 64-bit machine, the slices in a Container consume 72 bytes, and the Container itself is 80. But we only use one slice at a time! This patch shifts us to keeping a single slice in the Container, and converting provided slices to and from that type when we want to update it. (It is not safe to access the slice through the wrong type.) We also add some new tests, conditional on a build tag called `roaringparanoia`. These tests will be optimized away entirely by the compiler when the tag isn't present, because the conditionals use a const. These catch possible errors like trying to access the bitmap slice of a non-bitmap container. We also eliminate all direct creation of Container literals, so we can mess with the internals more. (On reflection and study, we decided not to go to the fancier design where references to .n and .typ were also converted to function calls, which would have allowed packing those attributes more tightly, because it was a lot more overhead and a lot of work to keep track of.) There's some circumstances where we appear to have been relying on incorrect guesses about the nature of containers. For instance, in xorBitmapRun, there's logic that makes sense only if the output's a run container, but it's not, it's a bitmap container. This creates strange behavior sometimes, though. Several of these are corrected now.
102 lines
2.7 KiB
Go
102 lines
2.7 KiB
Go
// Copyright (C) 2017-2018 Pilosa Corp. All rights reserved.
|
|
//
|
|
// 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 (
|
|
"testing"
|
|
)
|
|
|
|
func TestContainersIterator(t *testing.T) {
|
|
slc := NewFileBitmap().Containers
|
|
testContainersIterator(slc, t)
|
|
}
|
|
|
|
func testContainersIterator(cs Containers, t *testing.T) {
|
|
itr, found := cs.Iterator(0)
|
|
if found {
|
|
t.Fatalf("shouldn't have found 0 in empty btc")
|
|
}
|
|
if itr.Next() {
|
|
t.Fatal("Next() should be false for empty btc")
|
|
}
|
|
|
|
cs.Put(1, NewContainerArray([]uint16{1}))
|
|
cs.Put(2, NewContainerArray([]uint16{1, 2}))
|
|
|
|
itr, found = cs.Iterator(0)
|
|
if found {
|
|
t.Fatalf("shouldn't have found 0")
|
|
}
|
|
|
|
if !itr.Next() {
|
|
t.Fatalf("one should be next, but got false")
|
|
}
|
|
if key, val := itr.Value(); key != 1 || val.n != 1 {
|
|
t.Fatalf("Wrong k/v, exp: 1,1 got: %v,%v", key, val.n)
|
|
}
|
|
if !itr.Next() {
|
|
t.Fatalf("two should be next, but got false")
|
|
}
|
|
if key, val := itr.Value(); key != 2 || val.n != 2 {
|
|
t.Fatalf("Wrong k/v, exp: 2,2 got: %v,%v", key, val.n)
|
|
}
|
|
|
|
if itr.Next() {
|
|
t.Fatalf("itr should be done, but got true")
|
|
}
|
|
|
|
cs.Put(3, NewContainerArray([]uint16{1, 2, 3}))
|
|
cs.Put(5, NewContainerArray([]uint16{1, 2, 3, 4, 5}))
|
|
cs.Put(6, NewContainerArray([]uint16{1, 2, 3, 4, 5, 6}))
|
|
|
|
itr, found = cs.Iterator(3)
|
|
if !itr.Next() {
|
|
t.Fatalf("3 should be next, but got false")
|
|
}
|
|
if !found {
|
|
t.Fatalf("should have found 3")
|
|
}
|
|
if key, val := itr.Value(); key != 3 || val.n != 3 {
|
|
t.Fatalf("Wrong k/v, exp: 3,3 got: %v,%v", key, val.n)
|
|
}
|
|
if !itr.Next() {
|
|
t.Fatalf("5 should be next, but got false")
|
|
}
|
|
if key, val := itr.Value(); key != 5 || val.n != 5 {
|
|
t.Fatalf("Wrong k/v, exp: 5,5 got: %v,%v", key, val.n)
|
|
}
|
|
|
|
itr, found = cs.Iterator(4)
|
|
if found {
|
|
t.Fatalf("shouldn't have found 4")
|
|
}
|
|
if !itr.Next() {
|
|
t.Fatalf("5 should be next, but got false")
|
|
}
|
|
if key, val := itr.Value(); key != 5 || val.n != 5 {
|
|
t.Fatalf("Wrong k/v, exp: 5,5 got: %v,%v", key, val.n)
|
|
}
|
|
if !itr.Next() {
|
|
t.Fatalf("6 should be next, but got false")
|
|
}
|
|
if key, val := itr.Value(); key != 6 || val.n != 6 {
|
|
t.Fatalf("Wrong k/v, exp: 6,6 got: %v,%v", key, val.n)
|
|
}
|
|
|
|
if itr.Next() {
|
|
t.Fatalf("itr should be done, but got true")
|
|
}
|
|
|
|
}
|