github.com/goki/ki@v1.1.11/bitflag/bitflag.go (about) 1 // Copyright (c) 2018, The GoKi Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 /* 6 Package bitflag provides simple bit flag setting, checking, and clearing 7 methods that take bit position args as ints (from const int eunum iota's) 8 and do the bit shifting from there -- although a tiny bit slower, the 9 convenience of maintaining ordinal lists of bit positions greatly outweighs 10 that cost -- see kit type registry for further enum management functions 11 */ 12 package bitflag 13 14 import "sync/atomic" 15 16 // we assume 64bit bitflags by default -- 32 bit methods specifically marked 17 18 //////////////////////////////////////////////////////////////////////// 19 // Core Mask Impl methods, take the full bitmask 20 21 // SetMask sets bits in mask 22 func SetMask(bits *int64, mask int64) { 23 *bits |= mask 24 } 25 26 // SetMaskAtomic sets bits in mask 27 // using atomic compare-and-swap loop, safe for concurrent access 28 func SetMaskAtomic(bits *int64, mask int64) { 29 for { 30 cr := atomic.LoadInt64(bits) 31 nw := cr | mask 32 if atomic.CompareAndSwapInt64(bits, cr, nw) { 33 break 34 } 35 } 36 } 37 38 // ClearMask clears all of the bits in the mask 39 func ClearMask(bits *int64, mask int64) { 40 *bits &^= mask 41 } 42 43 // ClearMaskAtomic clears all of the bits in the mask 44 // using atomic compare-and-swap loop, safe for concurrent access 45 func ClearMaskAtomic(bits *int64, mask int64) { 46 for { 47 cr := atomic.LoadInt64(bits) 48 nw := cr &^ mask 49 if atomic.CompareAndSwapInt64(bits, cr, nw) { 50 break 51 } 52 } 53 } 54 55 // HasAnyMask checks if *any* of the bits in mask are set (logical OR) 56 func HasAnyMask(bits, mask int64) bool { 57 return bits&mask != 0 58 } 59 60 // HasAllMask checks if *all* of the bits in mask are set (logical AND) 61 func HasAllMask(bits, mask int64) bool { 62 return bits&mask == mask 63 } 64 65 // HasAnyMaskAtomic checks if *any* of the bits in mask are set (logical OR) 66 // using atomic compare-and-swap loop, safe for concurrent access 67 func HasAnyMaskAtomic(bits *int64, mask int64) bool { 68 return (atomic.LoadInt64(bits) & mask) != 0 69 } 70 71 // HasAllMaskAtomic checks if *all* of the bits in mask are set (logical AND) 72 // using atomic compare-and-swap loop, safe for concurrent access 73 func HasAllMaskAtomic(bits *int64, mask int64) bool { 74 return (atomic.LoadInt64(bits) & mask) == mask 75 } 76 77 //////////////////////////////////////////////////////////////////////// 78 // Convenience methods for ordinal bitflags 79 80 // Mask makes a mask for checking multiple different flags 81 func Mask(flags ...int) int64 { 82 var mask int64 83 for _, f := range flags { 84 mask |= 1 << uint32(f) 85 } 86 return mask 87 } 88 89 // Set sets bit value(s) for ordinal bit position flags 90 func Set(bits *int64, flags ...int) { 91 SetMask(bits, Mask(flags...)) 92 } 93 94 // SetAtomic sets bit value(s) for ordinal bit position flags 95 // using atomic compare-and-swap loop, safe for concurrent access 96 func SetAtomic(bits *int64, flags ...int) { 97 SetMaskAtomic(bits, Mask(flags...)) 98 } 99 100 // SetState sets or clears bit value(s) depending on state (on / off) for 101 // ordinal bit position flags 102 func SetState(bits *int64, state bool, flags ...int) { 103 if state { 104 Set(bits, flags...) 105 } else { 106 Clear(bits, flags...) 107 } 108 } 109 110 // SetStateAtomic sets or clears bit value(s) depending on state (on / off) 111 // for ordinal bit position flags, protected by atomic -- safe for concurrent access 112 func SetStateAtomic(bits *int64, state bool, flags ...int) { 113 if state { 114 SetAtomic(bits, flags...) 115 } else { 116 ClearAtomic(bits, flags...) 117 } 118 } 119 120 // Clear clears bit value(s) for ordinal bit position flags 121 func Clear(bits *int64, flags ...int) { 122 ClearMask(bits, Mask(flags...)) 123 } 124 125 // ClearAtomic clears bit value(s) for ordinal bit position flags 126 // using atomic compare-and-swap loop, safe for concurrent access 127 func ClearAtomic(bits *int64, flags ...int) { 128 ClearMaskAtomic(bits, Mask(flags...)) 129 } 130 131 // Has checks if given bit value is set for ordinal bit position flag 132 func Has(bits int64, flag int) bool { 133 return bits&(1<<uint32(flag)) != 0 134 } 135 136 // HasAtomic checks if given bit value is set for ordinal bit position flag, 137 // using an atomic load, safe for concurrent access 138 func HasAtomic(bits *int64, flag int) bool { 139 return atomic.LoadInt64(bits)&(1<<uint32(flag)) != 0 140 } 141 142 // HasAny checks if *any* of a set of flags are set for ordinal bit position flags (logical OR) 143 func HasAny(bits int64, flags ...int) bool { 144 return HasAnyMask(bits, Mask(flags...)) 145 } 146 147 // HasAll checks if *all* of a set of flags are set for ordinal bit position flags (logical AND) 148 func HasAll(bits int64, flags ...int) bool { 149 return HasAllMask(bits, Mask(flags...)) 150 } 151 152 // HasAnyAtomic checks if *any* of a set of flags are set for ordinal bit position flags (logical OR) 153 // using atomic compare-and-swap loop, safe for concurrent access 154 func HasAnyAtomic(bits *int64, flags ...int) bool { 155 return HasAnyMaskAtomic(bits, Mask(flags...)) 156 } 157 158 // HasAllAtomic checks if *all* of a set of flags are set for ordinal bit position flags (logical AND) 159 // using atomic compare-and-swap loop, safe for concurrent access 160 func HasAllAtomic(bits *int64, flags ...int) bool { 161 return HasAllMaskAtomic(bits, Mask(flags...)) 162 } 163 164 // Toggle toggles state of bit value(s) for ordinal bit position flags 165 func Toggle(bits *int64, flags ...int) { 166 for _, f := range flags { 167 if Has(*bits, f) { 168 Clear(bits, f) 169 } else { 170 Set(bits, f) 171 } 172 } 173 } 174 175 // ToggleAtomic toggles state of bit value(s) for ordinal bit position flags 176 // using atomic compare-and-swap loop, safe for concurrent access, but sequentially 177 func ToggleAtomic(bits *int64, flags ...int) { 178 for _, f := range flags { 179 if HasAtomic(bits, f) { 180 ClearAtomic(bits, f) 181 } else { 182 SetAtomic(bits, f) 183 } 184 } 185 } 186 187 ///////////////////////////////////////////////////////////////////////////////// 188 // 32 bit, core mask impls 189 190 // SetMask32 sets bits in mask 191 func SetMask32(bits *int32, mask int32) { 192 *bits |= mask 193 } 194 195 // SetMaskAtomic32 sets bits in mask 196 // using atomic compare-and-swap loop, safe for concurrent access 197 func SetMaskAtomic32(bits *int32, mask int32) { 198 for { 199 cr := atomic.LoadInt32(bits) 200 nw := cr | mask 201 if atomic.CompareAndSwapInt32(bits, cr, nw) { 202 break 203 } 204 } 205 } 206 207 // ClearMask32 clears all of the bits in the mask 208 func ClearMask32(bits *int32, mask int32) { 209 *bits &^= mask 210 } 211 212 // ClearMaskAtomic32 clears all of the bits in the mask 213 // using atomic compare-and-swap loop, safe for concurrent access 214 func ClearMaskAtomic32(bits *int32, mask int32) { 215 for { 216 cr := atomic.LoadInt32(bits) 217 nw := cr &^ mask 218 if atomic.CompareAndSwapInt32(bits, cr, nw) { 219 break 220 } 221 } 222 } 223 224 // HasAnyMask32 checks if *any* of the bits in mask are set (logical OR) 225 func HasAnyMask32(bits, mask int32) bool { 226 return bits&mask != 0 227 } 228 229 // HasAllMask32 checks if *all* of the bits in mask are set (logical AND) 230 func HasAllMask32(bits, mask int32) bool { 231 return bits&mask == mask 232 } 233 234 // HasAnyMaskAtomic32 checks if *any* of the bits in mask are set (logical OR) 235 // using atomic compare-and-swap loop, safe for concurrent access 236 func HasAnyMaskAtomic32(bits *int32, mask int32) bool { 237 return (atomic.LoadInt32(bits) & mask) != 0 238 } 239 240 // HasAllMaskAtomic32 checks if *all* of the bits in mask are set (logical AND) 241 // using atomic compare-and-swap loop, safe for concurrent access 242 func HasAllMaskAtomic32(bits *int32, mask int32) bool { 243 return (atomic.LoadInt32(bits) & mask) == mask 244 } 245 246 //////////////////////////////////////////////////////////////////////// 247 // Convenience methods for ordinal bitflags 248 249 // Mask32 makes a mask for checking multiple different flags 250 func Mask32(flags ...int) int32 { 251 var mask int32 252 for _, f := range flags { 253 mask |= 1 << uint32(f) 254 } 255 return mask 256 } 257 258 // Set32 sets bit value(s) for ordinal bit position flags 259 func Set32(bits *int32, flags ...int) { 260 SetMask32(bits, Mask32(flags...)) 261 } 262 263 // SetAtomic32 sets bit value(s) for ordinal bit position flags 264 // using atomic compare-and-swap loop, safe for concurrent access 265 func SetAtomic32(bits *int32, flags ...int) { 266 SetMaskAtomic32(bits, Mask32(flags...)) 267 } 268 269 // SetState32 sets or clears bit value(s) depending on state (on / off) for 270 // ordinal bit position flags 271 func SetState32(bits *int32, state bool, flags ...int) { 272 if state { 273 Set32(bits, flags...) 274 } else { 275 Clear32(bits, flags...) 276 } 277 } 278 279 // SetStateAtomic32 sets or clears bit value(s) depending on state (on / off) 280 // for ordinal bit position flags, protected by atomic -- safe for concurrent access 281 func SetStateAtomic32(bits *int32, state bool, flags ...int) { 282 if state { 283 SetAtomic32(bits, flags...) 284 } else { 285 ClearAtomic32(bits, flags...) 286 } 287 } 288 289 // Clear32 clears bit value(s) for ordinal bit position flags 290 func Clear32(bits *int32, flags ...int) { 291 ClearMask32(bits, Mask32(flags...)) 292 } 293 294 // ClearAtomic32 clears bit value(s) for ordinal bit position flags 295 // using atomic compare-and-swap loop, safe for concurrent access 296 func ClearAtomic32(bits *int32, flags ...int) { 297 ClearMaskAtomic32(bits, Mask32(flags...)) 298 } 299 300 // Has32 checks if given bit value is set for ordinal bit position flag 301 func Has32(bits int32, flag int) bool { 302 return bits&(1<<uint32(flag)) != 0 303 } 304 305 // HasAtomic32 checks if given bit value is set for ordinal bit position flag, 306 // using an atomic load, safe for concurrent access 307 func HasAtomic32(bits *int32, flag int) bool { 308 return atomic.LoadInt32(bits)&(1<<uint32(flag)) != 0 309 } 310 311 // HasAny32 checks if *any* of a set of flags are set for ordinal bit position flags (logical OR) 312 func HasAny32(bits int32, flags ...int) bool { 313 return HasAnyMask32(bits, Mask32(flags...)) 314 } 315 316 // HasAll32 checks if *all* of a set of flags are set for ordinal bit position flags (logical AND) 317 func HasAll32(bits int32, flags ...int) bool { 318 return HasAllMask32(bits, Mask32(flags...)) 319 } 320 321 // HasAnyAtomic32 checks if *any* of a set of flags are set for ordinal bit position flags (logical OR) 322 // using atomic compare-and-swap loop, safe for concurrent access 323 func HasAnyAtomic32(bits *int32, flags ...int) bool { 324 return HasAnyMaskAtomic32(bits, Mask32(flags...)) 325 } 326 327 // HasAllAtomic32 checks if *all* of a set of flags are set for ordinal bit position flags (logical AND) 328 // using atomic compare-and-swap loop, safe for concurrent access 329 func HasAllAtomic32(bits *int32, flags ...int) bool { 330 return HasAllMaskAtomic32(bits, Mask32(flags...)) 331 } 332 333 // Toggle32 toggles state of bit value(s) for ordinal bit position flags 334 func Toggle32(bits *int32, flags ...int) { 335 for _, f := range flags { 336 if Has32(*bits, f) { 337 Clear32(bits, f) 338 } else { 339 Set32(bits, f) 340 } 341 } 342 } 343 344 // ToggleAtomic32 toggles state of bit value(s) for ordinal bit position flags 345 // using atomic compare-and-swap loop, safe for concurrent access, but sequentially 346 func ToggleAtomic32(bits *int32, flags ...int) { 347 for _, f := range flags { 348 if HasAtomic32(bits, f) { 349 ClearAtomic32(bits, f) 350 } else { 351 SetAtomic32(bits, f) 352 } 353 } 354 }