cleanup - setting cardinality and conversions

This commit is contained in:
Matt Jaffee 2017-05-30 20:57:15 -05:00
parent c17c737264
commit 88e0e4d5b6
2 changed files with 89 additions and 15 deletions

View file

@ -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 {

View file

@ -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)
}
}
}