From 97346baa94e69d5b61a204f735d52f36e05dd6e4 Mon Sep 17 00:00:00 2001 From: Matt Jaffee Date: Tue, 30 May 2017 15:57:32 -0500 Subject: [PATCH] unionArrayRun implementation --- roaring/roaring.go | 28 +++++++++++++++++++--- roaring/roaring_internal_test.go | 40 ++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/roaring/roaring.go b/roaring/roaring.go index c032a83cd..7e23fae82 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -1860,8 +1860,31 @@ func unionArrayArray(a, b *container) *container { return output } +// unionArrayRun optimistically assumes that the result will be a run container, +// and converts to a bitmap or array container afterwards if necessary. func unionArrayRun(a, b *container) *container { - return nil + output := &container{} + na, nb := len(a.array), len(b.runs) + var vb interval32 + var va uint32 + for i, j := 0, 0; i < na || j < nb; { + if i < na { + va = a.array[i] + } + if j < nb { + vb = b.runs[j] + } + if i < na && (j >= nb || va < vb.start) { + output.runAppendInterval(interval32{start: va, last: va}) + i++ + } else { + output.runAppendInterval(vb) + j++ + } + } + return output +} + func (c *container) runAppendInterval(v interval32) { if len(c.runs) == 0 { c.runs = append(c.runs, v) @@ -1880,9 +1903,8 @@ func unionRunRun(a, b *container) *container { output := &container{ runs: make([]interval32, 0, na+nb), } - i, j := 0, 0 var va, vb interval32 - for i < na || j < nb { + for i, j := 0, 0; i < na || j < nb; { if i < na { va = a.runs[i] } diff --git a/roaring/roaring_internal_test.go b/roaring/roaring_internal_test.go index 5c8e46f93..324d4f670 100644 --- a/roaring/roaring_internal_test.go +++ b/roaring/roaring_internal_test.go @@ -584,3 +584,43 @@ func TestUnionRunRun(t *testing.T) { } } } + +func TestUnionArrayRun(t *testing.T) { + a := &container{} + b := &container{} + tests := []struct { + array []uint32 + runs []interval32 + exp []interval32 + }{ + { + array: []uint32{1, 4, 5, 7, 10, 11, 12}, + runs: []interval32{{start: 5, last: 10}}, + exp: []interval32{{start: 1, last: 1}, {start: 4, last: 12}}, + }, + { + array: []uint32{}, + runs: []interval32{{start: 5, last: 10}}, + exp: []interval32{{start: 5, last: 10}}, + }, + { + array: []uint32{1, 4, 5, 7, 10, 11, 12}, + runs: []interval32{}, + exp: []interval32{{start: 1, last: 1}, {start: 4, last: 5}, {start: 7, last: 7}, {start: 10, last: 12}}, + }, + { + array: []uint32{0, 1, 4, 5, 7, 10, 11, 12}, + runs: []interval32{{start: 0, last: 5}, {start: 7, last: 7}}, + exp: []interval32{{start: 0, last: 5}, {start: 7, last: 7}, {start: 10, last: 12}}, + }, + } + + for i, test := range tests { + a.array = test.array + b.runs = test.runs + ret := unionArrayRun(a, b) + if !reflect.DeepEqual(ret.runs, test.exp) { + t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.array) + } + } +}