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