github.com/apache/arrow/go/v14@v14.0.1/internal/bitutils/bit_run_reader_test.go (about) 1 // Licensed to the Apache Software Foundation (ASF) under one 2 // or more contributor license agreements. See the NOTICE file 3 // distributed with this work for additional information 4 // regarding copyright ownership. The ASF licenses this file 5 // to you under the Apache License, Version 2.0 (the 6 // "License"); you may not use this file except in compliance 7 // with the License. You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 package bitutils_test 18 19 import ( 20 "math/bits" 21 "testing" 22 "unsafe" 23 24 "github.com/apache/arrow/go/v14/arrow/bitutil" 25 "github.com/apache/arrow/go/v14/arrow/endian" 26 "github.com/apache/arrow/go/v14/internal/bitutils" 27 "github.com/stretchr/testify/assert" 28 ) 29 30 var toLittleEndian func(uint64) uint64 31 32 func init() { 33 if endian.IsBigEndian { 34 toLittleEndian = bits.ReverseBytes64 35 } else { 36 toLittleEndian = func(in uint64) uint64 { return in } 37 } 38 } 39 40 func TestBitRunReaderZeroLength(t *testing.T) { 41 reader := bitutils.NewBitRunReader(nil, 0, 0) 42 assert.Zero(t, reader.NextRun().Len) 43 } 44 45 func bitmapFromSlice(vals []int, bitOffset int64) []byte { 46 out := make([]byte, int(bitutil.BytesForBits(int64(len(vals))+bitOffset))) 47 writer := bitutil.NewBitmapWriter(out, int(bitOffset), len(vals)) 48 for _, val := range vals { 49 if val == 1 { 50 writer.Set() 51 } else { 52 writer.Clear() 53 } 54 writer.Next() 55 } 56 writer.Finish() 57 58 return out 59 } 60 61 func TestBitRunReader(t *testing.T) { 62 tests := []struct { 63 name string 64 val []int 65 bmvec []int 66 offset int64 67 len int64 68 expected []bitutils.BitRun 69 }{ 70 {"normal operation", 71 []int{5, 0, 7, 1, 3, 0, 25, 1, 21, 0, 26, 1, 130, 0, 65, 1}, 72 []int{1, 0, 1}, 73 0, -1, 74 []bitutils.BitRun{ 75 {1, true}, 76 {1, false}, 77 {1, true}, 78 {5, false}, 79 {7, true}, 80 {3, false}, 81 {25, true}, 82 {21, false}, 83 {26, true}, 84 {130, false}, 85 {65, true}, 86 }, 87 }, 88 {"truncated at word", []int{7, 1, 58, 0}, []int{}, 1, 63, 89 []bitutils.BitRun{{6, true}, {57, false}}, 90 }, 91 {"truncated within word multiple of 8 bits", 92 []int{7, 1, 5, 0}, []int{}, 1, 7, 93 []bitutils.BitRun{{6, true}, {1, false}}, 94 }, 95 {"truncated within word", []int{37 + 40, 0, 23, 1}, []int{}, 37, 53, 96 []bitutils.BitRun{{40, false}, {13, true}}, 97 }, 98 {"truncated multiple words", []int{5, 0, 30, 1, 95, 0}, []int{1, 0, 1}, 99 5, (3 + 5 + 30 + 95) - (5 + 3), []bitutils.BitRun{{3, false}, {30, true}, {92, false}}, 100 }, 101 } 102 103 for _, tt := range tests { 104 t.Run(tt.name, func(t *testing.T) { 105 bmvec := tt.bmvec 106 107 for i := 0; i < len(tt.val); i += 2 { 108 for j := 0; j < tt.val[i]; j++ { 109 bmvec = append(bmvec, tt.val[i+1]) 110 } 111 } 112 113 bitmap := bitmapFromSlice(bmvec, 0) 114 length := int64(len(bmvec)) - tt.offset 115 if tt.len != -1 { 116 length = tt.len 117 } 118 reader := bitutils.NewBitRunReader(bitmap, tt.offset, length) 119 120 results := make([]bitutils.BitRun, 0) 121 for { 122 results = append(results, reader.NextRun()) 123 if results[len(results)-1].Len == 0 { 124 break 125 } 126 } 127 assert.Zero(t, results[len(results)-1].Len) 128 results = results[:len(results)-1] 129 130 assert.Equal(t, tt.expected, results) 131 }) 132 } 133 } 134 135 func TestBitRunReaderAllFirstByteCombos(t *testing.T) { 136 for offset := int64(0); offset < 8; offset++ { 137 for x := int64(0); x < (1<<8)-1; x++ { 138 bits := int64(toLittleEndian(uint64(x))) 139 reader := bitutils.NewBitRunReader((*(*[8]byte)(unsafe.Pointer(&bits)))[:], offset, 8-offset) 140 141 results := make([]bitutils.BitRun, 0) 142 for { 143 results = append(results, reader.NextRun()) 144 if results[len(results)-1].Len == 0 { 145 break 146 } 147 } 148 assert.Zero(t, results[len(results)-1].Len) 149 results = results[:len(results)-1] 150 151 var sum int64 152 for _, r := range results { 153 sum += r.Len 154 } 155 assert.EqualValues(t, sum, 8-offset) 156 } 157 } 158 }