blob: 253d04fe98cc615c17e44a25505ab67c2c52a44a [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 bitutil_test
import (
"fmt"
"math/rand"
"testing"
"github.com/apache/arrow/go/v6/arrow/bitutil"
"github.com/apache/arrow/go/v6/arrow/internal/testing/tools"
"github.com/stretchr/testify/assert"
)
func TestIsMultipleOf8(t *testing.T) {
for _, tc := range []struct {
v int64
want bool
}{
{-16, true},
{-9, false},
{-8, true},
{-7, false},
{-4, false},
{-1, false},
{-0, true},
{0, true},
{1, false},
{4, false},
{7, false},
{8, true},
{9, false},
{16, true},
} {
t.Run(fmt.Sprintf("v=%d", tc.v), func(t *testing.T) {
got := bitutil.IsMultipleOf8(tc.v)
if got != tc.want {
t.Fatalf("IsMultipleOf8(%d): got=%v, want=%v", tc.v, got, tc.want)
}
})
}
}
func TestCeilByte(t *testing.T) {
tests := []struct {
name string
in, exp int
}{
{"zero", 0, 0},
{"five", 5, 8},
{"sixteen", 16, 16},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got := bitutil.CeilByte(test.in)
assert.Equal(t, test.exp, got)
})
}
}
func TestBitIsSet(t *testing.T) {
buf := make([]byte, 2)
buf[0] = 0xa1
buf[1] = 0xc2
exp := []bool{true, false, false, false, false, true, false, true, false, true, false, false, false, false, true, true}
var got []bool
for i := 0; i < 0x10; i++ {
got = append(got, bitutil.BitIsSet(buf, i))
}
assert.Equal(t, exp, got)
}
func TestBitIsNotSet(t *testing.T) {
buf := make([]byte, 2)
buf[0] = 0xa1
buf[1] = 0xc2
exp := []bool{false, true, true, true, true, false, true, false, true, false, true, true, true, true, false, false}
var got []bool
for i := 0; i < 0x10; i++ {
got = append(got, bitutil.BitIsNotSet(buf, i))
}
assert.Equal(t, exp, got)
}
func TestClearBit(t *testing.T) {
buf := make([]byte, 2)
buf[0] = 0xff
buf[1] = 0xff
for i, v := range []bool{false, true, true, true, true, false, true, false, true, false, true, true, true, true, false, false} {
if v {
bitutil.ClearBit(buf, i)
}
}
assert.Equal(t, []byte{0xa1, 0xc2}, buf)
}
func TestSetBit(t *testing.T) {
buf := make([]byte, 2)
for i, v := range []bool{true, false, false, false, false, true, false, true, false, true, false, false, false, false, true, true} {
if v {
bitutil.SetBit(buf, i)
}
}
assert.Equal(t, []byte{0xa1, 0xc2}, buf)
}
func TestSetBitTo(t *testing.T) {
buf := make([]byte, 2)
for i, v := range []bool{true, false, false, false, false, true, false, true, false, true, false, false, false, false, true, true} {
bitutil.SetBitTo(buf, i, v)
}
assert.Equal(t, []byte{0xa1, 0xc2}, buf)
}
func TestCountSetBits(t *testing.T) {
tests := []struct {
name string
buf []byte
off int
n int
exp int
}{
{"some 03 bits", bbits(0x11000000), 0, 3, 2},
{"some 11 bits", bbits(0x11000011, 0x01000000), 0, 11, 5},
{"some 72 bits", bbits(0x11001010, 0x11110000, 0x00001111, 0x11000011, 0x11001010, 0x11110000, 0x00001111, 0x11000011, 0x10001001), 0, 9 * 8, 35},
{"all 08 bits", bbits(0x11111110), 0, 8, 7},
{"all 03 bits", bbits(0x11100001), 0, 3, 3},
{"all 11 bits", bbits(0x11111111, 0x11111111), 0, 11, 11},
{"all 72 bits", bbits(0x11111111, 0x11111111, 0x11111111, 0x11111111, 0x11111111, 0x11111111, 0x11111111, 0x11111111, 0x11111111), 0, 9 * 8, 72},
{"none 03 bits", bbits(0x00000001), 0, 3, 0},
{"none 11 bits", bbits(0x00000000, 0x00000000), 0, 11, 0},
{"none 72 bits", bbits(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), 0, 9 * 8, 0},
{"some 03 bits - offset+1", bbits(0x11000000), 1, 3, 1},
{"some 03 bits - offset+2", bbits(0x11000000), 2, 3, 0},
{"some 11 bits - offset+1", bbits(0x11000011, 0x01000000, 0x00000000), 1, 11, 4},
{"some 11 bits - offset+2", bbits(0x11000011, 0x01000000, 0x00000000), 2, 11, 3},
{"some 11 bits - offset+3", bbits(0x11000011, 0x01000000, 0x00000000), 3, 11, 3},
{"some 11 bits - offset+6", bbits(0x11000011, 0x01000000, 0x00000000), 6, 11, 3},
{"some 11 bits - offset+7", bbits(0x11000011, 0x01000000, 0x00000000), 7, 11, 2},
{"some 11 bits - offset+8", bbits(0x11000011, 0x01000000, 0x00000000), 8, 11, 1},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got := bitutil.CountSetBits(test.buf, test.off, test.n)
assert.Equal(t, test.exp, got)
})
}
}
func TestCountSetBitsOffset(t *testing.T) {
slowCountSetBits := func(buf []byte, offset, n int) int {
count := 0
for i := offset; i < offset+n; i++ {
if bitutil.BitIsSet(buf, i) {
count++
}
}
return count
}
const (
bufSize = 1000
nbits = bufSize * 8
)
offsets := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 16, 32, 37, 63, 64, 128, nbits - 30, nbits - 64}
buf := make([]byte, bufSize)
rng := rand.New(rand.NewSource(0))
_, err := rng.Read(buf)
if err != nil {
t.Fatal(err)
}
for i, offset := range offsets {
want := slowCountSetBits(buf, offset, nbits-offset)
got := bitutil.CountSetBits(buf, offset, nbits-offset)
if got != want {
t.Errorf("offset[%2d/%2d]=%5d. got=%5d, want=%5d", i+1, len(offsets), offset, got, want)
}
}
}
func TestSetBitsTo(t *testing.T) {
for _, fillByte := range []byte{0x00, 0xFF} {
{
// set within a byte
bm := []byte{fillByte, fillByte, fillByte, fillByte}
bitutil.SetBitsTo(bm, 2, 2, true)
bitutil.SetBitsTo(bm, 4, 2, false)
assert.Equal(t, []byte{(fillByte &^ 0x3C) | 0xC}, bm[:1])
}
{
// test straddling a single byte boundary
bm := []byte{fillByte, fillByte, fillByte, fillByte}
bitutil.SetBitsTo(bm, 4, 7, true)
bitutil.SetBitsTo(bm, 11, 7, false)
assert.Equal(t, []byte{(fillByte & 0xF) | 0xF0, 0x7, fillByte &^ 0x3}, bm[:3])
}
{
// test byte aligned end
bm := []byte{fillByte, fillByte, fillByte, fillByte}
bitutil.SetBitsTo(bm, 4, 4, true)
bitutil.SetBitsTo(bm, 8, 8, false)
assert.Equal(t, []byte{(fillByte & 0xF) | 0xF0, 0x00, fillByte}, bm[:3])
}
{
// test byte aligned end, multiple bytes
bm := []byte{fillByte, fillByte, fillByte, fillByte}
bitutil.SetBitsTo(bm, 0, 24, false)
falseByte := byte(0)
assert.Equal(t, []byte{falseByte, falseByte, falseByte, fillByte}, bm)
}
}
}
func bbits(v ...int32) []byte {
return tools.IntsToBitsLSB(v...)
}
func BenchmarkBitIsSet(b *testing.B) {
buf := make([]byte, 32)
b.ResetTimer()
for i := 0; i < b.N; i++ {
bitutil.BitIsSet(buf, (i%32)&0x1a)
}
}
func BenchmarkSetBit(b *testing.B) {
buf := make([]byte, 32)
b.ResetTimer()
for i := 0; i < b.N; i++ {
bitutil.SetBit(buf, (i%32)&0x1a)
}
}
func BenchmarkSetBitTo(b *testing.B) {
vals := []bool{true, false, false, false, false, true, false, true, false, true, false, false, false, false, true, true}
buf := make([]byte, 32)
b.ResetTimer()
for i := 0; i < b.N; i++ {
bitutil.SetBitTo(buf, i%32, vals[i%len(vals)])
}
}
var (
intval int
)
func benchmarkCountSetBitsN(b *testing.B, offset, n int) {
nn := n/8 + 1
buf := make([]byte, nn)
//src := [4]byte{0x1f, 0xaa, 0xba, 0x11}
src := [4]byte{0x01, 0x01, 0x01, 0x01}
for i := 0; i < nn; i++ {
buf[i] = src[i&0x3]
}
b.ResetTimer()
var res int
for i := 0; i < b.N; i++ {
res = bitutil.CountSetBits(buf, offset, n-offset)
}
intval = res
}
func BenchmarkCountSetBits_3(b *testing.B) {
benchmarkCountSetBitsN(b, 0, 3)
}
func BenchmarkCountSetBits_32(b *testing.B) {
benchmarkCountSetBitsN(b, 0, 32)
}
func BenchmarkCountSetBits_128(b *testing.B) {
benchmarkCountSetBitsN(b, 0, 128)
}
func BenchmarkCountSetBits_1000(b *testing.B) {
benchmarkCountSetBitsN(b, 0, 1000)
}
func BenchmarkCountSetBits_1024(b *testing.B) {
benchmarkCountSetBitsN(b, 0, 1024)
}
func BenchmarkCountSetBitsOffset_3(b *testing.B) {
benchmarkCountSetBitsN(b, 1, 3)
}
func BenchmarkCountSetBitsOffset_32(b *testing.B) {
benchmarkCountSetBitsN(b, 1, 32)
}
func BenchmarkCountSetBitsOffset_128(b *testing.B) {
benchmarkCountSetBitsN(b, 1, 128)
}
func BenchmarkCountSetBitsOffset_1000(b *testing.B) {
benchmarkCountSetBitsN(b, 1, 1000)
}
func BenchmarkCountSetBitsOffset_1024(b *testing.B) {
benchmarkCountSetBitsN(b, 1, 1024)
}