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 }