Skip to content

Commit 5b0611a

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 b6cfb45 commit 5b0611a

File tree

3 files changed

+96
-44
lines changed

3 files changed

+96
-44
lines changed

doc/releases/release-notes-4.2.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ New APIs and options
213213

214214
* :c:func:`util_eq`
215215
* :c:func:`util_memeq`
216+
* :c:func:`zephyr_count_bits`
216217

217218
* LoRaWAN
218219
* :c:func:`lorawan_request_link_check`

include/zephyr/sys/util.h

Lines changed: 69 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,16 @@ extern "C" {
4646
*/
4747

4848
/** @brief Cast @p x, a pointer, to an unsigned integer. */
49-
#define POINTER_TO_UINT(x) ((uintptr_t) (x))
49+
#define POINTER_TO_UINT(x) ((uintptr_t)(x))
5050
/** @brief Cast @p x, an unsigned integer, to a <tt>void*</tt>. */
51-
#define UINT_TO_POINTER(x) ((void *) (uintptr_t) (x))
51+
#define UINT_TO_POINTER(x) ((void *)(uintptr_t)(x))
5252
/** @brief Cast @p x, a pointer, to a signed integer. */
53-
#define POINTER_TO_INT(x) ((intptr_t) (x))
53+
#define POINTER_TO_INT(x) ((intptr_t)(x))
5454
/** @brief Cast @p x, a signed integer, to a <tt>void*</tt>. */
55-
#define INT_TO_POINTER(x) ((void *) (intptr_t) (x))
55+
#define INT_TO_POINTER(x) ((void *)(intptr_t)(x))
5656

5757
#if !(defined(__CHAR_BIT__) && defined(__SIZEOF_LONG__) && defined(__SIZEOF_LONG_LONG__))
58-
# error Missing required predefined macros for BITS_PER_LONG calculation
58+
#error Missing required predefined macros for BITS_PER_LONG calculation
5959
#endif
6060

6161
/** Number of bits in a byte. */
@@ -68,27 +68,25 @@ extern "C" {
6868
#define NIBBLES_PER_BYTE (BITS_PER_BYTE / BITS_PER_NIBBLE)
6969

7070
/** Number of bits in a long int. */
71-
#define BITS_PER_LONG (__CHAR_BIT__ * __SIZEOF_LONG__)
71+
#define BITS_PER_LONG (__CHAR_BIT__ * __SIZEOF_LONG__)
7272

7373
/** Number of bits in a long long int. */
74-
#define BITS_PER_LONG_LONG (__CHAR_BIT__ * __SIZEOF_LONG_LONG__)
74+
#define BITS_PER_LONG_LONG (__CHAR_BIT__ * __SIZEOF_LONG_LONG__)
7575

7676
/**
7777
* @brief Create a contiguous bitmask starting at bit position @p l
7878
* and ending at position @p h.
7979
*/
80-
#define GENMASK(h, l) \
81-
(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
80+
#define GENMASK(h, l) (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
8281

8382
/**
8483
* @brief Create a contiguous 64-bit bitmask starting at bit position @p l
8584
* and ending at position @p h.
8685
*/
87-
#define GENMASK64(h, l) \
88-
(((~0ULL) - (1ULL << (l)) + 1) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h))))
86+
#define GENMASK64(h, l) (((~0ULL) - (1ULL << (l)) + 1) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h))))
8987

9088
/** @brief 0 if @p cond is true-ish; causes a compile error otherwise. */
91-
#define ZERO_OR_COMPILE_ERROR(cond) ((int) sizeof(char[1 - 2 * !(cond)]) - 1)
89+
#define ZERO_OR_COMPILE_ERROR(cond) ((int)sizeof(char[1 - 2 * !(cond)]) - 1)
9290

9391
#if defined(__cplusplus)
9492

