github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/util/intsets/fast_testonly.go (about)

     1  // Copyright 2020 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  //go:build fast_int_set_small || fast_int_set_large
    12  // +build fast_int_set_small fast_int_set_large
    13  
    14  // This file implements two variants of Fast used for testing which always
    15  // behaves like in either the "small" or "large" case (depending on
    16  // fastIntSetAlwaysSmall). Tests that exhibit a difference when using one of
    17  // these variants indicates a bug.
    18  
    19  package intsets
    20  
    21  import (
    22  	"bytes"
    23  	"encoding/binary"
    24  	"io"
    25  
    26  	"github.com/cockroachdb/errors"
    27  )
    28  
    29  // Fast keeps track of a set of integers. It does not perform any
    30  // allocations when the values are small. It is not thread-safe.
    31  type Fast struct {
    32  	// Used to keep the size of the struct the same.
    33  	_ struct{ lo, hi uint64 }
    34  	s *Sparse
    35  }
    36  
    37  // MakeFast returns a set initialized with the given values.
    38  func MakeFast(vals ...int) Fast {
    39  	var res Fast
    40  	for _, v := range vals {
    41  		res.Add(v)
    42  	}
    43  	return res
    44  }
    45  
    46  func (s *Fast) prepareForMutation() {
    47  	if s.s == nil {
    48  		s.s = &Sparse{}
    49  	} else if fastIntSetAlwaysSmall {
    50  		// We always make a full copy to prevent any aliasing; this simulates the
    51  		// semantics of the "small" regime of Fast.
    52  		*s = s.Copy()
    53  	}
    54  }
    55  
    56  // Add adds a value to the set. No-op if the value is already in the set.
    57  func (s *Fast) Add(i int) {
    58  	s.prepareForMutation()
    59  	s.s.Add(i)
    60  }
    61  
    62  // AddRange adds values 'from' up to 'to' (inclusively) to the set.
    63  // E.g. AddRange(1,5) adds the values 1, 2, 3, 4, 5 to the set.
    64  // 'to' must be >= 'from'.
    65  // AddRange is always more efficient than individual Adds.
    66  func (s *Fast) AddRange(from, to int) {
    67  	s.prepareForMutation()
    68  	for i := from; i <= to; i++ {
    69  		s.s.Add(i)
    70  	}
    71  }
    72  
    73  // Remove removes a value from the set. No-op if the value is not in the set.
    74  func (s *Fast) Remove(i int) {
    75  	s.prepareForMutation()
    76  	s.s.Remove(i)
    77  }
    78  
    79  // Contains returns true if the set contains the value.
    80  func (s Fast) Contains(i int) bool {
    81  	return s.s != nil && s.s.Contains(i)
    82  }
    83  
    84  // Empty returns true if the set is empty.
    85  func (s Fast) Empty() bool {
    86  	return s.s == nil || s.s.Empty()
    87  }
    88  
    89  // Len returns the number of the elements in the set.
    90  func (s Fast) Len() int {
    91  	if s.s == nil {
    92  		return 0
    93  	}
    94  	return s.s.Len()
    95  }
    96  
    97  // Next returns the first value in the set which is >= startVal. If there is no
    98  // value, the second return value is false.
    99  func (s Fast) Next(startVal int) (int, bool) {
   100  	if s.s == nil {
   101  		return MaxInt, false
   102  	}
   103  	res := s.s.LowerBound(startVal)
   104  	return res, res != MaxInt
   105  }
   106  
   107  // ForEach calls a function for each value in the set (in increasing order).
   108  func (s Fast) ForEach(f func(i int)) {
   109  	if s.s == nil {
   110  		return
   111  	}
   112  	for x := s.s.Min(); x != MaxInt; x = s.s.LowerBound(x + 1) {
   113  		f(x)
   114  	}
   115  }
   116  
   117  // Ordered returns a slice with all the integers in the set, in increasing order.
   118  func (s Fast) Ordered() []int {
   119  	if s.Empty() {
   120  		return nil
   121  	}
   122  	result := make([]int, 0, s.Len())
   123  	s.ForEach(func(i int) {
   124  		result = append(result, i)
   125  	})
   126  	return result
   127  }
   128  
   129  // Copy returns a copy of s which can be modified independently.
   130  func (s Fast) Copy() Fast {
   131  	n := &Sparse{}
   132  	if s.s != nil {
   133  		n.Copy(s.s)
   134  	}
   135  	return Fast{s: n}
   136  }
   137  
   138  // CopyFrom sets the receiver to a copy of other, which can then be modified
   139  // independently.
   140  func (s *Fast) CopyFrom(other Fast) {
   141  	*s = other.Copy()
   142  }
   143  
   144  // UnionWith adds all the elements from rhs to this set.
   145  func (s *Fast) UnionWith(rhs Fast) {
   146  	if rhs.s == nil {
   147  		return
   148  	}
   149  	s.prepareForMutation()
   150  	s.s.UnionWith(rhs.s)
   151  }
   152  
   153  // Union returns the union of s and rhs as a new set.
   154  func (s Fast) Union(rhs Fast) Fast {
   155  	r := s.Copy()
   156  	r.UnionWith(rhs)
   157  	return r
   158  }
   159  
   160  // IntersectionWith removes any elements not in rhs from this set.
   161  func (s *Fast) IntersectionWith(rhs Fast) {
   162  	if rhs.s == nil {
   163  		*s = Fast{}
   164  		return
   165  	}
   166  	s.prepareForMutation()
   167  	s.s.IntersectionWith(rhs.s)
   168  }
   169  
   170  // Intersection returns the intersection of s and rhs as a new set.
   171  func (s Fast) Intersection(rhs Fast) Fast {
   172  	r := s.Copy()
   173  	r.IntersectionWith(rhs)
   174  	return r
   175  }
   176  
   177  // Intersects returns true if s has any elements in common with rhs.
   178  func (s Fast) Intersects(rhs Fast) bool {
   179  	if s.s == nil || rhs.s == nil {
   180  		return false
   181  	}
   182  	return s.s.Intersects(rhs.s)
   183  }
   184  
   185  // DifferenceWith removes any elements in rhs from this set.
   186  func (s *Fast) DifferenceWith(rhs Fast) {
   187  	if rhs.s == nil {
   188  		return
   189  	}
   190  	s.prepareForMutation()
   191  	s.s.DifferenceWith(rhs.s)
   192  }
   193  
   194  // Difference returns the elements of s that are not in rhs as a new set.
   195  func (s Fast) Difference(rhs Fast) Fast {
   196  	r := s.Copy()
   197  	r.DifferenceWith(rhs)
   198  	return r
   199  }
   200  
   201  // Equals returns true if the two sets are identical.
   202  func (s Fast) Equals(rhs Fast) bool {
   203  	if s.Empty() || rhs.Empty() {
   204  		return s.Empty() == rhs.Empty()
   205  	}
   206  	return s.s.Equals(rhs.s)
   207  }
   208  
   209  // SubsetOf returns true if rhs contains all the elements in s.
   210  func (s Fast) SubsetOf(rhs Fast) bool {
   211  	if s.Empty() {
   212  		return true
   213  	}
   214  	if rhs.s == nil {
   215  		return false
   216  	}
   217  	return s.s.SubsetOf(rhs.s)
   218  }
   219  
   220  // Encode the set and write it to a bytes.Buffer using binary.varint byte
   221  // encoding.
   222  //
   223  // This method cannot be used if the set contains negative elements.
   224  //
   225  // If the set has only elements in the range [0, 63], we encode a 0 followed by
   226  // a 64-bit bitmap. Otherwise, we encode a length followed by each element.
   227  //
   228  // WARNING: this is used by plan gists, so if this encoding changes,
   229  // explain.gistVersion needs to be bumped.
   230  func (s *Fast) Encode(buf *bytes.Buffer) error {
   231  	if s.s != nil && s.s.Min() < 0 {
   232  		return errors.AssertionFailedf("Encode used with negative elements")
   233  	}
   234  
   235  	// This slice should stay on stack. We only need enough bytes to encode a 0
   236  	// and then an arbitrary 64-bit integer.
   237  	//gcassert:noescape
   238  	tmp := make([]byte, binary.MaxVarintLen64+1)
   239  
   240  	max := MinInt
   241  	s.ForEach(func(i int) {
   242  		if i > max {
   243  			max = i
   244  		}
   245  	})
   246  
   247  	if s.s == nil || max < 64 {
   248  		n := binary.PutUvarint(tmp, 0)
   249  		var bitmap uint64
   250  		for i, ok := s.Next(0); ok; i, ok = s.Next(i + 1) {
   251  			bitmap |= (1 << uint64(i))
   252  		}
   253  		n += binary.PutUvarint(tmp[n:], bitmap)
   254  		buf.Write(tmp[:n])
   255  	} else {
   256  		n := binary.PutUvarint(tmp, uint64(s.Len()))
   257  		buf.Write(tmp[:n])
   258  		for i, ok := s.Next(0); ok; i, ok = s.Next(i + 1) {
   259  			n := binary.PutUvarint(tmp, uint64(i))
   260  			buf.Write(tmp[:n])
   261  		}
   262  	}
   263  	return nil
   264  }
   265  
   266  // Decode does the opposite of Encode. The contents of the receiver are
   267  // overwritten.
   268  func (s *Fast) Decode(br io.ByteReader) error {
   269  	length, err := binary.ReadUvarint(br)
   270  	if err != nil {
   271  		return err
   272  	}
   273  	if s.s != nil {
   274  		s.s.Clear()
   275  	}
   276  
   277  	if length == 0 {
   278  		// Special case: the bitmap is encoded directly.
   279  		val, err := binary.ReadUvarint(br)
   280  		if err != nil {
   281  			return err
   282  		}
   283  		for i := 0; i < 64; i++ {
   284  			if val&(1<<uint64(i)) != 0 {
   285  				s.Add(i)
   286  			}
   287  		}
   288  	} else {
   289  		for i := 0; i < int(length); i++ {
   290  			elem, err := binary.ReadUvarint(br)
   291  			if err != nil {
   292  				*s = Fast{}
   293  				return err
   294  			}
   295  			s.Add(int(elem))
   296  		}
   297  	}
   298  	return nil
   299  }