xref: /linux-6.15/tools/include/linux/bitmap.h (revision 4e23eeeb)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
24ade0818SYury Norov #ifndef _TOOLS_LINUX_BITMAP_H
34ade0818SYury Norov #define _TOOLS_LINUX_BITMAP_H
4915b0882SArnaldo Carvalho de Melo 
5915b0882SArnaldo Carvalho de Melo #include <string.h>
6915b0882SArnaldo Carvalho de Melo #include <linux/bitops.h>
74ade0818SYury Norov #include <linux/find.h>
898c03296SJiri Olsa #include <stdlib.h>
9c68a2aabSMatthew Wilcox #include <linux/kernel.h>
10915b0882SArnaldo Carvalho de Melo 
11915b0882SArnaldo Carvalho de Melo #define DECLARE_BITMAP(name,bits) \
12915b0882SArnaldo Carvalho de Melo 	unsigned long name[BITS_TO_LONGS(bits)]
13915b0882SArnaldo Carvalho de Melo 
144e23eeebSLinus Torvalds unsigned int __bitmap_weight(const unsigned long *bitmap, int bits);
15915b0882SArnaldo Carvalho de Melo void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
16915b0882SArnaldo Carvalho de Melo 		 const unsigned long *bitmap2, int bits);
17*e2863a78SYury Norov bool __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
18741c74f5SJiri Olsa 		 const unsigned long *bitmap2, unsigned int bits);
19005f1700SKees Cook bool __bitmap_equal(const unsigned long *bitmap1,
208812ad41SAlexey Budankov 		    const unsigned long *bitmap2, unsigned int bits);
2158d6ea30SMatthew Wilcox void bitmap_clear(unsigned long *map, unsigned int start, int len);
22005f1700SKees Cook bool __bitmap_intersects(const unsigned long *bitmap1,
23f20510d5SAlexey Bayduraev 			 const unsigned long *bitmap2, unsigned int bits);
24915b0882SArnaldo Carvalho de Melo 
25915b0882SArnaldo Carvalho de Melo #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
26a719101fSYury Norov #define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (BITS_PER_LONG - 1)))
27915b0882SArnaldo Carvalho de Melo 
28e5b9252dSYury Norov static inline void bitmap_zero(unsigned long *dst, unsigned int nbits)
29915b0882SArnaldo Carvalho de Melo {
30915b0882SArnaldo Carvalho de Melo 	if (small_const_nbits(nbits))
31915b0882SArnaldo Carvalho de Melo 		*dst = 0UL;
32915b0882SArnaldo Carvalho de Melo 	else {
33915b0882SArnaldo Carvalho de Melo 		int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
34915b0882SArnaldo Carvalho de Melo 		memset(dst, 0, len);
35915b0882SArnaldo Carvalho de Melo 	}
36915b0882SArnaldo Carvalho de Melo }
37915b0882SArnaldo Carvalho de Melo 
38b328daf3SMatthew Wilcox static inline void bitmap_fill(unsigned long *dst, unsigned int nbits)
39b328daf3SMatthew Wilcox {
40b328daf3SMatthew Wilcox 	unsigned int nlongs = BITS_TO_LONGS(nbits);
41b328daf3SMatthew Wilcox 	if (!small_const_nbits(nbits)) {
42b328daf3SMatthew Wilcox 		unsigned int len = (nlongs - 1) * sizeof(unsigned long);
43b328daf3SMatthew Wilcox 		memset(dst, 0xff,  len);
44b328daf3SMatthew Wilcox 	}
45b328daf3SMatthew Wilcox 	dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
46b328daf3SMatthew Wilcox }
47b328daf3SMatthew Wilcox 
48*e2863a78SYury Norov static inline bool bitmap_empty(const unsigned long *src, unsigned int nbits)
49b328daf3SMatthew Wilcox {
50b328daf3SMatthew Wilcox 	if (small_const_nbits(nbits))
51b328daf3SMatthew Wilcox 		return ! (*src & BITMAP_LAST_WORD_MASK(nbits));
52b328daf3SMatthew Wilcox 
53b328daf3SMatthew Wilcox 	return find_first_bit(src, nbits) == nbits;
54b328daf3SMatthew Wilcox }
55b328daf3SMatthew Wilcox 
56*e2863a78SYury Norov static inline bool bitmap_full(const unsigned long *src, unsigned int nbits)
57b328daf3SMatthew Wilcox {
58b328daf3SMatthew Wilcox 	if (small_const_nbits(nbits))
59b328daf3SMatthew Wilcox 		return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits));
60b328daf3SMatthew Wilcox 
61b328daf3SMatthew Wilcox 	return find_first_zero_bit(src, nbits) == nbits;
62b328daf3SMatthew Wilcox }
63b328daf3SMatthew Wilcox 
644e23eeebSLinus Torvalds static inline unsigned int bitmap_weight(const unsigned long *src, unsigned int nbits)
65915b0882SArnaldo Carvalho de Melo {
66915b0882SArnaldo Carvalho de Melo 	if (small_const_nbits(nbits))
67915b0882SArnaldo Carvalho de Melo 		return hweight_long(*src & BITMAP_LAST_WORD_MASK(nbits));
68915b0882SArnaldo Carvalho de Melo 	return __bitmap_weight(src, nbits);
69915b0882SArnaldo Carvalho de Melo }
70915b0882SArnaldo Carvalho de Melo 
71915b0882SArnaldo Carvalho de Melo static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
72e5b9252dSYury Norov 			     const unsigned long *src2, unsigned int nbits)
73915b0882SArnaldo Carvalho de Melo {
74915b0882SArnaldo Carvalho de Melo 	if (small_const_nbits(nbits))
75915b0882SArnaldo Carvalho de Melo 		*dst = *src1 | *src2;
76915b0882SArnaldo Carvalho de Melo 	else
77915b0882SArnaldo Carvalho de Melo 		__bitmap_or(dst, src1, src2, nbits);
78915b0882SArnaldo Carvalho de Melo }
79915b0882SArnaldo Carvalho de Melo 
80915b0882SArnaldo Carvalho de Melo /**
81915b0882SArnaldo Carvalho de Melo  * test_and_set_bit - Set a bit and return its old value
82915b0882SArnaldo Carvalho de Melo  * @nr: Bit to set
83915b0882SArnaldo Carvalho de Melo  * @addr: Address to count from
84915b0882SArnaldo Carvalho de Melo  */
85915b0882SArnaldo Carvalho de Melo static inline int test_and_set_bit(int nr, unsigned long *addr)
86915b0882SArnaldo Carvalho de Melo {
87915b0882SArnaldo Carvalho de Melo 	unsigned long mask = BIT_MASK(nr);
88915b0882SArnaldo Carvalho de Melo 	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
89915b0882SArnaldo Carvalho de Melo 	unsigned long old;
90915b0882SArnaldo Carvalho de Melo 
91915b0882SArnaldo Carvalho de Melo 	old = *p;
92915b0882SArnaldo Carvalho de Melo 	*p = old | mask;
93915b0882SArnaldo Carvalho de Melo 
94915b0882SArnaldo Carvalho de Melo 	return (old & mask) != 0;
95915b0882SArnaldo Carvalho de Melo }
96915b0882SArnaldo Carvalho de Melo 
9798c03296SJiri Olsa /**
9807a262ccSPeter Xu  * test_and_clear_bit - Clear a bit and return its old value
9907a262ccSPeter Xu  * @nr: Bit to clear
10007a262ccSPeter Xu  * @addr: Address to count from
10107a262ccSPeter Xu  */
10207a262ccSPeter Xu static inline int test_and_clear_bit(int nr, unsigned long *addr)
10307a262ccSPeter Xu {
10407a262ccSPeter Xu 	unsigned long mask = BIT_MASK(nr);
10507a262ccSPeter Xu 	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
10607a262ccSPeter Xu 	unsigned long old;
10707a262ccSPeter Xu 
10807a262ccSPeter Xu 	old = *p;
10907a262ccSPeter Xu 	*p = old & ~mask;
11007a262ccSPeter Xu 
11107a262ccSPeter Xu 	return (old & mask) != 0;
11207a262ccSPeter Xu }
11307a262ccSPeter Xu 
11407a262ccSPeter Xu /**
1157fc5b571SAndy Shevchenko  * bitmap_zalloc - Allocate bitmap
116e2091cedSJiri Olsa  * @nbits: Number of bits
11798c03296SJiri Olsa  */
1187fc5b571SAndy Shevchenko static inline unsigned long *bitmap_zalloc(int nbits)
11998c03296SJiri Olsa {
12098c03296SJiri Olsa 	return calloc(1, BITS_TO_LONGS(nbits) * sizeof(unsigned long));
12198c03296SJiri Olsa }
12298c03296SJiri Olsa 
123820d12b7SJiri Olsa /*
1248812ad41SAlexey Budankov  * bitmap_free - Free bitmap
1258812ad41SAlexey Budankov  * @bitmap: pointer to bitmap
1268812ad41SAlexey Budankov  */
1278812ad41SAlexey Budankov static inline void bitmap_free(unsigned long *bitmap)
1288812ad41SAlexey Budankov {
1298812ad41SAlexey Budankov 	free(bitmap);
1308812ad41SAlexey Budankov }
1318812ad41SAlexey Budankov 
1328812ad41SAlexey Budankov /*
133820d12b7SJiri Olsa  * bitmap_scnprintf - print bitmap list into buffer
134820d12b7SJiri Olsa  * @bitmap: bitmap
135820d12b7SJiri Olsa  * @nbits: size of bitmap
136820d12b7SJiri Olsa  * @buf: buffer to store output
137820d12b7SJiri Olsa  * @size: size of @buf
138820d12b7SJiri Olsa  */
139e5b9252dSYury Norov size_t bitmap_scnprintf(unsigned long *bitmap, unsigned int nbits,
140820d12b7SJiri Olsa 			char *buf, size_t size);
141820d12b7SJiri Olsa 
142741c74f5SJiri Olsa /**
143741c74f5SJiri Olsa  * bitmap_and - Do logical and on bitmaps
144741c74f5SJiri Olsa  * @dst: resulting bitmap
145741c74f5SJiri Olsa  * @src1: operand 1
146741c74f5SJiri Olsa  * @src2: operand 2
147741c74f5SJiri Olsa  * @nbits: size of bitmap
148741c74f5SJiri Olsa  */
149*e2863a78SYury Norov static inline bool bitmap_and(unsigned long *dst, const unsigned long *src1,
150741c74f5SJiri Olsa 			     const unsigned long *src2, unsigned int nbits)
151741c74f5SJiri Olsa {
152741c74f5SJiri Olsa 	if (small_const_nbits(nbits))
153741c74f5SJiri Olsa 		return (*dst = *src1 & *src2 & BITMAP_LAST_WORD_MASK(nbits)) != 0;
154741c74f5SJiri Olsa 	return __bitmap_and(dst, src1, src2, nbits);
155741c74f5SJiri Olsa }
156741c74f5SJiri Olsa 
1578812ad41SAlexey Budankov #ifdef __LITTLE_ENDIAN
1588812ad41SAlexey Budankov #define BITMAP_MEM_ALIGNMENT 8
1598812ad41SAlexey Budankov #else
1608812ad41SAlexey Budankov #define BITMAP_MEM_ALIGNMENT (8 * sizeof(unsigned long))
1618812ad41SAlexey Budankov #endif
1628812ad41SAlexey Budankov #define BITMAP_MEM_MASK (BITMAP_MEM_ALIGNMENT - 1)
1638812ad41SAlexey Budankov #define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0)
1648812ad41SAlexey Budankov 
165005f1700SKees Cook static inline bool bitmap_equal(const unsigned long *src1,
1668812ad41SAlexey Budankov 				const unsigned long *src2, unsigned int nbits)
1678812ad41SAlexey Budankov {
1688812ad41SAlexey Budankov 	if (small_const_nbits(nbits))
1698812ad41SAlexey Budankov 		return !((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits));
1708812ad41SAlexey Budankov 	if (__builtin_constant_p(nbits & BITMAP_MEM_MASK) &&
1718812ad41SAlexey Budankov 	    IS_ALIGNED(nbits, BITMAP_MEM_ALIGNMENT))
1728812ad41SAlexey Budankov 		return !memcmp(src1, src2, nbits / 8);
1738812ad41SAlexey Budankov 	return __bitmap_equal(src1, src2, nbits);
1748812ad41SAlexey Budankov }
1758812ad41SAlexey Budankov 
176005f1700SKees Cook static inline bool bitmap_intersects(const unsigned long *src1,
177005f1700SKees Cook 				     const unsigned long *src2,
178005f1700SKees Cook 				     unsigned int nbits)
179f20510d5SAlexey Bayduraev {
180f20510d5SAlexey Bayduraev 	if (small_const_nbits(nbits))
181f20510d5SAlexey Bayduraev 		return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0;
182f20510d5SAlexey Bayduraev 	else
183f20510d5SAlexey Bayduraev 		return __bitmap_intersects(src1, src2, nbits);
184f20510d5SAlexey Bayduraev }
185f20510d5SAlexey Bayduraev 
1864ade0818SYury Norov #endif /* _TOOLS_LINUX_BITMAP_H */
187