Skip to content

Commit db3051b

Browse files
committed
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 <emil.gydesen@nordicsemi.no>
1 parent 2eb8cfb commit db3051b

File tree

3 files changed

+59
-2
lines changed

3 files changed

+59
-2
lines changed

doc/releases/release-notes-4.2.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ New APIs and options
143143

144144
* :c:func:`counter_reset`
145145

146+
* Other
147+
148+
* :c:func:`zephyr_count_bits`
149+
146150
New Boards
147151
**********
148152

include/zephyr/sys/util.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,35 @@ static inline void mem_xor_128(uint8_t dst[16], const uint8_t src1[16], const ui
783783
mem_xor_n(dst, src1, src2, 16);
784784
}
785785

786+
/**
787+
* @brief Returns the number of bits set in a value
788+
*
789+
* @param value The value to count number of bits set of
790+
* @param len The number of octets in @p value
791+
*/
792+
static inline size_t zephyr_count_bits(const void *value, size_t len)
793+
{
794+
const uint8_t *value_u8 = (const uint8_t *)value;
795+
size_t cnt = 0U;
796+
797+
for (size_t i = 0U; i < len; i++) {
798+
if (value_u8[i] != 0U) {
799+
#ifdef POPCOUNT
800+
cnt += POPCOUNT(value_u8[i]);
801+
#else
802+
/* Implements Brian Kernighan’s Algorithm to count bits */
803+
while (value_u8[i]) {
804+
value_u8[i] &= (value_u8[i] - 1);
805+
cnt++;
806+
}
807+
808+
#endif
809+
}
810+
}
811+
812+
return cnt;
813+
}
814+
786815
#ifdef __cplusplus
787816
}
788817
#endif

tests/unit/util/main.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
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.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/ztest_assert.h>
15+
#include <zephyr/ztest_test.h>
16+
1217
ZTEST(util, test_u8_to_dec) {
1318
char text[4];
1419
uint8_t len;
@@ -768,6 +773,25 @@ ZTEST(util, test_mem_xor_128)
768773
zassert_mem_equal(expected_result, dst, 16);
769774
}
770775

776+
ZTEST(util, test_zephyr_count_bits)
777+
{
778+
uint8_t zero = 0U;
779+
uint8_t u8 = 29U;
780+
uint16_t u16 = 29999U;
781+
uint32_t u32 = 2999999999U;
782+
uint64_t u64 = 123456789012345ULL;
783+
uint8_t u8_arr[] = {u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8,
784+
u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8};
785+
786+
zassert_equal(zephyr_count_bits(&zero, sizeof(zero)), 0);
787+
zassert_equal(zephyr_count_bits(&u8, sizeof(u8)), 4);
788+
zassert_equal(zephyr_count_bits(&u16, sizeof(u16)), 10);
789+
zassert_equal(zephyr_count_bits(&u32, sizeof(u32)), 20);
790+
zassert_equal(zephyr_count_bits(&u64, sizeof(u64)), 23);
791+
792+
zassert_equal(zephyr_count_bits(u8_arr, sizeof(u8_arr)), 128);
793+
}
794+
771795
ZTEST(util, test_CONCAT)
772796
{
773797
#define _CAT_PART1 1

0 commit comments

Comments
 (0)