gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/segment/test/segment_test.go (about)

     1  // Copyright 2018 The gVisor Authors.
     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 segment
    16  
    17  import (
    18  	"fmt"
    19  	"math/rand"
    20  	"slices"
    21  	"testing"
    22  )
    23  
    24  const (
    25  	// testSize is the baseline number of elements inserted into sets under
    26  	// test, and is chosen to be large enough to ensure interesting amounts of
    27  	// tree rebalancing.
    28  	//
    29  	// Note that because checkSet is called between each insertion/removal in
    30  	// some tests that use it, tests may be quadratic in testSize.
    31  	testSize = 8000
    32  
    33  	// valueOffset is the difference between the value and start of test
    34  	// segments.
    35  	valueOffset = 100000
    36  
    37  	// intervalLength is the interval used by random gap tests.
    38  	intervalLength = 10
    39  )
    40  
    41  func shuffle(xs []int) {
    42  	rand.Shuffle(len(xs), func(i, j int) { xs[i], xs[j] = xs[j], xs[i] })
    43  }
    44  
    45  func randIntervalPermutation(size int) []int {
    46  	p := make([]int, size)
    47  	for i := range p {
    48  		p[i] = intervalLength * i
    49  	}
    50  	shuffle(p)
    51  	return p
    52  }
    53  
    54  // validate can be passed to Check.
    55  func validate(nr int, r Range, v int) error {
    56  	if got, want := v, r.Start+valueOffset; got != want {
    57  		return fmt.Errorf("segment %d has key %d, value %d (expected %d)", nr, r.Start, got, want)
    58  	}
    59  	return nil
    60  }
    61  
    62  // checkSetMaxGap returns an error if maxGap inside all nodes of s is not well
    63  // maintained.
    64  func checkSetMaxGap(s *gapSet) error {
    65  	n := s.root
    66  	return checkNodeMaxGap(&n)
    67  }
    68  
    69  // checkNodeMaxGap returns an error if maxGap inside the subtree rooted by n is
    70  // not well maintained.
    71  func checkNodeMaxGap(n *gapnode) error {
    72  	var max int
    73  	if !n.hasChildren {
    74  		max = n.calculateMaxGapLeaf()
    75  	} else {
    76  		for i := 0; i <= n.nrSegments; i++ {
    77  			child := n.children[i]
    78  			if err := checkNodeMaxGap(child); err != nil {
    79  				return err
    80  			}
    81  			if temp := child.maxGap.Get(); i == 0 || temp > max {
    82  				max = temp
    83  			}
    84  		}
    85  	}
    86  	if max != n.maxGap.Get() {
    87  		return fmt.Errorf("maxGap wrong in node\n%vexpected: %d got: %d", n, max, n.maxGap)
    88  	}
    89  	return nil
    90  }
    91  
    92  func TestAddRandom(t *testing.T) {
    93  	var s Set
    94  	order := rand.Perm(testSize)
    95  	var nrInsertions int
    96  	for i, j := range order {
    97  		s.InsertWithoutMergingRange(Range{j, j + 1}, j+valueOffset)
    98  		nrInsertions++
    99  		if err := s.segmentTestCheck(nrInsertions, validate); err != nil {
   100  			t.Errorf("Iteration %d: %v", i, err)
   101  			break
   102  		}
   103  	}
   104  	if got, want := s.countSegments(), nrInsertions; got != want {
   105  		t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want)
   106  	}
   107  	if t.Failed() {
   108  		t.Logf("Insertion order: %v", order[:nrInsertions])
   109  		t.Logf("Set contents:\n%v", &s)
   110  	}
   111  }
   112  
   113  func TestRemoveRandom(t *testing.T) {
   114  	var s Set
   115  	for i := 0; i < testSize; i++ {
   116  		s.InsertWithoutMergingRange(Range{i, i + 1}, i+valueOffset)
   117  	}
   118  	order := rand.Perm(testSize)
   119  	var nrRemovals int
   120  	for i, j := range order {
   121  		seg := s.FindSegment(j)
   122  		if !seg.Ok() {
   123  			t.Errorf("Iteration %d: failed to find segment with key %d", i, j)
   124  			break
   125  		}
   126  		s.Remove(seg)
   127  		nrRemovals++
   128  		if err := s.segmentTestCheck(testSize-nrRemovals, validate); err != nil {
   129  			t.Errorf("Iteration %d: %v", i, err)
   130  			break
   131  		}
   132  	}
   133  	if got, want := s.countSegments(), testSize-nrRemovals; got != want {
   134  		t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want)
   135  	}
   136  	if t.Failed() {
   137  		t.Logf("Removal order: %v", order[:nrRemovals])
   138  		t.Logf("Set contents:\n%v", &s)
   139  		t.FailNow()
   140  	}
   141  }
   142  
   143  func TestMaxGapAddRandom(t *testing.T) {
   144  	var s gapSet
   145  	order := rand.Perm(testSize)
   146  	var nrInsertions int
   147  	for i, j := range order {
   148  		s.InsertWithoutMergingRange(Range{j, j + 1}, j+valueOffset)
   149  		nrInsertions++
   150  		if err := s.segmentTestCheck(nrInsertions, validate); err != nil {
   151  			t.Errorf("Iteration %d: %v", i, err)
   152  			break
   153  		}
   154  		if err := checkSetMaxGap(&s); err != nil {
   155  			t.Errorf("When inserting %d: %v", j, err)
   156  			break
   157  		}
   158  	}
   159  	if got, want := s.countSegments(), nrInsertions; got != want {
   160  		t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want)
   161  	}
   162  	if t.Failed() {
   163  		t.Logf("Insertion order: %v", order[:nrInsertions])
   164  		t.Logf("Set contents:\n%v", &s)
   165  	}
   166  }
   167  
   168  func TestMaxGapAddRandomWithRandomInterval(t *testing.T) {
   169  	var s gapSet
   170  	order := randIntervalPermutation(testSize)
   171  	var nrInsertions int
   172  	for i, j := range order {
   173  		s.InsertWithoutMergingRange(Range{j, j + rand.Intn(intervalLength-1) + 1}, j+valueOffset)
   174  		nrInsertions++
   175  		if err := s.segmentTestCheck(nrInsertions, validate); err != nil {
   176  			t.Errorf("Iteration %d: %v", i, err)
   177  			break
   178  		}
   179  		if err := checkSetMaxGap(&s); err != nil {
   180  			t.Errorf("When inserting %d: %v", j, err)
   181  			break
   182  		}
   183  	}
   184  	if got, want := s.countSegments(), nrInsertions; got != want {
   185  		t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want)
   186  	}
   187  	if t.Failed() {
   188  		t.Logf("Insertion order: %v", order[:nrInsertions])
   189  		t.Logf("Set contents:\n%v", &s)
   190  	}
   191  }
   192  
   193  func TestMaxGapAddRandomWithMerge(t *testing.T) {
   194  	var s gapSet
   195  	order := randIntervalPermutation(testSize)
   196  	for _, j := range order {
   197  		s.InsertRange(Range{j, j + intervalLength}, 0)
   198  		if err := checkSetMaxGap(&s); err != nil {
   199  			t.Errorf("When inserting %d: %v", j, err)
   200  			break
   201  		}
   202  	}
   203  	if got, want := s.countSegments(), 1; got != want {
   204  		t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want)
   205  	}
   206  	if t.Failed() {
   207  		t.Logf("Insertion order: %v", order)
   208  		t.Logf("Set contents:\n%v", &s)
   209  	}
   210  }
   211  
   212  func TestMaxGapRemoveRandom(t *testing.T) {
   213  	var s gapSet
   214  	for i := 0; i < testSize; i++ {
   215  		s.InsertWithoutMergingRange(Range{i, i + 1}, i+valueOffset)
   216  	}
   217  	order := rand.Perm(testSize)
   218  	var nrRemovals int
   219  	for i, j := range order {
   220  		seg := s.FindSegment(j)
   221  		if !seg.Ok() {
   222  			t.Errorf("Iteration %d: failed to find segment with key %d", i, j)
   223  			break
   224  		}
   225  		temprange := seg.Range()
   226  		s.Remove(seg)
   227  		nrRemovals++
   228  		if err := s.segmentTestCheck(testSize-nrRemovals, validate); err != nil {
   229  			t.Errorf("Iteration %d: %v", i, err)
   230  			break
   231  		}
   232  		if err := checkSetMaxGap(&s); err != nil {
   233  			t.Errorf("When removing %v: %v", temprange, err)
   234  			break
   235  		}
   236  	}
   237  	if got, want := s.countSegments(), testSize-nrRemovals; got != want {
   238  		t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want)
   239  	}
   240  	if t.Failed() {
   241  		t.Logf("Removal order: %v", order[:nrRemovals])
   242  		t.Logf("Set contents:\n%v", &s)
   243  		t.FailNow()
   244  	}
   245  }
   246  
   247  func TestMaxGapRemoveHalfRandom(t *testing.T) {
   248  	var s gapSet
   249  	for i := 0; i < testSize; i++ {
   250  		s.InsertWithoutMergingRange(Range{intervalLength * i, intervalLength*i + rand.Intn(intervalLength-1) + 1}, intervalLength*i+valueOffset)
   251  	}
   252  	order := randIntervalPermutation(testSize)
   253  	order = order[:testSize/2]
   254  	var nrRemovals int
   255  	for i, j := range order {
   256  		seg := s.FindSegment(j)
   257  		if !seg.Ok() {
   258  			t.Errorf("Iteration %d: failed to find segment with key %d", i, j)
   259  			break
   260  		}
   261  		temprange := seg.Range()
   262  		s.Remove(seg)
   263  		nrRemovals++
   264  		if err := s.segmentTestCheck(testSize-nrRemovals, validate); err != nil {
   265  			t.Errorf("Iteration %d: %v", i, err)
   266  			break
   267  		}
   268  		if err := checkSetMaxGap(&s); err != nil {
   269  			t.Errorf("When removing %v: %v", temprange, err)
   270  			break
   271  		}
   272  	}
   273  	if got, want := s.countSegments(), testSize-nrRemovals; got != want {
   274  		t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want)
   275  	}
   276  	if t.Failed() {
   277  		t.Logf("Removal order: %v", order[:nrRemovals])
   278  		t.Logf("Set contents:\n%v", &s)
   279  		t.FailNow()
   280  	}
   281  }
   282  
   283  func TestMaxGapRemoveHalfRandomWithMerge(t *testing.T) {
   284  	var s gapSet
   285  	s.InsertRange(Range{0, intervalLength * testSize}, 0)
   286  	order := randIntervalPermutation(testSize)
   287  	order = order[:testSize/2]
   288  	var nrRemovals int
   289  	for _, j := range order {
   290  		temprange := Range{j, j + intervalLength}
   291  		s.RemoveFullRange(temprange)
   292  		nrRemovals++
   293  		if err := checkSetMaxGap(&s); err != nil {
   294  			t.Errorf("When removing %v: %v", temprange, err)
   295  			break
   296  		}
   297  	}
   298  	if t.Failed() {
   299  		t.Logf("Removal order: %v", order[:nrRemovals])
   300  		t.Logf("Set contents:\n%v", &s)
   301  		t.FailNow()
   302  	}
   303  }
   304  
   305  func TestNextLargeEnoughGap(t *testing.T) {
   306  	var s gapSet
   307  	order := randIntervalPermutation(testSize * 2)
   308  	order = order[:testSize]
   309  	for _, j := range order {
   310  		s.InsertRange(Range{j, j + rand.Intn(intervalLength-1) + 1}, j+valueOffset)
   311  		if err := checkSetMaxGap(&s); err != nil {
   312  			t.Errorf("When inserting %d: %v", j, err)
   313  			break
   314  		}
   315  	}
   316  	shuffle(order)
   317  	order = order[:testSize/2]
   318  	for _, j := range order {
   319  		seg := s.FindSegment(j)
   320  		if !seg.Ok() {
   321  			continue
   322  		}
   323  		temprange := seg.Range()
   324  		s.Remove(seg)
   325  		if err := checkSetMaxGap(&s); err != nil {
   326  			t.Errorf("When removing %v: %v", temprange, err)
   327  			break
   328  		}
   329  	}
   330  	minSize := 7
   331  	var gapArr1 []int
   332  	for gap := s.LowerBoundGap(0).NextLargeEnoughGap(minSize); gap.Ok(); gap = gap.NextLargeEnoughGap(minSize) {
   333  		if gap.Range().Length() < minSize {
   334  			t.Errorf("NextLargeEnoughGap wrong, gap %v has length %d, wanted %d", gap.Range(), gap.Range().Length(), minSize)
   335  		} else {
   336  			gapArr1 = append(gapArr1, gap.Range().Start)
   337  		}
   338  	}
   339  	var gapArr2 []int
   340  	for gap := s.LowerBoundGap(0).NextGap(); gap.Ok(); gap = gap.NextGap() {
   341  		if gap.Range().Length() >= minSize {
   342  			gapArr2 = append(gapArr2, gap.Range().Start)
   343  		}
   344  	}
   345  
   346  	if !slices.Equal(gapArr2, gapArr1) {
   347  		t.Errorf("Search result not correct, got: %v, wanted: %v", gapArr1, gapArr2)
   348  	}
   349  	if t.Failed() {
   350  		t.Logf("Set contents:\n%v", &s)
   351  		t.FailNow()
   352  	}
   353  }
   354  
   355  func TestPrevLargeEnoughGap(t *testing.T) {
   356  	var s gapSet
   357  	order := randIntervalPermutation(testSize * 2)
   358  	order = order[:testSize]
   359  	for _, j := range order {
   360  		s.InsertRange(Range{j, j + rand.Intn(intervalLength-1) + 1}, j+valueOffset)
   361  		if err := checkSetMaxGap(&s); err != nil {
   362  			t.Errorf("When inserting %d: %v", j, err)
   363  			break
   364  		}
   365  	}
   366  	end := s.LastSegment().End()
   367  	shuffle(order)
   368  	order = order[:testSize/2]
   369  	for _, j := range order {
   370  		seg := s.FindSegment(j)
   371  		if !seg.Ok() {
   372  			continue
   373  		}
   374  		temprange := seg.Range()
   375  		s.Remove(seg)
   376  		if err := checkSetMaxGap(&s); err != nil {
   377  			t.Errorf("When removing %v: %v", temprange, err)
   378  			break
   379  		}
   380  	}
   381  	minSize := 7
   382  	var gapArr1 []int
   383  	for gap := s.UpperBoundGap(end + intervalLength).PrevLargeEnoughGap(minSize); gap.Ok(); gap = gap.PrevLargeEnoughGap(minSize) {
   384  		if gap.Range().Length() < minSize {
   385  			t.Errorf("PrevLargeEnoughGap wrong, gap length %d, wanted %d", gap.Range().Length(), minSize)
   386  		} else {
   387  			gapArr1 = append(gapArr1, gap.Range().Start)
   388  		}
   389  	}
   390  	var gapArr2 []int
   391  	for gap := s.UpperBoundGap(end + intervalLength).PrevGap(); gap.Ok(); gap = gap.PrevGap() {
   392  		if gap.Range().Length() >= minSize {
   393  			gapArr2 = append(gapArr2, gap.Range().Start)
   394  		}
   395  	}
   396  	if !slices.Equal(gapArr2, gapArr1) {
   397  		t.Errorf("Search result not correct, got: %v, wanted: %v", gapArr1, gapArr2)
   398  	}
   399  	if t.Failed() {
   400  		t.Logf("Set contents:\n%v", &s)
   401  		t.FailNow()
   402  	}
   403  }
   404  
   405  func TestAddSequentialAdjacent(t *testing.T) {
   406  	var s Set
   407  	var nrInsertions int
   408  	for i := 0; i < testSize; i++ {
   409  		s.InsertWithoutMergingRange(Range{i, i + 1}, i+valueOffset)
   410  		nrInsertions++
   411  		if err := s.segmentTestCheck(nrInsertions, validate); err != nil {
   412  			t.Errorf("Iteration %d: %v", i, err)
   413  			break
   414  		}
   415  	}
   416  	if got, want := s.countSegments(), nrInsertions; got != want {
   417  		t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want)
   418  	}
   419  	if t.Failed() {
   420  		t.Logf("Set contents:\n%v", &s)
   421  	}
   422  
   423  	first := s.FirstSegment()
   424  	gotSeg, gotGap := first.PrevNonEmpty()
   425  	if wantGap := s.FirstGap(); gotSeg.Ok() || gotGap != wantGap {
   426  		t.Errorf("FirstSegment().PrevNonEmpty(): got (%v, %v), wanted (<terminal iterator>, %v)", gotSeg, gotGap, wantGap)
   427  	}
   428  	gotSeg, gotGap = first.NextNonEmpty()
   429  	if wantSeg := first.NextSegment(); gotSeg != wantSeg || gotGap.Ok() {
   430  		t.Errorf("FirstSegment().NextNonEmpty(): got (%v, %v), wanted (%v, <terminal iterator>)", gotSeg, gotGap, wantSeg)
   431  	}
   432  
   433  	last := s.LastSegment()
   434  	gotSeg, gotGap = last.PrevNonEmpty()
   435  	if wantSeg := last.PrevSegment(); gotSeg != wantSeg || gotGap.Ok() {
   436  		t.Errorf("LastSegment().PrevNonEmpty(): got (%v, %v), wanted (%v, <terminal iterator>)", gotSeg, gotGap, wantSeg)
   437  	}
   438  	gotSeg, gotGap = last.NextNonEmpty()
   439  	if wantGap := s.LastGap(); gotSeg.Ok() || gotGap != wantGap {
   440  		t.Errorf("LastSegment().NextNonEmpty(): got (%v, %v), wanted (<terminal iterator>, %v)", gotSeg, gotGap, wantGap)
   441  	}
   442  
   443  	for seg := first.NextSegment(); seg != last; seg = seg.NextSegment() {
   444  		gotSeg, gotGap = seg.PrevNonEmpty()
   445  		if wantSeg := seg.PrevSegment(); gotSeg != wantSeg || gotGap.Ok() {
   446  			t.Errorf("%v.PrevNonEmpty(): got (%v, %v), wanted (%v, <terminal iterator>)", seg, gotSeg, gotGap, wantSeg)
   447  		}
   448  		gotSeg, gotGap = seg.NextNonEmpty()
   449  		if wantSeg := seg.NextSegment(); gotSeg != wantSeg || gotGap.Ok() {
   450  			t.Errorf("%v.NextNonEmpty(): got (%v, %v), wanted (%v, <terminal iterator>)", seg, gotSeg, gotGap, wantSeg)
   451  		}
   452  	}
   453  }
   454  
   455  func TestAddSequentialNonAdjacent(t *testing.T) {
   456  	var s Set
   457  	var nrInsertions int
   458  	for i := 0; i < testSize; i++ {
   459  		// The range here differs from TestAddSequentialAdjacent so that
   460  		// consecutive segments are not adjacent.
   461  		s.InsertWithoutMergingRange(Range{2 * i, 2*i + 1}, 2*i+valueOffset)
   462  		nrInsertions++
   463  		if err := s.segmentTestCheck(nrInsertions, validate); err != nil {
   464  			t.Errorf("Iteration %d: %v", i, err)
   465  			break
   466  		}
   467  	}
   468  	if got, want := s.countSegments(), nrInsertions; got != want {
   469  		t.Errorf("Wrong final number of segments: got %d, wanted %d", got, want)
   470  	}
   471  	if t.Failed() {
   472  		t.Logf("Set contents:\n%v", &s)
   473  	}
   474  
   475  	for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
   476  		gotSeg, gotGap := seg.PrevNonEmpty()
   477  		if wantGap := seg.PrevGap(); gotSeg.Ok() || gotGap != wantGap {
   478  			t.Errorf("%v.PrevNonEmpty(): got (%v, %v), wanted (<terminal iterator>, %v)", seg, gotSeg, gotGap, wantGap)
   479  		}
   480  		gotSeg, gotGap = seg.NextNonEmpty()
   481  		if wantGap := seg.NextGap(); gotSeg.Ok() || gotGap != wantGap {
   482  			t.Errorf("%v.NextNonEmpty(): got (%v, %v), wanted (<terminal iterator>, %v)", seg, gotSeg, gotGap, wantGap)
   483  		}
   484  	}
   485  }
   486  
   487  func TestMerge(t *testing.T) {
   488  	tests := []struct {
   489  		name      string
   490  		initial   []Range
   491  		split     bool
   492  		splitAddr int
   493  		final     []Range
   494  	}{
   495  		{
   496  			name:    "InsertRange merges after existing segment",
   497  			initial: []Range{{1000, 1100}, {1100, 1200}},
   498  			final:   []Range{{1000, 1200}},
   499  		},
   500  		{
   501  			name:    "InsertRange merges before existing segment",
   502  			initial: []Range{{1100, 1200}, {1000, 1100}},
   503  			final:   []Range{{1000, 1200}},
   504  		},
   505  		{
   506  			name:    "InsertRange merges between existing segments",
   507  			initial: []Range{{1000, 1100}, {1200, 1300}, {1100, 1200}},
   508  			final:   []Range{{1000, 1300}},
   509  		},
   510  	}
   511  Tests:
   512  	for _, test := range tests {
   513  		var s Set
   514  		for _, r := range test.initial {
   515  			s.InsertRange(r, 0)
   516  		}
   517  		var i int
   518  		for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
   519  			if i > len(test.final) {
   520  				t.Errorf("%s: Incorrect number of segments: got %d, wanted %d; set contents:\n%v", test.name, s.countSegments(), len(test.final), &s)
   521  				continue Tests
   522  			}
   523  			if got, want := seg.Range(), test.final[i]; got != want {
   524  				t.Errorf("%s: Segment %d mismatch: got %v, wanted %v; set contents:\n%v", test.name, i, got, want, &s)
   525  				continue Tests
   526  			}
   527  			i++
   528  		}
   529  		if i < len(test.final) {
   530  			t.Errorf("%s: Incorrect number of segments: got %d, wanted %d; set contents:\n%v", test.name, i, len(test.final), &s)
   531  		}
   532  	}
   533  }
   534  
   535  func TestIsolate(t *testing.T) {
   536  	tests := []struct {
   537  		name    string
   538  		initial Range
   539  		bounds  Range
   540  		final   []Range
   541  	}{
   542  		{
   543  			name:    "Isolate does not split a segment that falls inside bounds",
   544  			initial: Range{100, 200},
   545  			bounds:  Range{100, 200},
   546  			final:   []Range{{100, 200}},
   547  		},
   548  		{
   549  			name:    "Isolate splits at beginning of segment",
   550  			initial: Range{50, 200},
   551  			bounds:  Range{100, 200},
   552  			final:   []Range{{50, 100}, {100, 200}},
   553  		},
   554  		{
   555  			name:    "Isolate splits at end of segment",
   556  			initial: Range{100, 250},
   557  			bounds:  Range{100, 200},
   558  			final:   []Range{{100, 200}, {200, 250}},
   559  		},
   560  		{
   561  			name:    "Isolate splits at beginning and end of segment",
   562  			initial: Range{50, 250},
   563  			bounds:  Range{100, 200},
   564  			final:   []Range{{50, 100}, {100, 200}, {200, 250}},
   565  		},
   566  	}
   567  Tests:
   568  	for _, test := range tests {
   569  		var s Set
   570  		seg := s.Insert(s.FirstGap(), test.initial, 0)
   571  		seg = s.Isolate(seg, test.bounds)
   572  		if !test.bounds.IsSupersetOf(seg.Range()) {
   573  			t.Errorf("%s: Isolated segment %v lies outside bounds %v; set contents:\n%v", test.name, seg.Range(), test.bounds, &s)
   574  		}
   575  		var i int
   576  		for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
   577  			if i > len(test.final) {
   578  				t.Errorf("%s: Incorrect number of segments: got %d, wanted %d; set contents:\n%v", test.name, s.countSegments(), len(test.final), &s)
   579  				continue Tests
   580  			}
   581  			if got, want := seg.Range(), test.final[i]; got != want {
   582  				t.Errorf("%s: Segment %d mismatch: got %v, wanted %v; set contents:\n%v", test.name, i, got, want, &s)
   583  				continue Tests
   584  			}
   585  			i++
   586  		}
   587  		if i < len(test.final) {
   588  			t.Errorf("%s: Incorrect number of segments: got %d, wanted %d; set contents:\n%v", test.name, i, len(test.final), &s)
   589  		}
   590  	}
   591  }
   592  
   593  func TestMutateRange(t *testing.T) {
   594  	tests := []struct {
   595  		name      string
   596  		initial   []FlatSegment
   597  		increment Range
   598  		final     []FlatSegment
   599  	}{
   600  		{
   601  			name:      "MutateRange no-op in empty set",
   602  			increment: Range{100, 200},
   603  		},
   604  		{
   605  			name: "MutateRange modifies existing segment",
   606  			initial: []FlatSegment{
   607  				{100, 200, 0},
   608  			},
   609  			increment: Range{100, 200},
   610  			final: []FlatSegment{
   611  				{100, 200, 1},
   612  			},
   613  		},
   614  		{
   615  			name: "MutateRange splits segments",
   616  			initial: []FlatSegment{
   617  				{50, 150, 0},
   618  				{150, 250, 2},
   619  			},
   620  			increment: Range{100, 200},
   621  			final: []FlatSegment{
   622  				{50, 100, 0},
   623  				{100, 150, 1},
   624  				{150, 200, 3},
   625  				{200, 250, 2},
   626  			},
   627  		},
   628  		{
   629  			name: "MutateRange merges compatible segments",
   630  			initial: []FlatSegment{
   631  				{0, 100, 1},
   632  				{100, 200, 0},
   633  				{200, 300, 1},
   634  			},
   635  			increment: Range{100, 200},
   636  			final: []FlatSegment{
   637  				{0, 300, 1},
   638  			},
   639  		},
   640  	}
   641  	for _, test := range tests {
   642  		t.Run(test.name, func(t *testing.T) {
   643  			var s Set
   644  			if err := s.ImportSlice(test.initial); err != nil {
   645  				t.Fatalf("Failed to import initial set: %v", err)
   646  			}
   647  			s.MutateRange(test.increment, func(seg Iterator) bool {
   648  				(*seg.ValuePtr())++
   649  				return true
   650  			})
   651  			if got := s.ExportSlice(); !slices.Equal(got, test.final) {
   652  				t.Errorf("Set mismatch after mutation: got %v, wanted %v", got, test.final)
   653  			}
   654  		})
   655  	}
   656  }
   657  
   658  func benchmarkAddSequential(b *testing.B, size int) {
   659  	for n := 0; n < b.N; n++ {
   660  		var s Set
   661  		for i := 0; i < size; i++ {
   662  			s.InsertWithoutMergingRange(Range{i, i + 1}, i)
   663  		}
   664  	}
   665  }
   666  
   667  func benchmarkAddRandom(b *testing.B, size int) {
   668  	order := rand.Perm(size)
   669  
   670  	b.ResetTimer()
   671  	for n := 0; n < b.N; n++ {
   672  		var s Set
   673  		for _, i := range order {
   674  			s.InsertWithoutMergingRange(Range{i, i + 1}, i)
   675  		}
   676  	}
   677  }
   678  
   679  func benchmarkFindSequential(b *testing.B, size int) {
   680  	var s Set
   681  	for i := 0; i < size; i++ {
   682  		s.InsertWithoutMergingRange(Range{i, i + 1}, i)
   683  	}
   684  
   685  	b.ResetTimer()
   686  	for n := 0; n < b.N; n++ {
   687  		for i := 0; i < size; i++ {
   688  			if seg := s.FindSegment(i); !seg.Ok() {
   689  				b.Fatalf("Failed to find segment %d", i)
   690  			}
   691  		}
   692  	}
   693  }
   694  
   695  func benchmarkFindRandom(b *testing.B, size int) {
   696  	var s Set
   697  	for i := 0; i < size; i++ {
   698  		s.InsertWithoutMergingRange(Range{i, i + 1}, i)
   699  	}
   700  	order := rand.Perm(size)
   701  
   702  	b.ResetTimer()
   703  	for n := 0; n < b.N; n++ {
   704  		for _, i := range order {
   705  			if si := s.FindSegment(i); !si.Ok() {
   706  				b.Fatalf("Failed to find segment %d", i)
   707  			}
   708  		}
   709  	}
   710  }
   711  
   712  func benchmarkIteration(b *testing.B, size int) {
   713  	var s Set
   714  	for i := 0; i < size; i++ {
   715  		s.InsertWithoutMergingRange(Range{i, i + 1}, i)
   716  	}
   717  
   718  	b.ResetTimer()
   719  	var count uint64
   720  	for n := 0; n < b.N; n++ {
   721  		for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
   722  			count++
   723  		}
   724  	}
   725  	if got, want := count, uint64(size)*uint64(b.N); got != want {
   726  		b.Fatalf("Iterated wrong number of segments: got %d, wanted %d", got, want)
   727  	}
   728  }
   729  
   730  func benchmarkAddFindRemoveSequential(b *testing.B, size int) {
   731  	for n := 0; n < b.N; n++ {
   732  		var s Set
   733  		for i := 0; i < size; i++ {
   734  			s.InsertWithoutMergingRange(Range{i, i + 1}, i)
   735  		}
   736  		for i := 0; i < size; i++ {
   737  			seg := s.FindSegment(i)
   738  			if !seg.Ok() {
   739  				b.Fatalf("Failed to find segment %d", i)
   740  			}
   741  			s.Remove(seg)
   742  		}
   743  		if !s.IsEmpty() {
   744  			b.Fatalf("Set not empty after all removals:\n%v", &s)
   745  		}
   746  	}
   747  }
   748  
   749  func benchmarkAddFindRemoveRandom(b *testing.B, size int) {
   750  	order := rand.Perm(size)
   751  
   752  	b.ResetTimer()
   753  	for n := 0; n < b.N; n++ {
   754  		var s Set
   755  		for _, i := range order {
   756  			s.InsertWithoutMergingRange(Range{i, i + 1}, i)
   757  		}
   758  		for _, i := range order {
   759  			seg := s.FindSegment(i)
   760  			if !seg.Ok() {
   761  				b.Fatalf("Failed to find segment %d", i)
   762  			}
   763  			s.Remove(seg)
   764  		}
   765  		if !s.IsEmpty() {
   766  			b.Fatalf("Set not empty after all removals:\n%v", &s)
   767  		}
   768  	}
   769  }
   770  
   771  // Although we don't generally expect our segment sets to get this big, they're
   772  // useful for emulating the effect of cache pressure.
   773  var testSizes = []struct {
   774  	desc string
   775  	size int
   776  }{
   777  	{"64", 1 << 6},
   778  	{"256", 1 << 8},
   779  	{"1K", 1 << 10},
   780  	{"4K", 1 << 12},
   781  	{"16K", 1 << 14},
   782  	{"64K", 1 << 16},
   783  }
   784  
   785  func BenchmarkAddSequential(b *testing.B) {
   786  	for _, test := range testSizes {
   787  		b.Run(test.desc, func(b *testing.B) {
   788  			benchmarkAddSequential(b, test.size)
   789  		})
   790  	}
   791  }
   792  
   793  func BenchmarkAddRandom(b *testing.B) {
   794  	for _, test := range testSizes {
   795  		b.Run(test.desc, func(b *testing.B) {
   796  			benchmarkAddRandom(b, test.size)
   797  		})
   798  	}
   799  }
   800  
   801  func BenchmarkFindSequential(b *testing.B) {
   802  	for _, test := range testSizes {
   803  		b.Run(test.desc, func(b *testing.B) {
   804  			benchmarkFindSequential(b, test.size)
   805  		})
   806  	}
   807  }
   808  
   809  func BenchmarkFindRandom(b *testing.B) {
   810  	for _, test := range testSizes {
   811  		b.Run(test.desc, func(b *testing.B) {
   812  			benchmarkFindRandom(b, test.size)
   813  		})
   814  	}
   815  }
   816  
   817  func BenchmarkIteration(b *testing.B) {
   818  	for _, test := range testSizes {
   819  		b.Run(test.desc, func(b *testing.B) {
   820  			benchmarkIteration(b, test.size)
   821  		})
   822  	}
   823  }
   824  
   825  func BenchmarkAddFindRemoveSequential(b *testing.B) {
   826  	for _, test := range testSizes {
   827  		b.Run(test.desc, func(b *testing.B) {
   828  			benchmarkAddFindRemoveSequential(b, test.size)
   829  		})
   830  	}
   831  }
   832  
   833  func BenchmarkAddFindRemoveRandom(b *testing.B) {
   834  	for _, test := range testSizes {
   835  		b.Run(test.desc, func(b *testing.B) {
   836  			benchmarkAddFindRemoveRandom(b, test.size)
   837  		})
   838  	}
   839  }