udev: String substitutions can be done in ENV, too
[systemd_ALT.git] / src / basic / bitfield.h
blob25bc0ebda771704461de8154a7e86e8ddf016d94
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 #pragma once
4 #include "macro.h"
6 /* Bit index (0-based) to mask of specified type. Assertion failure if index is out of range. */
7 #define _INDEX_TO_MASK(type, i, uniq) \
8 ({ \
9 int UNIQ_T(_i, uniq) = (i); \
10 assert(UNIQ_T(_i, uniq) < (int)sizeof(type) * 8); \
11 ((type)1) << UNIQ_T(_i, uniq); \
13 #define INDEX_TO_MASK(type, i) \
14 ({ \
15 assert_cc(sizeof(type) <= sizeof(unsigned long long)); \
16 assert_cc(__builtin_choose_expr(__builtin_constant_p(i), i, 0) < (int)(sizeof(type) * 8)); \
17 __builtin_choose_expr(__builtin_constant_p(i), \
18 ((type)1) << (i), \
19 _INDEX_TO_MASK(type, i, UNIQ)); \
22 /* Builds a mask of specified type with multiple bits set. Note the result will not be constant, even if all
23 * indexes are constant. */
24 #define INDEXES_TO_MASK(type, ...) \
25 UNIQ_INDEXES_TO_MASK(type, UNIQ, ##__VA_ARGS__)
26 #define UNIQ_INDEXES_TO_MASK(type, uniq, ...) \
27 ({ \
28 typeof(type) UNIQ_T(_mask, uniq) = (type)0; \
29 int UNIQ_T(_i, uniq); \
30 VA_ARGS_FOREACH(UNIQ_T(_i, uniq), ##__VA_ARGS__) \
31 UNIQ_T(_mask, uniq) |= INDEX_TO_MASK(type, UNIQ_T(_i, uniq)); \
32 UNIQ_T(_mask, uniq); \
35 /* Same as the FLAG macros, but accept a 0-based bit index instead of a mask. Results in assertion failure if
36 * index is out of range for the type. */
37 #define SET_BIT(bits, i) SET_FLAG(bits, INDEX_TO_MASK(typeof(bits), i), true)
38 #define CLEAR_BIT(bits, i) SET_FLAG(bits, INDEX_TO_MASK(typeof(bits), i), false)
39 #define BIT_SET(bits, i) FLAGS_SET(bits, INDEX_TO_MASK(typeof(bits), i))
41 /* As above, but accepts multiple indexes. Note the result will not be constant, even if all indexes are
42 * constant. */
43 #define SET_BITS(bits, ...) SET_FLAG(bits, INDEXES_TO_MASK(typeof(bits), ##__VA_ARGS__), true)
44 #define CLEAR_BITS(bits, ...) SET_FLAG(bits, INDEXES_TO_MASK(typeof(bits), ##__VA_ARGS__), false)
45 #define BITS_SET(bits, ...) FLAGS_SET(bits, INDEXES_TO_MASK(typeof(bits), ##__VA_ARGS__))
47 /* Iterate through each set bit. Index is 0-based and type int. */
48 #define BIT_FOREACH(index, bits) _BIT_FOREACH(index, bits, UNIQ)
49 #define _BIT_FOREACH(index, bits, uniq) \
50 for (int UNIQ_T(_last, uniq) = -1, index; \
51 (index = BIT_NEXT_SET(bits, UNIQ_T(_last, uniq))) >= 0; \
52 UNIQ_T(_last, uniq) = index)
54 /* Find the next set bit after 0-based index 'prev'. Result is 0-based index of next set bit, or -1 if no
55 * more bits are set. */
56 #define BIT_FIRST_SET(bits) BIT_NEXT_SET(bits, -1)
57 #define BIT_NEXT_SET(bits, prev) \
58 UNIQ_BIT_NEXT_SET(bits, prev, UNIQ)
59 #define UNIQ_BIT_NEXT_SET(bits, prev, uniq) \
60 ({ \
61 typeof(bits) UNIQ_T(_bits, uniq) = (bits); \
62 int UNIQ_T(_prev, uniq) = (prev); \
63 int UNIQ_T(_next, uniq); \
64 _BIT_NEXT_SET(UNIQ_T(_bits, uniq), \
65 UNIQ_T(_prev, uniq), \
66 UNIQ_T(_next, uniq)); \
68 #define _BIT_NEXT_SET(bits, prev, next) \
69 ((int)(prev + 1) == (int)sizeof(bits) * 8 \
70 ? -1 /* Prev index was msb. */ \
71 : ((next = __builtin_ffsll(((unsigned long long)(bits)) >> (prev + 1))) == 0 \
72 ? -1 /* No more bits set. */ \
73 : prev + next))