Skip to content

Commit 0a6691a

Browse files
authored
Merge pull request #130 from maciej/rle-fast-and-array
Port Java version of array-run container intersection algorithm
2 parents a817a13 + ce9cbe5 commit 0a6691a

File tree

3 files changed

+40
-51
lines changed

3 files changed

+40
-51
lines changed

arraycontainer.go

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -517,19 +517,11 @@ func (ac *arrayContainer) iand(a container) container {
517517
if x.isFull() {
518518
return ac.clone()
519519
}
520-
return ac.iandRun16(x)
520+
return x.andArray(ac)
521521
}
522522
panic("unsupported container type")
523523
}
524524

525-
func (ac *arrayContainer) iandRun16(rc *runContainer16) container {
526-
bc1 := ac.toBitmapContainer()
527-
bc2 := newBitmapContainerFromRun(rc)
528-
bc2.iandBitmap(bc1)
529-
*ac = *newArrayContainerFromBitmap(bc2)
530-
return ac
531-
}
532-
533525
func (ac *arrayContainer) iandBitmap(bc *bitmapContainer) container {
534526
pos := 0
535527
c := ac.getCardinality()

rlei.go

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,6 @@ func (rc *runContainer16) andBitmapContainer(bc *bitmapContainer) container {
6262
return bc2.andBitmap(bc)
6363
}
6464

65-
func (rc *runContainer16) andArray(ac *arrayContainer) container {
66-
bc1 := ac.toBitmapContainer()
67-
bc2 := newBitmapContainerFromRun(rc)
68-
return bc2.andBitmap(bc1)
69-
}
70-
7165
func (rc *runContainer16) andArrayCardinality(ac *arrayContainer) int {
7266
pos := 0
7367
answer := 0
@@ -105,7 +99,7 @@ func (rc *runContainer16) iand(a container) container {
10599
case *runContainer16:
106100
return rc.inplaceIntersect(c)
107101
case *arrayContainer:
108-
return rc.iandArray(c)
102+
return rc.andArray(c)
109103
case *bitmapContainer:
110104
return rc.iandBitmapContainer(c)
111105
}
@@ -127,38 +121,34 @@ func (rc *runContainer16) iandBitmapContainer(bc *bitmapContainer) container {
127121
return rc
128122
}
129123

130-
func (rc *runContainer16) iandArray(ac *arrayContainer) container {
131-
132-
bc1 := newBitmapContainerFromRun(rc)
133-
bc2 := ac.toBitmapContainer()
134-
and := bc1.andBitmap(bc2)
135-
var rc2 *runContainer16
136-
switch x := and.(type) {
137-
case *bitmapContainer:
138-
rc2 = newRunContainer16FromBitmapContainer(x)
139-
case *arrayContainer:
140-
rc2 = newRunContainer16FromArray(x)
141-
case *runContainer16:
142-
rc2 = x
143-
default:
144-
panic("unknown container type")
124+
func (rc *runContainer16) andArray(ac *arrayContainer) container {
125+
if len(rc.iv) == 0 {
126+
return newArrayContainer()
145127
}
146-
*rc = *rc2
147-
return rc
148128

149-
/*
150-
// TODO: optimize by doing less allocation, possibly?
151-
out := newRunContainer16()
152-
for _, p := range rc.iv {
153-
for i := p.start; i <= p.last; i++ {
154-
if ac.contains(i) {
155-
out.Add(i)
156-
}
129+
acCardinality := ac.getCardinality()
130+
c := newArrayContainerCapacity(acCardinality)
131+
132+
for rlePos, arrayPos := 0, 0; arrayPos < acCardinality; {
133+
iv := rc.iv[rlePos]
134+
arrayVal := ac.content[arrayPos]
135+
136+
for iv.last() < arrayVal {
137+
rlePos++
138+
if rlePos == len(rc.iv) {
139+
return c
157140
}
141+
iv = rc.iv[rlePos]
158142
}
159-
*rc = *out
160-
return rc
161-
*/
143+
144+
if iv.start > arrayVal {
145+
arrayPos = advanceUntil(ac.content, arrayPos, len(ac.content), iv.start)
146+
} else {
147+
c.content = append(c.content, arrayVal)
148+
arrayPos++
149+
}
150+
}
151+
return c
162152
}
163153

164154
func (rc *runContainer16) andNot(a container) container {

rlei_test.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -402,13 +402,13 @@ func TestRle16RandomInplaceIntersectAgainstOtherContainers014(t *testing.T) {
402402
// vs runContainer
403403
rcb := newRunContainer16FromVals(false, b...)
404404

405-
rcVsBcIsect := rc.Clone()
406-
rcVsAcIsect := rc.Clone()
407-
rcVsRcbIsect := rc.Clone()
405+
var rcVsBcIsect container = rc.Clone()
406+
var rcVsAcIsect container = rc.Clone()
407+
var rcVsRcbIsect container = rc.Clone()
408408

409-
rcVsBcIsect.iand(bc)
410-
rcVsAcIsect.iand(ac)
411-
rcVsRcbIsect.iand(rcb)
409+
rcVsBcIsect = rcVsBcIsect.iand(bc)
410+
rcVsAcIsect = rcVsAcIsect.iand(ac)
411+
rcVsRcbIsect = rcVsRcbIsect.iand(rcb)
412412

413413
p("rcVsBcIsect is %v", rcVsBcIsect)
414414
p("rcVsAcIsect is %v", rcVsAcIsect)
@@ -1603,7 +1603,6 @@ type twofer struct {
16031603
}
16041604

16051605
func TestAllContainerMethodsAllContainerTypesWithData067(t *testing.T) {
1606-
16071606
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() {
16081607

16091608
//rleVerbose = true
@@ -1688,6 +1687,14 @@ func TestAllContainerMethodsAllContainerTypesWithData067(t *testing.T) {
16881687

16891688
z := c1.name
16901689

1690+
// In-place operation are best effort
1691+
// User should not assume the receiver is modified, returned container has to be used
1692+
if strings.HasPrefix(z, "i") {
1693+
c1.cn = res1
1694+
c2.cn = res2
1695+
c3.cn = res3
1696+
}
1697+
16911698
if strings.HasPrefix(z, "lazy") {
16921699
// on purpose, the lazy functions
16931700
// do not scan to update their cardinality

0 commit comments

Comments
 (0)