123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- package roaring
-
- import (
- "container/heap"
- )
-
- // Or function that requires repairAfterLazy
- func lazyOR(x1, x2 *Bitmap) *Bitmap {
- answer := NewBitmap()
- pos1 := 0
- pos2 := 0
- length1 := x1.highlowcontainer.size()
- length2 := x2.highlowcontainer.size()
- main:
- for (pos1 < length1) && (pos2 < length2) {
- s1 := x1.highlowcontainer.getKeyAtIndex(pos1)
- s2 := x2.highlowcontainer.getKeyAtIndex(pos2)
-
- for {
- if s1 < s2 {
- answer.highlowcontainer.appendCopy(x1.highlowcontainer, pos1)
- pos1++
- if pos1 == length1 {
- break main
- }
- s1 = x1.highlowcontainer.getKeyAtIndex(pos1)
- } else if s1 > s2 {
- answer.highlowcontainer.appendCopy(x2.highlowcontainer, pos2)
- pos2++
- if pos2 == length2 {
- break main
- }
- s2 = x2.highlowcontainer.getKeyAtIndex(pos2)
- } else {
- c1 := x1.highlowcontainer.getContainerAtIndex(pos1)
- switch t := c1.(type) {
- case *arrayContainer:
- c1 = t.toBitmapContainer()
- case *runContainer16:
- if !t.isFull() {
- c1 = t.toBitmapContainer()
- }
- }
-
- answer.highlowcontainer.appendContainer(s1, c1.lazyOR(x2.highlowcontainer.getContainerAtIndex(pos2)), false)
- pos1++
- pos2++
- if (pos1 == length1) || (pos2 == length2) {
- break main
- }
- s1 = x1.highlowcontainer.getKeyAtIndex(pos1)
- s2 = x2.highlowcontainer.getKeyAtIndex(pos2)
- }
- }
- }
- if pos1 == length1 {
- answer.highlowcontainer.appendCopyMany(x2.highlowcontainer, pos2, length2)
- } else if pos2 == length2 {
- answer.highlowcontainer.appendCopyMany(x1.highlowcontainer, pos1, length1)
- }
- return answer
- }
-
- // In-place Or function that requires repairAfterLazy
- func (x1 *Bitmap) lazyOR(x2 *Bitmap) *Bitmap {
- pos1 := 0
- pos2 := 0
- length1 := x1.highlowcontainer.size()
- length2 := x2.highlowcontainer.size()
- main:
- for (pos1 < length1) && (pos2 < length2) {
- s1 := x1.highlowcontainer.getKeyAtIndex(pos1)
- s2 := x2.highlowcontainer.getKeyAtIndex(pos2)
-
- for {
- if s1 < s2 {
- pos1++
- if pos1 == length1 {
- break main
- }
- s1 = x1.highlowcontainer.getKeyAtIndex(pos1)
- } else if s1 > s2 {
- x1.highlowcontainer.insertNewKeyValueAt(pos1, s2, x2.highlowcontainer.getContainerAtIndex(pos2).clone())
- pos2++
- pos1++
- length1++
- if pos2 == length2 {
- break main
- }
- s2 = x2.highlowcontainer.getKeyAtIndex(pos2)
- } else {
- c1 := x1.highlowcontainer.getContainerAtIndex(pos1)
- switch t := c1.(type) {
- case *arrayContainer:
- c1 = t.toBitmapContainer()
- case *runContainer16:
- if !t.isFull() {
- c1 = t.toBitmapContainer()
- }
- case *bitmapContainer:
- c1 = x1.highlowcontainer.getWritableContainerAtIndex(pos1)
- }
-
- x1.highlowcontainer.containers[pos1] = c1.lazyIOR(x2.highlowcontainer.getContainerAtIndex(pos2))
- x1.highlowcontainer.needCopyOnWrite[pos1] = false
- pos1++
- pos2++
- if (pos1 == length1) || (pos2 == length2) {
- break main
- }
- s1 = x1.highlowcontainer.getKeyAtIndex(pos1)
- s2 = x2.highlowcontainer.getKeyAtIndex(pos2)
- }
- }
- }
- if pos1 == length1 {
- x1.highlowcontainer.appendCopyMany(x2.highlowcontainer, pos2, length2)
- }
- return x1
- }
-
- // to be called after lazy aggregates
- func (x1 *Bitmap) repairAfterLazy() {
- for pos := 0; pos < x1.highlowcontainer.size(); pos++ {
- c := x1.highlowcontainer.getContainerAtIndex(pos)
- switch c.(type) {
- case *bitmapContainer:
- if c.(*bitmapContainer).cardinality == invalidCardinality {
- c = x1.highlowcontainer.getWritableContainerAtIndex(pos)
- c.(*bitmapContainer).computeCardinality()
- if c.(*bitmapContainer).getCardinality() <= arrayDefaultMaxSize {
- x1.highlowcontainer.setContainerAtIndex(pos, c.(*bitmapContainer).toArrayContainer())
- } else if c.(*bitmapContainer).isFull() {
- x1.highlowcontainer.setContainerAtIndex(pos, newRunContainer16Range(0, MaxUint16))
- }
- }
- }
- }
- }
-
- // FastAnd computes the intersection between many bitmaps quickly
- // Compared to the And function, it can take many bitmaps as input, thus saving the trouble
- // of manually calling "And" many times.
- func FastAnd(bitmaps ...*Bitmap) *Bitmap {
- if len(bitmaps) == 0 {
- return NewBitmap()
- } else if len(bitmaps) == 1 {
- return bitmaps[0].Clone()
- }
- answer := And(bitmaps[0], bitmaps[1])
- for _, bm := range bitmaps[2:] {
- answer.And(bm)
- }
- return answer
- }
-
- // FastOr computes the union between many bitmaps quickly, as opposed to having to call Or repeatedly.
- // It might also be faster than calling Or repeatedly.
- func FastOr(bitmaps ...*Bitmap) *Bitmap {
- if len(bitmaps) == 0 {
- return NewBitmap()
- } else if len(bitmaps) == 1 {
- return bitmaps[0].Clone()
- }
- answer := lazyOR(bitmaps[0], bitmaps[1])
- for _, bm := range bitmaps[2:] {
- answer = answer.lazyOR(bm)
- }
- // here is where repairAfterLazy is called.
- answer.repairAfterLazy()
- return answer
- }
-
- // HeapOr computes the union between many bitmaps quickly using a heap.
- // It might be faster than calling Or repeatedly.
- func HeapOr(bitmaps ...*Bitmap) *Bitmap {
- if len(bitmaps) == 0 {
- return NewBitmap()
- }
- // TODO: for better speed, we could do the operation lazily, see Java implementation
- pq := make(priorityQueue, len(bitmaps))
- for i, bm := range bitmaps {
- pq[i] = &item{bm, i}
- }
- heap.Init(&pq)
-
- for pq.Len() > 1 {
- x1 := heap.Pop(&pq).(*item)
- x2 := heap.Pop(&pq).(*item)
- heap.Push(&pq, &item{Or(x1.value, x2.value), 0})
- }
- return heap.Pop(&pq).(*item).value
- }
-
- // HeapXor computes the symmetric difference between many bitmaps quickly (as opposed to calling Xor repeated).
- // Internally, this function uses a heap.
- // It might be faster than calling Xor repeatedly.
- func HeapXor(bitmaps ...*Bitmap) *Bitmap {
- if len(bitmaps) == 0 {
- return NewBitmap()
- }
-
- pq := make(priorityQueue, len(bitmaps))
- for i, bm := range bitmaps {
- pq[i] = &item{bm, i}
- }
- heap.Init(&pq)
-
- for pq.Len() > 1 {
- x1 := heap.Pop(&pq).(*item)
- x2 := heap.Pop(&pq).(*item)
- heap.Push(&pq, &item{Xor(x1.value, x2.value), 0})
- }
- return heap.Pop(&pq).(*item).value
- }
|