github.com/protolambda/zssz@v0.1.5/bitfields/bitfield_test.go (about) 1 package bitfields 2 3 import ( 4 "fmt" 5 "testing" 6 ) 7 8 func TestBitIndex(t *testing.T) { 9 cases := []struct { 10 v byte 11 index uint64 12 }{ 13 {0, 0}, 14 {1, 0}, 15 {2, 1}, 16 {3, 1}, 17 {4, 2}, 18 {34, 5}, 19 {127, 6}, 20 {128, 7}, 21 {255, 7}, 22 } 23 for _, testCase := range cases { 24 t.Run(fmt.Sprintf("v %b (bin) index %d", testCase.v, testCase.index), func(t *testing.T) { 25 if res := BitIndex(testCase.v); res != testCase.index { 26 t.Errorf("unexpected bit index: %d for value %b (bin), expected index: %d", 27 res, testCase.v, testCase.index) 28 } 29 }) 30 } 31 } 32 33 func BenchmarkBitIndex(b *testing.B) { 34 // sum results for fun, and verify it has the same result with different benched solutions with same N. 35 out := uint64(0) 36 b.StartTimer() 37 for i := 0; i < b.N; i++ { 38 out += BitIndex(byte(i)) 39 } 40 b.StopTimer() 41 b.Logf("result after %d runs: %d", b.N, out) 42 } 43 44 // For speed performance comparison. 2x faster, but dependent on global 256 bytes var. 45 // (Also consider heap/stack location, take 2x with a grain of salt) 46 var lookup = [256]byte{ 47 0, 48 0, 49 1, 1, 50 2, 2, 2, 2, 51 3, 3, 3, 3, 3, 3, 3, 3, 52 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 53 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 54 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 55 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 56 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 57 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 58 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 59 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 60 } 61 62 func BenchmarkLookupBitIndex(b *testing.B) { 63 // sum results for fun, and verify it has the same result with different benched solutions with same N. 64 out := uint64(0) 65 b.StartTimer() 66 for i := 0; i < b.N; i++ { 67 out += uint64(lookup[byte(i)]) 68 } 69 b.StopTimer() 70 b.Logf("result after %d runs: %d", b.N, out) 71 } 72 73 func TestSetBit(t *testing.T) { 74 cases := []struct { 75 v []byte 76 index uint64 77 expected1 string 78 expected0 string 79 }{ 80 {[]byte{0}, 0, "00000001 ", "00000000 "}, 81 {[]byte{1}, 1, "00000011 ", "00000001 "}, 82 {[]byte{1}, 2, "00000101 ", "00000001 "}, 83 {[]byte{8}, 1, "00001010 ", "00001000 "}, 84 {[]byte{10}, 1, "00001010 ", "00001000 "}, 85 {[]byte{255}, 5, "11111111 ", "11011111 "}, 86 {[]byte{0x00, 0x00}, 0, "00000001 00000000 ", "00000000 00000000 "}, 87 {[]byte{0x00, 0x00}, 3, "00001000 00000000 ", "00000000 00000000 "}, 88 {[]byte{0x00, 0x00}, 15, "00000000 10000000 ", "00000000 00000000 "}, 89 {[]byte{0xff, 0xff}, 0, "11111111 11111111 ", "11111110 11111111 "}, 90 {[]byte{0xff, 0xff}, 5, "11111111 11111111 ", "11011111 11111111 "}, 91 {[]byte{0x13, 0x37}, 5, "00110011 00110111 ", "00010011 00110111 "}, 92 {[]byte{0x13, 0x37}, 8, "00010011 00110111 ", "00010011 00110110 "}, 93 {[]byte{0xff, 0xff}, 10, "11111111 11111111 ", "11111111 11111011 "}, 94 {[]byte{0x13, 0x37}, 10, "00010011 00110111 ", "00010011 00110011 "}, 95 {[]byte{0xff, 0xff}, 15, "11111111 11111111 ", "11111111 01111111 "}, 96 } 97 for _, testCase := range cases { 98 t.Run(fmt.Sprintf("v %b (bin) index %d", testCase.v, testCase.index), func(t *testing.T) { 99 t.Run("set to 1", func(t *testing.T) { 100 a := make([]byte, len(testCase.v)) 101 copy(a, testCase.v) 102 SetBit(a, testCase.index, true) 103 res := "" 104 for _, b := range a { 105 res += fmt.Sprintf("%08b ", b) 106 } 107 if res != testCase.expected1 { 108 t.Errorf("expected %s but got %s", testCase.expected1, res) 109 } 110 }) 111 t.Run("set to 0", func(t *testing.T) { 112 a := make([]byte, len(testCase.v)) 113 copy(a, testCase.v) 114 SetBit(a, testCase.index, false) 115 res := "" 116 for _, b := range a { 117 res += fmt.Sprintf("%08b ", b) 118 } 119 if res != testCase.expected0 { 120 t.Errorf("expected %s but got %s", testCase.expected1, res) 121 } 122 }) 123 t.Run("get bit", func(t *testing.T) { 124 data := "" 125 for _, b := range testCase.v { 126 data += fmt.Sprintf("%08b", b) 127 } 128 bit := GetBit(testCase.v, testCase.index) 129 expected := data[(testCase.index/8)*8+7-(testCase.index%8)] == '1' 130 if bit != expected { 131 t.Errorf("expected %v but got %v, data: %s", bit, expected, data) 132 } 133 }) 134 }) 135 } 136 } 137 138 func TestIsZeroBitlist(t *testing.T) { 139 cases := []struct { 140 v []byte 141 isZero bool 142 }{ 143 {[]byte{0}, true}, 144 {[]byte{1}, true}, 145 {[]byte{2}, true}, 146 {[]byte{3}, false}, 147 {[]byte{5}, false}, 148 {[]byte{8}, true}, 149 {[]byte{0x80}, true}, 150 {[]byte{0x81}, false}, 151 {[]byte{0x90}, false}, 152 {[]byte{0, 0}, true}, 153 {[]byte{0, 1}, true}, 154 {[]byte{0, 2}, true}, 155 {[]byte{2, 2}, false}, 156 {[]byte{0, 3}, false}, 157 {[]byte{0, 5}, false}, 158 {[]byte{0, 8}, true}, 159 {[]byte{0, 0x80}, true}, 160 {[]byte{3, 0x80}, false}, 161 {[]byte{0, 0x81}, false}, 162 {[]byte{0, 0x90}, false}, 163 {[]byte{0, 0, 0}, true}, 164 {[]byte{0, 0, 1}, true}, 165 {[]byte{0, 0, 2}, true}, 166 {[]byte{0, 0, 3}, false}, 167 {[]byte{0, 0, 5}, false}, 168 {[]byte{0, 0, 8}, true}, 169 {[]byte{0, 0, 0x80}, true}, 170 {[]byte{0, 0, 0x81}, false}, 171 {[]byte{0, 0, 0x90}, false}, 172 {[]byte{3, 0, 0x80}, false}, 173 } 174 for _, testCase := range cases { 175 t.Run(fmt.Sprintf("is-zero checking %b (bin)", testCase.v), func(t *testing.T) { 176 if res := IsZeroBitlist(testCase.v); res != testCase.isZero { 177 t.Errorf("unexpected is-zero result for %b (bin). Expected: %v, got: %v", 178 testCase.v, testCase.isZero, res) 179 } 180 }) 181 } 182 }