mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-10-08 20:07:51 +00:00
added roaring min
This commit is contained in:
parent
c8a3dc8c18
commit
f15cb9e05c
5 changed files with 144 additions and 5 deletions
|
|
@ -114,6 +114,13 @@ func (sc *sliceContainers) Clone() Containers {
|
|||
return other
|
||||
}
|
||||
|
||||
func (sc *sliceContainers) First() (key uint64, c *Container) {
|
||||
if len(sc.keys) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
return sc.keys[0], sc.containers[0]
|
||||
}
|
||||
|
||||
func (sc *sliceContainers) Last() (key uint64, c *Container) {
|
||||
if len(sc.keys) == 0 {
|
||||
return 0, nil
|
||||
|
|
|
|||
|
|
@ -142,6 +142,13 @@ func (btc *bTreeContainers) Clone() Containers {
|
|||
return nbtc
|
||||
}
|
||||
|
||||
func (btc *bTreeContainers) First() (key uint64, c *Container) {
|
||||
if btc.tree.Len() == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
return btc.tree.First()
|
||||
}
|
||||
|
||||
func (btc *bTreeContainers) Last() (key uint64, c *Container) {
|
||||
if btc.tree.Len() == 0 {
|
||||
return 0, nil
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
package roaring
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -98,5 +99,46 @@ func testContainersIterator(cs Containers, t *testing.T) {
|
|||
if itr.Next() {
|
||||
t.Fatalf("itr should be done, but got true")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestContainers(t *testing.T) {
|
||||
cs := NewFileBitmap().Containers
|
||||
first := NewContainerArray([]uint16{1, 2, 3})
|
||||
last := NewContainerArray([]uint16{1, 2, 3, 4, 5, 6})
|
||||
cs.Put(3, first)
|
||||
cs.Put(6, last)
|
||||
|
||||
key, container := cs.First()
|
||||
if key != 3 {
|
||||
t.Fatalf("cs.First key 3 != %d", key)
|
||||
}
|
||||
if !reflect.DeepEqual(first, container) {
|
||||
t.Fatalf("cs.First container %v != %v", first, container)
|
||||
}
|
||||
|
||||
key, container = cs.Last()
|
||||
if key != 6 {
|
||||
t.Fatalf("cs.First key 6 != %d", key)
|
||||
}
|
||||
if !reflect.DeepEqual(last, container) {
|
||||
t.Fatalf("cs.First container %v != %v", last, container)
|
||||
}
|
||||
|
||||
cs = NewFileBitmap().Containers
|
||||
|
||||
key, container = cs.First()
|
||||
if key != 0 {
|
||||
t.Fatalf("cs.First key 0 != %d", key)
|
||||
}
|
||||
if nil != container {
|
||||
t.Fatalf("cs.First container nil != %v", container)
|
||||
}
|
||||
|
||||
key, container = cs.Last()
|
||||
if key != 0 {
|
||||
t.Fatalf("cs.First key 0 != %d", key)
|
||||
}
|
||||
if nil != container {
|
||||
t.Fatalf("cs.First container nil != %v", container)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,6 +95,9 @@ type Containers interface {
|
|||
// Clone does a deep copy of Containers, including cloning all containers contained.
|
||||
Clone() Containers
|
||||
|
||||
// First returns the lowest key and associated container.
|
||||
First() (key uint64, c *Container)
|
||||
|
||||
// Last returns the highest key and associated container.
|
||||
Last() (key uint64, c *Container)
|
||||
|
||||
|
|
@ -320,6 +323,18 @@ func (b *Bitmap) remove(v uint64) bool {
|
|||
return c.remove(lowbits(v))
|
||||
}
|
||||
|
||||
// Min returns the lowest value in the bitmap.
|
||||
// Second return value is true if containers exist in the bitmap.
|
||||
func (b *Bitmap) Min() (uint64, bool) {
|
||||
if b.Containers.Size() == 0 {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
hb, c := b.Containers.First()
|
||||
lb, ok := c.min()
|
||||
return hb<<16 | uint64(lb), ok
|
||||
}
|
||||
|
||||
// Max returns the highest value in the bitmap.
|
||||
// Returns zero if the bitmap is empty.
|
||||
func (b *Bitmap) Max() uint64 {
|
||||
|
|
@ -1860,6 +1875,17 @@ func (c *Container) runRemove(v uint16) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// min returns the minimum value in the container.
|
||||
func (c *Container) min() (uint16, bool) {
|
||||
if c.isArray() {
|
||||
return c.arrayMin()
|
||||
} else if c.isRun() {
|
||||
return c.runMin()
|
||||
} else {
|
||||
return c.bitmapMin()
|
||||
}
|
||||
}
|
||||
|
||||
// max returns the maximum value in the container.
|
||||
func (c *Container) max() uint16 {
|
||||
if c.isArray() {
|
||||
|
|
@ -1871,6 +1897,15 @@ func (c *Container) max() uint16 {
|
|||
}
|
||||
}
|
||||
|
||||
// Second result value is true if array is non-empty.
|
||||
func (c *Container) arrayMin() (uint16, bool) {
|
||||
array := c.array()
|
||||
if len(array) == 0 {
|
||||
return 0, false
|
||||
}
|
||||
return array[0], true
|
||||
}
|
||||
|
||||
func (c *Container) arrayMax() uint16 {
|
||||
array := c.array()
|
||||
if len(array) == 0 {
|
||||
|
|
@ -1879,21 +1914,43 @@ func (c *Container) arrayMax() uint16 {
|
|||
return array[len(array)-1]
|
||||
}
|
||||
|
||||
// Second result value is true if array is non-empty.
|
||||
func (c *Container) bitmapMin() (uint16, bool) {
|
||||
bitmap := c.bitmap()
|
||||
for i := 0; i < len(bitmap); i++ {
|
||||
// If value is zero then skip.
|
||||
v := bitmap[i]
|
||||
if v != 0 {
|
||||
r := bits.TrailingZeros64(v)
|
||||
return uint16(r + i*64), true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func (c *Container) bitmapMax() uint16 {
|
||||
// Search bitmap in reverse order.
|
||||
bitmap := c.bitmap()
|
||||
for i := len(bitmap); i > 0; i-- {
|
||||
for i := len(bitmap) - 1; i > 0; i-- {
|
||||
// If value is zero then skip.
|
||||
v := bitmap[i-1]
|
||||
v := bitmap[i]
|
||||
if v != 0 {
|
||||
r := bits.LeadingZeros64(v)
|
||||
return uint16((i-1)*64 + 63 - r)
|
||||
return uint16(i*64 + 63 - r)
|
||||
}
|
||||
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Second result value is true if array is non-empty.
|
||||
func (c *Container) runMin() (uint16, bool) {
|
||||
runs := c.runs()
|
||||
if len(runs) == 0 {
|
||||
return 0, false
|
||||
}
|
||||
return runs[0].start, true
|
||||
}
|
||||
|
||||
func (c *Container) runMax() uint16 {
|
||||
runs := c.runs()
|
||||
if len(runs) == 0 {
|
||||
|
|
|
|||
|
|
@ -309,6 +309,32 @@ func TestBitmap_Max(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Ensure bitmap can return the lowest value.
|
||||
func TestBitmap_Min(t *testing.T) {
|
||||
bm := roaring.NewFileBitmap()
|
||||
for i := uint64(100000); i > 0; i-- {
|
||||
if _, err := bm.Add(i); err != nil {
|
||||
t.Fatalf("adding bits: %v", err)
|
||||
}
|
||||
|
||||
v, ok := bm.Min()
|
||||
if !ok {
|
||||
t.Fatalf("ok should be true")
|
||||
}
|
||||
|
||||
if v != i {
|
||||
t.Fatalf("min: got=%d; want=%d", v, i)
|
||||
}
|
||||
}
|
||||
|
||||
// empty bitmap
|
||||
bm = roaring.NewFileBitmap()
|
||||
_, ok := bm.Min()
|
||||
if ok {
|
||||
t.Fatalf("ok should be false")
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure CountRange is correct even if rangekey is prior to initial container.
|
||||
func TestBitmap_BitmapCountRangeEdgeCase(t *testing.T) {
|
||||
s := uint64(2009 * pilosa.ShardWidth)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue