-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathfixed_bitset.h
More file actions
283 lines (252 loc) · 8.89 KB
/
fixed_bitset.h
File metadata and controls
283 lines (252 loc) · 8.89 KB
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
/*
* Copyright (c) 2026 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_UTIL_FIXED_BITSET_H
#define _PICO_UTIL_FIXED_BITSET_H
#include "pico.h"
/** \file fixed_bitset.h
* \defgroup fixed_bitset fixed_bitset
* \brief Simple fixed-size bitset implementation
*
* \ingroup pico_util
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
uint16_t size; \
uint16_t word_size; \
uint32_t words[];
} fixed_bitset_t;
/*! \brief Macro used to define a fixed-size bitset of a given size
* \ingroup fixed_bitset
* This macro is used to declare the type of a fixed-size bitset. It is used as follows:
* ```
* typedef fixed_bitset_type_t(17) my_bitset_t;
* ```
* will define a new bitset type called `my_bitset_t` that can hold 17 boolean values.
*
* The type can be used as `my_bitset_t bitset;` to declare a new bitset.
*
* \param N the number of boolean values in the bitset
*/
#define fixed_bitset_type(N) union { \
fixed_bitset_t bitset; \
struct { \
uint16_t size; \
uint16_t word_size; \
uint32_t words[((N) + 31) / 32]; \
} sized_bitset; \
}
#define fixed_bitset_sizeof_for(N) ((((N) + 63u) / 32u) * 4u)
/*! \brief Macro used to create a bitset with all bits set to a value
* \ingroup fixed_bitset
* \param type the type of the bitset
* \param N the number of bits in the bitset
* \param fill the value to set the bits to (0 or 1)
* \return the bitset
*/
#define fixed_bitset_with_fill(type, N, fill) ({ type bitset; fixed_bitset_init(&bitset, type, N, fill); bitset; })
// Quick test that the bitset macros give the correct size
extern fixed_bitset_type(32) __not_real_bitset32;
extern fixed_bitset_type(33) __not_real_bitset33;
static_assert(sizeof(__not_real_bitset32) == fixed_bitset_sizeof_for(1),"");
static_assert(sizeof(__not_real_bitset33) == fixed_bitset_sizeof_for(37), "");
static_assert(sizeof(__not_real_bitset33) != fixed_bitset_sizeof_for(1), "");
/*! \brief Initialize a bitset
* \ingroup fixed_bitset
* \param ptr the bitset to initialize
* \param type the type of the bitset
* \param N the number of bits in the bitset
* \param fill the value to fill the bitset with (0 or 1)
*/
#define fixed_bitset_init(ptr, type, N, fill) ({ \
assert(sizeof(type) == fixed_bitset_sizeof_for(N)); \
__unused type *type_check = ptr; \
(ptr)->bitset.size = N; \
(ptr)->bitset.word_size = ((N) + 31u) / 32u; \
__builtin_memset(&(ptr)->bitset.words, (fill) ? 0xff : 0, (ptr)->bitset.word_size * sizeof(uint32_t)); \
})
/*! \brief Get the size of the bitset
* \ingroup fixed_bitset
* \param bitset the bitset to get the size of
* \return the size of the bitset
*/
static inline uint fixed_bitset_size(const fixed_bitset_t *bitset) {
return bitset->size;
}
/*! \brief Get the size of the bitset in words
* \ingroup fixed_bitset
* \param bitset the bitset to get the size of
* \return the size of the bitset in words
*/
static inline uint fixed_bitset_word_size(const fixed_bitset_t *bitset) {
return bitset->word_size;
}
/*! \brief Check that the bitset is valid
* \ingroup fixed_bitset
* This function will assert if the bitset is not valid.
* \param bitset the bitset to check
*/
static inline void check_fixed_bitset(const fixed_bitset_t *bitset) {
assert(bitset->word_size == (bitset->size + 31) / 32);
}
/*! \brief Write a word in the bitset
* \ingroup fixed_bitset
* \param bitset the bitset to write to
* \param word_num the word number to write to
* \param value the value to write to the word
* \return the bitset
*/
static inline fixed_bitset_t *fixed_bitset_write_word(fixed_bitset_t *bitset, uint word_num, uint32_t value) {
check_fixed_bitset(bitset);
if (word_num < fixed_bitset_word_size(bitset)) {
bitset->words[word_num] = value;
}
return bitset;
}
/*! \brief Read a word in the bitset
* \ingroup fixed_bitset
* \param bitset the bitset
* \param word_num the word number to read from
* \return the value of the word
*/
static inline uint32_t fixed_bitset_read_word(const fixed_bitset_t *bitset, uint word_num) {
check_fixed_bitset(bitset);
if (word_num < fixed_bitset_word_size(bitset)) {
return bitset->words[word_num];
}
return 0;
}
/*! \brief Clear all bits in the bitset
* \ingroup fixed_bitset
* \param bitset the bitset
* \return the bitset
*/
static inline fixed_bitset_t *fixed_bitset_clear_all(fixed_bitset_t *bitset) {
check_fixed_bitset(bitset);
__builtin_memset(bitset->words, 0, bitset->word_size * sizeof(uint32_t));
return bitset;
}
/*! \brief Set all bits in the bitset
* \ingroup fixed_bitset
* \param bitset the bitset
* \return the bitset
*/
static inline fixed_bitset_t *fixed_bitset_set_all(fixed_bitset_t *bitset) {
check_fixed_bitset(bitset);
__builtin_memset(bitset->words, 0xff, bitset->word_size * sizeof(uint32_t));
return bitset;
}
/*! \brief Flip all bits in the bitset
* \ingroup fixed_bitset
* \param bitset the bitset
* \return the bitset
*/
fixed_bitset_t *fixed_bitset_flip_all(fixed_bitset_t *bitset);
/*! \brief Determine if bitset is empty
* \ingroup fixed_bitset
* \param bitset the bitset
* \return true if not bits are set
*/
bool fixed_bitset_is_empty(fixed_bitset_t *bitset);
/*! \brief Set a single bit in the bitset
* \ingroup fixed_bitset
* \param bitset the bitset
* \param bit_index the bit to set
* \return the bitset
*/
static inline fixed_bitset_t *fixed_bitset_set(fixed_bitset_t *bitset, uint bit_index) {
check_fixed_bitset(bitset);
if (bit_index < bitset->size) {
bitset->words[bit_index / 32u] |= 1u << (bit_index % 32u);
}
return bitset;
}
/*! \brief Clear a single bit in the bitset
* \ingroup fixed_bitset
* \param bitset the bitset
* \param bit_index the bit to clear
* \return the bitset
*/
static inline fixed_bitset_t *fixed_bitset_clear(fixed_bitset_t *bitset, uint bit_index) {
check_fixed_bitset(bitset);
if (bit_index < bitset->size) {
bitset->words[bit_index / 32u] &= ~(1u << (bit_index % 32u));
}
return bitset;
}
/*! \brief Flip a single bit in the bitset
* \ingroup fixed_bitset
* \param bitset the bitset
* \param bit_index the bit to flip
* \return the bitset
*/
static inline fixed_bitset_t *fixed_bitset_flip(fixed_bitset_t *bitset, uint bit_index) {
check_fixed_bitset(bitset);
if (bit_index < bitset->size) {
bitset->words[bit_index / 32u] ^= 1u << (bit_index % 32u);
}
return bitset;
}
/*! \brief Get the value of a single bit in the bitset
* \ingroup fixed_bitset
* \param bitset the bitset
* \param bit_index the bit to get the value of
* \return the value of the bit
*/
static inline bool fixed_bitset_get(const fixed_bitset_t *bitset, uint bit_index) {
check_fixed_bitset(bitset);
assert(bit_index < bitset->size);
// if (bit < bitset->size) {
return bitset->words[bit_index / 32u] & (1u << (bit_index % 32u));
// }
return false;
}
/*! \brief Check if two bitsets are equal
* \ingroup fixed_bitset
* \param bitset1 the first bitset to check
* \param bitset2 the second bitset to check
* \return true if the bitsets are equal, false otherwise
*/
static inline bool fixed_bitset_equal(const fixed_bitset_t *bitset1, const fixed_bitset_t *bitset2) {
check_fixed_bitset(bitset1);
check_fixed_bitset(bitset2);
assert(bitset1->size == bitset2->size);
return __builtin_memcmp(bitset1->words, bitset2->words, bitset1->word_size * sizeof(uint32_t)) == 0;
}
#if 0 // not currently used
typedef uint32_t tiny_ordinal_list_t; // ordinals must be 0->255
typedef uint64_t small_ordinal_list_t; // ordinals must be 0->255
#define ordinal_list_empty() 0
#define ordinal_list_of1(v) (1u | ((v) << 8))
#define ordinal_list_of2(v1, v2) (2u | ((v1) << 8) | ((v2) << 16))
#define ordinal_list_of3(v1, v2, v3) (3u | ((v1) << 8) | ((v2) << 16) | (((v3) << 24)))
#define ordinal_list_of4(v1, v2, v3, v4) (4u | ((v1) << 8) | ((v2) << 16) | (((v3) << 24)) | (((uint64_t)(v4)) << 32))
#define ordinal_list_of5(v1, v2, v3, v4, v5) (5u | ((v1) << 8) | ((v2) << 16) | (((v3) << 24)) | (((uint64_t)((v4) | ((v5)<<8u))) << 32))
#define small_ordinal_list_foreach(bitarray, x) ({ \
for(uint _i=1;_i<=((bitarray)&0xffu);_i++) { \
uint bit = (uint8_t)((bitarray) >> (8 * _i)); \
x; \
} \
})
static inline fixed_bitset_t *fixed_bitset_set_bits(fixed_bitset_t *bitset, small_ordinal_list_t list) {
small_ordinal_list_foreach(list, fixed_bitset_set(bitset, bit));
return bitset;
}
static inline fixed_bitset_t *fixed_bitset_clear_bits(fixed_bitset_t *bitset, small_ordinal_list_t list) {
small_ordinal_list_foreach(list, fixed_bitset_clear(bitset, bit));
return bitset;
}
#define fixed_bitset_init_with_bits(ptr, type, N, list) ({ \
/* not this performs checks */ \
fixed_bitset_init(ptr, type, N, 0); \
fixed_bitset_set_bits(&(ptr)->bitset, list); \
})
#endif
#ifdef __cplusplus
}
#endif
#endif