diff --git a/roaring/printutil.go b/roaring/printutil.go new file mode 100644 index 000000000..1f4e8feaa --- /dev/null +++ b/roaring/printutil.go @@ -0,0 +1,95 @@ +// Copyright 2020 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 ( + "fmt" + "math" + + "github.com/pilosa/pilosa/v2/shardwidth" +) + +// TODO: once fastRows2 merges, take out these redundant const definitions +const ( + rowExponent = (shardwidth.Exponent - 16) // e.g. 20 - 16 == 4 + rowWidth = 1 << rowExponent // containers per row // e.g. 1 << 4 == 16 + keyMask = (rowWidth - 1) // a mask for offset within the row // e.g. 0x0000000f or 15 +) + +func (b *Bitmap) String() (r string) { + r = "c(" + slc := b.Slice() + width := 0 + s := "" + for _, v := range slc { + if width == 0 { + s = fmt.Sprintf("%v", v) + } else { + s = fmt.Sprintf(", %v", v) + } + width += len(s) + r += s + if width > 70 { + r += ",\n" + width = 0 + } + } + if width == 0 && len(r) > 2 { + r = r[:len(r)-2] + } + return r + ")" +} + +// AsContainerMatrixString returns a string showing +// the matrix of rows in a shard, showing the count of hot (1) bits +// in each container. +func (b *Bitmap) AsContainerMatrixString() (r string) { + slc := b.Slice() + n := len(slc) + max := slc[n-1] + const rowWidthInContainerCount = 1 << (shardwidth.Exponent - 16) // - 16 because roaring.Container always holds 2^16 bits. + + sw := uint64(1 << shardwidth.Exponent) + //fmt.Printf("sw = %v, shardwidth.Exponent = %v, rowWidthInContainerCount=%v\n", sw, shardwidth.Exponent, rowWidthInContainerCount) + maxrow := uint64(math.Ceil(float64(max) / float64(sw))) + if max == 0 { + maxrow++ + } + matrix := make([][]uint64, maxrow) + for i := uint64(0); i < maxrow; i++ { + matrix[i] = make([]uint64, rowWidthInContainerCount) + } + iter, _ := b.Containers.Iterator(0) + for iter.Next() { + k, v := iter.Value() + j := k & keyMask + i := (k << 16) >> shardwidth.Exponent + matrix[i][j] = uint64(v.N()) + } + r = "\n " + for j := 0; j < rowWidthInContainerCount; j++ { + r += fmt.Sprintf("%-5v ", j) + } + r += "\n" + for i, row := range matrix { + r += fmt.Sprintf("[row %05v] ", i) + for j, col := range row { + _ = j + r += fmt.Sprintf("%-5v ", col) + } + r += "\n" + } + return +} diff --git a/roaring/printutil_test.go b/roaring/printutil_test.go new file mode 100644 index 000000000..9734efac2 --- /dev/null +++ b/roaring/printutil_test.go @@ -0,0 +1,92 @@ +// Copyright 2020 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 ( + "fmt" + "testing" + + "github.com/pilosa/pilosa/v2/shardwidth" +) + +func TestAsContainerMatrixString(t *testing.T) { + b := NewBitmap(0) + obs := b.AsContainerMatrixString() + exp20 := ` + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 +[row 00000] 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +` + exp22 := ` + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 +[row 00000] 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +` + exp := exp20 + if shardwidth.Exponent == 22 { + exp = exp22 + } + if obs != exp { + panic(fmt.Sprintf("unexpected output: obs='%v', exp='%v'", obs, exp)) + } +} + +func TestAsContainerMatrixString2(t *testing.T) { + b := NewBitmap(1<<16, 4<<16, 18<<16) + obs := b.AsContainerMatrixString() + exp20 := ` + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 +[row 00000] 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 +[row 00001] 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +` + + exp22 := ` + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 +[row 00000] 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +` + + exp := exp20 + if shardwidth.Exponent == 22 { + exp = exp22 + } + + if obs != exp { + panic(fmt.Sprintf("unexpected output: obs='%v', exp='%v'", obs, exp)) + } +} + +func TestAsContainerMatrixString3(t *testing.T) { + b := NewBitmap() + for i := uint64(0); i < 1<<16; i++ { + _, _ = b.AddN(i) + } + obs := b.AsContainerMatrixString() + exp20 := ` + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 +[row 00000] 65536 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +` + + exp22 := ` + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 +[row 00000] 65536 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +` + + exp := exp20 + if shardwidth.Exponent == 22 { + exp = exp22 + } + + if obs != exp { + panic(fmt.Sprintf("unexpected output: obs='%v', exp='%v'", obs, exp)) + } +}