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  }