github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/go/callgraph/vta/internal/trie/bits_test.go (about)

     1  // Copyright 2021 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build go1.13
     6  // +build go1.13
     7  
     8  package trie
     9  
    10  import (
    11  	"math/rand"
    12  	"testing"
    13  )
    14  
    15  func TestMask(t *testing.T) {
    16  	for _, c := range []struct {
    17  		p    prefix
    18  		b    bitpos
    19  		want prefix
    20  	}{
    21  		{
    22  			p:    0b00001000,
    23  			b:    0b00000100,
    24  			want: 0b00001011,
    25  		}, {
    26  			p:    0b01011011,
    27  			b:    0b00000000,
    28  			want: ^prefix(0),
    29  		}, {
    30  			p:    0b01011011,
    31  			b:    0b00000001,
    32  			want: 0b01011010,
    33  		}, {
    34  			p:    0b01011011,
    35  			b:    0b00000010,
    36  			want: 0b01011001,
    37  		}, {
    38  			p:    0b01011011,
    39  			b:    0b00000100,
    40  			want: 0b01011011,
    41  		}, {
    42  			p:    0b01011011,
    43  			b:    0b00001000,
    44  			want: 0b01010111,
    45  		}, {
    46  			p:    0b01011011,
    47  			b:    0b00010000,
    48  			want: 0b01001111,
    49  		}, {
    50  			p:    0b01011011,
    51  			b:    0b00100000,
    52  			want: 0b01011111,
    53  		}, {
    54  			p:    0b01011011,
    55  			b:    0b01000000,
    56  			want: 0b00111111,
    57  		}, {
    58  			p:    0b01011011,
    59  			b:    0b01000000,
    60  			want: 0b00111111,
    61  		}, {
    62  			p:    0b01011011,
    63  			b:    0b10000000,
    64  			want: 0b01111111,
    65  		},
    66  	} {
    67  		if got := mask(c.p, c.b); got != c.want {
    68  			t.Errorf("mask(%#b,%#b) got %#b. want %#b", c.p, c.b, got, c.want)
    69  		}
    70  	}
    71  }
    72  
    73  func TestMaskImpotent(t *testing.T) {
    74  	// test mask(mask(p, b), b) == mask(p,b)
    75  	for _, p := range []prefix{
    76  		0b0, 0b1, 0b100, ^prefix(0b0), ^prefix(0b10),
    77  	} {
    78  		for _, b := range []bitpos{
    79  			0, 0b1, 1 << 2, 1 << 63,
    80  		} {
    81  			once := mask(p, b)
    82  			twice := mask(once, b)
    83  			if once != twice {
    84  				t.Errorf("mask(mask(%#b,%#b), %#b) != mask(%#b,%#b) got %#b. want %#b",
    85  					p, b, b, p, b, twice, once)
    86  			}
    87  		}
    88  	}
    89  }
    90  
    91  func TestMatchPrefix(t *testing.T) {
    92  	for _, c := range []struct {
    93  		k prefix
    94  		p prefix
    95  		b bitpos
    96  	}{
    97  		{
    98  			k: 0b1000,
    99  			p: 0b1011,
   100  			b: 0b0100,
   101  		}, {
   102  			k: 0b1001,
   103  			p: 0b1011,
   104  			b: 0b0100,
   105  		}, {
   106  			k: 0b1010,
   107  			p: 0b1011,
   108  			b: 0b0100,
   109  		}, {
   110  			k: 0b1011,
   111  			p: 0b1011,
   112  			b: 0b0100,
   113  		}, {
   114  			k: 0b1100,
   115  			p: 0b1011,
   116  			b: 0b0100,
   117  		}, {
   118  			k: 0b1101,
   119  			p: 0b1011,
   120  			b: 0b0100,
   121  		}, {
   122  			k: 0b1110,
   123  			p: 0b1011,
   124  			b: 0b0100,
   125  		}, {
   126  			k: 0b1111,
   127  			p: 0b1011,
   128  			b: 0b0100,
   129  		},
   130  	} {
   131  		if !matchPrefix(c.k, c.p, c.b) {
   132  			t.Errorf("matchPrefix(%#b, %#b,%#b) should be true", c.k, c.p, c.b)
   133  		}
   134  	}
   135  }
   136  
   137  func TestNotMatchPrefix(t *testing.T) {
   138  	for _, c := range []struct {
   139  		k prefix
   140  		p prefix
   141  		b bitpos
   142  	}{
   143  		{
   144  			k: 0b0000,
   145  			p: 0b1011,
   146  			b: 0b0100,
   147  		}, {
   148  			k: 0b0010,
   149  			p: 0b1011,
   150  			b: 0b0100,
   151  		},
   152  	} {
   153  		if matchPrefix(c.k, c.p, c.b) {
   154  			t.Errorf("matchPrefix(%#b, %#b,%#b) should be false", c.k, c.p, c.b)
   155  		}
   156  	}
   157  }
   158  
   159  func TestBranchingBit(t *testing.T) {
   160  	for _, c := range []struct {
   161  		x    prefix
   162  		y    prefix
   163  		want bitpos
   164  	}{
   165  		{
   166  			x:    0b0000,
   167  			y:    0b1011,
   168  			want: 0b1000,
   169  		}, {
   170  			x:    0b1010,
   171  			y:    0b1011,
   172  			want: 0b0001,
   173  		}, {
   174  			x:    0b1011,
   175  			y:    0b1111,
   176  			want: 0b0100,
   177  		}, {
   178  			x:    0b1011,
   179  			y:    0b1001,
   180  			want: 0b0010,
   181  		},
   182  	} {
   183  		if got := branchingBit(c.x, c.y); got != c.want {
   184  			t.Errorf("branchingBit(%#b, %#b,) is not expected value. got %#b want %#b",
   185  				c.x, c.y, got, c.want)
   186  		}
   187  	}
   188  }
   189  
   190  func TestZeroBit(t *testing.T) {
   191  	for _, c := range []struct {
   192  		k prefix
   193  		b bitpos
   194  	}{
   195  		{
   196  			k: 0b1000,
   197  			b: 0b0100,
   198  		}, {
   199  			k: 0b1001,
   200  			b: 0b0100,
   201  		}, {
   202  			k: 0b1010,
   203  			b: 0b0100,
   204  		},
   205  	} {
   206  		if !zeroBit(c.k, c.b) {
   207  			t.Errorf("zeroBit(%#b, %#b) should be true", c.k, c.b)
   208  		}
   209  	}
   210  }
   211  func TestZeroBitFails(t *testing.T) {
   212  	for _, c := range []struct {
   213  		k prefix
   214  		b bitpos
   215  	}{
   216  		{
   217  			k: 0b1000,
   218  			b: 0b1000,
   219  		}, {
   220  			k: 0b1001,
   221  			b: 0b0001,
   222  		}, {
   223  			k: 0b1010,
   224  			b: 0b0010,
   225  		}, {
   226  			k: 0b1011,
   227  			b: 0b0001,
   228  		},
   229  	} {
   230  		if zeroBit(c.k, c.b) {
   231  			t.Errorf("zeroBit(%#b, %#b) should be false", c.k, c.b)
   232  		}
   233  	}
   234  }
   235  
   236  func TestOrd(t *testing.T) {
   237  	a := bitpos(0b0010)
   238  	b := bitpos(0b1000)
   239  	if ord(a, b) {
   240  		t.Errorf("ord(%#b, %#b) should be false", a, b)
   241  	}
   242  	if !ord(b, a) {
   243  		t.Errorf("ord(%#b, %#b) should be true", b, a)
   244  	}
   245  	if ord(a, a) {
   246  		t.Errorf("ord(%#b, %#b) should be false", a, a)
   247  	}
   248  	if !ord(a, 0) {
   249  		t.Errorf("ord(%#b, %#b) should be true", a, 0)
   250  	}
   251  }
   252  
   253  func TestPrefixesOverlapLemma(t *testing.T) {
   254  	// test
   255  	//   mask(p, fbb) == mask(q, fbb)
   256  	// iff
   257  	//   m > n && matchPrefix(q, p, m) or  (note: big endian encoding)
   258  	//   m < n && matchPrefix(p, q, n) or  (note: big endian encoding)
   259  	//   m ==n && p == q
   260  
   261  	// Case 1: mask(p, fbb) == mask(q, fbb) => m > n && matchPrefix(q, p, m)
   262  	m, n := bitpos(1<<2), bitpos(1<<1)
   263  	p, q := mask(0b100, m), mask(0b010, n)
   264  	if !(prefixesOverlap(p, m, q, n) && m > n && matchPrefix(q, p, m)) {
   265  		t.Errorf("prefixesOverlap(%#b, %#b, %#b, %#b) lemma does not hold",
   266  			p, m, q, n)
   267  	}
   268  	// Case 2: mask(p, fbb) == mask(q, fbb) => m < n && matchPrefix(p, q, n)
   269  	m, n = bitpos(1<<2), bitpos(1<<3)
   270  	p, q = mask(0b100, m), mask(0b1000, n)
   271  	if !(prefixesOverlap(p, m, q, n) && m < n && matchPrefix(p, q, n)) {
   272  		t.Errorf("prefixesOverlap(%#b, %#b, %#b, %#b) lemma does not hold",
   273  			p, m, q, n)
   274  	}
   275  	// Case 3: mask(p, fbb) == mask(q, fbb) => m < n && matchPrefix(p, q, n)
   276  	m, n = bitpos(1<<2), bitpos(1<<2)
   277  	p, q = mask(0b100, m), mask(0b001, n)
   278  	if !(prefixesOverlap(p, m, q, n) && m == n && p == q) {
   279  		t.Errorf("prefixesOverlap(%#b, %#b, %#b, %#b) lemma does not hold",
   280  			p, m, q, n)
   281  	}
   282  	// Case 4: mask(p, fbb) != mask(q, fbb)
   283  	m, n = bitpos(1<<1), bitpos(1<<1)
   284  	p, q = mask(0b100, m), mask(0b001, n)
   285  	if prefixesOverlap(p, m, q, n) ||
   286  		(m > n && matchPrefix(q, p, m)) ||
   287  		(m < n && matchPrefix(p, q, n)) ||
   288  		(m == n && p == q) {
   289  		t.Errorf("prefixesOverlap(%#b, %#b, %#b, %#b) lemma does not hold",
   290  			p, m, q, n)
   291  	}
   292  
   293  	// Do a few more random cases
   294  	r := rand.New(rand.NewSource(123))
   295  	N := 2000
   296  	for i := 0; i < N; i++ {
   297  		m := bitpos(1 << (r.Uint64() % (64 + 1)))
   298  		n := bitpos(1 << (r.Uint64() % (64 + 1)))
   299  
   300  		p := mask(prefix(r.Uint64()), m)
   301  		q := mask(prefix(r.Uint64()), n)
   302  
   303  		lhs := prefixesOverlap(p, m, q, n)
   304  		rhs := (m > n && matchPrefix(q, p, m)) ||
   305  			(m < n && matchPrefix(p, q, n)) ||
   306  			(m == n && p == q)
   307  
   308  		if lhs != rhs {
   309  			t.Errorf("prefixesOverlap(%#b, %#b, %#b, %#b) != <lemma> got %v. want %v",
   310  				p, m, q, n, lhs, rhs)
   311  		}
   312  	}
   313  }