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  }