lib: utils: Add function for finding group of cleared bits in a bit mask

Add function which finds contiguous number of bits which are not set
in the 32 bit mask.

Signed-off-by: Krzysztof Chruściński <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruściński
2025-09-03 16:41:47 +02:00
committed by Benjamin Cabé
parent 993b642f2e
commit 53c2d58ff8
3 changed files with 67 additions and 0 deletions

View File

@@ -434,6 +434,22 @@ extern "C" {
*/
#define IN_RANGE(val, min, max) ((val) >= (min) && (val) <= (max))
/**
* Find number of contiguous bits which are not set in the bit mask (32 bits).
*
* It is possible to return immediately when requested number of bits is found or
* iterate over whole mask and return the best fit (smallest from available options).
*
* @param[in] mask 32 bit mask.
* @param[in] num_bits Number of bits to find.
* @param[in] total_bits Total number of LSB bits that can be used in the mask.
* @param[in] first_match If true returns when first match is found, else returns the best fit.
*
* @retval -1 Contiguous bits not found.
* @retval non-negative Starting index of the bits group.
*/
int bitmask_find_gap(uint32_t mask, size_t num_bits, size_t total_bits, bool first_match);
/**
* @brief Is @p x a power of two?
* @param x value to check

View File

@@ -8,6 +8,7 @@ zephyr_sources(
rb.c
timeutil.c
bitarray.c
bitmask.c
)
zephyr_sources_ifdef(CONFIG_ONOFF onoff.c)

50
lib/utils/bitmask.c Normal file
View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/sys/util.h>
#include <zephyr/sys/math_extras.h>
int bitmask_find_gap(uint32_t mask, size_t num_bits, size_t total_bits, bool first_match)
{
uint32_t max = UINT32_MAX;
int max_loc = -1;
if (total_bits < 32) {
mask |= ~BIT_MASK(total_bits);
}
mask = ~mask;
while (mask != 0U) {
uint32_t block_size;
uint32_t loc;
int nidx;
uint32_t idx = 31 - u32_count_leading_zeros(mask);
uint32_t rmask = ~BIT_MASK(idx);
rmask |= mask;
rmask = ~rmask;
if (rmask != 0U) {
nidx = 31 - u32_count_leading_zeros(rmask);
block_size = idx - nidx;
loc = nidx + 1;
mask &= BIT_MASK(nidx);
} else {
mask = 0;
block_size = idx + 1;
loc = 0;
}
if ((block_size == num_bits) || (first_match && block_size > num_bits)) {
max_loc = loc;
max = block_size;
break;
} else if (block_size >= num_bits && block_size < max) {
max_loc = loc;
max = block_size;
}
}
return max_loc;
}