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 }