vitess.io/vitess@v0.16.2/go/vt/vtgate/semantics/bitset/bitset.go (about) 1 /* 2 Copyright 2022 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package bitset 18 19 import ( 20 "math/bits" 21 "unsafe" 22 ) 23 24 // A Bitset is an immutable collection of bits. You can perform logical operations 25 // on it, but all mutable operations return a new Bitset. 26 // It is safe to compare directly using the comparison operator and to use as a map key. 27 type Bitset string 28 29 const bitsetWidth = 8 30 31 func bitsetWordSize(max int) int { 32 return max/bitsetWidth + 1 33 } 34 35 // toBiset converts a slice of bytes into a Bitset without allocating memory. 36 // Bitset is actually a type alias for `string`, which is the only native type in Go that is dynamic _and_ 37 // immutable, so it can be used as a key in maps or compared directly. 38 func toBitset(words []byte) Bitset { 39 if len(words) == 0 { 40 return "" 41 } 42 if words[len(words)-1] == 0 { 43 panic("toBitset: did not truncate") 44 } 45 // to convert a byte slice into a bitset without cloning the slice, we use the same trick as 46 // the Go standard library's `strings.Builder`. A slice header is [data, len, cap] while a 47 // string header is [data, len], hence the first two words of a slice header can be reinterpreted 48 // as a string header simply by casting into it. 49 // This assumes that the `words` slice will never be written to after returning from this function. 50 return *(*Bitset)(unsafe.Pointer(&words)) 51 } 52 53 func minlen(a, b Bitset) int { 54 if len(a) < len(b) { 55 return len(a) 56 } 57 return len(b) 58 } 59 60 // Overlaps returns whether this Bitset and the input have any bits in common 61 func (bs Bitset) Overlaps(b2 Bitset) bool { 62 min := minlen(bs, b2) 63 for i := 0; i < min; i++ { 64 if bs[i]&b2[i] != 0 { 65 return true 66 } 67 } 68 return false 69 } 70 71 // Or returns the logical OR of the two Bitsets as a new Bitset 72 func (bs Bitset) Or(b2 Bitset) Bitset { 73 if len(bs) == 0 { 74 return b2 75 } 76 if len(b2) == 0 { 77 return bs 78 } 79 80 small, large := bs, b2 81 if len(small) > len(large) { 82 small, large = large, small 83 } 84 85 merged := make([]byte, len(large)) 86 m := 0 87 88 for m < len(small) { 89 merged[m] = small[m] | large[m] 90 m++ 91 } 92 for m < len(large) { 93 merged[m] = large[m] 94 m++ 95 } 96 return toBitset(merged) 97 } 98 99 // AndNot returns the logical AND NOT of the two Bitsets as a new Bitset 100 func (bs Bitset) AndNot(b2 Bitset) Bitset { 101 if len(b2) == 0 { 102 return bs 103 } 104 105 merged := make([]byte, len(bs)) 106 m := 0 107 108 for m = 0; m < len(bs); m++ { 109 if m < len(b2) { 110 merged[m] = bs[m] & ^b2[m] 111 } else { 112 merged[m] = bs[m] 113 } 114 } 115 for ; m > 0; m-- { 116 if merged[m-1] != 0 { 117 break 118 } 119 } 120 return toBitset(merged[:m]) 121 } 122 123 // And returns the logical AND of the two bitsets as a new Bitset 124 func (bs Bitset) And(b2 Bitset) Bitset { 125 if len(bs) == 0 || len(b2) == 0 { 126 return "" 127 } 128 129 merged := make([]byte, minlen(bs, b2)) 130 m := 0 131 132 for m = 0; m < len(merged); m++ { 133 merged[m] = bs[m] & b2[m] 134 } 135 for ; m > 0; m-- { 136 if merged[m-1] != 0 { 137 break 138 } 139 } 140 return toBitset(merged[:m]) 141 } 142 143 // Set returns a copy of this Bitset where the bit at `offset` is set 144 func (bs Bitset) Set(offset int) Bitset { 145 alloc := len(bs) 146 if max := bitsetWordSize(offset); max > alloc { 147 alloc = max 148 } 149 150 words := make([]byte, alloc) 151 copy(words, bs) 152 words[offset/bitsetWidth] |= 1 << (offset % bitsetWidth) 153 return toBitset(words) 154 } 155 156 // SingleBit returns the position of the single bit that is set in this Bitset 157 // If the Bitset is empty, or contains more than one set bit, it returns -1 158 func (bs Bitset) SingleBit() int { 159 offset := -1 160 for i := 0; i < len(bs); i++ { 161 t := bs[i] 162 if t == 0 { 163 continue 164 } 165 if offset >= 0 || bits.OnesCount8(t) != 1 { 166 return -1 167 } 168 offset = i*bitsetWidth + bits.TrailingZeros8(t) 169 } 170 return offset 171 } 172 173 // IsContainedBy returns whether this Bitset is contained by the given Bitset 174 func (bs Bitset) IsContainedBy(b2 Bitset) bool { 175 if len(bs) > len(b2) { 176 return false 177 } 178 for i := 0; i < len(bs); i++ { 179 left := bs[i] 180 rigt := b2[i] 181 if left&rigt != left { 182 return false 183 } 184 } 185 return true 186 } 187 188 // Popcount returns the number of bits that are set in this Bitset 189 func (bs Bitset) Popcount() (count int) { 190 for i := 0; i < len(bs); i++ { 191 count += bits.OnesCount8(bs[i]) 192 } 193 return 194 } 195 196 // ForEach calls the given callback with the position of each bit set in this Bitset 197 func (bs Bitset) ForEach(yield func(int)) { 198 // From Lemire, "Iterating over set bits quickly" 199 // https://lemire.me/blog/2018/02/21/iterating-over-set-bits-quickly/ 200 for i := 0; i < len(bs); i++ { 201 bitset := bs[i] 202 for bitset != 0 { 203 t := bitset & -bitset 204 r := bits.TrailingZeros8(bitset) 205 yield(i*bitsetWidth + r) 206 bitset ^= t 207 } 208 } 209 } 210 211 // Build creates a new immutable Bitset where all the given bits are set 212 func Build(bits ...int) Bitset { 213 if len(bits) == 0 { 214 return "" 215 } 216 217 max := bits[0] 218 for _, b := range bits[1:] { 219 if b > max { 220 max = b 221 } 222 } 223 224 words := make([]byte, bitsetWordSize(max)) 225 for _, b := range bits { 226 words[b/bitsetWidth] |= 1 << (b % bitsetWidth) 227 } 228 return toBitset(words) 229 } 230 231 const singleton = "\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x08\x00\x00\x00\x10\x00\x00\x00\x20\x00\x00\x00\x40\x00\x00\x00\x80" 232 233 // Single returns a new Bitset where only the given bit is set. 234 // If the given bit is less than 32, Single does not allocate to create a new Bitset. 235 func Single(bit int) Bitset { 236 switch { 237 case bit < 8: 238 bit = (bit + 1) << 2 239 return Bitset(singleton[bit-1 : bit]) 240 case bit < 16: 241 bit = (bit + 1 - 8) << 2 242 return Bitset(singleton[bit-2 : bit]) 243 case bit < 24: 244 bit = (bit + 1 - 16) << 2 245 return Bitset(singleton[bit-3 : bit]) 246 case bit < 32: 247 bit = (bit + 1 - 24) << 2 248 return Bitset(singleton[bit-4 : bit]) 249 default: 250 words := make([]byte, bitsetWordSize(bit)) 251 words[bit/bitsetWidth] |= 1 << (bit % bitsetWidth) 252 return toBitset(words) 253 } 254 }