4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "spdk/bit_array.h"
45 #include "spdk/likely.h"
46 #include "spdk/util.h"
48 typedef uint64_t spdk_bit_array_word
;
49 #define SPDK_BIT_ARRAY_WORD_TZCNT(x) (__builtin_ctzll(x))
50 #define SPDK_BIT_ARRAY_WORD_C(x) ((spdk_bit_array_word)(x))
51 #define SPDK_BIT_ARRAY_WORD_BYTES sizeof(spdk_bit_array_word)
52 #define SPDK_BIT_ARRAY_WORD_BITS (SPDK_BIT_ARRAY_WORD_BYTES * 8)
53 #define SPDK_BIT_ARRAY_WORD_INDEX_SHIFT spdk_u32log2(SPDK_BIT_ARRAY_WORD_BITS)
54 #define SPDK_BIT_ARRAY_WORD_INDEX_MASK ((1u << SPDK_BIT_ARRAY_WORD_INDEX_SHIFT) - 1)
56 struct spdk_bit_array
{
58 spdk_bit_array_word words
[];
61 struct spdk_bit_array
*
62 spdk_bit_array_create(uint32_t num_bits
)
64 struct spdk_bit_array
*ba
= NULL
;
66 spdk_bit_array_resize(&ba
, num_bits
);
72 spdk_bit_array_free(struct spdk_bit_array
**bap
)
74 struct spdk_bit_array
*ba
;
85 static inline uint32_t
86 spdk_bit_array_word_count(uint32_t num_bits
)
88 return (num_bits
+ SPDK_BIT_ARRAY_WORD_BITS
- 1) >> SPDK_BIT_ARRAY_WORD_INDEX_SHIFT
;
91 static inline spdk_bit_array_word
92 spdk_bit_array_word_mask(uint32_t num_bits
)
94 assert(num_bits
< SPDK_BIT_ARRAY_WORD_BITS
);
95 return (SPDK_BIT_ARRAY_WORD_C(1) << num_bits
) - 1;
99 spdk_bit_array_resize(struct spdk_bit_array
**bap
, uint32_t num_bits
)
101 struct spdk_bit_array
*new_ba
;
102 uint32_t old_word_count
, new_word_count
;
109 new_word_count
= spdk_bit_array_word_count(num_bits
);
110 new_size
= offsetof(struct spdk_bit_array
, words
) + new_word_count
* SPDK_BIT_ARRAY_WORD_BYTES
;
113 * Always keep one extra word with a 0 and a 1 past the actual required size so that the
114 * find_first functions can just keep going until they match.
116 new_size
+= SPDK_BIT_ARRAY_WORD_BYTES
;
118 new_ba
= (struct spdk_bit_array
*)spdk_realloc(*bap
, new_size
, 64, NULL
);
124 * Set up special extra word (see above comment about find_first_clear).
126 * This is set to 0b10 so that find_first_clear will find a 0 at the very first
127 * bit past the end of the buffer, and find_first_set will find a 1 at the next bit
130 new_ba
->words
[new_word_count
] = 0x2;
134 new_ba
->bit_count
= 0;
136 old_word_count
= spdk_bit_array_word_count(new_ba
->bit_count
);
139 if (new_word_count
> old_word_count
) {
140 /* Zero out new entries */
141 memset(&new_ba
->words
[old_word_count
], 0,
142 (new_word_count
- old_word_count
) * SPDK_BIT_ARRAY_WORD_BYTES
);
143 } else if (new_word_count
== old_word_count
&& num_bits
< new_ba
->bit_count
) {
144 /* Make sure any existing partial last word is cleared beyond the new num_bits. */
145 uint32_t last_word_bits
;
146 spdk_bit_array_word mask
;
148 last_word_bits
= num_bits
& SPDK_BIT_ARRAY_WORD_INDEX_MASK
;
149 mask
= spdk_bit_array_word_mask(last_word_bits
);
150 new_ba
->words
[old_word_count
- 1] &= mask
;
153 new_ba
->bit_count
= num_bits
;
159 spdk_bit_array_capacity(const struct spdk_bit_array
*ba
)
161 return ba
->bit_count
;
165 _spdk_bit_array_get_word(const struct spdk_bit_array
*ba
, uint32_t bit_index
,
166 uint32_t *word_index
, uint32_t *word_bit_index
)
168 if (spdk_unlikely(bit_index
>= ba
->bit_count
)) {
172 *word_index
= bit_index
>> SPDK_BIT_ARRAY_WORD_INDEX_SHIFT
;
173 *word_bit_index
= bit_index
& SPDK_BIT_ARRAY_WORD_INDEX_MASK
;
179 spdk_bit_array_get(const struct spdk_bit_array
*ba
, uint32_t bit_index
)
181 uint32_t word_index
, word_bit_index
;
183 if (_spdk_bit_array_get_word(ba
, bit_index
, &word_index
, &word_bit_index
)) {
187 return (ba
->words
[word_index
] >> word_bit_index
) & 1U;
191 spdk_bit_array_set(struct spdk_bit_array
*ba
, uint32_t bit_index
)
193 uint32_t word_index
, word_bit_index
;
195 if (_spdk_bit_array_get_word(ba
, bit_index
, &word_index
, &word_bit_index
)) {
199 ba
->words
[word_index
] |= (SPDK_BIT_ARRAY_WORD_C(1) << word_bit_index
);
204 spdk_bit_array_clear(struct spdk_bit_array
*ba
, uint32_t bit_index
)
206 uint32_t word_index
, word_bit_index
;
208 if (_spdk_bit_array_get_word(ba
, bit_index
, &word_index
, &word_bit_index
)) {
210 * Clearing past the end of the bit array is a no-op, since bit past the end
216 ba
->words
[word_index
] &= ~(SPDK_BIT_ARRAY_WORD_C(1) << word_bit_index
);
219 static inline uint32_t
220 _spdk_bit_array_find_first(const struct spdk_bit_array
*ba
, uint32_t start_bit_index
,
221 spdk_bit_array_word xor_mask
)
223 uint32_t word_index
, first_word_bit_index
;
224 spdk_bit_array_word word
, first_word_mask
;
225 const spdk_bit_array_word
*words
, *cur_word
;
227 if (spdk_unlikely(start_bit_index
>= ba
->bit_count
)) {
228 return ba
->bit_count
;
231 word_index
= start_bit_index
>> SPDK_BIT_ARRAY_WORD_INDEX_SHIFT
;
233 cur_word
= &words
[word_index
];
236 * Special case for first word: skip start_bit_index % SPDK_BIT_ARRAY_WORD_BITS bits
237 * within the first word.
239 first_word_bit_index
= start_bit_index
& SPDK_BIT_ARRAY_WORD_INDEX_MASK
;
240 first_word_mask
= spdk_bit_array_word_mask(first_word_bit_index
);
242 word
= (*cur_word
^ xor_mask
) & ~first_word_mask
;
245 * spdk_bit_array_resize() guarantees that an extra word with a 1 and a 0 will always be
246 * at the end of the words[] array, so just keep going until a word matches.
249 word
= *++cur_word
^ xor_mask
;
252 return ((uintptr_t)cur_word
- (uintptr_t)words
) * 8 + SPDK_BIT_ARRAY_WORD_TZCNT(word
);
257 spdk_bit_array_find_first_set(const struct spdk_bit_array
*ba
, uint32_t start_bit_index
)
261 bit_index
= _spdk_bit_array_find_first(ba
, start_bit_index
, 0);
264 * If we ran off the end of the array and found the 1 bit in the extra word,
265 * return UINT32_MAX to indicate no actual 1 bits were found.
267 if (bit_index
>= ba
->bit_count
) {
268 bit_index
= UINT32_MAX
;
275 spdk_bit_array_find_first_clear(const struct spdk_bit_array
*ba
, uint32_t start_bit_index
)
277 return _spdk_bit_array_find_first(ba
, start_bit_index
, SPDK_BIT_ARRAY_WORD_C(-1));