mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-10-09 20:37:52 +00:00
cleanup - setting cardinality and conversions
This commit is contained in:
parent
c17c737264
commit
88e0e4d5b6
2 changed files with 89 additions and 15 deletions
|
|
@ -892,6 +892,9 @@ func (itr *BufIterator) Unread() {
|
|||
// The maximum size of array containers.
|
||||
const ArrayMaxSize = 4096
|
||||
|
||||
// The maximum size of run length encoded containers.
|
||||
const RunMaxSize = 2048
|
||||
|
||||
// container represents a container for uint32 integers.
|
||||
//
|
||||
// These are used for storing the low bits. Containers are separated into two
|
||||
|
|
@ -1316,6 +1319,22 @@ func (c *container) arrayToBitmap() {
|
|||
c.mapped = false
|
||||
}
|
||||
|
||||
func (c *container) runToBitmap() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
func (c *container) bitmapToRun() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
func (c *container) arrayToRun() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
func (c *container) runToArray() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
// clone returns a copy of c.
|
||||
func (c *container) clone() *container {
|
||||
other := &container{n: c.n}
|
||||
|
|
@ -1666,12 +1685,8 @@ func intersectArrayRun(a, b *container) *container {
|
|||
return output
|
||||
}
|
||||
|
||||
// intersectRunRun computes the intersect of two run containers. The output is
|
||||
// always a run container, since it can't possible have more runs than either of
|
||||
// the inputs. (note: it is possible that an array container would be better in
|
||||
// some cases, but probably not worth complicating the implementation)
|
||||
// intersectRunRun computes the intersect of two run containers.
|
||||
func intersectRunRun(a, b *container) *container {
|
||||
// TODO need to take the last element of output.runs into account during each loop - possible that instead of appending, the last run should just be expanded
|
||||
output := &container{}
|
||||
na, nb := len(a.runs), len(b.runs)
|
||||
for i, j := 0, 0; i < na && j < nb; {
|
||||
|
|
@ -1684,23 +1699,27 @@ func intersectRunRun(a, b *container) *container {
|
|||
j++
|
||||
} else if va.last > vb.last && va.start >= vb.start {
|
||||
// |--vb-|-|-va--|
|
||||
output.runAppendInterval(interval32{start: va.start, last: vb.last})
|
||||
output.n += output.runAppendInterval(interval32{start: va.start, last: vb.last})
|
||||
j++
|
||||
} else if va.last > vb.last && va.start < vb.start {
|
||||
// |--va|--vb--|--|
|
||||
output.runAppendInterval(vb)
|
||||
output.n += output.runAppendInterval(vb)
|
||||
j++
|
||||
} else if va.last <= vb.last && va.start >= vb.start {
|
||||
// |--vb|--va--|--|
|
||||
output.runs = append(output.runs, va)
|
||||
output.runAppendInterval(va)
|
||||
output.n += output.runAppendInterval(va)
|
||||
i++
|
||||
} else if va.last <= vb.last && va.start < vb.start {
|
||||
// |--va-|-|-vb--|
|
||||
output.runAppendInterval(interval32{start: vb.start, last: va.last})
|
||||
output.n += output.runAppendInterval(interval32{start: vb.start, last: va.last})
|
||||
i++
|
||||
}
|
||||
}
|
||||
if n < 4096 && len(output.runs) > n/2 {
|
||||
output.runToArray()
|
||||
} else if len(output.runs) > RunMaxSize {
|
||||
output.runToBitmap()
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
|
|
@ -1886,17 +1905,27 @@ func unionArrayRun(a, b *container) *container {
|
|||
return output
|
||||
}
|
||||
|
||||
func (c *container) runAppendInterval(v interval32) {
|
||||
// runAppendInterval adds the given interval to the run container. It assumes
|
||||
// that the interval comes at the end of the list of runs, and does not check
|
||||
// that this is the case. It will not behave correctly if the start of the given
|
||||
// interval is earlier than the start of the last interval in the list of runs.
|
||||
// Its return value is the amount by which the cardinality of the container was
|
||||
// increased.
|
||||
func (c *container) runAppendInterval(v interval32) int {
|
||||
if len(c.runs) == 0 {
|
||||
c.runs = append(c.runs, v)
|
||||
return int(v.last - v.start + 1)
|
||||
} else {
|
||||
lastidx := len(c.runs) - 1
|
||||
if c.runs[lastidx].last+1 >= v.start && v.last > c.runs[lastidx].last {
|
||||
c.runs[lastidx].last = v.last
|
||||
} else if c.runs[lastidx].last+1 < v.start {
|
||||
last := c.runs[len(c.runs)-1]
|
||||
if last.last+1 >= v.start && v.last > last.last {
|
||||
c.runs[len(c.runs)-1].last = v.last
|
||||
return int(v.last - last.last)
|
||||
} else if last.last+1 < v.start {
|
||||
c.runs = append(c.runs, v)
|
||||
return int(v.last - v.start + 1)
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func unionRunRun(a, b *container) *container {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,44 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func TestRunAppendInterval(t *testing.T) {
|
||||
a := container{}
|
||||
tests := []struct {
|
||||
base []interval32
|
||||
app interval32
|
||||
exp int
|
||||
}{
|
||||
{
|
||||
base: []interval32{},
|
||||
app: interval32{start: 22, last: 25},
|
||||
exp: 4,
|
||||
},
|
||||
{
|
||||
base: []interval32{{start: 20, last: 23}},
|
||||
app: interval32{start: 22, last: 25},
|
||||
exp: 2,
|
||||
},
|
||||
{
|
||||
base: []interval32{{start: 20, last: 23}},
|
||||
app: interval32{start: 21, last: 22},
|
||||
exp: 0,
|
||||
},
|
||||
{
|
||||
base: []interval32{{start: 20, last: 23}},
|
||||
app: interval32{start: 19, last: 25},
|
||||
exp: 3,
|
||||
},
|
||||
}
|
||||
|
||||
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 TestInterval32RunLen(t *testing.T) {
|
||||
iv := interval32{start: 7, last: 9}
|
||||
if iv.runlen() != 3 {
|
||||
|
|
@ -399,21 +437,25 @@ func TestIntersectRunRun(t *testing.T) {
|
|||
aruns []interval32
|
||||
bruns []interval32
|
||||
exp []interval32
|
||||
expN int
|
||||
}{
|
||||
{
|
||||
aruns: []interval32{},
|
||||
bruns: []interval32{{start: 5, last: 10}},
|
||||
exp: []interval32(nil),
|
||||
expN: 0,
|
||||
},
|
||||
{
|
||||
aruns: []interval32{{start: 5, last: 12}},
|
||||
bruns: []interval32{{start: 5, last: 10}},
|
||||
exp: []interval32{{start: 5, last: 10}},
|
||||
expN: 6,
|
||||
},
|
||||
{
|
||||
aruns: []interval32{{start: 1, last: 3}, {start: 5, last: 5}, {start: 7, last: 8}, {start: 9, last: 12}},
|
||||
bruns: []interval32{{start: 5, last: 10}},
|
||||
exp: []interval32{{start: 5, last: 5}, {start: 7, last: 10}},
|
||||
expN: 5,
|
||||
},
|
||||
}
|
||||
for i, test := range tests {
|
||||
|
|
@ -423,6 +465,9 @@ func TestIntersectRunRun(t *testing.T) {
|
|||
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 to be %v, but got %v", i, test.expN, ret.n)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue