You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
99 lines
5.2 KiB
99 lines
5.2 KiB
From 55a262020c0a61b639c17a1be4f7b5b6fd3f5087 Mon Sep 17 00:00:00 2001
|
|
From: Dan Streetman <ddstreet@ieee.org>
|
|
Date: Thu, 2 Feb 2023 15:58:10 -0500
|
|
Subject: [PATCH] basic/bitfield: add bitfield operations
|
|
|
|
Add macros to manage bits in a bitfield (e.g. uint32_t, uint64_t, etc),
|
|
such as setting, clearing, checking bits, and iterating all set bits.
|
|
|
|
These are similiar to the bitmap operations, but operate on basic types
|
|
instead of requiring a Bitmap object.
|
|
|
|
(cherry picked from commit 33d9beed07b3dab05d07d57e8af13bb19b9e3095)
|
|
|
|
Related: RHEL-16182
|
|
---
|
|
src/basic/bitfield.h | 73 ++++++++++++++++++++++++++++++++++++++++++++
|
|
1 file changed, 73 insertions(+)
|
|
create mode 100644 src/basic/bitfield.h
|
|
|
|
diff --git a/src/basic/bitfield.h b/src/basic/bitfield.h
|
|
new file mode 100644
|
|
index 0000000000..25bc0ebda7
|
|
--- /dev/null
|
|
+++ b/src/basic/bitfield.h
|
|
@@ -0,0 +1,73 @@
|
|
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
+#pragma once
|
|
+
|
|
+#include "macro.h"
|
|
+
|
|
+/* Bit index (0-based) to mask of specified type. Assertion failure if index is out of range. */
|
|
+#define _INDEX_TO_MASK(type, i, uniq) \
|
|
+ ({ \
|
|
+ int UNIQ_T(_i, uniq) = (i); \
|
|
+ assert(UNIQ_T(_i, uniq) < (int)sizeof(type) * 8); \
|
|
+ ((type)1) << UNIQ_T(_i, uniq); \
|
|
+ })
|
|
+#define INDEX_TO_MASK(type, i) \
|
|
+ ({ \
|
|
+ assert_cc(sizeof(type) <= sizeof(unsigned long long)); \
|
|
+ assert_cc(__builtin_choose_expr(__builtin_constant_p(i), i, 0) < (int)(sizeof(type) * 8)); \
|
|
+ __builtin_choose_expr(__builtin_constant_p(i), \
|
|
+ ((type)1) << (i), \
|
|
+ _INDEX_TO_MASK(type, i, UNIQ)); \
|
|
+ })
|
|
+
|
|
+/* Builds a mask of specified type with multiple bits set. Note the result will not be constant, even if all
|
|
+ * indexes are constant. */
|
|
+#define INDEXES_TO_MASK(type, ...) \
|
|
+ UNIQ_INDEXES_TO_MASK(type, UNIQ, ##__VA_ARGS__)
|
|
+#define UNIQ_INDEXES_TO_MASK(type, uniq, ...) \
|
|
+ ({ \
|
|
+ typeof(type) UNIQ_T(_mask, uniq) = (type)0; \
|
|
+ int UNIQ_T(_i, uniq); \
|
|
+ VA_ARGS_FOREACH(UNIQ_T(_i, uniq), ##__VA_ARGS__) \
|
|
+ UNIQ_T(_mask, uniq) |= INDEX_TO_MASK(type, UNIQ_T(_i, uniq)); \
|
|
+ UNIQ_T(_mask, uniq); \
|
|
+ })
|
|
+
|
|
+/* Same as the FLAG macros, but accept a 0-based bit index instead of a mask. Results in assertion failure if
|
|
+ * index is out of range for the type. */
|
|
+#define SET_BIT(bits, i) SET_FLAG(bits, INDEX_TO_MASK(typeof(bits), i), true)
|
|
+#define CLEAR_BIT(bits, i) SET_FLAG(bits, INDEX_TO_MASK(typeof(bits), i), false)
|
|
+#define BIT_SET(bits, i) FLAGS_SET(bits, INDEX_TO_MASK(typeof(bits), i))
|
|
+
|
|
+/* As above, but accepts multiple indexes. Note the result will not be constant, even if all indexes are
|
|
+ * constant. */
|
|
+#define SET_BITS(bits, ...) SET_FLAG(bits, INDEXES_TO_MASK(typeof(bits), ##__VA_ARGS__), true)
|
|
+#define CLEAR_BITS(bits, ...) SET_FLAG(bits, INDEXES_TO_MASK(typeof(bits), ##__VA_ARGS__), false)
|
|
+#define BITS_SET(bits, ...) FLAGS_SET(bits, INDEXES_TO_MASK(typeof(bits), ##__VA_ARGS__))
|
|
+
|
|
+/* Iterate through each set bit. Index is 0-based and type int. */
|
|
+#define BIT_FOREACH(index, bits) _BIT_FOREACH(index, bits, UNIQ)
|
|
+#define _BIT_FOREACH(index, bits, uniq) \
|
|
+ for (int UNIQ_T(_last, uniq) = -1, index; \
|
|
+ (index = BIT_NEXT_SET(bits, UNIQ_T(_last, uniq))) >= 0; \
|
|
+ UNIQ_T(_last, uniq) = index)
|
|
+
|
|
+/* Find the next set bit after 0-based index 'prev'. Result is 0-based index of next set bit, or -1 if no
|
|
+ * more bits are set. */
|
|
+#define BIT_FIRST_SET(bits) BIT_NEXT_SET(bits, -1)
|
|
+#define BIT_NEXT_SET(bits, prev) \
|
|
+ UNIQ_BIT_NEXT_SET(bits, prev, UNIQ)
|
|
+#define UNIQ_BIT_NEXT_SET(bits, prev, uniq) \
|
|
+ ({ \
|
|
+ typeof(bits) UNIQ_T(_bits, uniq) = (bits); \
|
|
+ int UNIQ_T(_prev, uniq) = (prev); \
|
|
+ int UNIQ_T(_next, uniq); \
|
|
+ _BIT_NEXT_SET(UNIQ_T(_bits, uniq), \
|
|
+ UNIQ_T(_prev, uniq), \
|
|
+ UNIQ_T(_next, uniq)); \
|
|
+ })
|
|
+#define _BIT_NEXT_SET(bits, prev, next) \
|
|
+ ((int)(prev + 1) == (int)sizeof(bits) * 8 \
|
|
+ ? -1 /* Prev index was msb. */ \
|
|
+ : ((next = __builtin_ffsll(((unsigned long long)(bits)) >> (prev + 1))) == 0 \
|
|
+ ? -1 /* No more bits set. */ \
|
|
+ : prev + next))
|