github.com/dolthub/swiss@v0.2.2-0.20240312182618-f4b2babd2bc1/bits_test.go (about)

     1  // Copyright 2023 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package swiss
    16  
    17  import (
    18  	"math/bits"
    19  	"math/rand"
    20  	"testing"
    21  	"unsafe"
    22  
    23  	"github.com/stretchr/testify/assert"
    24  )
    25  
    26  func TestMatchMetadata(t *testing.T) {
    27  	var meta metadata
    28  	for i := range meta {
    29  		meta[i] = int8(i)
    30  	}
    31  	t.Run("metaMatchH2", func(t *testing.T) {
    32  		for _, x := range meta {
    33  			mask := metaMatchH2(&meta, h2(x))
    34  			assert.NotZero(t, mask)
    35  			assert.Equal(t, uint32(x), nextMatch(&mask))
    36  		}
    37  	})
    38  	t.Run("metaMatchEmpty", func(t *testing.T) {
    39  		mask := metaMatchEmpty(&meta)
    40  		assert.Equal(t, mask, bitset(0))
    41  		for i := range meta {
    42  			meta[i] = empty
    43  			mask = metaMatchEmpty(&meta)
    44  			assert.NotZero(t, mask)
    45  			assert.Equal(t, uint32(i), nextMatch(&mask))
    46  			meta[i] = int8(i)
    47  		}
    48  	})
    49  	t.Run("nextMatch", func(t *testing.T) {
    50  		// test iterating multiple matches
    51  		meta = newEmptyMetadata()
    52  		mask := metaMatchEmpty(&meta)
    53  		for i := range meta {
    54  			assert.Equal(t, uint32(i), nextMatch(&mask))
    55  		}
    56  		for i := 0; i < len(meta); i += 2 {
    57  			meta[i] = int8(42)
    58  		}
    59  		mask = metaMatchH2(&meta, h2(42))
    60  		for i := 0; i < len(meta); i += 2 {
    61  			assert.Equal(t, uint32(i), nextMatch(&mask))
    62  		}
    63  	})
    64  }
    65  
    66  func BenchmarkMatchMetadata(b *testing.B) {
    67  	var meta metadata
    68  	for i := range meta {
    69  		meta[i] = int8(i)
    70  	}
    71  	var mask bitset
    72  	for i := 0; i < b.N; i++ {
    73  		mask = metaMatchH2(&meta, h2(i))
    74  	}
    75  	b.Log(mask)
    76  }
    77  
    78  func TestNextPow2(t *testing.T) {
    79  	assert.Equal(t, 0, int(nextPow2(0)))
    80  	assert.Equal(t, 1, int(nextPow2(1)))
    81  	assert.Equal(t, 2, int(nextPow2(2)))
    82  	assert.Equal(t, 4, int(nextPow2(3)))
    83  	assert.Equal(t, 8, int(nextPow2(7)))
    84  	assert.Equal(t, 8, int(nextPow2(8)))
    85  	assert.Equal(t, 16, int(nextPow2(9)))
    86  }
    87  
    88  func nextPow2(x uint32) uint32 {
    89  	return 1 << (32 - bits.LeadingZeros32(x-1))
    90  }
    91  
    92  func TestConstants(t *testing.T) {
    93  	c1, c2 := empty, tombstone
    94  	assert.Equal(t, byte(0b1000_0000), byte(c1))
    95  	assert.Equal(t, byte(0b1000_0000), reinterpretCast(c1))
    96  	assert.Equal(t, byte(0b1111_1110), byte(c2))
    97  	assert.Equal(t, byte(0b1111_1110), reinterpretCast(c2))
    98  }
    99  
   100  func reinterpretCast(i int8) byte {
   101  	return *(*byte)(unsafe.Pointer(&i))
   102  }
   103  
   104  func TestFastMod(t *testing.T) {
   105  	t.Run("n=10", func(t *testing.T) {
   106  		testFastMod(t, 10)
   107  	})
   108  	t.Run("n=100", func(t *testing.T) {
   109  		testFastMod(t, 100)
   110  	})
   111  	t.Run("n=1000", func(t *testing.T) {
   112  		testFastMod(t, 1000)
   113  	})
   114  }
   115  
   116  func testFastMod(t *testing.T, n uint32) {
   117  	const trials = 32 * 1024
   118  	for i := 0; i < trials; i++ {
   119  		x := rand.Uint32()
   120  		y := fastModN(x, n)
   121  		assert.Less(t, y, n)
   122  		t.Logf("fastMod(%d, %d): %d", x, n, y)
   123  	}
   124  }