diff --git a/roaring/roaring.go b/roaring/roaring.go index 9c4274df9..a94121dc9 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -3006,6 +3006,85 @@ func xorBitmapBitmap(a, b *Container) *Container { return output } +func shift(a *Container) (*Container, bool) { + if a.isArray() { + return shiftArray(a) + } else if a.isRun() { + return shiftRun(a) + } + return shiftBitmap(a) +} + +func shiftArray(a *Container) (*Container, bool) { + statsHit("shift/Array") + carry := false + output := &Container{containerType: containerArray} + output.array = make([]uint16, len(a.array)) + output.array = output.array[:0] + output.n = a.n + for _, v := range a.array { + fmt.Println(v,v+1) + if v+1 == 0 { //overflow + carry = true + output.n -= 1 + } else { + output.array = append(output.array, v+1) + } + } + return output, carry +} + +func shiftBitmap(a *Container) (*Container, bool) { + statsHit("shift/Bitmap") + carry := false + output := &Container{containerType: containerBitmap} + output.bitmap = make([]uint64, len(a.bitmap)) + output.bitmap = output.bitmap[:0] + output.n = a.n + lastcarry:=false + for i, v := range a.bitmap { + carry = (v&(1<<63))!= 0 + v = v << 1 + if i != 0 { + if lastcarry { + v |= 1 + } + } + output.bitmap = append(output.bitmap, v) + lastcarry = carry + } + if carry { + output.n -= 1 + } + return output, carry +} + +func shiftRun(a *Container) (*Container, bool) { + statsHit("shift/Run") + carry := false + output := &Container{containerType: containerRun} + output.runs = make([]interval16, len(a.runs)) + output.runs = output.runs[:0] + for _, v := range a.runs { + if v.start+1 == 0 { + carry = true + output.n -= 1 + break + } else if v.last+1 == 0 { + v.start += 1 + carry = true + output.n -= 1 + } else { + v.start += 1 + v.last += 1 + carry = false + } + output.runs = append(output.runs, v) + } + + return output, carry +} + // opType represents a type of operation. type opType uint8 diff --git a/roaring/roaring_helpers_test.go b/roaring/roaring_helpers_test.go index cd22978fb..36963425e 100644 --- a/roaring/roaring_helpers_test.go +++ b/roaring/roaring_helpers_test.go @@ -106,6 +106,25 @@ func bitmapFirstBitSet() []uint64 { return bitmap } +func bitmapSecondBitSet() []uint64 { + bitmap := make([]uint64, bitmapN) + bitmap[0] = 0x0000000000000002 + return bitmap +} + +func bitmapLastBitFirstRowSet() []uint64 { + bitmap := make([]uint64, bitmapN) + bitmap[0] = 0x8000000000000000 + return bitmap +} + +func bitmapFirstBitSecoundRowSet() []uint64 { + bitmap := make([]uint64, bitmapN) + bitmap[1] = 0x0000000000000001 + return bitmap +} + + func bitmapLastBitSet() []uint64 { bitmap := make([]uint64, bitmapN) bitmap[bitmapN-1] = 0x8000000000000000 diff --git a/roaring/roaring_internal_test.go b/roaring/roaring_internal_test.go index 78b686371..ffa8be812 100644 --- a/roaring/roaring_internal_test.go +++ b/roaring/roaring_internal_test.go @@ -3289,3 +3289,115 @@ func TestEquals(t *testing.T) { } } */ +func TestShiftArray(t *testing.T) { + a := &Container{ + containerType: containerArray, +} + tests := []struct { + array []uint16 + exp []uint16 + }{ + { + array: []uint16{1}, + exp: []uint16{2}, + }, + { + array: []uint16{}, + exp: []uint16{}, + }, + { + array: []uint16{1, 2, 3, 4, 5, 11, 12}, + exp: []uint16{2, 3, 4, 5, 6, 12,13}, + }, + { + array: []uint16{65535}, + exp: []uint16{}, + }, + } + + for i, test := range tests { + a.array = test.array + a.n = int32(len(a.array)) + ret,_ := shiftArray(a) + if !reflect.DeepEqual(ret.array, test.exp) { + t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.array) + } + } +} + + +func TestShiftBitmap(t *testing.T) { + a := &Container{ + containerType: containerBitmap, + } + tests := []struct { + bitmap []uint64 + exp []uint64 + }{ + { + bitmap:bitmapFirstBitSet() , + exp: bitmapSecondBitSet(), + }, + { + bitmap:bitmapLastBitSet() , + exp: bitmapEmpty(), + }, + { + bitmap:bitmapLastBitFirstRowSet() , + exp: bitmapFirstBitSecoundRowSet (), + }, + } + + for i, test := range tests { + a.bitmap = test.bitmap + a.n = 1 + ret,_ := shiftBitmap(a) + if !reflect.DeepEqual(ret.bitmap, test.exp) { + t.Fatalf("test #%v expected %v, but got %v", i, test.exp, ret.bitmap) + } + } +} +func TestShiftRun(t *testing.T) { + a := &Container{ + containerType: containerRun, + } + + tests := []struct { + runs []interval16 + n int32 + en int32 + exp []interval16 + carry bool + }{ + { + runs: []interval16{{start: 5, last: 10}}, + n: 5, + en: 5, + exp: []interval16{{start: 6, last: 11}}, + carry: false, + }, + { + runs: []interval16{{start: 5, last:65535 }}, + n: 65530, + en: 65529, + exp: []interval16{{start: 6, last: 65535}}, + carry: true, + }, + { + runs: []interval16{{start: 65535, last:65535 }}, + n: 1, + en: 0, + exp: []interval16{}, + carry: true, + }, + } + + for i, test := range tests { + a.runs = test.runs + a.n = test.n + ret,c := shiftRun(a) + if !reflect.DeepEqual(ret.runs, test.exp) && c == test.carry && ret.n == test.en { + t.Fatalf("test #%v expected %v, but got %v %d", i, test.exp, ret.runs,ret.n) + } + } +}