@@ -104,10 +102,9 @@ extern "C" {
104102
*
105103
* This macro is available only from C, not C++.
106104
*/
107-
#define IS_ARRAY(array) \
108-
ZERO_OR_COMPILE_ERROR( \
109-
!__builtin_types_compatible_p(__typeof__(array), \
110-
__typeof__(&(array)[0])))
105+
#define IS_ARRAY(array) \
106+
ZERO_OR_COMPILE_ERROR( \
107+
!__builtin_types_compatible_p(__typeof__(array), __typeof__(&(array)[0])))
111108

112109
/**
113110
* @brief Number of elements in the given @p array
@@ -118,8 +115,7 @@ extern "C" {
118115
*
119116
* In C, passing a pointer as @p array causes a compile error.
120117
*/
121-
#define ARRAY_SIZE(array) \
122-
((size_t) (IS_ARRAY(array) + (sizeof(array) / sizeof((array)[0]))))
118+
#define ARRAY_SIZE(array) ((size_t)(IS_ARRAY(array) + (sizeof(array) / sizeof((array)[0]))))
123119

124120
#endif /* __cplusplus */
125121

@@ -140,10 +136,11 @@ extern "C" {
140136
* It is specially useful for cases where flexible arrays are
141137
* used in unions or are not the last element in the struct.
142138
*/
143-
#define FLEXIBLE_ARRAY_DECLARE(type, name) \
144-
struct { \
145-
struct { } __unused_##name; \
146-
type name[]; \
139+
#define FLEXIBLE_ARRAY_DECLARE(type, name) \
140+
struct { \
141+
struct { \
142+
} __unused_##name; \
143+
type name[]; \
147144
}
148145

149146
/**
@@ -161,7 +158,7 @@ extern "C" {
161158
* @return 1 if @p ptr is part of @p array, 0 otherwise
162159
*/
163160
#define IS_ARRAY_ELEMENT(array, ptr) \
164-
((ptr) && POINTER_TO_UINT(array) <= POINTER_TO_UINT(ptr) && \
161+
((ptr) && POINTER_TO_UINT(array) <= POINTER_TO_UINT(ptr) && \
165162
POINTER_TO_UINT(ptr) < POINTER_TO_UINT(&(array)[ARRAY_SIZE(array)]) && \
166163
(POINTER_TO_UINT(ptr) - POINTER_TO_UINT(array)) % sizeof((array)[0]) == 0)
167164

@@ -253,9 +250,8 @@ extern "C" {
253250
* @brief Validate CONTAINER_OF parameters, only applies to C mode.
254251
*/
255252
#ifndef __cplusplus
256-
#define CONTAINER_OF_VALIDATE(ptr, type, field) \
257-
BUILD_ASSERT(SAME_TYPE(*(ptr), ((type *)0)->field) || \
258-
SAME_TYPE(*(ptr), void), \
253+
#define CONTAINER_OF_VALIDATE(ptr, type, field) \
254+
BUILD_ASSERT(SAME_TYPE(*(ptr), ((type *)0)->field) || SAME_TYPE(*(ptr), void), \
259255
"pointer type mismatch in CONTAINER_OF");
260256
#else
261257
#define CONTAINER_OF_VALIDATE(ptr, type, field)
@@ -282,10 +278,10 @@ extern "C" {
282278
* @param field the name of the field within the struct @p ptr points to
283279
* @return a pointer to the structure that contains @p ptr
284280
*/
285-
#define CONTAINER_OF(ptr, type, field) \
286-
({ \
287-
CONTAINER_OF_VALIDATE(ptr, type, field) \
288-
((type *)(((char *)(ptr)) - offsetof(type, field))); \
281+
#define CONTAINER_OF(ptr, type, field) \
282+
({ \
283+
CONTAINER_OF_VALIDATE(ptr, type, field) \
284+
((type *)(((char *)(ptr)) - offsetof(type, field))); \
289285
})
290286

291287
/**
@@ -309,8 +305,7 @@ extern "C" {
309305
*
310306
* @return Concatenated token.
311307
*/
312-
#define CONCAT(...) \
313-
UTIL_CAT(_CONCAT_, NUM_VA_ARGS_LESS_1(__VA_ARGS__))(__VA_ARGS__)
308+
#define CONCAT(...) UTIL_CAT(_CONCAT_, NUM_VA_ARGS_LESS_1(__VA_ARGS__))(__VA_ARGS__)
314309

315310
/**
316311
* @brief Check if @p ptr is aligned to @p align alignment
@@ -320,14 +315,14 @@ extern "C" {
320315
/**
321316
* @brief Value of @p x rounded up to the next multiple of @p align.
322317
*/
323-
#define ROUND_UP(x, align) \
324-
((((unsigned long)(x) + ((unsigned long)(align) - 1)) / \
325-
(unsigned long)(align)) * (unsigned long)(align))
318+
#define ROUND_UP(x, align) \
319+
((((unsigned long)(x) + ((unsigned long)(align) - 1)) / (unsigned long)(align)) * \
320+
(unsigned long)(align))
326321

327322
/**
328323
* @brief Value of @p x rounded down to the previous multiple of @p align.
329324
*/
330-
#define ROUND_DOWN(x, align) \
325+
#define ROUND_DOWN(x, align) \
331326
(((unsigned long)(x) / (unsigned long)(align)) * (unsigned long)(align))
332327

333328
/** @brief Value of @p x rounded up to the next word boundary. */
@@ -689,7 +684,7 @@ char *utf8_lcpy(char *dst, const char *src, size_t n);
689684

690685
#define __z_log2d(x) (32 - __builtin_clz(x) - 1)
691686
#define __z_log2q(x) (64 - __builtin_clzll(x) - 1)
692-
#define __z_log2(x) (sizeof(__typeof__(x)) > 4 ? __z_log2q(x) : __z_log2d(x))
687+
#define __z_log2(x) (sizeof(__typeof__(x)) > 4 ? __z_log2q(x) : __z_log2d(x))
693688

694689
/**
695690
* @brief Compute log2(x)
@@ -713,7 +708,7 @@ char *utf8_lcpy(char *dst, const char *src, size_t n);
713708
*
714709
* @return ceil(log2(x)) when 1 <= x <= max(type(x)), 0 when x < 1
715710
*/
716-
#define LOG2CEIL(x) ((x) <= 1 ? 0 : __z_log2((x)-1) + 1)
711+
#define LOG2CEIL(x) ((x) <= 1 ? 0 : __z_log2((x) - 1) + 1)
717712

718713
/**
719714
* @brief Compute next highest power of two
@@ -727,7 +722,7 @@ char *utf8_lcpy(char *dst, const char *src, size_t n);
727722
*
728723
* @return 2^ceil(log2(x)) or 0 if 2^ceil(log2(x)) would saturate 64-bits
729724
*/
730-
#define NHPOT(x) ((x) < 1 ? 1 : ((x) > (1ULL<<63) ? 0 : 1ULL << LOG2CEIL(x)))
725+
#define NHPOT(x) ((x) < 1 ? 1 : ((x) > (1ULL << 63) ? 0 : 1ULL << LOG2CEIL(x)))
731726

732727
/**
733728
* @brief Determine if a buffer exceeds highest address
@@ -741,9 +736,8 @@ char *utf8_lcpy(char *dst, const char *src, size_t n);
741736
*
742737
* @return true if pointer overflow detected, false otherwise
743738
*/
744-
#define Z_DETECT_POINTER_OVERFLOW(addr, buflen) \
745-
(((buflen) != 0) && \
746-
((UINTPTR_MAX - (uintptr_t)(addr)) <= ((uintptr_t)((buflen) - 1))))
739+
#define Z_DETECT_POINTER_OVERFLOW(addr, buflen) \
740+
(((buflen) != 0) && ((UINTPTR_MAX - (uintptr_t)(addr)) <= ((uintptr_t)((buflen) - 1))))
747741

748742
/**
749743
* @brief XOR n bytes
@@ -818,6 +812,39 @@ static inline bool util_eq(const void *m1, size_t len1, const void *m2, size_t l
818812
return len1 == len2 && (m1 == m2 || util_memeq(m1, m2, len1));
819813
}
820814

815+
/**
816+
* @brief Returns the number of bits set in a value
817+
*
818+
* @param value The value to count number of bits set of
819+
* @param len The number of octets in @p value
820+
*/
821+
static inline size_t zephyr_count_bits(const void *value, size_t len)
822+
{
823+
size_t cnt = 0U;
824+
size_t i = 0;
825+
826+
#ifdef POPCOUNT
827+
for (; i < len / sizeof(unsigned int); i++) {
828+
unsigned int val = ((const unsigned int *)value)[i];
829+
830+
cnt += POPCOUNT(val);
831+
}
832+
i *= sizeof(unsigned int); /* convert to a uint8_t index for the remainder (if any) */
833+
#endif
834+
835+
for (; i < len; i++) {
836+
uint8_t value_u8 = ((const uint8_t *)value)[i];
837+
838+
/* Implements Brian Kernighan’s Algorithm to count bits */
839+
while (value_u8) {
840+
value_u8 &= (value_u8 - 1);
841+
cnt++;
842+
}
843+
}
844+
845+
return cnt;
846+
}
847+
821848
#ifdef __cplusplus
822849
}
823850
#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)