diff --git a/roaring/internal_test.go b/roaring/internal_test.go deleted file mode 100644 index 107851489..000000000 --- a/roaring/internal_test.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2017 Pilosa Corp. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package roaring - -import ( - "reflect" - "testing" -) - -// Ensure iterator returns values from a bitmap. -func TestBitmapIterator(t *testing.T) { - for i, tt := range []struct { - bitmap []uint64 - values []uint16 - }{ - // Empty - { - bitmap: []uint64{6}, // 0110 - values: []uint16{1, 2}, - }, - - // Single uint64 bitmap - { - bitmap: []uint64{6}, // 0110 - values: []uint16{1, 2}, - }, - - // Multi uint64 bitmap - { - bitmap: []uint64{1 << 63, 1, 0, 1, 3 << 62}, - values: []uint16{63, 64, 192, 318, 319}, - }, - } { - itr := newBitmapIterator(tt.bitmap) - - var a []uint16 - for v, eof := itr.next(); !eof; v, eof = itr.next() { - a = append(a, v) - } - - if !reflect.DeepEqual(a, tt.values) { - t.Errorf("%d. unexpected values: exp=%+v, got=%+v", i, a, tt.values) - } - } -} diff --git a/roaring/roaring.go b/roaring/roaring.go index fc01b3783..85a975f05 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// package roaring implements roaring bitmaps with support for incremental changes. +// Package roaring implements roaring bitmaps with support for incremental changes. package roaring import ( @@ -50,11 +50,15 @@ const ( // bitmapN is the number of values in a container.bitmap. bitmapN = (1 << 16) / 64 - // manual allocation size tuned to our average client data - manualAlloc = 524288 - ContainerArray = byte(1) + //ContainerArray indicates a container of bit position values + ContainerArray = byte(1) + + //ContainerBitmap indicates a container of bits packed in a uint64 array block ContainerBitmap = byte(2) - ContainerRun = byte(3) + + //ContainerRun indicates a container of run encoded bits + ContainerRun = byte(3) + maxContainerVal = 0xffff ) @@ -128,7 +132,7 @@ func (b *Bitmap) add(v uint64) bool { // If index is negative then there's not an exact match // and a container needs to be added. if i < 0 { - b.insertAt(hb, newContainer(), int(-i-1)) + b.insertAt(hb, newContainer(), -i-1) i = -i - 1 } return b.containers[i].add(lowbits(v)) @@ -181,7 +185,7 @@ func (b *Bitmap) Max() uint64 { hb := b.keys[len(b.keys)-1] lb := b.containers[len(b.containers)-1].max() - return uint64(hb)<<16 | uint64(lb) + return hb<<16 | uint64(lb) } // Count returns the number of bits set in the bitmap. @@ -216,7 +220,7 @@ func (b *Bitmap) CountRange(start, end uint64) (n uint64) { } else { // Count first partial container and advance i so we don't recount it n += uint64(b.containers[i].countRange(int(lowbits(start)), maxContainerVal+1)) - i += 1 + i++ } // Count last container. @@ -364,10 +368,8 @@ func (b *Bitmap) Intersect(other *Bitmap) *Bitmap { if ni == 0 && nj == 0 { // eof(i,j) break } else if ni == 0 || (nj != 0 && ki[0] > kj[0]) { // eof(i) or i > j - key, container = kj[0], cj[0].clone() kj, cj = kj[1:], cj[1:] } else if nj == 0 || (ki[0] < kj[0]) { // eof(j) or i < j - key, container = ki[0], ci[0].clone() ki, ci = ki[1:], ci[1:] } else { // i == j key, container = ki[0], intersect(ci[0], cj[0]) @@ -518,19 +520,39 @@ func (b *Bitmap) Optimize() { } } -//hoping this in-lines -func WriteUint16(w io.Writer, b []byte, v uint16) (int, error) { - binary.LittleEndian.PutUint16(b, v) - return w.Write(b) -} -func WriteUint32(w io.Writer, b []byte, v uint32) (int, error) { - binary.LittleEndian.PutUint32(b, v) - return w.Write(b) +type errWriter struct { + w io.Writer + err error + n int } -func WriteUint64(w io.Writer, b []byte, v uint64) (int, error) { +func (ew *errWriter) WriteUint16(b []byte, v uint16) { + if ew.err != nil { + return + } + var n int + binary.LittleEndian.PutUint16(b, v) + n, ew.err = ew.w.Write(b) + ew.n += n +} +func (ew *errWriter) WriteUint32(b []byte, v uint32) { + if ew.err != nil { + return + } + var n int + binary.LittleEndian.PutUint32(b, v) + n, ew.err = ew.w.Write(b) + ew.n += n +} + +func (ew *errWriter) WriteUint64(b []byte, v uint64) { + if ew.err != nil { + return + } + var n int binary.LittleEndian.PutUint64(b, v) - return w.Write(b) + n, ew.err = ew.w.Write(b) + ew.n += n } // WriteTo writes b to w. @@ -546,11 +568,15 @@ func (b *Bitmap) WriteTo(w io.Writer) (n int64, err error) { byte8 := make([]byte, 8) // Build header before writing individual container blocks. - // Metadata for each container is 8+2+2+4 = sizeof(key) + sizeof(container_type)+sizeof(cardinality) + sizeof(file offset) + // Metadata for each container is 8+2+2+4 = sizeof(key) + sizeof(containerType)+sizeof(cardinality) + sizeof(file offset) // Cookie header section. + ew := &errWriter{ + w: w, + n: 0, + } - WriteUint32(w, byte4, cookie) - WriteUint32(w, byte4, uint32(containerCount)) + ew.WriteUint32(byte4, cookie) + ew.WriteUint32(byte4, uint32(containerCount)) // Descriptive header section: encode keys and cardinality. // Key and cardinality are stored interleaved here, 12 bytes per container. @@ -562,9 +588,9 @@ func (b *Bitmap) WriteTo(w io.Writer) (n int64, err error) { //count := c.count() //assert(c.count() == c.n, "cannot write container count, mismatch: count=%d, n=%d", count, c.n) if c.n > 0 { - WriteUint64(w, byte8, uint64(key)) - WriteUint16(w, byte2, uint16(c.container_type)) - WriteUint16(w, byte2, uint16(c.n-1)) + ew.WriteUint64(byte8, key) + ew.WriteUint16(byte2, uint16(c.containerType)) + ew.WriteUint16(byte2, uint16(c.n-1)) } } @@ -574,15 +600,15 @@ func (b *Bitmap) WriteTo(w io.Writer) (n int64, err error) { for _, c := range b.containers { if c.n > 0 { - WriteUint32(w, byte4, uint32(offset)) + ew.WriteUint32(byte4, offset) offset += uint32(c.size()) } } + if ew.err != nil { + return int64(ew.n), ew.err + } n = int64(headerSize + (containerCount * (8 + 2 + 2 + 4))) - if err != nil { - return n, err - } // Container storage section: write each container block. for _, c := range b.containers { @@ -638,14 +664,14 @@ func (b *Bitmap) UnmarshalBinary(data []byte) error { if i >= len(b.keys) { b.keys = append(b.keys, binary.LittleEndian.Uint64(buf[0:8])) b.containers = append(b.containers, &container{ - container_type: byte(binary.LittleEndian.Uint16(buf[8:10])), - n: int(binary.LittleEndian.Uint16(buf[10:12])) + 1, - mapped: true, + containerType: byte(binary.LittleEndian.Uint16(buf[8:10])), + n: int(binary.LittleEndian.Uint16(buf[10:12])) + 1, + mapped: true, }) } else { b.keys[i] = binary.LittleEndian.Uint64(buf[0:8]) c := b.containers[i] - c.container_type = byte(binary.LittleEndian.Uint16(buf[8:10])) + c.containerType = byte(binary.LittleEndian.Uint16(buf[8:10])) c.n = int(binary.LittleEndian.Uint16(buf[10:12])) + 1 c.mapped = true @@ -663,7 +689,7 @@ func (b *Bitmap) UnmarshalBinary(data []byte) error { // Map byte slice directly to the container data. c := b.containers[i] - switch c.container_type { + switch c.containerType { case ContainerRun: c.array = nil c.bitmap = nil @@ -692,18 +718,18 @@ func (b *Bitmap) UnmarshalBinary(data []byte) error { } // Unmarshal the op and apply it. - var op op - if err := op.UnmarshalBinary(buf); err != nil { + var opr op + if err := opr.UnmarshalBinary(buf); err != nil { // FIXME(benbjohnson): return error with position so file can be trimmed. return err } - op.apply(b) + opr.apply(b) // Increase the op count. b.opN++ // Move the buffer forward. - buf = buf[op.size():] + buf = buf[opr.size():] } return nil @@ -769,7 +795,7 @@ func (b *Bitmap) Check() error { return a } -//Perform a logical negate of the bits in the range [start,end]. +// Flip performs a logical negate of the bits in the range [start,end]. func (b *Bitmap) Flip(start, end uint64) *Bitmap { result := NewBitmap() itr := b.Iterator() @@ -810,7 +836,7 @@ type Iterator struct { } // eof returns true if the iterator is at the end of the bitmap. -func (itr *Iterator) eof() bool { return int(itr.i) >= len(itr.bitmap.containers) } +func (itr *Iterator) eof() bool { return itr.i >= len(itr.bitmap.containers) } // Seek moves to the first value equal to or greater than `seek`. func (itr *Iterator) Seek(seek uint64) { @@ -829,7 +855,7 @@ func (itr *Iterator) Seek(seek uint64) { // Move to the correct value index inside the container. lb := lowbits(seek) - if int(itr.i) >= len(itr.bitmap.containers) { + if itr.i >= len(itr.bitmap.containers) { panic(fmt.Sprintf("data Corruption %d %d %d", itr.i, len(itr.bitmap.containers), seek)) } c := itr.bitmap.containers[itr.i] @@ -839,7 +865,7 @@ func (itr *Iterator) Seek(seek uint64) { if itr.j < 0 { itr.j = -itr.j - 1 } - if int(itr.j) < len(c.array) { + if itr.j < len(c.array) { itr.j-- return } @@ -882,7 +908,7 @@ func (itr *Iterator) Next() (v uint64, eof bool) { c := itr.bitmap.containers[itr.i] if c.isArray() { - if itr.j >= int(c.n-1) { + if itr.j >= c.n-1 { // Reached end of array, move to the next container. itr.i, itr.j = itr.i+1, -1 continue @@ -931,7 +957,7 @@ func (itr *Iterator) Next() (v uint64, eof bool) { itr.j++ // Find first non-zero bit in current bitmap, if possible. - hb := int(itr.j >> 6) + hb := itr.j >> 6 if hb >= len(c.bitmap) { itr.i, itr.j = itr.i+1, -1 @@ -939,14 +965,14 @@ func (itr *Iterator) Next() (v uint64, eof bool) { } lb := c.bitmap[hb] >> (uint(itr.j) % 64) if lb != 0 { - itr.j = int(itr.j) + trailingZeroN(lb) + itr.j = itr.j + trailingZeroN(lb) return itr.peek(), false } // Otherwise iterate through remaining bitmaps to find next bit. for hb++; hb < len(c.bitmap); hb++ { if c.bitmap[hb] != 0 { - itr.j = int(hb<<6) + trailingZeroN(c.bitmap[hb]) + itr.j = hb<<6 + trailingZeroN(c.bitmap[hb]) return itr.peek(), false } } @@ -961,18 +987,18 @@ func (itr *Iterator) peek() uint64 { key := itr.bitmap.keys[itr.i] c := itr.bitmap.containers[itr.i] if c.isArray() { - return uint64(key)<<16 | uint64(c.array[itr.j]) + return key<<16 | uint64(c.array[itr.j]) } if c.isRun() { - return uint64(key)<<16 | uint64(c.runs[itr.j].start+uint16(itr.k)) + return key<<16 | uint64(c.runs[itr.j].start+uint16(itr.k)) } - return uint64(key)<<16 | uint64(itr.j) + return key<<16 | uint64(itr.j) } -// The maximum size of array containers. +// ArrayMaxSize represents the maximum size of array containers. const ArrayMaxSize = 4096 -// The maximum size of run length encoded containers. +// RunMaxSize represents the maximum size of run length encoded containers. const RunMaxSize = 2048 // container represents a container for uint32 integers. @@ -982,12 +1008,12 @@ const RunMaxSize = 2048 // an array or RLE container is used, depending on the contents. For containers // with more than 4,096 values, the values are encoded into bitmaps. type container struct { - container_type byte // array, bitmap, or run - n int // number of integers in container - array []uint16 // used for array containers - bitmap []uint64 // used for bitmap containers - runs []interval16 // used for RLE containers - mapped bool // mapped directly to a byte slice when true + mapped bool // mapped directly to a byte slice when true + containerType byte // array, bitmap, or run + n int // number of integers in container + array []uint16 // used for array containers + bitmap []uint64 // used for bitmap containers + runs []interval16 // used for RLE containers } type interval16 struct { @@ -1002,22 +1028,22 @@ func (iv interval16) runlen() int { // newContainer returns a new instance of container. func newContainer() *container { - return &container{container_type: ContainerArray} + return &container{containerType: ContainerArray} } // isArray returns true if the container is an array container. func (c *container) isArray() bool { - return c.container_type == ContainerArray + return c.containerType == ContainerArray } // isBitmap returns true if the container is a bitmap container. func (c *container) isBitmap() bool { - return c.container_type == ContainerBitmap + return c.containerType == ContainerBitmap } // isRun returns true if the container is a run-length-encoded container. func (c *container) isRun() bool { - return c.container_type == ContainerRun + return c.containerType == ContainerRun } // unmap creates copies of the containers data in the heap. @@ -1029,7 +1055,7 @@ func (c *container) unmap() { return } - switch c.container_type { + switch c.containerType { case ContainerArray: tmp := make([]uint16, len(c.array)) copy(tmp, c.array) @@ -1095,7 +1121,7 @@ func (c *container) bitmapCountRange(start, end int) int { } // Count partial ending word. - if int(j) < len(c.bitmap) { + if j < len(c.bitmap) { off := 64 - (uint(end) % 64) n += popcount(c.bitmap[j] << off) } @@ -1115,7 +1141,7 @@ func (c *container) runCountRange(start, end int) (n int) { } // iv is superset of range if int(iv.start) < start && int(iv.last) > end { - return int(end - start) + return end - start } // iv is subset of range if int(iv.start) >= start && int(iv.last) < end { @@ -1207,7 +1233,7 @@ func (c *container) runAdd(v uint16) bool { c.unmap() if iv.last < v { if iv.last == v-1 { - c.runs[i].last += 1 + c.runs[i].last++ } else { c.runs = append(c.runs, interval16{start: v, last: v}) } @@ -1219,10 +1245,10 @@ func (c *container) runAdd(v uint16) bool { return true } // just before an interval - c.runs[i].start -= 1 + c.runs[i].start-- } else if i > 0 && v-1 == c.runs[i-1].last { // just after an interval - c.runs[i-1].last += 1 + c.runs[i-1].last++ } else { // alone newIv := interval16{start: v, last: v} @@ -1256,7 +1282,7 @@ func (c *container) arrayCountRuns() (r int) { prev := -2 for _, v := range c.array { if prev+1 != int(v) { - r += 1 + r++ } prev = int(v) } @@ -1395,9 +1421,9 @@ func (c *container) runRemove(v uint16) bool { if v == c.runs[i].last && v == c.runs[i].start { c.runs = append(c.runs[:i], c.runs[i+1:]...) } else if v == c.runs[i].last { - c.runs[i].last -= 1 + c.runs[i].last-- } else if v == c.runs[i].start { - c.runs[i].start += 1 + c.runs[i].start++ } else if v > c.runs[i].start { last := c.runs[i].last c.runs[i].last = v - 1 @@ -1434,10 +1460,13 @@ func (c *container) bitmapMax() uint16 { } // Find the highest set bit. - for j := uint16(63); j >= 0; j-- { + for j := uint16(63); ; j-- { if v&(1<= na && j >= nb { @@ -2149,10 +2178,10 @@ func unionArrayArray(a, b *container) *container { // 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 { - if b.n == maxContainerVal { + if b.n == maxContainerVal+1 { return b.clone() } - output := &container{container_type: ContainerRun} + output := &container{containerType: ContainerRun} na, nb := len(a.array), len(b.runs) var vb interval16 var va uint16 @@ -2189,33 +2218,33 @@ func (c *container) runAppendInterval(v interval16) int { if len(c.runs) == 0 { c.runs = append(c.runs, v) return int(v.last-v.start) + 1 - } else { - last := c.runs[len(c.runs)-1] - if last.last == maxContainerVal { //protect against overflow - return 0 - } - 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 - } + } + + last := c.runs[len(c.runs)-1] + if last.last == maxContainerVal { //protect against overflow + return 0 + } + 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 { - if a.n == maxContainerVal { + if a.n == maxContainerVal+1 { return a.clone() } - if b.n == maxContainerVal { + if b.n == maxContainerVal+1 { return b.clone() } na, nb := len(a.runs), len(b.runs) output := &container{ - runs: make([]interval16, 0, na+nb), - container_type: ContainerRun, + runs: make([]interval16, 0, na+nb), + containerType: ContainerRun, } var va, vb interval16 for i, j := 0, 0; i < na || j < nb; { @@ -2240,9 +2269,12 @@ func unionRunRun(a, b *container) *container { } func unionBitmapRun(a, b *container) *container { - if b.n == maxContainerVal { + if b.n == maxContainerVal+1 { return b.clone() } + if a.n == maxContainerVal+1 { + return a.clone() + } output := a.clone() for j := 0; j < len(b.runs); j++ { output.bitmapSetRange(uint64(b.runs[j].start), uint64(b.runs[j].last)+1) @@ -2257,7 +2289,7 @@ func (c *container) bitmapSetRange(i, j uint64) { x := i >> 6 y := (j - 1) >> 6 var X uint64 = maxBitmap << (i % 64) - var Y uint64 = maxBitmap >> (64 - (j % 64)) + var Y uint64 = maxBitmap >> (63 - ((j - 1) % 64)) xcnt := popcnt(X) ycnt := popcnt(Y) if x == y { @@ -2280,7 +2312,7 @@ func (c *container) bitmapXorRange(i, j uint64) { x := i >> 6 y := (j - 1) >> 6 var X uint64 = maxBitmap << (i % 64) - var Y uint64 = maxBitmap >> (64 - (j % 64)) + var Y uint64 = maxBitmap >> (63 - ((j - 1) % 64)) if x == y { cnt := popcnt(c.bitmap[x]) c.bitmap[x] ^= (X & Y) //// flip @@ -2334,8 +2366,8 @@ func unionArrayBitmap(a, b *container) *container { func unionBitmapBitmap(a, b *container) *container { output := &container{ - bitmap: make([]uint64, bitmapN), - container_type: ContainerBitmap, + bitmap: make([]uint64, bitmapN), + containerType: ContainerBitmap, } for i := 0; i < bitmapN; i++ { @@ -2377,7 +2409,7 @@ func difference(a, b *container) *container { // differenceArrayArray computes the difference bween two arrays. func differenceArrayArray(a, b *container) *container { - output := &container{container_type: ContainerArray} + output := &container{containerType: ContainerArray} na, nb := len(a.array), len(b.array) for i, j := 0, 0; i < na; { va := a.array[i] @@ -2408,14 +2440,14 @@ func differenceArrayRun(a, b *container) *container { return a.clone() } - output := &container{array: make([]uint16, 0, a.n), container_type: ContainerArray} + output := &container{array: make([]uint16, 0, a.n), containerType: ContainerArray} // cardinality upper bound: card(A) i := 0 // array index j := 0 // run index // handle overlap - for i < int(a.n) { + for i < a.n { // keep all array elements before beginning of runs if a.array[i] < b.runs[j].start { @@ -2441,10 +2473,18 @@ func differenceArrayRun(a, b *container) *container { if i < len(a.array) { // keep all array elements after end of runs - output.array = append(output.array, a.array[i:]...) - // TODO: consider handling container.n mutations in one place - // like we do with container.add(). - output.n += int(len(a.array[i:])) + // It's possible that output was converted from array to bitmap in output.add() + // so check container type before proceeding. + if output.containerType == ContainerArray { + output.array = append(output.array, a.array[i:]...) + // TODO: consider handling container.n mutations in one place + // like we do with container.add(). + output.n += len(a.array[i:]) + } else { + for _, v := range a.array[i:] { + output.add(v) + } + } } return output } @@ -2468,7 +2508,7 @@ func differenceRunArray(a, b *container) *container { if a.n == 0 || b.n == 0 { return a.clone() } - output := &container{runs: make([]interval16, 0, len(a.runs)), container_type: ContainerRun} + output := &container{runs: make([]interval16, 0, len(a.runs)), containerType: ContainerRun} bidx := 0 vb := b.array[bidx] @@ -2524,7 +2564,7 @@ func differenceRunBitmap(a, b *container) *container { if len(a.runs) > 0 && a.runs[0].start == 0 && a.runs[0].last == 65535 { return b.flipBitmap() } - output := &container{container_type: ContainerRun} + output := &container{containerType: ContainerRun} output.n = a.n if len(a.runs) == 0 { return output @@ -2567,61 +2607,6 @@ func differenceRunBitmap(a, b *container) *container { } } - if output.n < ArrayMaxSize && int(len(output.runs)) > output.n/2 { - output.runToArray() - } else if len(output.runs) > RunMaxSize { - output.runToBitmap() - } - return output -} - -func differenceRunIterator(a *container, itr containerIterator) *container { - - output := &container{runs: make([]interval16, 0, a.n), container_type: ContainerRun} - - vb, eof := itr.next() - j := 0 - vr := a.runs[j] - working := !eof - for working { - switch { - case vb < vr.start: //before - case vb > vr.last: //after - if vr.start <= vr.last { - output.n += output.runAppendInterval(vr) - } - j++ - if j < len(a.runs) { - vr = a.runs[j] - } else { - working = false - } - case vb == vr.start: //begining of run - vr.start++ - case vb == a.runs[j].last: //end of run - vr.last-- - if vr.last >= vr.start { - output.n += output.runAppendInterval(vr) - } - j++ - if j < len(a.runs) { - vr = a.runs[j] - } else { - working = false - } - case vb > vr.start: //inside run - output.n += output.runAppendInterval(interval16{start: vr.start, last: vb - 1}) - vr.start = vb + 1 - - } - vb, eof = itr.next() - if eof { - working = false - } - } - if vr.start <= vr.last { - output.n += output.runAppendInterval(vr) - } if output.n < ArrayMaxSize && len(output.runs) > output.n/2 { output.runToArray() } else if len(output.runs) > RunMaxSize { @@ -2645,7 +2630,7 @@ func differenceRunRun(a, b *container) *container { alen := len(a.runs) blen := len(b.runs) - output := &container{runs: make([]interval16, 0, alen+blen), container_type: ContainerRun} // TODO allocate max then truncate? or something else + output := &container{runs: make([]interval16, 0, alen+blen), containerType: ContainerRun} // TODO allocate max then truncate? or something else // cardinality upper bound: sum of number of runs // each B-run could split an A-run in two, up to len(b.runs) times @@ -2653,7 +2638,7 @@ func differenceRunRun(a, b *container) *container { switch { case alast < bstart: // current A-run entirely preceeds current B-run: keep full A-run, advance to next A-run - output.runs = append(output.runs, interval16{start: uint16(astart), last: uint16(alast)}) + output.runs = append(output.runs, interval16{start: astart, last: alast}) apos++ if apos < alen { astart = a.runs[apos].start @@ -2669,7 +2654,7 @@ func differenceRunRun(a, b *container) *container { default: // overlap if astart < bstart { - output.runs = append(output.runs, interval16{start: uint16(astart), last: uint16(bstart - 1)}) + output.runs = append(output.runs, interval16{start: astart, last: bstart - 1}) } if alast > blast { astart = blast + 1 @@ -2683,7 +2668,7 @@ func differenceRunRun(a, b *container) *container { } } if apos < alen { - output.runs = append(output.runs, interval16{start: uint16(astart), last: uint16(alast)}) + output.runs = append(output.runs, interval16{start: astart, last: alast}) apos++ if apos < alen { output.runs = append(output.runs, a.runs[apos:]...) @@ -2695,7 +2680,7 @@ func differenceRunRun(a, b *container) *container { } func differenceArrayBitmap(a, b *container) *container { - output := &container{container_type: ContainerArray} + output := &container{containerType: ContainerArray} for _, va := range a.array { bmidx := va / 64 bidx := va % 64 @@ -2726,7 +2711,7 @@ func differenceBitmapArray(a, b *container) *container { } func differenceBitmapBitmap(a, b *container) *container { - output := &container{bitmap: make([]uint64, bitmapN), container_type: ContainerBitmap} + output := &container{bitmap: make([]uint64, bitmapN), containerType: ContainerBitmap} for i := range a.bitmap { v := a.bitmap[i] & (^b.bitmap[i]) @@ -2769,7 +2754,7 @@ func xor(a, b *container) *container { } func xorArrayArray(a, b *container) *container { - output := &container{container_type: ContainerArray} + output := &container{containerType: ContainerArray} na, nb := len(a.array), len(b.array) for i, j := 0, 0; i < na || j < nb; { if i < na && j >= nb { @@ -2807,7 +2792,9 @@ func xorArrayBitmap(a, b *container) *container { } } - if output.count() < ArrayMaxSize { + // It's possible that output was converted from bitmap to array in output.remove() + // so we only do this conversion if output is still a bitmap container. + if output.containerType == ContainerBitmap && output.count() < ArrayMaxSize { output.bitmapToArray() } @@ -2816,8 +2803,8 @@ func xorArrayBitmap(a, b *container) *container { func xorBitmapBitmap(a, b *container) *container { output := &container{ - bitmap: make([]uint64, bitmapN), - container_type: ContainerBitmap, + bitmap: make([]uint64, bitmapN), + containerType: ContainerBitmap, } for i := 0; i < bitmapN; i++ { v := a.bitmap[i] ^ b.bitmap[i] @@ -2855,7 +2842,6 @@ func (op *op) apply(b *Bitmap) bool { default: panic(fmt.Sprintf("invalid op type: %d", op.typ)) } - return false } // WriteTo writes op to the w. @@ -2899,7 +2885,7 @@ func (op *op) UnmarshalBinary(data []byte) error { // size returns the encoded size of the op, in bytes. func (*op) size() int { return 1 + 8 + 4 } -func highbits(v uint64) uint64 { return uint64(v >> 16) } +func highbits(v uint64) uint64 { return v >> 16 } func lowbits(v uint64) uint16 { return uint16(v & 0xFFFF) } // search32 returns the index of value in a. If value is not found, it works the @@ -3002,7 +2988,7 @@ func trailingZeroN(v uint64) int { if y := v << 2; y != 0 { n, v = n-2, y } - return int(n - int64(uint64(v<<1)>>63)) + return int(n - int64(v<<1>>63)) } // bit population count, taken from @@ -3017,110 +3003,6 @@ func popcount(x uint64) (n uint64) { return x >> 56 } -// Returns eof as true if there are no values left in the iterator. -type containerIterator interface { - next() (uint16, bool) -} - -// arrayIterator represents an iterator over container array values. -type arrayIterator struct { - array []uint16 - i int -} - -func newArrayIterator(array []uint16) *arrayIterator { - return &arrayIterator{ - array: array, - i: -1, - } -} - -// next returns the next value in the array. -func (itr *arrayIterator) next() (v uint16, eof bool) { - - itr.i++ - if itr.i >= len(itr.array) { - return 0, true - } - return itr.array[itr.i], false -} - -// bitmapIterator represents an iterator over container bitmap values. -type bitmapIterator struct { - bitmap []uint64 - i int -} - -func newBitmapIterator(bitmap []uint64) *bitmapIterator { - return &bitmapIterator{ - bitmap: bitmap, - i: -1, - } -} - -// next returns the next value in the bitmap. -// Returns eof as true if there are no values left in the iterator. -func (itr *bitmapIterator) next() (v uint16, eof bool) { - if itr.i+1 >= int(len(itr.bitmap)*64) { - return 0, true - } - itr.i++ - - // Find first non-zero bit in current bitmap, if possible. - hb := int(itr.i >> 6) - lb := itr.bitmap[hb] >> (uint(itr.i) % 64) - if lb != 0 { - itr.i = int(itr.i) + trailingZeroN(lb) - return uint16(itr.i), false - } - - // Otherwise iterate through remaining bitmaps to find next bit. - for hb++; hb < len(itr.bitmap); hb++ { - if itr.bitmap[hb] != 0 { - itr.i = int(hb<<6) + trailingZeroN(itr.bitmap[hb]) - return uint16(itr.i), false - } - } - - return 0, true -} - -// bufBitmapIterator wraps an iterator to provide the ability to unread values. -type bufBitmapIterator struct { - buf struct { - v uint16 - eof bool - full bool - } - itr *bitmapIterator -} - -// newBufBitmapIterator returns a buffered iterator that wraps a bitmapIterator. -func newBufBitmapIterator(itr *bitmapIterator) *bufBitmapIterator { - return &bufBitmapIterator{itr: itr} -} - -// next returns the next pair in the bitmap. -// If a value has been buffered then it is returned and the buffer is cleared. -func (itr *bufBitmapIterator) next() (v uint16, eof bool) { - if itr.buf.full { - itr.buf.full = false - return itr.buf.v, itr.buf.eof - } - - // Read value onto buffer in case of unread. - itr.buf.v, itr.buf.eof = itr.itr.next() - return itr.buf.v, itr.buf.eof -} - -// unread pushes previous pair on to the buffer. Panics if the buffer is already full. -func (itr *bufBitmapIterator) unread() { - if itr.buf.full { - panic("roaring.bufBitmapIterator: buffer full") - } - itr.buf.full = true -} - // ErrorList represents a list of errors. type ErrorList []error @@ -3156,29 +3038,22 @@ func (a *ErrorList) AppendWithPrefix(err error, prefix string) { } } -// assert panics with a formatted message if condition is false. -func assert(condition bool, format string, a ...interface{}) { - if !condition { - panic(fmt.Sprintf(format, a...)) - } -} - // xorArrayRun computes the exclusive or of an array and a run container. func xorArrayRun(a, b *container) *container { - output := &container{container_type: ContainerRun} + output := &container{containerType: ContainerRun} na, nb := len(a.array), len(b.runs) var vb interval16 var va uint16 - last_i, last_j := -1, -1 + lastI, lastJ := -1, -1 for i, j := 0, 0; i < na || j < nb; { - if i < na && i != last_i { + if i < na && i != lastI { va = a.array[i] } - if j < nb && j != last_j { + if j < nb && j != lastJ { vb = b.runs[j] } - last_i = i - last_j = j + lastI = i + lastJ = j if i < na && (j >= nb || va < vb.start) { //before output.n += output.runAppendInterval(interval16{start: va, last: va}) @@ -3228,91 +3103,91 @@ func xorArrayRun(a, b *container) *container { } // xorCompare computes first exclusive run between two runs. -func xorCompare(x *xorstm) (r1 interval16, has_data bool) { - has_data = false - if !x.va_valid || !x.vb_valid { - if x.vb_valid { - x.vb_valid = false +func xorCompare(x *xorstm) (r1 interval16, hasData bool) { + hasData = false + if !x.vaValid || !x.vbValid { + if x.vbValid { + x.vbValid = false r1 = x.vb - has_data = true + hasData = true return } - if x.va_valid { - x.va_valid = false + if x.vaValid { + x.vaValid = false r1 = x.va - has_data = true + hasData = true return } return } if x.va.last < x.vb.start { //va before - x.va_valid = false + x.vaValid = false r1 = x.va - has_data = true + hasData = true } else if x.vb.last < x.va.start { //vb before - x.vb_valid = false + x.vbValid = false r1 = x.vb - has_data = true + hasData = true } else if x.va.start == x.vb.start && x.va.last == x.vb.last { // Equal - x.va_valid = false - x.vb_valid = false + x.vaValid = false + x.vbValid = false } else if x.va.start <= x.vb.start && x.va.last >= x.vb.last { //vb inside - x.vb_valid = false + x.vbValid = false if x.va.start != x.vb.start { r1 = interval16{start: x.va.start, last: x.vb.start - 1} - has_data = true + hasData = true } if x.vb.last == maxContainerVal { // Check for overflow - x.va_valid = false + x.vaValid = false } else { x.va.start = x.vb.last + 1 if x.va.start > x.va.last { - x.va_valid = false + x.vaValid = false } } } else if x.vb.start <= x.va.start && x.vb.last >= x.va.last { //va inside - x.va_valid = false + x.vaValid = false if x.vb.start != x.va.start { r1 = interval16{start: x.vb.start, last: x.va.start - 1} - has_data = true + hasData = true } if x.va.last == maxContainerVal { //check for overflow - x.vb_valid = false + x.vbValid = false } else { x.vb.start = x.va.last + 1 if x.vb.start > x.vb.last { - x.vb_valid = false + x.vbValid = false } } } else if x.va.start < x.vb.start && x.va.last <= x.vb.last { //va first overlap - x.va_valid = false + x.vaValid = false r1 = interval16{start: x.va.start, last: x.vb.start - 1} - has_data = true + hasData = true if x.va.last == maxContainerVal { // check for overflow - x.vb_valid = false + x.vbValid = false } else { x.vb.start = x.va.last + 1 if x.vb.start > x.vb.last { - x.vb_valid = false + x.vbValid = false } } } else if x.vb.start < x.va.start && x.vb.last <= x.va.last { //vb first overlap - x.vb_valid = false + x.vbValid = false r1 = interval16{start: x.vb.start, last: x.va.start - 1} - has_data = true + hasData = true if x.vb.last == maxContainerVal { // check for overflow - x.va_valid = false + x.vaValid = false } else { x.va.start = x.vb.last + 1 if x.va.start > x.va.last { - x.va_valid = false + x.vaValid = false } } } @@ -3321,8 +3196,8 @@ func xorCompare(x *xorstm) (r1 interval16, has_data bool) { //stm is state machine used to "xor" iterate over runs. type xorstm struct { - va_valid, vb_valid bool - va, vb interval16 + vaValid, vbValid bool + va, vb interval16 } // xorRunRun computes the exclusive or of two run containers. @@ -3334,38 +3209,38 @@ func xorRunRun(a, b *container) *container { if nb == 0 { return a.clone() } - output := &container{} + output := &container{containerType: ContainerRun} - last_i, last_j := -1, -1 + lastI, lastJ := -1, -1 state := &xorstm{} for i, j := 0, 0; i < na || j < nb; { - if i < na && last_i != i { + if i < na && lastI != i { state.va = a.runs[i] - state.va_valid = true + state.vaValid = true } - if j < nb && last_j != j { + if j < nb && lastJ != j { state.vb = b.runs[j] - state.vb_valid = true + state.vbValid = true } - last_i, last_j = i, j + lastI, lastJ = i, j r1, ok := xorCompare(state) if ok { output.n += output.runAppendInterval(r1) } - if !state.va_valid { + if !state.vaValid { i++ } - if !state.vb_valid { + if !state.vbValid { j++ } } - if output.n < ArrayMaxSize && int(len(output.runs)) > output.n/2 { + if output.n < ArrayMaxSize && len(output.runs) > output.n/2 { output.runToArray() } else if len(output.runs) > RunMaxSize { output.runToBitmap() @@ -3380,7 +3255,7 @@ func xorBitmapRun(a, b *container) *container { output.bitmapXorRange(uint64(b.runs[j].start), uint64(b.runs[j].last)+1) } - if output.n < ArrayMaxSize && int(len(output.runs)) > output.n/2 { + if output.n < ArrayMaxSize && len(output.runs) > output.n/2 { output.runToArray() } else if len(output.runs) > RunMaxSize { output.runToBitmap() diff --git a/roaring/roaring_helpers_test.go b/roaring/roaring_helpers_test.go new file mode 100644 index 000000000..ea6d86cd9 --- /dev/null +++ b/roaring/roaring_helpers_test.go @@ -0,0 +1,295 @@ +// Copyright 2017 Pilosa Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package roaring + +/////////////////////////////////////////////////////////////////////////// + +var containerWidth uint64 = 65536 + +////////////////// array +func arrayEmpty() []uint16 { + return make([]uint16, 0) +} + +func arrayFull() []uint16 { + array := make([]uint16, containerWidth) + for i := 0; i < int(containerWidth); i++ { + array[i] = uint16(i) + } + return array +} + +func arrayFirstBitSet() []uint16 { + array := make([]uint16, 0) + array = append(array, uint16(0)) + return array +} + +func arrayLastBitSet() []uint16 { + array := make([]uint16, 0) + array = append(array, uint16(65535)) + return array +} + +func arrayFirstBitUnset() []uint16 { + array := make([]uint16, containerWidth-1) + for i := 1; i < int(containerWidth); i++ { + array[i-1] = uint16(i) + } + return array +} + +func arrayLastBitUnset() []uint16 { + array := make([]uint16, containerWidth-1) + for i := 0; i < int(containerWidth)-1; i++ { + array[i] = uint16(i) + } + return array +} + +func arrayInnerBitsSet() []uint16 { + array := make([]uint16, containerWidth-2) + for i := 1; i < int(containerWidth)-1; i++ { + array[i-1] = uint16(i) + } + return array +} + +func arrayOuterBitsSet() []uint16 { + return []uint16{0, 65535} +} + +func arrayOddBitsSet() []uint16 { + array := make([]uint16, containerWidth/2) + for i := 0; i < int(containerWidth/2); i++ { + array[i] = uint16(2*i + 1) + } + return array +} + +func arrayEvenBitsSet() []uint16 { + array := make([]uint16, containerWidth/2) + for i := 0; i < int(containerWidth/2); i++ { + array[i] = uint16(2 * i) + } + return array +} + +////////////////// bitmap +func bitmapEmpty() []uint64 { + return make([]uint64, bitmapN) +} + +func bitmapFull() []uint64 { + bitmap := make([]uint64, bitmapN) + for i := 0; i < bitmapN; i++ { + bitmap[i] = 0xFFFFFFFFFFFFFFFF + } + return bitmap +} + +func bitmapFirstBitSet() []uint64 { + bitmap := make([]uint64, bitmapN) + bitmap[0] = 0x0000000000000001 + return bitmap +} + +func bitmapLastBitSet() []uint64 { + bitmap := make([]uint64, bitmapN) + bitmap[bitmapN-1] = 0x8000000000000000 + return bitmap +} + +func bitmapFirstBitUnset() []uint64 { + bitmap := bitmapFull() + bitmap[0] = 0xFFFFFFFFFFFFFFFE + return bitmap +} + +func bitmapLastBitUnset() []uint64 { + bitmap := bitmapFull() + bitmap[bitmapN-1] = 0x7FFFFFFFFFFFFFFF + return bitmap +} + +func bitmapInnerBitsSet() []uint64 { + bitmap := bitmapFull() + bitmap[0] = 0xFFFFFFFFFFFFFFFE + bitmap[bitmapN-1] = 0x7FFFFFFFFFFFFFFF + return bitmap +} + +func bitmapOuterBitsSet() []uint64 { + bitmap := bitmapEmpty() + bitmap[0] = 0x0000000000000001 + bitmap[bitmapN-1] = 0x8000000000000000 + return bitmap +} + +func bitmapOddBitsSet() []uint64 { + bitmap := make([]uint64, bitmapN) + for i := 0; i < bitmapN; i++ { + bitmap[i] = 0xAAAAAAAAAAAAAAAA + } + return bitmap +} + +func bitmapEvenBitsSet() []uint64 { + bitmap := make([]uint64, bitmapN) + for i := 0; i < bitmapN; i++ { + bitmap[i] = 0x5555555555555555 + } + return bitmap +} + +////////////////// run +func runEmpty() []interval16 { + return make([]interval16, 0) +} + +func runFull() []interval16 { + run := make([]interval16, 0) + run = append(run, interval16{start: 0, last: 65535}) + return run +} + +func runFirstBitSet() []interval16 { + run := make([]interval16, 0) + run = append(run, interval16{start: 0, last: 0}) + return run +} + +func runLastBitSet() []interval16 { + run := make([]interval16, 0) + run = append(run, interval16{start: 65535, last: 65535}) + return run +} + +func runFirstBitUnset() []interval16 { + run := make([]interval16, 0) + run = append(run, interval16{start: 1, last: 65535}) + return run +} + +func runLastBitUnset() []interval16 { + run := make([]interval16, 0) + run = append(run, interval16{start: 0, last: 65534}) + return run +} + +func runInnerBitsSet() []interval16 { + run := make([]interval16, 0) + run = append(run, interval16{start: 1, last: 65534}) + return run +} + +func runOuterBitsSet() []interval16 { + run := make([]interval16, 0) + run = append(run, interval16{start: 0, last: 0}) + run = append(run, interval16{start: 65535, last: 65535}) + return run +} + +func runOddBitsSet() []interval16 { + run := make([]interval16, containerWidth/2) + for i := 0; i < int(containerWidth/2); i++ { + run[i] = interval16{start: uint16(2*i + 1), last: uint16(2*i + 1)} + } + return run +} + +func runEvenBitsSet() []interval16 { + run := make([]interval16, containerWidth/2) + for i := 0; i < int(containerWidth/2); i++ { + run[i] = interval16{start: uint16(2 * i), last: uint16(2 * i)} + } + return run +} + +/////////////////////////////////////////////////////////////////////////// + +type testOp struct { + f func(a, b *container) *container + x string + y string + exp string +} + +func doContainer(containerType byte, data interface{}) *container { + c := &container{ + containerType: containerType, + } + + switch containerType { + case ContainerArray: + c.array = data.([]uint16) + case ContainerBitmap: + c.bitmap = data.([]uint64) + case ContainerRun: + c.runs = data.([]interval16) + } + c.n = c.count() + + return c +} + +func setupContainerTests() map[byte]map[string]*container { + + cts := make(map[byte]map[string]*container) + + // array containers + cts[ContainerArray] = map[string]*container{ + "empty": doContainer(ContainerArray, arrayEmpty()), + "full": doContainer(ContainerArray, arrayFull()), + "firstBitSet": doContainer(ContainerArray, arrayFirstBitSet()), + "lastBitSet": doContainer(ContainerArray, arrayLastBitSet()), + "firstBitUnset": doContainer(ContainerArray, arrayFirstBitUnset()), + "lastBitUnset": doContainer(ContainerArray, arrayLastBitUnset()), + "innerBitsSet": doContainer(ContainerArray, arrayInnerBitsSet()), + "outerBitsSet": doContainer(ContainerArray, arrayOuterBitsSet()), + "oddBitsSet": doContainer(ContainerArray, arrayOddBitsSet()), + "evenBitsSet": doContainer(ContainerArray, arrayEvenBitsSet()), + } + + // bitmap containers + cts[ContainerBitmap] = map[string]*container{ + "empty": doContainer(ContainerBitmap, bitmapEmpty()), + "full": doContainer(ContainerBitmap, bitmapFull()), + "firstBitSet": doContainer(ContainerBitmap, bitmapFirstBitSet()), + "lastBitSet": doContainer(ContainerBitmap, bitmapLastBitSet()), + "firstBitUnset": doContainer(ContainerBitmap, bitmapFirstBitUnset()), + "lastBitUnset": doContainer(ContainerBitmap, bitmapLastBitUnset()), + "innerBitsSet": doContainer(ContainerBitmap, bitmapInnerBitsSet()), + "outerBitsSet": doContainer(ContainerBitmap, bitmapOuterBitsSet()), + "oddBitsSet": doContainer(ContainerBitmap, bitmapOddBitsSet()), + "evenBitsSet": doContainer(ContainerBitmap, bitmapEvenBitsSet()), + } + + // run containers + cts[ContainerRun] = map[string]*container{ + "empty": doContainer(ContainerRun, runEmpty()), + "full": doContainer(ContainerRun, runFull()), + "firstBitSet": doContainer(ContainerRun, runFirstBitSet()), + "lastBitSet": doContainer(ContainerRun, runLastBitSet()), + "firstBitUnset": doContainer(ContainerRun, runFirstBitUnset()), + "lastBitUnset": doContainer(ContainerRun, runLastBitUnset()), + "innerBitsSet": doContainer(ContainerRun, runInnerBitsSet()), + "outerBitsSet": doContainer(ContainerRun, runOuterBitsSet()), + "oddBitsSet": doContainer(ContainerRun, runOddBitsSet()), + "evenBitsSet": doContainer(ContainerRun, runEvenBitsSet()), + } + + return cts +} diff --git a/roaring/roaring_internal_test.go b/roaring/roaring_internal_test.go index 8ce9ba9c1..dca413811 100644 --- a/roaring/roaring_internal_test.go +++ b/roaring/roaring_internal_test.go @@ -18,6 +18,8 @@ import ( "bytes" "fmt" "reflect" + "runtime" + "strings" "testing" ) @@ -27,11 +29,11 @@ func (iv interval16) String() string { } func (c *container) String() string { - return fmt.Sprintf("<%s container n=%d, array[%d], runs[%d], bitmap[%d]> type:%d", c.info().Type, c.n, len(c.array), len(c.runs), len(c.bitmap), c.container_type) + return fmt.Sprintf("<%s container n=%d, array[%d], runs[%d], bitmap[%d]> type:%d", c.info().Type, c.n, len(c.array), len(c.runs), len(c.bitmap), c.containerType) } func TestRunAppendInterval(t *testing.T) { - a := container{container_type: ContainerRun} + a := container{containerType: ContainerRun} tests := []struct { base []interval16 app interval16 @@ -80,7 +82,7 @@ func TestInterval16RunLen(t *testing.T) { } func TestContainerRunAdd(t *testing.T) { - c := container{runs: make([]interval16, 0), container_type: ContainerRun} + c := container{runs: make([]interval16, 0), containerType: ContainerRun} tests := []struct { op uint16 exp []interval16 @@ -111,7 +113,7 @@ func TestContainerRunAdd(t *testing.T) { } func TestContainerRunAdd2(t *testing.T) { - c := container{runs: make([]interval16, 0), container_type: ContainerRun} + c := container{runs: make([]interval16, 0), containerType: ContainerRun} ret := c.add(0) if !ret { t.Fatalf("result of adding new bit should be true: %v", c.runs) @@ -126,7 +128,7 @@ func TestContainerRunAdd2(t *testing.T) { } func TestRunCountRange(t *testing.T) { - c := container{runs: make([]interval16, 0), container_type: ContainerRun} + c := container{runs: make([]interval16, 0), containerType: ContainerRun} cnt := c.runCountRange(2, 9) if cnt != 0 { t.Fatalf("should get 0 from empty container, but got: %v", cnt) @@ -179,7 +181,7 @@ func TestRunCountRange(t *testing.T) { } func TestRunContains(t *testing.T) { - c := container{runs: make([]interval16, 0), container_type: ContainerRun} + c := container{runs: make([]interval16, 0), containerType: ContainerRun} if c.runContains(5) { t.Fatalf("empty run container should not contain 5") } @@ -201,7 +203,7 @@ func TestRunContains(t *testing.T) { } func TestBitmapCountRange(t *testing.T) { - c := container{container_type: ContainerBitmap} + c := container{containerType: ContainerBitmap} tests := []struct { start int end int @@ -227,11 +229,11 @@ func TestBitmapCountRange(t *testing.T) { func TestIntersectionCountArrayBitmap3(t *testing.T) { a, b := &container{}, &container{} - a.container_type = ContainerBitmap + a.containerType = ContainerBitmap a.bitmap = getFullBitmap() a.n = maxContainerVal + 1 - b.container_type = ContainerBitmap + b.containerType = ContainerBitmap b.bitmap = getFullBitmap() b.n = maxContainerVal + 1 res := intersectBitmapBitmap(a, b) @@ -288,9 +290,9 @@ func TestIntersectionCountArrayBitmap2(t *testing.T) { for i, test := range tests { a.array = test.array - a.container_type = ContainerArray + a.containerType = ContainerArray b.bitmap = test.bitmap - b.container_type = ContainerBitmap + b.containerType = ContainerBitmap ret := intersectionCountArrayBitmap(a, b) if ret != test.exp { t.Fatalf("test #%v intersectCountArrayBitmap fail received: %v exp: %v", i, ret, test.exp) @@ -299,7 +301,7 @@ func TestIntersectionCountArrayBitmap2(t *testing.T) { } func TestRunRemove(t *testing.T) { - c := container{runs: []interval16{{start: 2, last: 10}, {start: 12, last: 13}, {start: 15, last: 16}}, container_type: ContainerRun} + c := container{runs: []interval16{{start: 2, last: 10}, {start: 12, last: 13}, {start: 15, last: 16}}, containerType: ContainerRun} tests := []struct { op uint16 exp []interval16 @@ -333,7 +335,7 @@ func TestRunRemove(t *testing.T) { } func TestRunMax(t *testing.T) { - c := container{runs: []interval16{{start: 2, last: 10}, {start: 12, last: 13}, {start: 15, last: 16}}, container_type: ContainerRun} + c := container{runs: []interval16{{start: 2, last: 10}, {start: 12, last: 13}, {start: 15, last: 16}}, containerType: ContainerRun} max := c.max() if max != 16 { t.Fatalf("max for %v should be 16", c.runs) @@ -347,8 +349,8 @@ func TestRunMax(t *testing.T) { } func TestIntersectionCountArrayRun(t *testing.T) { - a := &container{container_type: ContainerArray, array: []uint16{1, 5, 10, 11, 12}} - b := &container{container_type: ContainerRun, runs: []interval16{{start: 2, last: 10}, {start: 12, last: 13}, {start: 15, last: 16}}} + a := &container{containerType: ContainerArray, array: []uint16{1, 5, 10, 11, 12}} + b := &container{containerType: ContainerRun, runs: []interval16{{start: 2, last: 10}, {start: 12, last: 13}, {start: 15, last: 16}}} ret := intersectionCountArrayRun(a, b) if ret != 3 { @@ -357,16 +359,16 @@ func TestIntersectionCountArrayRun(t *testing.T) { } func TestIntersectionCountBitmapRun(t *testing.T) { - a := &container{container_type: ContainerBitmap, bitmap: []uint64{0x8000000000000000}} - b := &container{container_type: ContainerRun, runs: []interval16{{start: 63, last: 64}}} + a := &container{containerType: ContainerBitmap, bitmap: []uint64{0x8000000000000000}} + b := &container{containerType: ContainerRun, runs: []interval16{{start: 63, last: 64}}} ret := intersectionCountBitmapRun(a, b) if ret != 1 { t.Fatalf("count of %v with %v should be 1, but got %v", a.bitmap, b.runs, ret) } - a = &container{container_type: ContainerBitmap, bitmap: []uint64{0xF0000001, 0xFF00000000000000, 0xFF000000000000F0, 0x0F0000}} - b = &container{container_type: ContainerRun, runs: []interval16{{start: 29, last: 31}, {start: 125, last: 134}, {start: 191, last: 197}, {start: 200, last: 300}}} + a = &container{containerType: ContainerBitmap, bitmap: []uint64{0xF0000001, 0xFF00000000000000, 0xFF000000000000F0, 0x0F0000}} + b = &container{containerType: ContainerRun, runs: []interval16{{start: 29, last: 31}, {start: 125, last: 134}, {start: 191, last: 197}, {start: 200, last: 300}}} ret = intersectionCountBitmapRun(a, b) if ret != 14 { @@ -414,8 +416,8 @@ func TestIntersectionCountRunRun(t *testing.T) { bruns: []interval16{{start: 9, last: 9}, {start: 11, last: 17}}, exp: 6}, } for i, test := range tests { - a.container_type = ContainerRun - b.container_type = ContainerRun + a.containerType = ContainerRun + b.containerType = ContainerRun a.runs = test.aruns b.runs = test.bruns ret := intersectionCountRunRun(a, b) @@ -456,8 +458,8 @@ func TestIntersectArrayRun(t *testing.T) { } for i, test := range tests { - a.container_type = ContainerArray - b.container_type = ContainerRun + a.containerType = ContainerArray + b.containerType = ContainerRun a.array = test.array b.runs = test.runs ret := intersectArrayRun(a, b) @@ -514,8 +516,8 @@ func TestIntersectRunRun(t *testing.T) { }, } for i, test := range tests { - a.container_type = ContainerRun - b.container_type = ContainerRun + a.containerType = ContainerRun + b.containerType = ContainerRun a.runs = test.aruns b.runs = test.bruns ret := intersectRunRun(a, b) @@ -579,8 +581,8 @@ func TestIntersectBitmapRunBitmap(t *testing.T) { for i, v := range test.exp { exp[i] = v } - a.container_type = ContainerBitmap - b.container_type = ContainerRun + a.containerType = ContainerBitmap + b.containerType = ContainerRun ret := intersectBitmapRun(a, b) if ret.isArray() { ret.arrayToBitmap() @@ -640,8 +642,8 @@ func TestIntersectBitmapRunArray(t *testing.T) { a.bitmap[i] = v } b.runs = test.runs - a.container_type = ContainerBitmap - b.container_type = ContainerRun + a.containerType = ContainerBitmap + b.containerType = ContainerRun ret := intersectBitmapRun(a, b) if !reflect.DeepEqual(ret.array, test.exp) { t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.array) @@ -658,19 +660,19 @@ func TestUnionMixed(t *testing.T) { // array container a := &container{} a.array = []uint16{1, 4, 5, 7, 10, 11, 12} - a.container_type = ContainerArray + a.containerType = ContainerArray a.n = 7 // bitmap container b := &container{bitmap: make([]uint64, bitmapN)} b.bitmap[0] = uint64(0x3) b.n = 2 - b.container_type = ContainerBitmap + b.containerType = ContainerBitmap // run container r := &container{} r.runs = []interval16{{start: 5, last: 10}} - r.container_type = ContainerRun + r.containerType = ContainerRun r.n = 6 t.Run("various container Unions", func(t *testing.T) { @@ -711,10 +713,10 @@ func TestIntersectMixed(t *testing.T) { a.runs = []interval16{{start: 5, last: 10}} a.n = 6 - a.container_type = ContainerRun + a.containerType = ContainerRun b.array = []uint16{1, 4, 5, 7, 10, 11, 12} b.n = 7 - b.container_type = ContainerArray + b.containerType = ContainerArray res := intersect(a, b) if !reflect.DeepEqual(res.array, []uint16{5, 7, 10}) { t.Fatalf("test #1 expected %v, but got %v", []uint16{5, 7, 10}, res.array) @@ -730,7 +732,7 @@ func TestIntersectMixed(t *testing.T) { } c.bitmap = []uint64{0x60} c.n = 2 - c.container_type = ContainerBitmap + c.containerType = ContainerBitmap res = intersect(c, a) if !reflect.DeepEqual(res.array, []uint16{5, 6}) { @@ -760,15 +762,15 @@ func TestDifferenceMixed(t *testing.T) { a.runs = []interval16{{start: 5, last: 10}} a.n = a.runCountRange(0, 100) - a.container_type = ContainerRun + a.containerType = ContainerRun b.array = []uint16{0, 2, 4, 6, 8, 10, 12} b.n = len(b.array) - b.container_type = ContainerArray + b.containerType = ContainerArray d.array = []uint16{1, 3, 5, 7, 9, 11, 12} d.n = len(d.array) - d.container_type = ContainerArray + d.containerType = ContainerArray res := difference(a, b) @@ -788,7 +790,7 @@ func TestDifferenceMixed(t *testing.T) { c.bitmap = []uint64{0x64} c.n = c.countRange(0, 100) - c.container_type = ContainerBitmap + c.containerType = ContainerBitmap res = difference(c, a) if !reflect.DeepEqual(res.bitmap, []uint64{0x4}) { t.Fatalf("test #4 expected %v, but got %v", []uint16{4}, res.bitmap) @@ -883,8 +885,8 @@ func TestUnionRunRun(t *testing.T) { for i, test := range tests { a.runs = test.aruns b.runs = test.bruns - a.container_type = ContainerRun - b.container_type = ContainerRun + a.containerType = ContainerRun + b.containerType = ContainerRun ret := unionRunRun(a, b) if !reflect.DeepEqual(ret.runs, test.exp) { t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.runs) @@ -925,8 +927,8 @@ func TestUnionArrayRun(t *testing.T) { for i, test := range tests { a.array = test.array b.runs = test.runs - a.container_type = ContainerArray - b.container_type = ContainerRun + a.containerType = ContainerArray + b.containerType = ContainerRun ret := unionArrayRun(a, b) if !reflect.DeepEqual(ret.array, test.exp) { t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.array) @@ -935,7 +937,7 @@ func TestUnionArrayRun(t *testing.T) { } func TestBitmapSetRange(t *testing.T) { - c := &container{container_type: ContainerBitmap, bitmap: make([]uint64, bitmapN)} + c := &container{containerType: ContainerBitmap, bitmap: make([]uint64, bitmapN)} tests := []struct { bitmap []uint64 start uint64 @@ -975,7 +977,7 @@ func TestBitmapSetRange(t *testing.T) { } func TestArrayToBitmap(t *testing.T) { - a := &container{container_type: ContainerArray} + a := &container{containerType: ContainerArray} tests := []struct { array []uint16 exp []uint64 @@ -1006,7 +1008,7 @@ func TestArrayToBitmap(t *testing.T) { } func TestBitmapToArray(t *testing.T) { - a := &container{container_type: ContainerBitmap} + a := &container{containerType: ContainerBitmap} tests := []struct { bitmap []uint64 exp []uint16 @@ -1037,7 +1039,7 @@ func TestBitmapToArray(t *testing.T) { } func TestRunToBitmap(t *testing.T) { - a := &container{container_type: ContainerRun} + a := &container{containerType: ContainerRun} tests := []struct { runs []interval16 exp []uint64 @@ -1091,7 +1093,7 @@ func getFullBitmap() []uint64 { } func TestBitmapToRun(t *testing.T) { - a := &container{container_type: ContainerBitmap} + a := &container{containerType: ContainerBitmap} tests := []struct { bitmap []uint64 exp []interval16 @@ -1169,7 +1171,7 @@ func TestBitmapToRun(t *testing.T) { } func TestArrayToRun(t *testing.T) { - a := &container{container_type: ContainerArray} + a := &container{containerType: ContainerArray} tests := []struct { array []uint16 exp []interval16 @@ -1203,7 +1205,7 @@ func TestArrayToRun(t *testing.T) { } func TestRunToArray(t *testing.T) { - a := &container{container_type: ContainerRun} + a := &container{containerType: ContainerRun} tests := []struct { runs []interval16 exp []uint16 @@ -1237,7 +1239,7 @@ func TestRunToArray(t *testing.T) { } func TestBitmapZeroRange(t *testing.T) { - c := &container{container_type: ContainerBitmap, bitmap: make([]uint64, bitmapN)} + c := &container{containerType: ContainerBitmap, bitmap: make([]uint64, bitmapN)} tests := []struct { bitmap []uint64 start uint64 @@ -1273,7 +1275,7 @@ func TestBitmapZeroRange(t *testing.T) { if test.expN != c.n { t.Fatalf("test #%v expected n to be %v, but got %v", i, test.expN, c.n) } - for i, _ := range test.bitmap { + for i := range test.bitmap { c.bitmap[i] = 0 } } @@ -1281,8 +1283,8 @@ func TestBitmapZeroRange(t *testing.T) { } func TestUnionBitmapRun(t *testing.T) { - a := &container{container_type: ContainerBitmap, bitmap: make([]uint64, bitmapN)} - b := &container{container_type: ContainerRun} + a := &container{containerType: ContainerBitmap, bitmap: make([]uint64, bitmapN)} + b := &container{containerType: ContainerRun} tests := []struct { bitmap []uint64 runs []interval16 @@ -1313,14 +1315,14 @@ func TestUnionBitmapRun(t *testing.T) { if ret.n != test.expN { t.Fatalf("test #%v expected n to be %v, but got %v", i, test.expN, ret.n) } - for i, _ := range test.bitmap { + for i := range test.bitmap { a.bitmap[i] = 0 } } } func TestBitmapCountRuns(t *testing.T) { - c := &container{container_type: ContainerBitmap, bitmap: make([]uint64, bitmapN)} + c := &container{containerType: ContainerBitmap, bitmap: make([]uint64, bitmapN)} tests := []struct { bitmap []uint64 exp int @@ -1353,7 +1355,7 @@ func TestBitmapCountRuns(t *testing.T) { t.Fatalf("test #%v expected %v but got %v", i, test.exp, ret) } - for j, _ := range test.bitmap { + for j := range test.bitmap { c.bitmap[j] = 0 } } @@ -1370,7 +1372,7 @@ func TestBitmapCountRuns(t *testing.T) { } func TestArrayCountRuns(t *testing.T) { - c := &container{container_type: ContainerArray} + c := &container{containerType: ContainerArray} tests := []struct { array []uint16 exp int @@ -1411,8 +1413,8 @@ func TestArrayCountRuns(t *testing.T) { } func TestDifferenceArrayRun(t *testing.T) { - a := &container{container_type: ContainerArray} - b := &container{container_type: ContainerRun} + a := &container{containerType: ContainerArray} + b := &container{containerType: ContainerRun} tests := []struct { array []uint16 runs []interval16 @@ -1437,8 +1439,8 @@ func TestDifferenceArrayRun(t *testing.T) { } func TestDifferenceRunArray(t *testing.T) { - a := &container{container_type: ContainerRun} - b := &container{container_type: ContainerArray} + a := &container{containerType: ContainerRun} + b := &container{containerType: ContainerArray} tests := []struct { runs []interval16 array []uint16 @@ -1518,8 +1520,8 @@ func MakeLastBitSet() []uint64 { } func TestDifferenceRunBitmap(t *testing.T) { - a := &container{container_type: ContainerRun} - b := &container{container_type: ContainerBitmap, bitmap: make([]uint64, bitmapN)} + a := &container{containerType: ContainerRun} + b := &container{containerType: ContainerBitmap, bitmap: make([]uint64, bitmapN)} tests := []struct { runs []interval16 bitmap []uint64 @@ -1581,8 +1583,8 @@ func TestDifferenceRunBitmap(t *testing.T) { } func TestDifferenceBitmapRun(t *testing.T) { - a := &container{container_type: ContainerBitmap, bitmap: make([]uint64, bitmapN)} - b := &container{container_type: ContainerRun} + a := &container{containerType: ContainerBitmap, bitmap: make([]uint64, bitmapN)} + b := &container{containerType: ContainerRun} tests := []struct { bitmap []uint64 runs []interval16 @@ -1639,7 +1641,7 @@ func TestDifferenceBitmapRun(t *testing.T) { exp: []uint64{0x0000000000000000}, }, { - bitmap: bitmapLast(), + bitmap: bitmapLastBitSet(), runs: []interval16{{start: 65535, last: 65535}}, exp: bitmapEmpty(), }, @@ -1664,8 +1666,8 @@ func TestDifferenceBitmapRun(t *testing.T) { } func TestDifferenceBitmapArray(t *testing.T) { - b := &container{container_type: ContainerBitmap, bitmap: make([]uint64, bitmapN)} - a := &container{container_type: ContainerArray} + b := &container{containerType: ContainerBitmap, bitmap: make([]uint64, bitmapN)} + a := &container{containerType: ContainerArray} tests := []struct { bitmap []uint64 array []uint16 @@ -1687,12 +1689,12 @@ func TestDifferenceBitmapArray(t *testing.T) { exp: []uint16{8, 9, 11, 12, 13, 14, 15}, }, { - bitmap: bitmapOdds(), + bitmap: bitmapOddBitsSet(), array: []uint16{0, 1, 2, 3, 4, 5, 6, 7, 10}, exp: []uint16{9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63}, }, { - bitmap: bitmapOdds(), + bitmap: bitmapOddBitsSet(), array: []uint16{63}, exp: []uint16{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61}, }, @@ -1714,8 +1716,8 @@ func TestDifferenceBitmapArray(t *testing.T) { } func TestDifferenceBitmapBitmap(t *testing.T) { - a := &container{bitmap: make([]uint64, bitmapN), container_type: ContainerBitmap} - b := &container{bitmap: make([]uint64, bitmapN), container_type: ContainerBitmap} + a := &container{bitmap: make([]uint64, bitmapN), containerType: ContainerBitmap} + b := &container{bitmap: make([]uint64, bitmapN), containerType: ContainerBitmap} tests := []struct { abitmap []uint64 bbitmap []uint64 @@ -1744,8 +1746,8 @@ func TestDifferenceBitmapBitmap(t *testing.T) { } func TestDifferenceRunRun(t *testing.T) { - a := &container{container_type: ContainerRun} - b := &container{container_type: ContainerRun} + a := &container{containerType: ContainerRun} + b := &container{containerType: ContainerRun} tests := []struct { aruns []interval16 bruns []interval16 @@ -1778,7 +1780,7 @@ func TestDifferenceRunRun(t *testing.T) { } func TestWriteReadArray(t *testing.T) { - ca := &container{array: []uint16{1, 10, 100, 1000}, n: 4, container_type: ContainerArray} + ca := &container{array: []uint16{1, 10, 100, 1000}, n: 4, containerType: ContainerArray} ba := &Bitmap{keys: []uint64{0}, containers: []*container{ca}} ba2 := &Bitmap{} var buf bytes.Buffer @@ -1797,7 +1799,7 @@ func TestWriteReadArray(t *testing.T) { func TestWriteReadBitmap(t *testing.T) { // create bitmap containing > 4096 bits - cb := &container{bitmap: make([]uint64, bitmapN), n: 129 * 32, container_type: ContainerBitmap} + cb := &container{bitmap: make([]uint64, bitmapN), n: 129 * 32, containerType: ContainerBitmap} for i := 0; i < 129; i++ { cb.bitmap[i] = 0x5555555555555555 } @@ -1819,7 +1821,7 @@ func TestWriteReadBitmap(t *testing.T) { func TestWriteReadFullBitmap(t *testing.T) { // create bitmap containing > 4096 bits - cb := &container{bitmap: make([]uint64, bitmapN), n: 65536, container_type: ContainerBitmap} + cb := &container{bitmap: make([]uint64, bitmapN), n: 65536, containerType: ContainerBitmap} for i := 0; i < bitmapN; i++ { cb.bitmap[i] = 0xffffffffffffffff } @@ -1847,7 +1849,7 @@ func TestWriteReadFullBitmap(t *testing.T) { } func TestWriteReadRun(t *testing.T) { - cr := &container{runs: []interval16{{start: 3, last: 13}, {start: 100, last: 109}}, n: 21, container_type: ContainerRun} + cr := &container{runs: []interval16{{start: 3, last: 13}, {start: 100, last: 109}}, n: 21, containerType: ContainerRun} br := &Bitmap{keys: []uint64{0}, containers: []*container{cr}} br2 := &Bitmap{} var buf bytes.Buffer @@ -1871,21 +1873,21 @@ func TestXorArrayRun(t *testing.T) { exp *container }{ { - a: &container{array: []uint16{1, 5, 10, 11, 12}, container_type: ContainerArray}, - b: &container{runs: []interval16{{start: 2, last: 10}, {start: 12, last: 13}, {start: 15, last: 16}}, container_type: ContainerRun}, - exp: &container{array: []uint16{1, 2, 3, 4, 6, 7, 8, 9, 11, 13, 15, 16}, container_type: ContainerArray, n: 12}, + a: &container{array: []uint16{1, 5, 10, 11, 12}, containerType: ContainerArray}, + b: &container{runs: []interval16{{start: 2, last: 10}, {start: 12, last: 13}, {start: 15, last: 16}}, containerType: ContainerRun}, + exp: &container{array: []uint16{1, 2, 3, 4, 6, 7, 8, 9, 11, 13, 15, 16}, containerType: ContainerArray, n: 12}, }, { - a: &container{array: []uint16{1, 5, 10, 11, 12, 13, 14}, container_type: ContainerArray}, - b: &container{runs: []interval16{{start: 2, last: 10}, {start: 12, last: 13}, {start: 15, last: 16}}, container_type: ContainerRun}, - exp: &container{array: []uint16{1, 2, 3, 4, 6, 7, 8, 9, 11, 14, 15, 16}, container_type: ContainerArray, n: 12}, + a: &container{array: []uint16{1, 5, 10, 11, 12, 13, 14}, containerType: ContainerArray}, + b: &container{runs: []interval16{{start: 2, last: 10}, {start: 12, last: 13}, {start: 15, last: 16}}, containerType: ContainerRun}, + exp: &container{array: []uint16{1, 2, 3, 4, 6, 7, 8, 9, 11, 14, 15, 16}, containerType: ContainerArray, n: 12}, }, { - a: &container{array: []uint16{65535}, container_type: ContainerArray}, - b: &container{runs: []interval16{{start: 65534, last: 65535}}, container_type: ContainerRun}, - exp: &container{array: []uint16{65534}, container_type: ContainerArray, n: 1}, + a: &container{array: []uint16{65535}, containerType: ContainerArray}, + b: &container{runs: []interval16{{start: 65534, last: 65535}}, containerType: ContainerRun}, + exp: &container{array: []uint16{65534}, containerType: ContainerArray, n: 1}, }, { - a: &container{array: []uint16{65535}, container_type: ContainerArray}, - b: &container{runs: []interval16{{start: 65535, last: 65535}}, container_type: ContainerRun}, - exp: &container{array: []uint16{}, container_type: ContainerArray, n: 0}, + a: &container{array: []uint16{65535}, containerType: ContainerArray}, + b: &container{runs: []interval16{{start: 65535, last: 65535}}, containerType: ContainerRun}, + exp: &container{array: []uint16{}, containerType: ContainerArray, n: 0}, }, } @@ -1906,8 +1908,8 @@ func TestXorArrayRun(t *testing.T) { //special case that didn't fit the xorrunrun table testing below. func TestXorRunRun1(t *testing.T) { - a := &container{container_type: ContainerRun} - b := &container{container_type: ContainerRun} + a := &container{containerType: ContainerRun} + b := &container{containerType: ContainerRun} a.runs = []interval16{{start: 4, last: 10}} b.runs = []interval16{{start: 5, last: 10}} ret := xorRunRun(a, b) @@ -1921,8 +1923,8 @@ func TestXorRunRun1(t *testing.T) { } func TestXorRunRun(t *testing.T) { - a := &container{container_type: ContainerRun} - b := &container{container_type: ContainerRun} + a := &container{containerType: ContainerRun} + b := &container{containerType: ContainerRun} tests := []struct { aruns []interval16 bruns []interval16 @@ -2019,7 +2021,7 @@ func TestXorRunRun(t *testing.T) { } func TestBitmapFlip(t *testing.T) { - c := &container{bitmap: make([]uint64, bitmapN), container_type: ContainerBitmap} + c := &container{bitmap: make([]uint64, bitmapN), containerType: ContainerBitmap} ttable := []struct { original uint64 @@ -2051,7 +2053,7 @@ func TestBitmapFlip(t *testing.T) { } func TestBitmapXorRange(t *testing.T) { - c := &container{bitmap: make([]uint64, bitmapN), container_type: ContainerBitmap} + c := &container{bitmap: make([]uint64, bitmapN), containerType: ContainerBitmap} tests := []struct { bitmap []uint64 start uint64 @@ -2119,8 +2121,8 @@ func TestBitmapXorRange(t *testing.T) { } func TestXorBitmapRun(t *testing.T) { - a := &container{container_type: ContainerBitmap} - b := &container{container_type: ContainerRun} + a := &container{containerType: ContainerBitmap} + b := &container{containerType: ContainerRun} tests := []struct { bitmap []uint64 runs []interval16 @@ -2493,65 +2495,6 @@ func TestBitmap_BitmapWriteToWithEmpty(t *testing.T) { } } -func Test_BufBitmapIterator_Next(t *testing.T) { - b := NewBitmap() - for i := uint64(0); i < 4097; i++ { - b.Add(i) - } - if !b.containers[0].isBitmap() { - t.Fatalf("wrong container type") - } - - bin := []uint16{} - - itr := newBufBitmapIterator(newBitmapIterator(b.containers[0].bitmap)) - x := uint16(0) - - for i := 0; i < 10; i++ { - x, _ = itr.next() - bin = append(bin, x) - } - exp := []uint16{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} - if !reflect.DeepEqual(bin, exp) { - t.Fatalf("BufBitmapIterator expected (%v) but got (%v)", exp, bin) - } - - // ensure that unread points next back one such that the last value is repeated - itr.unread() - x, _ = itr.next() - bin = append(bin, x) - exp = append(exp, uint16(9)) - if !reflect.DeepEqual(bin, exp) { - t.Fatalf("BufBitmapIterator expected (%v) but got (%v)", exp, bin) - } -} - -func Test_BufBitmapIterator_UnreadPanic(t *testing.T) { - - defer func() { - if r := recover(); r == nil { - t.Errorf("BufBitmapIterator unread did not panic") - } - }() - - b := NewBitmap() - for i := uint64(0); i < 4097; i++ { - b.Add(i) - } - if !b.containers[0].isBitmap() { - t.Fatalf("wrong container type") - } - - itr := newBufBitmapIterator(newBitmapIterator(b.containers[0].bitmap)) - for i := 0; i < 10; i++ { - itr.next() - } - - // ensure that unreading back-to-back panics - itr.unread() - itr.unread() -} - func TestSearch64(t *testing.T) { tests := []struct { a []uint64 @@ -2631,9 +2574,9 @@ func TestSearch64(t *testing.T) { } func TestIntersectArrayBitmap(t *testing.T) { - a, b := &container{container_type: ContainerArray}, &container{ - container_type: ContainerBitmap, - bitmap: make([]uint64, bitmapN), + a, b := &container{containerType: ContainerArray}, &container{ + containerType: ContainerBitmap, + bitmap: make([]uint64, bitmapN), } tests := []struct { array []uint16 @@ -2667,23 +2610,23 @@ func TestIntersectArrayBitmap(t *testing.T) { }, { array: []uint16{0, 1, 63, 120, 543, 639, 12000, 65534, 65535}, - bitmap: bitmapOdds(), + bitmap: bitmapOddBitsSet(), exp: []uint16{1, 63, 543, 639, 65535}, }, { array: []uint16{0, 1, 63, 120, 543, 639, 12000, 65534, 65535}, - bitmap: bitmapEvens(), + bitmap: bitmapEvenBitsSet(), exp: []uint16{0, 120, 12000, 65534}, }, } for i, test := range tests { a.array = test.array - a.container_type = ContainerArray + a.containerType = ContainerArray for i, bmval := range test.bitmap { b.bitmap[i] = bmval } - b.container_type = ContainerBitmap + b.containerType = ContainerBitmap ret := intersectArrayBitmap(a, b).array if len(ret) == 0 && len(test.exp) == 0 { continue @@ -2694,49 +2637,6 @@ func TestIntersectArrayBitmap(t *testing.T) { } } -func bitmapOdds() []uint64 { - bitmap := make([]uint64, bitmapN) - for i := 0; i < bitmapN; i++ { - bitmap[i] = 0xAAAAAAAAAAAAAAAA - } - return bitmap -} - -func bitmapEvens() []uint64 { - bitmap := make([]uint64, bitmapN) - for i := 0; i < bitmapN; i++ { - bitmap[i] = 0x5555555555555555 - } - return bitmap -} - -func bitmapLast() []uint64 { - bitmap := make([]uint64, bitmapN) - for i := 0; i < bitmapN-1; i++ { - bitmap[i] = 0 - } - bitmap[bitmapN-1] = 0x8000000000000000 - return bitmap -} - -func bitmapFull() []uint64 { - bitmap := make([]uint64, bitmapN) - for i := 0; i < bitmapN; i++ { - bitmap[i] = 0xFFFFFFFFFFFFFFFF - } - return bitmap -} - -func bitmapEmpty() []uint64 { - bitmap := make([]uint64, bitmapN) - for i := 0; i < bitmapN; i++ { - bitmap[i] = 0 - } - return bitmap -} - -var containerWidth uint64 = 65536 - // rleCont returns a slice of numbers all in the range starting from // container_width*num, and ending at container_width*(num+1)-1. If left is // true, then the first 100 bits will be set, if mid is true, 100 bits in the @@ -2818,3 +2718,525 @@ func bitmapVariousContainers() *Bitmap { bm.Optimize() return bm } + +/////////////////////////////////////////////////////////////////////////// + +func getFunctionName(i interface{}) string { + x := runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name() + y := strings.Split(x, ".") + y = y[len(y)-1:] + return y[0] +} + +func TestContainerCombinations(t *testing.T) { + + cts := setupContainerTests() + + containerTypes := []byte{ContainerArray, ContainerBitmap, ContainerRun} + + // map used for a more descriptive print + cm := map[byte]string{ + ContainerArray: "array", + ContainerBitmap: "bitmap", + ContainerRun: "run", + } + + testOps := []testOp{ + // intersect + {intersect, "empty", "empty", "empty"}, + {intersect, "empty", "full", "empty"}, + {intersect, "empty", "firstBitSet", "empty"}, + {intersect, "empty", "lastBitSet", "empty"}, + {intersect, "empty", "firstBitUnset", "empty"}, + {intersect, "empty", "lastBitUnset", "empty"}, + {intersect, "empty", "innerBitsSet", "empty"}, + {intersect, "empty", "outerBitsSet", "empty"}, + {intersect, "empty", "oddBitsSet", "empty"}, + {intersect, "empty", "evenBitsSet", "empty"}, + // + {intersect, "full", "empty", "empty"}, + {intersect, "full", "full", "full"}, + {intersect, "full", "firstBitSet", "firstBitSet"}, + {intersect, "full", "lastBitSet", "lastBitSet"}, + {intersect, "full", "firstBitUnset", "firstBitUnset"}, + {intersect, "full", "lastBitUnset", "lastBitUnset"}, + {intersect, "full", "innerBitsSet", "innerBitsSet"}, + {intersect, "full", "outerBitsSet", "outerBitsSet"}, + {intersect, "full", "oddBitsSet", "oddBitsSet"}, + {intersect, "full", "evenBitsSet", "evenBitsSet"}, + // + {intersect, "firstBitSet", "empty", "empty"}, + {intersect, "firstBitSet", "full", "firstBitSet"}, + {intersect, "firstBitSet", "firstBitSet", "firstBitSet"}, + {intersect, "firstBitSet", "lastBitSet", "empty"}, + {intersect, "firstBitSet", "firstBitUnset", "empty"}, + {intersect, "firstBitSet", "lastBitUnset", "firstBitSet"}, + {intersect, "firstBitSet", "innerBitsSet", "empty"}, + {intersect, "firstBitSet", "outerBitsSet", "firstBitSet"}, + {intersect, "firstBitSet", "oddBitsSet", "empty"}, + {intersect, "firstBitSet", "evenBitsSet", "firstBitSet"}, + // + {intersect, "lastBitSet", "empty", "empty"}, + {intersect, "lastBitSet", "full", "lastBitSet"}, + {intersect, "lastBitSet", "firstBitSet", "empty"}, + {intersect, "lastBitSet", "lastBitSet", "lastBitSet"}, + {intersect, "lastBitSet", "firstBitUnset", "lastBitSet"}, + {intersect, "lastBitSet", "lastBitUnset", "empty"}, + {intersect, "lastBitSet", "innerBitsSet", "empty"}, + {intersect, "lastBitSet", "outerBitsSet", "lastBitSet"}, + {intersect, "lastBitSet", "oddBitsSet", "lastBitSet"}, + {intersect, "lastBitSet", "evenBitsSet", "empty"}, + // + {intersect, "firstBitUnset", "empty", "empty"}, + {intersect, "firstBitUnset", "full", "firstBitUnset"}, + {intersect, "firstBitUnset", "firstBitSet", "empty"}, + {intersect, "firstBitUnset", "lastBitSet", "lastBitSet"}, + {intersect, "firstBitUnset", "firstBitUnset", "firstBitUnset"}, + {intersect, "firstBitUnset", "lastBitUnset", "innerBitsSet"}, + {intersect, "firstBitUnset", "innerBitsSet", "innerBitsSet"}, + {intersect, "firstBitUnset", "outerBitsSet", "lastBitSet"}, + {intersect, "firstBitUnset", "oddBitsSet", "oddBitsSet"}, + //{intersect, "firstBitUnset", "evenBitsSet", ""}, + // + {intersect, "lastBitUnset", "empty", "empty"}, + {intersect, "lastBitUnset", "full", "lastBitUnset"}, + {intersect, "lastBitUnset", "firstBitSet", "firstBitSet"}, + {intersect, "lastBitUnset", "lastBitSet", "empty"}, + {intersect, "lastBitUnset", "firstBitUnset", "innerBitsSet"}, + {intersect, "lastBitUnset", "lastBitUnset", "lastBitUnset"}, + {intersect, "lastBitUnset", "innerBitsSet", "innerBitsSet"}, + {intersect, "lastBitUnset", "outerBitsSet", "firstBitSet"}, + //{intersect, "lastBitUnset", "oddBitsSet", ""}, + {intersect, "lastBitUnset", "evenBitsSet", "evenBitsSet"}, + // + {intersect, "innerBitsSet", "empty", "empty"}, + {intersect, "innerBitsSet", "full", "innerBitsSet"}, + {intersect, "innerBitsSet", "firstBitSet", "empty"}, + {intersect, "innerBitsSet", "lastBitSet", "empty"}, + {intersect, "innerBitsSet", "firstBitUnset", "innerBitsSet"}, + {intersect, "innerBitsSet", "lastBitUnset", "innerBitsSet"}, + {intersect, "innerBitsSet", "innerBitsSet", "innerBitsSet"}, + {intersect, "innerBitsSet", "outerBitsSet", "empty"}, + //{intersect, "innerBitsSet", "oddBitsSet", ""}, + //{intersect, "innerBitsSet", "evenBitsSet", ""}, + // + {intersect, "outerBitsSet", "empty", "empty"}, + {intersect, "outerBitsSet", "full", "outerBitsSet"}, + {intersect, "outerBitsSet", "firstBitSet", "firstBitSet"}, + {intersect, "outerBitsSet", "lastBitSet", "lastBitSet"}, + {intersect, "outerBitsSet", "firstBitUnset", "lastBitSet"}, + {intersect, "outerBitsSet", "lastBitUnset", "firstBitSet"}, + {intersect, "outerBitsSet", "innerBitsSet", "empty"}, + {intersect, "outerBitsSet", "outerBitsSet", "outerBitsSet"}, + {intersect, "outerBitsSet", "oddBitsSet", "lastBitSet"}, + {intersect, "outerBitsSet", "evenBitsSet", "firstBitSet"}, + // + {intersect, "oddBitsSet", "empty", "empty"}, + {intersect, "oddBitsSet", "full", "oddBitsSet"}, + {intersect, "oddBitsSet", "firstBitSet", "empty"}, + {intersect, "oddBitsSet", "lastBitSet", "lastBitSet"}, + {intersect, "oddBitsSet", "firstBitUnset", "oddBitsSet"}, + //{intersect, "oddBitsSet", "lastBitUnset", ""}, + //{intersect, "oddBitsSet", "innerBitsSet", ""}, + {intersect, "oddBitsSet", "outerBitsSet", "lastBitSet"}, + {intersect, "oddBitsSet", "oddBitsSet", "oddBitsSet"}, + {intersect, "oddBitsSet", "evenBitsSet", "empty"}, + // + {intersect, "evenBitsSet", "empty", "empty"}, + {intersect, "evenBitsSet", "full", "evenBitsSet"}, + {intersect, "evenBitsSet", "firstBitSet", "firstBitSet"}, + {intersect, "evenBitsSet", "lastBitSet", "empty"}, + //{intersect, "evenBitsSet", "firstBitUnset", ""}, + {intersect, "evenBitsSet", "lastBitUnset", "evenBitsSet"}, + //{intersect, "evenBitsSet", "innerBitsSet", ""}, + {intersect, "evenBitsSet", "outerBitsSet", "firstBitSet"}, + {intersect, "evenBitsSet", "oddBitsSet", "empty"}, + {intersect, "evenBitsSet", "evenBitsSet", "evenBitsSet"}, + + // union + {union, "empty", "empty", "empty"}, + {union, "empty", "full", "full"}, + {union, "empty", "firstBitSet", "firstBitSet"}, + {union, "empty", "lastBitSet", "lastBitSet"}, + {union, "empty", "firstBitUnset", "firstBitUnset"}, + {union, "empty", "lastBitUnset", "lastBitUnset"}, + {union, "empty", "innerBitsSet", "innerBitsSet"}, + {union, "empty", "outerBitsSet", "outerBitsSet"}, + {union, "empty", "oddBitsSet", "oddBitsSet"}, + {union, "empty", "evenBitsSet", "evenBitsSet"}, + // + {union, "full", "empty", "full"}, + {union, "full", "full", "full"}, + {union, "full", "firstBitSet", "full"}, + {union, "full", "lastBitSet", "full"}, + {union, "full", "firstBitUnset", "full"}, + {union, "full", "lastBitUnset", "full"}, + {union, "full", "innerBitsSet", "full"}, + {union, "full", "outerBitsSet", "full"}, + {union, "full", "oddBitsSet", "full"}, + {union, "full", "evenBitsSet", "full"}, + // + {union, "firstBitSet", "empty", "firstBitSet"}, + {union, "firstBitSet", "full", "full"}, + {union, "firstBitSet", "firstBitSet", "firstBitSet"}, + {union, "firstBitSet", "lastBitSet", "outerBitsSet"}, + {union, "firstBitSet", "firstBitUnset", "full"}, + {union, "firstBitSet", "lastBitUnset", "lastBitUnset"}, + {union, "firstBitSet", "innerBitsSet", "lastBitUnset"}, + {union, "firstBitSet", "outerBitsSet", "outerBitsSet"}, + //{union, "firstBitSet", "oddBitsSet", ""}, + {union, "firstBitSet", "evenBitsSet", "evenBitsSet"}, + // + {union, "lastBitSet", "empty", "lastBitSet"}, + {union, "lastBitSet", "full", "full"}, + {union, "lastBitSet", "firstBitSet", "outerBitsSet"}, + {union, "lastBitSet", "lastBitSet", "lastBitSet"}, + {union, "lastBitSet", "firstBitUnset", "firstBitUnset"}, + {union, "lastBitSet", "lastBitUnset", "full"}, + {union, "lastBitSet", "innerBitsSet", "firstBitUnset"}, + {union, "lastBitSet", "outerBitsSet", "outerBitsSet"}, + {union, "lastBitSet", "oddBitsSet", "oddBitsSet"}, + //{union, "lastBitSet", "evenBitsSet", ""}, + // + {union, "firstBitUnset", "empty", "firstBitUnset"}, + {union, "firstBitUnset", "full", "full"}, + {union, "firstBitUnset", "firstBitSet", "full"}, + {union, "firstBitUnset", "lastBitSet", "firstBitUnset"}, + {union, "firstBitUnset", "firstBitUnset", "firstBitUnset"}, + {union, "firstBitUnset", "lastBitUnset", "full"}, + {union, "firstBitUnset", "innerBitsSet", "firstBitUnset"}, + {union, "firstBitUnset", "outerBitsSet", "full"}, + {union, "firstBitUnset", "oddBitsSet", "firstBitUnset"}, + {union, "firstBitUnset", "evenBitsSet", "full"}, + // + {union, "lastBitUnset", "empty", "lastBitUnset"}, + {union, "lastBitUnset", "full", "full"}, + {union, "lastBitUnset", "firstBitSet", "lastBitUnset"}, + {union, "lastBitUnset", "lastBitSet", "full"}, + {union, "lastBitUnset", "firstBitUnset", "full"}, + {union, "lastBitUnset", "lastBitUnset", "lastBitUnset"}, + {union, "lastBitUnset", "innerBitsSet", "lastBitUnset"}, + {union, "lastBitUnset", "outerBitsSet", "full"}, + {union, "lastBitUnset", "oddBitsSet", "full"}, + {union, "lastBitUnset", "evenBitsSet", "lastBitUnset"}, + // + {union, "innerBitsSet", "empty", "innerBitsSet"}, + {union, "innerBitsSet", "full", "full"}, + {union, "innerBitsSet", "firstBitSet", "lastBitUnset"}, + {union, "innerBitsSet", "lastBitSet", "firstBitUnset"}, + {union, "innerBitsSet", "firstBitUnset", "firstBitUnset"}, + {union, "innerBitsSet", "lastBitUnset", "lastBitUnset"}, + {union, "innerBitsSet", "innerBitsSet", "innerBitsSet"}, + {union, "innerBitsSet", "outerBitsSet", "full"}, + {union, "innerBitsSet", "oddBitsSet", "firstBitUnset"}, + {union, "innerBitsSet", "evenBitsSet", "lastBitUnset"}, + // + {union, "outerBitsSet", "empty", "outerBitsSet"}, + {union, "outerBitsSet", "full", "full"}, + {union, "outerBitsSet", "firstBitSet", "outerBitsSet"}, + {union, "outerBitsSet", "lastBitSet", "outerBitsSet"}, + {union, "outerBitsSet", "firstBitUnset", "full"}, + {union, "outerBitsSet", "lastBitUnset", "full"}, + {union, "outerBitsSet", "innerBitsSet", "full"}, + {union, "outerBitsSet", "outerBitsSet", "outerBitsSet"}, + //{union, "outerBitsSet", "oddBitsSet", ""}, + //{union, "outerBitsSet", "evenBitsSet", ""}, + // + {union, "oddBitsSet", "empty", "oddBitsSet"}, + {union, "oddBitsSet", "full", "full"}, + //{union, "oddBitsSet", "firstBitSet", ""}, + {union, "oddBitsSet", "lastBitSet", "oddBitsSet"}, + {union, "oddBitsSet", "firstBitUnset", "firstBitUnset"}, + {union, "oddBitsSet", "lastBitUnset", "full"}, + {union, "oddBitsSet", "innerBitsSet", "firstBitUnset"}, + //{union, "oddBitsSet", "outerBitsSet", ""}, + {union, "oddBitsSet", "oddBitsSet", "oddBitsSet"}, + {union, "oddBitsSet", "evenBitsSet", "full"}, + // + {union, "evenBitsSet", "empty", "evenBitsSet"}, + {union, "evenBitsSet", "full", "full"}, + {union, "evenBitsSet", "firstBitSet", "evenBitsSet"}, + //{union, "evenBitsSet", "lastBitSet", ""}, + {union, "evenBitsSet", "firstBitUnset", "full"}, + {union, "evenBitsSet", "lastBitUnset", "lastBitUnset"}, + {union, "evenBitsSet", "innerBitsSet", "lastBitUnset"}, + //{union, "evenBitsSet", "outerBitsSet", ""}, + {union, "evenBitsSet", "oddBitsSet", "full"}, + {union, "evenBitsSet", "evenBitsSet", "evenBitsSet"}, + + // difference + {difference, "empty", "empty", "empty"}, + {difference, "empty", "full", "empty"}, + {difference, "empty", "firstBitSet", "empty"}, + {difference, "empty", "lastBitSet", "empty"}, + {difference, "empty", "firstBitUnset", "empty"}, + {difference, "empty", "lastBitUnset", "empty"}, + {difference, "empty", "innerBitsSet", "empty"}, + {difference, "empty", "outerBitsSet", "empty"}, + {difference, "empty", "oddBitsSet", "empty"}, + {difference, "empty", "evenBitsSet", "empty"}, + // + {difference, "full", "empty", "full"}, + {difference, "full", "full", "empty"}, + {difference, "full", "firstBitSet", "firstBitUnset"}, + {difference, "full", "lastBitSet", "lastBitUnset"}, + {difference, "full", "firstBitUnset", "firstBitSet"}, + {difference, "full", "lastBitUnset", "lastBitSet"}, + {difference, "full", "innerBitsSet", "outerBitsSet"}, + {difference, "full", "outerBitsSet", "innerBitsSet"}, + {difference, "full", "oddBitsSet", "evenBitsSet"}, + {difference, "full", "evenBitsSet", "oddBitsSet"}, + // + {difference, "firstBitSet", "empty", "firstBitSet"}, + {difference, "firstBitSet", "full", "empty"}, + {difference, "firstBitSet", "firstBitSet", "empty"}, + {difference, "firstBitSet", "lastBitSet", "firstBitSet"}, + {difference, "firstBitSet", "firstBitUnset", "firstBitSet"}, + {difference, "firstBitSet", "lastBitUnset", "empty"}, + {difference, "firstBitSet", "innerBitsSet", "firstBitSet"}, + {difference, "firstBitSet", "outerBitsSet", "empty"}, + {difference, "firstBitSet", "oddBitsSet", "firstBitSet"}, + {difference, "firstBitSet", "evenBitsSet", "empty"}, + // + {difference, "lastBitSet", "empty", "lastBitSet"}, + {difference, "lastBitSet", "full", "empty"}, + {difference, "lastBitSet", "firstBitSet", "lastBitSet"}, + {difference, "lastBitSet", "lastBitSet", "empty"}, + {difference, "lastBitSet", "firstBitUnset", "empty"}, + {difference, "lastBitSet", "lastBitUnset", "lastBitSet"}, + {difference, "lastBitSet", "innerBitsSet", "lastBitSet"}, + {difference, "lastBitSet", "outerBitsSet", "empty"}, + {difference, "lastBitSet", "oddBitsSet", "empty"}, + {difference, "lastBitSet", "evenBitsSet", "lastBitSet"}, + // + {difference, "firstBitUnset", "empty", "firstBitUnset"}, + {difference, "firstBitUnset", "full", "empty"}, + {difference, "firstBitUnset", "firstBitSet", "firstBitUnset"}, + {difference, "firstBitUnset", "lastBitSet", "innerBitsSet"}, + {difference, "firstBitUnset", "firstBitUnset", "empty"}, + {difference, "firstBitUnset", "lastBitUnset", "lastBitSet"}, + {difference, "firstBitUnset", "innerBitsSet", "lastBitSet"}, + {difference, "firstBitUnset", "outerBitsSet", "innerBitsSet"}, + //{difference, "firstBitUnset", "oddBitsSet", ""}, + {difference, "firstBitUnset", "evenBitsSet", "oddBitsSet"}, + // + {difference, "lastBitUnset", "empty", "lastBitUnset"}, + {difference, "lastBitUnset", "full", "empty"}, + {difference, "lastBitUnset", "firstBitSet", "innerBitsSet"}, + {difference, "lastBitUnset", "lastBitSet", "lastBitUnset"}, + {difference, "lastBitUnset", "firstBitUnset", "firstBitSet"}, + {difference, "lastBitUnset", "lastBitUnset", "empty"}, + {difference, "lastBitUnset", "innerBitsSet", "firstBitSet"}, + {difference, "lastBitUnset", "outerBitsSet", "innerBitsSet"}, + {difference, "lastBitUnset", "oddBitsSet", "evenBitsSet"}, + //{difference, "lastBitUnset", "evenBitsSet", ""}, + // + {difference, "innerBitsSet", "empty", "innerBitsSet"}, + {difference, "innerBitsSet", "full", "empty"}, + {difference, "innerBitsSet", "firstBitSet", "innerBitsSet"}, + {difference, "innerBitsSet", "lastBitSet", "innerBitsSet"}, + {difference, "innerBitsSet", "firstBitUnset", "empty"}, + {difference, "innerBitsSet", "lastBitUnset", "empty"}, + {difference, "innerBitsSet", "innerBitsSet", "empty"}, + {difference, "innerBitsSet", "outerBitsSet", "innerBitsSet"}, + //{difference, "innerBitsSet", "oddBitsSet", ""}, + //{difference, "innerBitsSet", "evenBitsSet", ""}, + // + {difference, "outerBitsSet", "empty", "outerBitsSet"}, + {difference, "outerBitsSet", "full", "empty"}, + {difference, "outerBitsSet", "firstBitSet", "lastBitSet"}, + {difference, "outerBitsSet", "lastBitSet", "firstBitSet"}, + {difference, "outerBitsSet", "firstBitUnset", "firstBitSet"}, + {difference, "outerBitsSet", "lastBitUnset", "lastBitSet"}, + {difference, "outerBitsSet", "innerBitsSet", "outerBitsSet"}, + {difference, "outerBitsSet", "outerBitsSet", "empty"}, + {difference, "outerBitsSet", "oddBitsSet", "firstBitSet"}, + {difference, "outerBitsSet", "evenBitsSet", "lastBitSet"}, + // + {difference, "oddBitsSet", "empty", "oddBitsSet"}, + {difference, "oddBitsSet", "full", "empty"}, + {difference, "oddBitsSet", "firstBitSet", "oddBitsSet"}, + //{difference, "oddBitsSet", "lastBitSet", ""}, + {difference, "oddBitsSet", "firstBitUnset", "empty"}, + {difference, "oddBitsSet", "lastBitUnset", "lastBitSet"}, + {difference, "oddBitsSet", "innerBitsSet", "lastBitSet"}, + //{difference, "oddBitsSet", "outerBitsSet", ""}, + {difference, "oddBitsSet", "oddBitsSet", "empty"}, + {difference, "oddBitsSet", "evenBitsSet", "oddBitsSet"}, + // + {difference, "evenBitsSet", "empty", "evenBitsSet"}, + {difference, "evenBitsSet", "full", "empty"}, + //{difference, "evenBitsSet", "firstBitSet", ""}, + {difference, "evenBitsSet", "lastBitSet", "evenBitsSet"}, + {difference, "evenBitsSet", "firstBitUnset", "firstBitSet"}, + {difference, "evenBitsSet", "lastBitUnset", "empty"}, + {difference, "evenBitsSet", "innerBitsSet", "firstBitSet"}, + //{difference, "evenBitsSet", "outerBitsSet", ""}, + {difference, "evenBitsSet", "oddBitsSet", "evenBitsSet"}, + {difference, "evenBitsSet", "evenBitsSet", "empty"}, + + // xor + {xor, "empty", "empty", "empty"}, + {xor, "empty", "full", "full"}, + {xor, "empty", "firstBitSet", "firstBitSet"}, + {xor, "empty", "lastBitSet", "lastBitSet"}, + {xor, "empty", "firstBitUnset", "firstBitUnset"}, + {xor, "empty", "lastBitUnset", "lastBitUnset"}, + {xor, "empty", "innerBitsSet", "innerBitsSet"}, + {xor, "empty", "outerBitsSet", "outerBitsSet"}, + {xor, "empty", "oddBitsSet", "oddBitsSet"}, + {xor, "empty", "evenBitsSet", "evenBitsSet"}, + // + {xor, "full", "empty", "full"}, + {xor, "full", "full", "empty"}, + {xor, "full", "firstBitSet", "firstBitUnset"}, + {xor, "full", "lastBitSet", "lastBitUnset"}, + {xor, "full", "firstBitUnset", "firstBitSet"}, + {xor, "full", "lastBitUnset", "lastBitSet"}, + {xor, "full", "innerBitsSet", "outerBitsSet"}, + {xor, "full", "outerBitsSet", "innerBitsSet"}, + {xor, "full", "oddBitsSet", "evenBitsSet"}, + {xor, "full", "evenBitsSet", "oddBitsSet"}, + // + {xor, "firstBitSet", "empty", "firstBitSet"}, + {xor, "firstBitSet", "full", "firstBitUnset"}, + {xor, "firstBitSet", "firstBitSet", "empty"}, + {xor, "firstBitSet", "lastBitSet", "outerBitsSet"}, + {xor, "firstBitSet", "firstBitUnset", "full"}, + {xor, "firstBitSet", "lastBitUnset", "innerBitsSet"}, + {xor, "firstBitSet", "innerBitsSet", "lastBitUnset"}, + {xor, "firstBitSet", "outerBitsSet", "lastBitSet"}, + //{xor, "firstBitSet", "oddBitsSet", ""}, + //{xor, "firstBitSet", "evenBitsSet", ""}, + // + {xor, "lastBitSet", "empty", "lastBitSet"}, + {xor, "lastBitSet", "full", "lastBitUnset"}, + {xor, "lastBitSet", "firstBitSet", "outerBitsSet"}, + {xor, "lastBitSet", "lastBitSet", "empty"}, + {xor, "lastBitSet", "firstBitUnset", "innerBitsSet"}, + {xor, "lastBitSet", "lastBitUnset", "full"}, + {xor, "lastBitSet", "innerBitsSet", "firstBitUnset"}, + {xor, "lastBitSet", "outerBitsSet", "firstBitSet"}, + //{xor, "lastBitSet", "oddBitsSet", ""}, + //{xor, "lastBitSet", "evenBitsSet", ""}, + // + {xor, "firstBitUnset", "empty", "firstBitUnset"}, + {xor, "firstBitUnset", "full", "firstBitSet"}, + {xor, "firstBitUnset", "firstBitSet", "full"}, + {xor, "firstBitUnset", "lastBitSet", "innerBitsSet"}, + {xor, "firstBitUnset", "firstBitUnset", "empty"}, + {xor, "firstBitUnset", "lastBitUnset", "outerBitsSet"}, + {xor, "firstBitUnset", "innerBitsSet", "lastBitSet"}, + {xor, "firstBitUnset", "outerBitsSet", "lastBitUnset"}, + //{xor, "firstBitUnset", "oddBitsSet", ""}, + //{xor, "firstBitUnset", "evenBitsSet", ""}, + // + {xor, "lastBitUnset", "empty", "lastBitUnset"}, + {xor, "lastBitUnset", "full", "lastBitSet"}, + {xor, "lastBitUnset", "firstBitSet", "innerBitsSet"}, + {xor, "lastBitUnset", "lastBitSet", "full"}, + {xor, "lastBitUnset", "firstBitUnset", "outerBitsSet"}, + {xor, "lastBitUnset", "lastBitUnset", "empty"}, + {xor, "lastBitUnset", "innerBitsSet", "firstBitSet"}, + {xor, "lastBitUnset", "outerBitsSet", "firstBitUnset"}, + //{xor, "lastBitUnset", "oddBitsSet", ""}, + //{xor, "lastBitUnset", "evenBitsSet", ""}, + // + {xor, "innerBitsSet", "empty", "innerBitsSet"}, + {xor, "innerBitsSet", "full", "outerBitsSet"}, + {xor, "innerBitsSet", "firstBitSet", "lastBitUnset"}, + {xor, "innerBitsSet", "lastBitSet", "firstBitUnset"}, + {xor, "innerBitsSet", "firstBitUnset", "lastBitSet"}, + {xor, "innerBitsSet", "lastBitUnset", "firstBitSet"}, + {xor, "innerBitsSet", "innerBitsSet", "empty"}, + {xor, "innerBitsSet", "outerBitsSet", "full"}, + //{xor, "innerBitsSet", "oddBitsSet", ""}, + //{xor, "innerBitsSet", "evenBitsSet", ""}, + // + {xor, "outerBitsSet", "empty", "outerBitsSet"}, + {xor, "outerBitsSet", "full", "innerBitsSet"}, + {xor, "outerBitsSet", "firstBitSet", "lastBitSet"}, + {xor, "outerBitsSet", "lastBitSet", "firstBitSet"}, + {xor, "outerBitsSet", "firstBitUnset", "lastBitUnset"}, + {xor, "outerBitsSet", "lastBitUnset", "firstBitUnset"}, + {xor, "outerBitsSet", "innerBitsSet", "full"}, + {xor, "outerBitsSet", "outerBitsSet", "empty"}, + //{xor, "outerBitsSet", "oddBitsSet", ""}, + //{xor, "outerBitsSet", "evenBitsSet", ""}, + // + {xor, "oddBitsSet", "empty", "oddBitsSet"}, + {xor, "oddBitsSet", "full", "evenBitsSet"}, + //{xor, "oddBitsSet", "firstBitSet", ""}, + //{xor, "oddBitsSet", "lastBitSet", ""}, + //{xor, "oddBitsSet", "firstBitUnset", ""}, + //{xor, "oddBitsSet", "lastBitUnset", ""}, + //{xor, "oddBitsSet", "innerBitsSet", ""}, + //{xor, "oddBitsSet", "outerBitsSet", ""}, + {xor, "oddBitsSet", "oddBitsSet", "empty"}, + {xor, "oddBitsSet", "evenBitsSet", "full"}, + // + {xor, "evenBitsSet", "empty", "evenBitsSet"}, + {xor, "evenBitsSet", "full", "oddBitsSet"}, + //{xor, "evenBitsSet", "firstBitSet", ""}, + //{xor, "evenBitsSet", "lastBitSet", ""}, + //{xor, "evenBitsSet", "firstBitUnset", ""}, + //{xor, "evenBitsSet", "lastBitUnset", ""}, + //{xor, "evenBitsSet", "innerBitsSet", ""}, + //{xor, "evenBitsSet", "outerBitsSet", ""}, + {xor, "evenBitsSet", "oddBitsSet", "full"}, + {xor, "evenBitsSet", "evenBitsSet", "empty"}, + } + for _, testOp := range testOps { + for _, x := range containerTypes { + for _, y := range containerTypes { + desc := fmt.Sprintf("%s(%s/%s, %s/%s)", getFunctionName(testOp.f), cm[x], testOp.x, cm[y], testOp.y) + ret := testOp.f(cts[x][testOp.x], cts[y][testOp.y]) + exp := testOp.exp + + // Convert to all container types and check result. + for _, ct := range containerTypes { + clone := ret.clone() + if ct == ContainerArray { + if clone.isBitmap() { + clone.bitmapToArray() + } else if clone.isRun() { + clone.runToArray() + } + if clone.n != cts[ct][exp].n { + t.Fatalf("test %s expected array n=%d, but got n=%d", desc, cts[ct][exp].n, clone.n) + } + // Because xorRunRun resulting in an empty container returns an array container with a + // nil slice array, then we need to check len() on array first (look for 0). + if !(len(clone.array) == 0 && len(cts[ct][exp].array) == 0) && !reflect.DeepEqual(clone.array, cts[ct][exp].array) { + t.Fatalf("test %s expected array %X, but got %X", desc, cts[ct][exp].array, clone.array) + } + } else if ct == ContainerBitmap { + if clone.isArray() { + clone.arrayToBitmap() + } else if clone.isRun() { + clone.runToBitmap() + } + if clone.n != cts[ct][exp].n { + t.Fatalf("test %s expected bitmap n=%d, but got n=%d", desc, cts[ct][exp].n, clone.n) + } + if !reflect.DeepEqual(clone.bitmap, cts[ct][exp].bitmap) { + t.Fatalf("test %s expected bitmap %X, but got %X", desc, cts[ct][exp].bitmap, clone.bitmap) + } + } else if ct == ContainerRun { + if clone.isArray() { + clone.arrayToRun() + } else if clone.isBitmap() { + clone.bitmapToRun() + } + if clone.n != cts[ct][exp].n { + t.Fatalf("test %s expected runs n=%d, but got n=%d", desc, cts[ct][exp].n, clone.n) + } + if !reflect.DeepEqual(clone.runs, cts[ct][exp].runs) { + t.Fatalf("test %s expected runs %X, but got %X", desc, cts[ct][exp].runs, clone.runs) + } + } + } + } + } + } +}