github.com/kubewharf/katalyst-core@v0.5.3/pkg/util/bitmask/bitmask.go (about) 1 /* 2 Copyright 2022 The Katalyst 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 bitmask 18 19 import ( 20 "fmt" 21 "math/bits" 22 "strconv" 23 ) 24 25 // BitMask interface allows hint providers to create BitMasks for TopologyHints 26 type BitMask interface { 27 Add(bits ...int) error 28 Remove(bits ...int) error 29 And(masks ...BitMask) 30 Or(masks ...BitMask) 31 Clear() 32 Fill() 33 IsEqual(mask BitMask) bool 34 IsEmpty() bool 35 IsSet(bit int) bool 36 AnySet(bits []int) bool 37 IsNarrowerThan(mask BitMask) bool 38 String() string 39 Count() int 40 GetBits() []int 41 } 42 43 type bitMask uint64 44 45 // NewEmptyBitMask creates a new, empty BitMask 46 func NewEmptyBitMask() BitMask { 47 s := bitMask(0) 48 return &s 49 } 50 51 // NewBitMask creates a new BitMask 52 func NewBitMask(bits ...int) (BitMask, error) { 53 s := bitMask(0) 54 err := (&s).Add(bits...) 55 if err != nil { 56 return nil, err 57 } 58 return &s, nil 59 } 60 61 // Add adds the bits with topology affinity to the BitMask 62 func (s *bitMask) Add(bits ...int) error { 63 mask := *s 64 for _, i := range bits { 65 if i < 0 || i >= 64 { 66 return fmt.Errorf("bit number must be in range 0-63") 67 } 68 mask |= 1 << uint64(i) 69 } 70 *s = mask 71 return nil 72 } 73 74 // Remove removes specified bits from BitMask 75 func (s *bitMask) Remove(bits ...int) error { 76 mask := *s 77 for _, i := range bits { 78 if i < 0 || i >= 64 { 79 return fmt.Errorf("bit number must be in range 0-63") 80 } 81 mask &^= 1 << uint64(i) 82 } 83 *s = mask 84 return nil 85 } 86 87 // And performs and operation on all bits in masks 88 func (s *bitMask) And(masks ...BitMask) { 89 for _, m := range masks { 90 *s &= *m.(*bitMask) 91 } 92 } 93 94 // Or performs or operation on all bits in masks 95 func (s *bitMask) Or(masks ...BitMask) { 96 for _, m := range masks { 97 *s |= *m.(*bitMask) 98 } 99 } 100 101 // Clear resets all bits in mask to zero 102 func (s *bitMask) Clear() { 103 *s = 0 104 } 105 106 // Fill sets all bits in mask to one 107 func (s *bitMask) Fill() { 108 *s = bitMask(^uint64(0)) 109 } 110 111 // IsEmpty checks mask to see if all bits are zero 112 func (s *bitMask) IsEmpty() bool { 113 return *s == 0 114 } 115 116 // IsSet checks bit in mask to see if bit is set to one 117 func (s *bitMask) IsSet(bit int) bool { 118 if bit < 0 || bit >= 64 { 119 return false 120 } 121 return (*s & (1 << uint64(bit))) > 0 122 } 123 124 // AnySet checks bit in mask to see if any provided bit is set to one 125 func (s *bitMask) AnySet(bits []int) bool { 126 for _, b := range bits { 127 if s.IsSet(b) { 128 return true 129 } 130 } 131 return false 132 } 133 134 // IsEqual checks if masks are equal 135 func (s *bitMask) IsEqual(mask BitMask) bool { 136 return *s == *mask.(*bitMask) 137 } 138 139 // IsNarrowerThan checks if one mask is narrower than another. 140 // 141 // A mask is said to be "narrower" than another if it has lets bits set. If the 142 // same number of bits are set in both masks, then the mask with more 143 // lower-numbered bits set wins out. 144 func (s *bitMask) IsNarrowerThan(mask BitMask) bool { 145 if s.Count() == mask.Count() { 146 if *s < *mask.(*bitMask) { 147 return true 148 } 149 } 150 return s.Count() < mask.Count() 151 } 152 153 // String converts mask to string 154 func (s *bitMask) String() string { 155 grouping := 2 156 for shift := 64 - grouping; shift > 0; shift -= grouping { 157 if *s > (1 << uint(shift)) { 158 return fmt.Sprintf("%0"+strconv.Itoa(shift+grouping)+"b", *s) 159 } 160 } 161 return fmt.Sprintf("%0"+strconv.Itoa(grouping)+"b", *s) 162 } 163 164 // Count counts number of bits in mask set to one 165 func (s *bitMask) Count() int { 166 return bits.OnesCount64(uint64(*s)) 167 } 168 169 // Getbits returns each bit number with bits set to one 170 func (s *bitMask) GetBits() []int { 171 var bits []int 172 for i := uint64(0); i < 64; i++ { 173 if (*s & (1 << i)) > 0 { 174 bits = append(bits, int(i)) 175 } 176 } 177 return bits 178 } 179 180 // And is a package level implementation of 'and' between first and masks 181 func And(first BitMask, masks ...BitMask) BitMask { 182 s := *first.(*bitMask) 183 s.And(masks...) 184 return &s 185 } 186 187 // Or is a package level implementation of 'or' between first and masks 188 func Or(first BitMask, masks ...BitMask) BitMask { 189 s := *first.(*bitMask) 190 s.Or(masks...) 191 return &s 192 } 193 194 // IterateBitMasks iterates all possible masks from a list of bits, 195 // issuing a callback on each mask. 196 func IterateBitMasks(bits []int, callback func(BitMask)) { 197 var iterate func(bits, accum []int, size int) 198 iterate = func(bits, accum []int, size int) { 199 if len(accum) == size { 200 mask, _ := NewBitMask(accum...) 201 callback(mask) 202 return 203 } 204 for i := range bits { 205 iterate(bits[i+1:], append(accum, bits[i]), size) 206 } 207 } 208 209 for i := 1; i <= len(bits); i++ { 210 iterate(bits, []int{}, i) 211 } 212 }