From fb9a862177c651089f8621cd9683d56dfb5815a0 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Tue, 9 Jun 2015 12:10:20 +0200 Subject: [PATCH 1/2] sys: bitfield: add bf_get_unset --- sys/bitfield/Makefile | 1 + sys/bitfield/bitfield.c | 48 +++++++++++++++++++++++++++++++++++++++++ sys/include/bitfield.h | 13 +++++++++++ 3 files changed, 62 insertions(+) create mode 100644 sys/bitfield/Makefile create mode 100644 sys/bitfield/bitfield.c diff --git a/sys/bitfield/Makefile b/sys/bitfield/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/sys/bitfield/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/bitfield/bitfield.c b/sys/bitfield/bitfield.c new file mode 100644 index 0000000000..110967dba1 --- /dev/null +++ b/sys/bitfield/bitfield.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015 Kaspar Schleiser + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_util + * @{ + * + * @file + * @brief Bitfield auxillary functions + * + * @author Kaspar Schleiser + * + * @} + */ + +#include +#include "bitfield.h" +#include "irq.h" + +int bf_get_unset(uint8_t field[], int size) +{ + int result = -1; + int nbytes = (size + 7) / 8; + int i = 0; + + unsigned state = disableIRQ(); + + /* skip full bytes */ + for (int j = 0; (j < nbytes) && (field[j] == 255); j++) { + i += 8; + } + + for (; i < size; i++) { + if (!bf_isset(field, i)) { + bf_set(field, i); + result = i; + break; + } + } + + restoreIRQ(state); + return(result); +} diff --git a/sys/include/bitfield.h b/sys/include/bitfield.h index 4d13a3b4cd..a0e89acd62 100644 --- a/sys/include/bitfield.h +++ b/sys/include/bitfield.h @@ -85,6 +85,19 @@ static inline bool bf_isset(uint8_t field[], size_t idx) return (field[idx / 8] & (1u << (idx % 8))); } +/** + * @brief Atomically get the number of an unset bit and set it + * + * This function can be used to record e.g., empty entries in an array. + * + * @param[in,out] field The bitfield + * @param[in] size The size of the bitfield + * + * @return number of bit that was set + * @return -1 if no bit was unset + */ +int bf_get_unset(uint8_t field[], int size); + #ifdef __cplusplus } #endif From 43ecf6d2c3258cb7419e9a12c95f706681843de2 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Wed, 1 Jul 2015 12:05:38 +0200 Subject: [PATCH 2/2] tests: unittests: add some bitfield unit tests --- tests/unittests/tests-bitfield/Makefile | 1 + .../unittests/tests-bitfield/Makefile.include | 1 + .../unittests/tests-bitfield/tests-bitfield.c | 137 ++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 tests/unittests/tests-bitfield/Makefile create mode 100644 tests/unittests/tests-bitfield/Makefile.include create mode 100644 tests/unittests/tests-bitfield/tests-bitfield.c diff --git a/tests/unittests/tests-bitfield/Makefile b/tests/unittests/tests-bitfield/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/tests/unittests/tests-bitfield/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/tests/unittests/tests-bitfield/Makefile.include b/tests/unittests/tests-bitfield/Makefile.include new file mode 100644 index 0000000000..ec804edb6f --- /dev/null +++ b/tests/unittests/tests-bitfield/Makefile.include @@ -0,0 +1 @@ +USEMODULE += bitfield diff --git a/tests/unittests/tests-bitfield/tests-bitfield.c b/tests/unittests/tests-bitfield/tests-bitfield.c new file mode 100644 index 0000000000..8df527cc52 --- /dev/null +++ b/tests/unittests/tests-bitfield/tests-bitfield.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2015 Kaspar Schleiser + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#include +#include + +#include "embUnit.h" + +#include "bitfield.h" + +static void test_bf_get_unset_empty(void) +{ + int res = 0; + uint8_t field[5]; + + memset(field, 0, sizeof(field)); + res = bf_get_unset(field, 0); + TEST_ASSERT_EQUAL_INT(-1, res); + + memset(field, 0, sizeof(field)); + res = bf_get_unset(field, 1); + TEST_ASSERT_EQUAL_INT(0, res); + + memset(field, 0, sizeof(field)); + res = bf_get_unset(field, 3); + TEST_ASSERT_EQUAL_INT(0, res); + + memset(field, 0, sizeof(field)); + res = bf_get_unset(field, 8); + TEST_ASSERT_EQUAL_INT(0, res); + + memset(field, 0, sizeof(field)); + res = bf_get_unset(field, 9); + TEST_ASSERT_EQUAL_INT(0, res); + + memset(field, 0, sizeof(field)); + res = bf_get_unset(field, 40); + TEST_ASSERT_EQUAL_INT(0, res); +} + +static void test_bf_get_unset_firstbyte(void) +{ + int res = 0; + uint8_t field[5]; + memset(field, 0xff, sizeof(field)); + + field[0] = 0x00; + res = bf_get_unset(field, 40); + TEST_ASSERT_EQUAL_INT(0, res); + + field[0] = 0x01; + res = bf_get_unset(field, 40); + TEST_ASSERT_EQUAL_INT(1, res); + + field[0] = 0x0f; + res = bf_get_unset(field, 40); + TEST_ASSERT_EQUAL_INT(4, res); + + field[0] = 0x7f; + res = bf_get_unset(field, 40); + TEST_ASSERT_EQUAL_INT(7, res); + + field[0] = 0xff; + res = bf_get_unset(field, 40); + TEST_ASSERT_EQUAL_INT(-1, res); +} + +static void test_bf_get_unset_middle(void) +{ + int res = 0; + uint8_t field[5]; + memset(field, 0xff, sizeof(field)); + + field[2] = 0x00; + res = bf_get_unset(field, 40); + TEST_ASSERT_EQUAL_INT(16, res); + + field[2] = 0x01; + res = bf_get_unset(field, 40); + TEST_ASSERT_EQUAL_INT(17, res); + + field[2] = 0x0f; + res = bf_get_unset(field, 40); + TEST_ASSERT_EQUAL_INT(20, res); + + field[2] = 0x7f; + res = bf_get_unset(field, 40); + TEST_ASSERT_EQUAL_INT(23, res); +} + +static void test_bf_get_unset_lastbyte(void) +{ + int res = 0; + uint8_t field[5]; + memset(field, 0xff, sizeof(field)); + + field[4] = 0x00; + res = bf_get_unset(field, 40); + TEST_ASSERT_EQUAL_INT(32, res); + + field[4] = 0x01; + res = bf_get_unset(field, 40); + TEST_ASSERT_EQUAL_INT(33, res); + + field[4] = 0x0f; + res = bf_get_unset(field, 40); + TEST_ASSERT_EQUAL_INT(36, res); + + field[4] = 0x7f; + res = bf_get_unset(field, 40); + TEST_ASSERT_EQUAL_INT(39, res); +} + +Test *tests_bitfield_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_bf_get_unset_empty), + new_TestFixture(test_bf_get_unset_firstbyte), + new_TestFixture(test_bf_get_unset_middle), + new_TestFixture(test_bf_get_unset_lastbyte), + }; + + EMB_UNIT_TESTCALLER(bitfield_tests, NULL, NULL, fixtures); + + return (Test *)&bitfield_tests; +} + + +void tests_bitfield(void) +{ + TESTS_RUN(tests_bitfield_tests()); +}