From ceab3d473a6473f3e97c7b9c42f86ed878f563ce Mon Sep 17 00:00:00 2001 From: Maciej Bilas Date: Wed, 3 Jan 2018 18:12:47 +0100 Subject: [PATCH 1/2] rlei_test: don't assume iand or ior are always in-place In TestRle16RandomInplaceIntersectAgainstOtherContainers014 and in TestAllContainerMethodsAllContainerTypesWithData067 don't assume that an `iand` or `ior` will be inplace. It's best effort. Sometimes the resulting container can be of a different type. --- rlei_test.go | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/rlei_test.go b/rlei_test.go index 80b72d59..9ddec5e7 100644 --- a/rlei_test.go +++ b/rlei_test.go @@ -402,13 +402,13 @@ func TestRle16RandomInplaceIntersectAgainstOtherContainers014(t *testing.T) { // vs runContainer rcb := newRunContainer16FromVals(false, b...) - rcVsBcIsect := rc.Clone() - rcVsAcIsect := rc.Clone() - rcVsRcbIsect := rc.Clone() + var rcVsBcIsect container = rc.Clone() + var rcVsAcIsect container = rc.Clone() + var rcVsRcbIsect container = rc.Clone() - rcVsBcIsect.iand(bc) - rcVsAcIsect.iand(ac) - rcVsRcbIsect.iand(rcb) + rcVsBcIsect = rcVsBcIsect.iand(bc) + rcVsAcIsect = rcVsAcIsect.iand(ac) + rcVsRcbIsect = rcVsRcbIsect.iand(rcb) p("rcVsBcIsect is %v", rcVsBcIsect) p("rcVsAcIsect is %v", rcVsAcIsect) @@ -1603,7 +1603,6 @@ type twofer struct { } func TestAllContainerMethodsAllContainerTypesWithData067(t *testing.T) { - Convey("each of the container methods that takes two containers should handle all 3x3==9 possible ways of being called -- and return results that agree with each other", t, func() { //rleVerbose = true @@ -1687,6 +1686,14 @@ func TestAllContainerMethodsAllContainerTypesWithData067(t *testing.T) { z := c1.name + // In-place operation are best effort + // User should not assume the receiver is modified, returned container has to be used + if strings.HasPrefix(z, "i") { + c1.cn = res1 + c2.cn = res2 + c3.cn = res3 + } + if strings.HasPrefix(z, "lazy") { // on purpose, the lazy functions // do not scan to update their cardinality From ce9cbe5a9a85f32239ab6d6990b1e25fcea1ed78 Mon Sep 17 00:00:00 2001 From: Maciej Bilas Date: Wed, 3 Jan 2018 19:24:14 +0100 Subject: [PATCH 2/2] Port Java version of array-run container intersection algorithm This commit ports the Java version of the array-run intersection algorithm. In a private benchmark the performance improves significantly. --- arraycontainer.go | 10 +------- rlei.go | 60 ++++++++++++++++++++--------------------------- 2 files changed, 26 insertions(+), 44 deletions(-) diff --git a/arraycontainer.go b/arraycontainer.go index f7b8be5c..82eaec84 100644 --- a/arraycontainer.go +++ b/arraycontainer.go @@ -517,19 +517,11 @@ func (ac *arrayContainer) iand(a container) container { if x.isFull() { return ac.clone() } - return ac.iandRun16(x) + return x.andArray(ac) } panic("unsupported container type") } -func (ac *arrayContainer) iandRun16(rc *runContainer16) container { - bc1 := ac.toBitmapContainer() - bc2 := newBitmapContainerFromRun(rc) - bc2.iandBitmap(bc1) - *ac = *newArrayContainerFromBitmap(bc2) - return ac -} - func (ac *arrayContainer) iandBitmap(bc *bitmapContainer) container { pos := 0 c := ac.getCardinality() diff --git a/rlei.go b/rlei.go index 0da3422a..e97a3da5 100644 --- a/rlei.go +++ b/rlei.go @@ -62,12 +62,6 @@ func (rc *runContainer16) andBitmapContainer(bc *bitmapContainer) container { return bc2.andBitmap(bc) } -func (rc *runContainer16) andArray(ac *arrayContainer) container { - bc1 := ac.toBitmapContainer() - bc2 := newBitmapContainerFromRun(rc) - return bc2.andBitmap(bc1) -} - func (rc *runContainer16) andArrayCardinality(ac *arrayContainer) int { pos := 0 answer := 0 @@ -105,7 +99,7 @@ func (rc *runContainer16) iand(a container) container { case *runContainer16: return rc.inplaceIntersect(c) case *arrayContainer: - return rc.iandArray(c) + return rc.andArray(c) case *bitmapContainer: return rc.iandBitmapContainer(c) } @@ -127,38 +121,34 @@ func (rc *runContainer16) iandBitmapContainer(bc *bitmapContainer) container { return rc } -func (rc *runContainer16) iandArray(ac *arrayContainer) container { - - bc1 := newBitmapContainerFromRun(rc) - bc2 := ac.toBitmapContainer() - and := bc1.andBitmap(bc2) - var rc2 *runContainer16 - switch x := and.(type) { - case *bitmapContainer: - rc2 = newRunContainer16FromBitmapContainer(x) - case *arrayContainer: - rc2 = newRunContainer16FromArray(x) - case *runContainer16: - rc2 = x - default: - panic("unknown container type") +func (rc *runContainer16) andArray(ac *arrayContainer) container { + if len(rc.iv) == 0 { + return newArrayContainer() } - *rc = *rc2 - return rc - /* - // TODO: optimize by doing less allocation, possibly? - out := newRunContainer16() - for _, p := range rc.iv { - for i := p.start; i <= p.last; i++ { - if ac.contains(i) { - out.Add(i) - } + acCardinality := ac.getCardinality() + c := newArrayContainerCapacity(acCardinality) + + for rlePos, arrayPos := 0, 0; arrayPos < acCardinality; { + iv := rc.iv[rlePos] + arrayVal := ac.content[arrayPos] + + for iv.last() < arrayVal { + rlePos++ + if rlePos == len(rc.iv) { + return c } + iv = rc.iv[rlePos] } - *rc = *out - return rc - */ + + if iv.start > arrayVal { + arrayPos = advanceUntil(ac.content, arrayPos, len(ac.content), iv.start) + } else { + c.content = append(c.content, arrayVal) + arrayPos++ + } + } + return c } func (rc *runContainer16) andNot(a container) container {