Skip to content

Commit b201cb7

Browse files
Thalleykartben
authored andcommitted
include: util: Add generic function to count bits set in a value
Adds a generic function that will count the number of bits set in a value. It uses POPCOUNT (e.g. __builtin_popcount for GCC) if available, or else it will use Brian Kernighan’s Algorithm to count bits. POPCOUNT will likely always support unsigned ints, but the function was implemented to use it with uint8_t for the sake of simplicity and compatibility with Brian Kernighan’s Algorithm. A generic solution was chosen rather than a macro/function per type (e.g. uint8_t, uint16_t, etc.) as that is easier to maintain and also supports array types (e.g. counting the number of bits in 128 or 256 octet arrays). Signed-off-by: Emil Gydesen <[email protected]>
1 parent 6de7702 commit b201cb7

File tree

3 files changed

+68
-2
lines changed

3 files changed

+68
-2
lines changed

doc/releases/release-notes-4.3.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ New APIs and options
189189
* :kconfig:option:`CONFIG_SHELL_MQTT_WORK_DELAY_MS`
190190
* :kconfig:option:`CONFIG_SHELL_MQTT_LISTEN_TIMEOUT_MS`
191191

192+
* Sys
193+
194+
* :c:func:`sys_count_bits`
195+
192196
.. zephyr-keep-sorted-stop
193197
194198
New Boards

include/zephyr/sys/util.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,41 @@ static inline bool util_eq(const void *m1, size_t len1, const void *m2, size_t l
792792
return len1 == len2 && (m1 == m2 || util_memeq(m1, m2, len1));
793793
}
794794

795+
/**
796+
* @brief Returns the number of bits set in a value
797+
*
798+
* @param value The value to count number of bits set of
799+
* @param len The number of octets in @p value
800+
*/
801+
static inline size_t sys_count_bits(const void *value, size_t len)
802+
{
803+
size_t cnt = 0U;
804+
size_t i = 0U;
805+
806+
#ifdef POPCOUNT
807+
for (; i < len / sizeof(unsigned int); i++) {
808+
unsigned int val;
809+
(void)memcpy(&val, (const uint8_t *)value + i * sizeof(unsigned int),
810+
sizeof(unsigned int));
811+
812+
cnt += POPCOUNT(val);
813+
}
814+
i *= sizeof(unsigned int); /* convert to a uint8_t index for the remainder (if any) */
815+
#endif
816+
817+
for (; i < len; i++) {
818+
uint8_t value_u8 = ((const uint8_t *)value)[i];
819+
820+
/* Implements Brian Kernighan’s Algorithm to count bits */
821+
while (value_u8) {
822+
value_u8 &= (value_u8 - 1);
823+
cnt++;
824+
}
825+
}
826+
827+
return cnt;
828+
}
829+
795830
#ifdef __cplusplus
796831
}
797832
#endif

tests/unit/util/main.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
/*
22
* Copyright (c) 2019 Oticon A/S
3+
* Copyright (c) 2025 Nordic Semiconductor ASA
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
67

7-
#include <zephyr/ztest.h>
8-
#include <zephyr/sys/util_utf8.h>
8+
#include <stdint.h>
99
#include <stdio.h>
1010
#include <string.h>
1111

12+
#include <zephyr/ztest.h>
13+
#include <zephyr/sys/util.h>
14+
#include <zephyr/sys/util_utf8.h>
15+
#include <zephyr/ztest.h>
16+
#include <zephyr/ztest_assert.h>
17+
#include <zephyr/ztest_test.h>
18+
1219
ZTEST(util, test_u8_to_dec) {
1320
char text[4];
1421
uint8_t len;
@@ -845,6 +852,26 @@ ZTEST(util, test_mem_xor_128)
845852
zassert_mem_equal(expected_result, dst, 16);
846853
}
847854

855+
ZTEST(util, test_sys_count_bits)
856+
{
857+
uint8_t zero = 0U;
858+
uint8_t u8 = 29U;
859+
uint16_t u16 = 29999U;
860+
uint32_t u32 = 2999999999U;
861+
uint64_t u64 = 123456789012345ULL;
862+
uint8_t u8_arr[] = {u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8,
863+
u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8};
864+
865+
zassert_equal(sys_count_bits(&zero, sizeof(zero)), 0);
866+
zassert_equal(sys_count_bits(&u8, sizeof(u8)), 4);
867+
zassert_equal(sys_count_bits(&u16, sizeof(u16)), 10);
868+
zassert_equal(sys_count_bits(&u32, sizeof(u32)), 20);
869+
zassert_equal(sys_count_bits(&u64, sizeof(u64)), 23);
870+
871+
zassert_equal(sys_count_bits(u8_arr, sizeof(u8_arr)), 128);
872+
zassert_equal(sys_count_bits(&u8_arr[1], sizeof(u8_arr) - sizeof(u8_arr[0])), 124);
873+
}
874+
848875
ZTEST(util, test_CONCAT)
849876
{
850877
#define _CAT_PART1 1

0 commit comments

Comments
 (0)