Doesn't this give you if alpha OR blue is set?
Errors like this are another reason syntactical sugar for readability is important.
Doesn't this give you if alpha OR blue is set?
Errors like this are another reason syntactical sugar for readability is important.
if((mask & WGPUColorWriteMask_Alpha) && (mask & WGPUColorWriteMask_Blue)) { //… }
This is the least confusing form I’ve seen that doesn’t require a function, macro, custom operator, etc. static bool all_bits_set(i32 value, i32 mask) { return (value & mask) == mask; }
Here I'm assuming 32-bit values. In C, with relatively little support for generics, you can consider making multiple versions, possibly using _Generic (note, I haven't evaluated the sanity of using _Generic).Alternatively you can use a #define. However, you need to use "mask" twice, so that gets tricky - either it requires care to keep the corresponding expression at the call site side-effect free. Or the macro needs to be written using compiler extensions like statement expressions and typeof() variable declarations à la Linux kernel.
#define all_bits_set(value, mask) ({__typeof__(value) v = (value), m = (mask); (v & m) == m; })
I personally would go for the extension aboveor a single 64 bit function, but here's the _Generic version: static bool all_bits_set32(i32 value, i32 mask) { return (value & mask) == mask; }
static bool all_bits_set64(i64 value, i64 mask) { return (value & mask) == mask; }
#define all_bits_set(value, mask) _Generic((value), int32_t: all_bits_set32, int64_t: all_bits_set64)(value, mask) if ((mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) == (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) { ... }
...which is quite a mouthful. if (mask &== WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue) { … }
I find only two very minor problems with it: firstly, that it’s not commutative (that is, a &== b is not equivalent to b &== a). Secondly, that it can be confused with the bitwise-and assignment operator &= (a &= b being equivalent to a = a & b for singly-evaluated lvalue a).I’d then add |== for consistency and because it is conceivably useful. ^== is tempting, but since a ^== b would be just another spelling of a == 0, I’d skip it.
Why is that a problem? That is, if a has additional bits set compared to b, then ((a & b) == b) != ((b & a) == a), no?
For equality comparisons, there are two opposing conventions: actual == expected (the more popular, in my experience), and expected == actual (by no means rare). Having &== and |== be order-sensitive (though there’s absolutely no question in my mind about what the ordering should be) is mildly unfortunate.
It’s very minor.
It's a separate operator after all, one I also miss a lot...
But then, continuing that thinking, if you have '&==', you'd also need '&!=' -- that looks really confusing.
Can't we turn that into a '==0' test somehow? Maybe '^&', because '((a ^ b) & b) == 0' is equivalent to '(a & b) == b'. And, as somehow said: '~&' also works: '(~a & b) == 0' is also equivalent to '(a & b) == b'.
if ((a ~& b) == 0) { ... }
Wait -- we can swap that into '&~' and we're back in C. However, it reverses the logical order, with the test bits first: if ((b & ~a) == 0) { ... }
if (((WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue) & ~mask) == 0) {
...
}
So we're back -- this is standard C now. But I find it incomprehensible. if (!(b & ~a)) { … }
if (!((WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue) & ~mask)) { … }
if (!(~a & b)) { … }
if (!(~mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue))) { … }
Actually, that latter makes a little more intuitive sense to me because of how ! and ~ are both negation¹, so they kinda cancel out and leave just the masking. Kinda.—⁂—
¹ Fun fact: Rust uses ! for both logical and bitwise negation, backed by core::ops::Not, with bool → bool and {integer} → {integer}, since bool is a proper type and there’s no boolean coercion anywhere—so you would have to stick with `== 0` in Rust, though in practice you’d probably go all typey with the bitflags crate’s macro to generate good types with some handy extra methods, and write `mask.contains(WgpuColorWriteMask::Alpha | WgpuColorWriteMask::Blue)`.
if (mask.contains(WGPUColorWriteMask_Alpha) || mask.contains(WGPUColorWriteMask_Blue)) { ... } // To check for either flag:
if mask.contains(WgpuColorWriteMask::Alpha) || mask.contains(WgpuColorWriteMask::Blue) { … }
if mask.intersects(WgpuColorWriteMask::Alpha | WgpuColorWriteMask::Blue) { … }
// To check for both flags:
if mask.contains(WgpuColorWriteMask::Alpha | WgpuColorWriteMask::Blue) { … } if (!(~mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue))) { ... }
Not quite as long but perhaps less readable. if (mask & WGPUColorWriteMask_Alpha & WGPUColorWriteMask_Blue) {
// alpha and blue are set..
}If WGPUColorWriteMask_Alpha and WGPUColorWriteMask_Blue doesn't share bits, isn't this garanteed 100% to be false?
if (all_of(mask, WGPUColorWriteMask_Alpha | WGPUColorWriteMask_Blue))
with all_of() being a #define. Likewise none_of(), any_of().No need for special operators.
if (@popCount(mask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) == 2)
I do not know Zig, so the syntax might not be right. I did check to see that it has popcount [1].If it has some concise way to flip all the bits, then this would be another possibility that isn't too verbose, but might raise other objections. Let fmask be mask with all the bits flipped (how would one do that in Zig?).
if ((fmask & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue)) == 0)
[1] https://ziglang.org/documentation/master/#popCount if (mask.alpha and mask.blue) { // cannot convert i (variable of type int) to type bool
bool(i)
youd need to use a function: func to_bool(i int) bool { return i != 0 }https://developer.mozilla.org/docs/Glossary/Truthy
and I fully support that decision. If you want to use a boolean, you need to be explicit about it.
The compiler isn't going to make that function, it's going to optimize back to a cast to boolean. Why make the poor shmoe user type it out?
If you want to call it arbitrary, it's been arbitrated decades ago, but Boolean logic is much older than computers and works as it does for a reason. I suspect you know that.
People keep telling me this koolaid is delicious but I just don't see it.
edit: oh, i think i'm wrong, nevermind.
Correct usage would be if you want both flags.
(flag & (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue) == (WGPUColorWriteMask_Alpha|WGPUColorWriteMask_Blue) if WGPUColorWriteMask.Alpha in mask and WGPUColorWriteMask.Blue in mask: ...