1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 04:52:59 +01:00

Merge pull request #18833 from benpicco/bitfield-ops

sys/bitfield: add bf_find_first_{set, unset}()
This commit is contained in:
Marian Buschsieweke 2022-11-07 20:27:48 +01:00 committed by GitHub
commit 7e0af3cd22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 163 additions and 7 deletions

View File

@ -13,26 +13,34 @@
* @brief Bitfield auxiliary functions
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
*
* @}
*/
#include <stdint.h>
#include <string.h>
#include "bitfield.h"
#include "irq.h"
static inline unsigned _skip_bytes(const uint8_t field[], unsigned nbytes, uint8_t byte)
{
unsigned i = 0;
for (unsigned j = 0; (j < nbytes) && (field[j] == byte); j++) {
i += 8;
}
return i;
}
int bf_get_unset(uint8_t field[], size_t size)
{
int result = -1;
int nbytes = (size + 7) / 8;
size_t i = 0;
unsigned nbytes = (size + 7) / 8;
unsigned state = irq_disable();
/* skip full bytes */
for (int j = 0; (j < nbytes) && (field[j] == 255); j++) {
i += 8;
}
unsigned i = _skip_bytes(field, nbytes, 0xff);
for (; i < size; i++) {
if (!bf_isset(field, i)) {
@ -45,3 +53,42 @@ int bf_get_unset(uint8_t field[], size_t size)
irq_restore(state);
return result;
}
int bf_find_first_set(const uint8_t field[], size_t size)
{
unsigned nbytes = (size + 7) / 8;
unsigned i = _skip_bytes(field, nbytes, 0);
for (; i < size; i++) {
if (bf_isset(field, i)) {
return i;
}
}
return -1;
}
int bf_find_first_unset(const uint8_t field[], size_t size)
{
unsigned nbytes = (size + 7) / 8;
unsigned i = _skip_bytes(field, nbytes, 0xff);
for (; i < size; i++) {
if (!bf_isset(field, i)) {
return i;
}
}
return -1;
}
void bf_set_all(uint8_t field[], size_t size)
{
unsigned bytes = size >> 3;
unsigned bits = size & 0x7;
memset(field, 0xff, bytes);
if (bits) {
field[bytes] = ~((1U << (8 - bits)) - 1);
}
}

View File

@ -84,7 +84,7 @@ static inline void bf_toggle(uint8_t field[], size_t idx)
* @param[in,out] field The bitfield
* @param[in] idx The number of the bit to check
*/
static inline bool bf_isset(uint8_t field[], size_t idx)
static inline bool bf_isset(const uint8_t field[], size_t idx)
{
return (field[idx / 8] & (1u << (7 - (idx % 8))));
}
@ -189,6 +189,36 @@ static inline void bf_inv(uint8_t out[], const uint8_t a[], size_t len)
*/
int bf_get_unset(uint8_t field[], size_t len);
/**
* @brief Get the index of the first set bit in the field
*
* @param[in] field The bitfield
* @param[in] size The size of the bitfield
*
* @return number of the first set bit
* @return -1 if no bit is set
*/
int bf_find_first_set(const uint8_t field[], size_t size);
/**
* @brief Get the index of the zero bit in the field
*
* @param[in] field The bitfield
* @param[in] size The size of the bitfield
*
* @return number of the first unset bit
* @return -1 if all bits are set
*/
int bf_find_first_unset(const uint8_t field[], size_t size);
/**
* @brief Set all bits in the bitfield to 1
*
* @param[in] field The bitfield
* @param[in] size The size of the bitfield
*/
void bf_set_all(uint8_t field[], size_t size);
#ifdef __cplusplus
}
#endif

View File

@ -222,8 +222,84 @@ static void test_bf_ops(void)
TEST_ASSERT_EQUAL_INT(0, memcmp(c, b, sizeof(c)));
}
Test *tests_bitfield_tests(void)
static void test_bf_find_first_set(void)
{
int res;
uint8_t field[5];
memset(field, 0, sizeof(field));
res = bf_find_first_set(field, 40);
TEST_ASSERT_EQUAL_INT(-1, res);
bf_set(field, 23);
res = bf_find_first_set(field, 40);
TEST_ASSERT_EQUAL_INT(23, res);
bf_set(field, 24);
res = bf_find_first_set(field, 40);
TEST_ASSERT_EQUAL_INT(23, res);
bf_set(field, 13);
res = bf_find_first_set(field, 40);
TEST_ASSERT_EQUAL_INT(13, res);
bf_set(field, 3);
res = bf_find_first_set(field, 40);
TEST_ASSERT_EQUAL_INT(3, res);
}
static void test_bf_find_first_unset(void)
{
int res;
uint8_t field[5];
memset(field, 0xff, sizeof(field));
res = bf_find_first_unset(field, 40);
TEST_ASSERT_EQUAL_INT(-1, res);
bf_unset(field, 23);
res = bf_find_first_unset(field, 40);
TEST_ASSERT_EQUAL_INT(23, res);
bf_unset(field, 24);
res = bf_find_first_unset(field, 40);
TEST_ASSERT_EQUAL_INT(23, res);
bf_unset(field, 13);
res = bf_find_first_unset(field, 40);
TEST_ASSERT_EQUAL_INT(13, res);
bf_unset(field, 3);
res = bf_find_first_unset(field, 40);
TEST_ASSERT_EQUAL_INT(3, res);
}
static void test_bf_set_all(void)
{
uint8_t field[5];
memset(field, 0, sizeof(field));
bf_set_all(field, 5);
TEST_ASSERT_EQUAL_INT(0xf8, field[0]);
TEST_ASSERT_EQUAL_INT(0, field[1]);
memset(field, 0, sizeof(field));
bf_set_all(field, 24);
TEST_ASSERT_EQUAL_INT(0xff, field[0]);
TEST_ASSERT_EQUAL_INT(0xff, field[1]);
TEST_ASSERT_EQUAL_INT(0xff, field[2]);
TEST_ASSERT_EQUAL_INT(0, field[3]);
memset(field, 0, sizeof(field));
bf_set_all(field, 30);
TEST_ASSERT_EQUAL_INT(0xff, field[0]);
TEST_ASSERT_EQUAL_INT(0xff, field[1]);
TEST_ASSERT_EQUAL_INT(0xff, field[2]);
TEST_ASSERT_EQUAL_INT(0xfc, field[3]);
TEST_ASSERT_EQUAL_INT(0, field[4]);
}
Test *tests_bitfield_tests(void) {
EMB_UNIT_TESTFIXTURES(fixtures) {
new_TestFixture(test_bf_set),
new_TestFixture(test_bf_unset),
@ -234,6 +310,9 @@ Test *tests_bitfield_tests(void)
new_TestFixture(test_bf_get_unset_middle),
new_TestFixture(test_bf_get_unset_lastbyte),
new_TestFixture(test_bf_ops),
new_TestFixture(test_bf_find_first_set),
new_TestFixture(test_bf_find_first_unset),
new_TestFixture(test_bf_set_all),
};
EMB_UNIT_TESTCALLER(bitfield_tests, NULL, NULL, fixtures);