mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-26 09:50:06 +01:00
util: add a bitmask_t type for bit masks
Previously we used uint32_t for bitmasks but having a custom type means we're less likely to confuse an int value with a mask type. Two types of API here, the u32 api for passing in masks and a bit API for passing in single bits. Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1218>
This commit is contained in:
parent
905b4c6a4c
commit
8974a15178
2 changed files with 326 additions and 0 deletions
127
src/util-bits.h
127
src/util-bits.h
|
|
@ -28,8 +28,10 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define bit(x_) (1UL << (x_))
|
||||
#define NBITS(b) (b * 8)
|
||||
|
|
@ -98,3 +100,128 @@ long_any_bit_set(unsigned long *array, size_t size)
|
|||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* A wrapper around a bit mask to avoid type confusion */
|
||||
typedef struct {
|
||||
uint32_t mask;
|
||||
} bitmask_t;
|
||||
|
||||
static inline uint32_t
|
||||
bitmask_as_u32(bitmask_t mask)
|
||||
{
|
||||
return mask.mask;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bitmask_is_empty(bitmask_t mask) {
|
||||
return mask.mask == 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bitmask_any(bitmask_t mask, bitmask_t bits) {
|
||||
return !!(mask.mask & bits.mask);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bitmask_all(bitmask_t mask, bitmask_t bits) {
|
||||
return bits.mask != 0 && (mask.mask & bits.mask) == bits.mask;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bitmask_merge(bitmask_t *mask, bitmask_t bits) {
|
||||
bool all = bitmask_all(*mask, bits);
|
||||
|
||||
mask->mask |= bits.mask;
|
||||
|
||||
return all;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bitmask_clear(bitmask_t *mask, bitmask_t bits) {
|
||||
bool all = bitmask_all(*mask, bits);
|
||||
|
||||
mask->mask &= ~bits.mask;
|
||||
|
||||
return all;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bitmask_bit_is_set(bitmask_t mask, unsigned int bit) {
|
||||
return !!(mask.mask & bit(bit));
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bitmask_set_bit(bitmask_t *mask, unsigned int bit) {
|
||||
bool isset = bitmask_bit_is_set(*mask, bit);
|
||||
mask->mask |= bit(bit);
|
||||
return isset;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bitmask_clear_bit(bitmask_t *mask, unsigned int bit) {
|
||||
bool isset = bitmask_bit_is_set(*mask, bit);
|
||||
mask->mask &= ~bit(bit);
|
||||
return isset;
|
||||
}
|
||||
|
||||
static inline bitmask_t
|
||||
bitmask_new(void) {
|
||||
bitmask_t m = {0};
|
||||
return m;
|
||||
}
|
||||
|
||||
static inline bitmask_t
|
||||
bitmask_from_bit(unsigned int bit) {
|
||||
bitmask_t m = {
|
||||
.mask = bit(bit)
|
||||
};
|
||||
return m;
|
||||
}
|
||||
|
||||
static inline bitmask_t
|
||||
bitmask_from_u32(uint32_t mask) {
|
||||
bitmask_t m = {
|
||||
.mask = mask
|
||||
};
|
||||
return m;
|
||||
}
|
||||
|
||||
static inline bitmask_t
|
||||
_bitmask_from_masks(uint32_t mask1, ...)
|
||||
{
|
||||
uint32_t mask = mask1;
|
||||
va_list args;
|
||||
va_start(args, mask1);
|
||||
|
||||
uint32_t v = va_arg(args, unsigned int);
|
||||
while (v != 0) {
|
||||
mask |= v;
|
||||
v = va_arg(args, unsigned int);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return bitmask_from_u32(mask);
|
||||
}
|
||||
|
||||
#define bitmask_from_masks(...) \
|
||||
_bitmask_from_masks(__VA_ARGS__, 0)
|
||||
|
||||
static inline bitmask_t
|
||||
_bitmask_from_bits(unsigned int bit1, ...)
|
||||
{
|
||||
uint32_t mask = bit(bit1);
|
||||
va_list args;
|
||||
va_start(args, bit1);
|
||||
|
||||
uint32_t v = va_arg(args, unsigned int);
|
||||
while (v < 32) {
|
||||
mask |= bit(v);
|
||||
v = va_arg(args, unsigned int);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return bitmask_from_u32(mask);
|
||||
}
|
||||
|
||||
#define bitmask_from_bits(...) \
|
||||
_bitmask_from_bits(__VA_ARGS__, 32)
|
||||
|
|
|
|||
|
|
@ -317,6 +317,204 @@ START_TEST(bitfield_helpers)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(bitmask_test)
|
||||
{
|
||||
{
|
||||
bitmask_t mask1 = bitmask_from_u32(0x12345678U);
|
||||
litest_assert(bitmask_as_u32(mask1) == 0x12345678U);
|
||||
|
||||
bitmask_t mask2 = bitmask_from_u32(0);
|
||||
litest_assert_int_eq(bitmask_as_u32(mask2), 0U);
|
||||
|
||||
bitmask_t mask3 = bitmask_from_u32(0xFFFFFFFFU);
|
||||
litest_assert_int_eq(bitmask_as_u32(mask3), 0xFFFFFFFFU);
|
||||
}
|
||||
{
|
||||
bitmask_t mask1 = bitmask_new();
|
||||
litest_assert(bitmask_is_empty(mask1));
|
||||
|
||||
bitmask_t mask2 = bitmask_from_u32(0x00000001U);
|
||||
litest_assert(!bitmask_is_empty(mask2));
|
||||
|
||||
bitmask_t mask3 = bitmask_from_u32(0xFFFFFFFFU);
|
||||
litest_assert(!bitmask_is_empty(mask3));
|
||||
}
|
||||
{
|
||||
bitmask_t mask1 = bitmask_from_u32(0x0000000FU);
|
||||
bitmask_t bits1 = bitmask_from_u32(0x00000003U);
|
||||
litest_assert(bitmask_any(mask1, bits1));
|
||||
|
||||
bitmask_t mask2 = bitmask_from_u32(0x0000000FU);
|
||||
bitmask_t bits2 = bitmask_from_u32(0x000000F0U);
|
||||
litest_assert(!bitmask_any(mask2, bits2));
|
||||
|
||||
bitmask_t mask3 = bitmask_from_u32(0x00000000U);
|
||||
bitmask_t bits3 = bitmask_from_u32(0x00000001U);
|
||||
litest_assert(!bitmask_any(mask3, bits3));
|
||||
|
||||
bitmask_t mask4 = bitmask_from_u32(0xFFFFFFFFU);
|
||||
bitmask_t bits4 = bitmask_from_u32(0xFFFFFFFFU);
|
||||
litest_assert(bitmask_any(mask4, bits4));
|
||||
|
||||
bitmask_t mask5 = bitmask_from_u32(0x10000000U);
|
||||
bitmask_t bits5 = bitmask_from_u32(0x10000000U);
|
||||
litest_assert(bitmask_any(mask5, bits5));
|
||||
}
|
||||
{
|
||||
bitmask_t mask1 = bitmask_from_u32(0x0000000FU);
|
||||
bitmask_t bits1 = bitmask_from_u32(0x00000003U);
|
||||
litest_assert(bitmask_all(mask1, bits1));
|
||||
litest_assert(!bitmask_all(bits1, mask1));
|
||||
|
||||
bitmask_t mask2 = bitmask_from_u32(0x0000000FU);
|
||||
bitmask_t bits2 = bitmask_from_u32(0x0000000FU);
|
||||
litest_assert(bitmask_all(mask2, bits2));
|
||||
litest_assert(bitmask_all(bits2, mask2));
|
||||
|
||||
bitmask_t mask3 = bitmask_from_u32(0x00000000U);
|
||||
bitmask_t bits3 = bitmask_from_u32(0x00000000U);
|
||||
litest_assert(!bitmask_all(mask3, bits3)); /* zero is special */
|
||||
|
||||
bitmask_t mask4 = bitmask_from_u32(0xFFFFFFFFU);
|
||||
bitmask_t bits4 = bitmask_from_u32(0xFFFFFFFFU);
|
||||
litest_assert(bitmask_all(mask4, bits4));
|
||||
|
||||
bitmask_t mask5 = bitmask_from_u32(0x10000000U);
|
||||
bitmask_t bits5 = bitmask_from_u32(0x10000000U);
|
||||
litest_assert(bitmask_all(mask5, bits5));
|
||||
}
|
||||
{
|
||||
|
||||
bitmask_t mask1 = bitmask_from_u32(0x0000000FU);
|
||||
bitmask_t bits1 = bitmask_from_u32(0x000000F0U);
|
||||
litest_assert(!bitmask_merge(&mask1, bits1));
|
||||
litest_assert_int_eq(mask1.mask, 0x000000FFU);
|
||||
|
||||
bitmask_t mask2 = bitmask_from_u32(0x0000000FU);
|
||||
bitmask_t bits2 = bitmask_from_u32(0x0000000FU);
|
||||
litest_assert(bitmask_merge(&mask2, bits2));
|
||||
litest_assert_int_eq(mask2.mask, 0x0000000FU);
|
||||
|
||||
bitmask_t mask3 = bitmask_new();
|
||||
bitmask_t bits3 = bitmask_from_u32(0xFFFFFFFFU);
|
||||
litest_assert(!bitmask_merge(&mask3, bits3));
|
||||
litest_assert_int_eq(mask3.mask, 0xFFFFFFFFU);
|
||||
|
||||
bitmask_t mask4 = bitmask_from_u32(0x80000000U);
|
||||
bitmask_t bits4 = bitmask_from_u32(0x00000001U);
|
||||
litest_assert(!bitmask_merge(&mask4, bits4));
|
||||
litest_assert_int_eq(mask4.mask, 0x80000001U);
|
||||
}
|
||||
{
|
||||
bitmask_t mask1 = bitmask_from_u32(0x000000FFU);
|
||||
bitmask_t bits1 = bitmask_from_u32(0x0000000FU);
|
||||
litest_assert(bitmask_clear(&mask1, bits1));
|
||||
litest_assert_int_eq(mask1.mask, 0x000000F0U);
|
||||
|
||||
bitmask_t mask2 = bitmask_from_u32(0x0000000FU);
|
||||
bitmask_t bits2 = bitmask_from_u32(0x0000000FU);
|
||||
litest_assert(bitmask_clear(&mask2, bits2));
|
||||
litest_assert_int_eq(mask2.mask, 0x00000000U);
|
||||
|
||||
bitmask_t mask3 = bitmask_from_u32(0xFFFFFFFFU);
|
||||
bitmask_t bits3 = bitmask_from_u32(0x00000000U);
|
||||
litest_assert(!bitmask_clear(&mask3, bits3)); /* zero is special */
|
||||
litest_assert_int_eq(mask3.mask, 0xFFFFFFFFU);
|
||||
|
||||
bitmask_t mask4 = bitmask_from_u32(0xFFFFFFFFU);
|
||||
bitmask_t bits4 = bitmask_from_u32(0xFFFFFFFFU);
|
||||
litest_assert(bitmask_clear(&mask4, bits4));
|
||||
litest_assert_int_eq(mask4.mask, 0x0U);
|
||||
}
|
||||
{
|
||||
bitmask_t mask1 = bitmask_from_u32(0x00000001U);
|
||||
litest_assert(bitmask_bit_is_set(mask1, 0));
|
||||
litest_assert(!bitmask_bit_is_set(mask1, 1));
|
||||
|
||||
bitmask_t mask2 = bitmask_from_u32(0x80000000U);
|
||||
litest_assert(bitmask_bit_is_set(mask2, 31));
|
||||
litest_assert(!bitmask_bit_is_set(mask2, 0));
|
||||
|
||||
bitmask_t mask3 = bitmask_from_u32(0xFFFFFFFFU);
|
||||
litest_assert(bitmask_bit_is_set(mask3, 0));
|
||||
litest_assert(bitmask_bit_is_set(mask3, 31));
|
||||
litest_assert(bitmask_bit_is_set(mask3, 16));
|
||||
|
||||
bitmask_t mask4 = bitmask_new();
|
||||
litest_assert(!bitmask_bit_is_set(mask4, 0));
|
||||
litest_assert(!bitmask_bit_is_set(mask4, 1));
|
||||
}
|
||||
{
|
||||
bitmask_t mask1 = bitmask_new();
|
||||
litest_assert(!bitmask_set_bit(&mask1, 0));
|
||||
litest_assert_int_eq(mask1.mask, 0x00000001U);
|
||||
|
||||
litest_assert(bitmask_set_bit(&mask1, 0));
|
||||
litest_assert_int_eq(mask1.mask, 0x00000001U);
|
||||
|
||||
litest_assert(!bitmask_set_bit(&mask1, 31));
|
||||
litest_assert_int_eq(mask1.mask, 0x80000001U);
|
||||
|
||||
bitmask_t mask2 = bitmask_from_u32(0x0000000FU);
|
||||
litest_assert(!bitmask_set_bit(&mask2, 4));
|
||||
litest_assert_int_eq(mask2.mask, 0x0000001FU);
|
||||
litest_assert(bitmask_set_bit(&mask2, 4));
|
||||
litest_assert_int_eq(mask2.mask, 0x0000001FU);
|
||||
}
|
||||
{
|
||||
bitmask_t mask1 = bitmask_from_u32(0xFFFFFFFFU);
|
||||
litest_assert(bitmask_clear_bit(&mask1, 0));
|
||||
litest_assert_int_eq(mask1.mask, 0xFFFFFFFEU);
|
||||
|
||||
litest_assert(!bitmask_clear_bit(&mask1, 0));
|
||||
litest_assert_int_eq(mask1.mask, 0xFFFFFFFEU);
|
||||
|
||||
litest_assert(bitmask_clear_bit(&mask1, 31));
|
||||
litest_assert_int_eq(mask1.mask, 0x7FFFFFFEU);
|
||||
|
||||
bitmask_t mask2 = bitmask_from_u32(0x0000001FU);
|
||||
litest_assert(bitmask_clear_bit(&mask2, 4));
|
||||
litest_assert_int_eq(mask2.mask, 0x0000000FU);
|
||||
litest_assert(!bitmask_clear_bit(&mask2, 4));
|
||||
litest_assert_int_eq(mask2.mask, 0x0000000FU);
|
||||
}
|
||||
{
|
||||
bitmask_t mask1 = bitmask_from_bit(0);
|
||||
litest_assert_int_eq(mask1.mask, 0x00000001U);
|
||||
|
||||
bitmask_t mask2 = bitmask_from_bit(31);
|
||||
litest_assert_int_eq(mask2.mask, 0x80000000U);
|
||||
|
||||
bitmask_t mask3 = bitmask_from_bit(16);
|
||||
litest_assert_int_eq(mask3.mask, 0x00010000U);
|
||||
}
|
||||
{
|
||||
bitmask_t mask1 = bitmask_from_u32(0x12345678U);
|
||||
litest_assert_int_eq(mask1.mask, 0x12345678U);
|
||||
|
||||
bitmask_t mask2 = bitmask_from_u32(0);
|
||||
litest_assert_int_eq(mask2.mask, 0U);
|
||||
|
||||
bitmask_t mask3 = bitmask_from_u32(0xFFFFFFFFU);
|
||||
litest_assert_int_eq(mask3.mask, 0xFFFFFFFFU);
|
||||
}
|
||||
{
|
||||
bitmask_t mask1 = bitmask_from_bits(1, 2, 5);
|
||||
litest_assert_int_eq(mask1.mask, bit(1) | bit(2) | bit(5));
|
||||
|
||||
bitmask_t mask2 = bitmask_from_bits(0);
|
||||
litest_assert_int_eq(mask2.mask, bit(0));
|
||||
}
|
||||
{
|
||||
bitmask_t mask1 = bitmask_from_masks(0x1, 0x2, 0x8);
|
||||
litest_assert_int_eq(mask1.mask, 0x0000000BU);
|
||||
|
||||
bitmask_t mask2 = bitmask_from_masks(0x0);
|
||||
litest_assert_int_eq(mask2.mask, 0x00000000U);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(matrix_helpers)
|
||||
{
|
||||
struct matrix m1, m2, m3;
|
||||
|
|
@ -2719,6 +2917,7 @@ int main(void)
|
|||
ADD_TEST(array_for_each);
|
||||
|
||||
ADD_TEST(bitfield_helpers);
|
||||
ADD_TEST(bitmask_test);
|
||||
ADD_TEST(matrix_helpers);
|
||||
ADD_TEST(ratelimit_helpers);
|
||||
ADD_TEST(dpi_parser);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue