xref: /linux/lib/memweight.c (revision a8b70ccf10e38775785d9cb12ead916474549f99)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/export.h>
3 #include <linux/bug.h>
4 #include <linux/bitmap.h>
5 
6 /**
7  * memweight - count the total number of bits set in memory area
8  * @ptr: pointer to the start of the area
9  * @bytes: the size of the area
10  */
11 size_t memweight(const void *ptr, size_t bytes)
12 {
13 	size_t ret = 0;
14 	size_t longs;
15 	const unsigned char *bitmap = ptr;
16 
17 	for (; bytes > 0 && ((unsigned long)bitmap) % sizeof(long);
18 			bytes--, bitmap++)
19 		ret += hweight8(*bitmap);
20 
21 	longs = bytes / sizeof(long);
22 	if (longs) {
23 		BUG_ON(longs >= INT_MAX / BITS_PER_LONG);
24 		ret += bitmap_weight((unsigned long *)bitmap,
25 				longs * BITS_PER_LONG);
26 		bytes -= longs * sizeof(long);
27 		bitmap += longs * sizeof(long);
28 	}
29 	/*
30 	 * The reason that this last loop is distinct from the preceding
31 	 * bitmap_weight() call is to compute 1-bits in the last region smaller
32 	 * than sizeof(long) properly on big-endian systems.
33 	 */
34 	for (; bytes > 0; bytes--, bitmap++)
35 		ret += hweight8(*bitmap);
36 
37 	return ret;
38 }
39 EXPORT_SYMBOL(memweight);
40