1 /* This file is part of Mailfromd.
2    Copyright (C) 2009-2021 Sergey Poznyakoff
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3, or (at your option)
7    any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16 
17 #include <stdlib.h>
18 
19 /* FIXME: Ensure that sizeof(bitmask_bits_t)<=sizeof(void*) */
20 typedef unsigned bitmask_bits_t;
21 
22 struct bitmask
23 {
24 	size_t bm_nset;              /* Number of bits set */
25 	size_t bm_size;              /* Number of elements in bm_bits */
26 	bitmask_bits_t *bm_bits;
27 };
28 
29 #define NBMBITS (sizeof(bitmask_bits_t) * 8)
30 
31 #define BIT_WORD(n) ((n) / NBMBITS)
32 #define BIT_MASK(n) ((bitmask_bits_t)1 << ((n) % NBMBITS))
33 
34 #define bitmask_zero(bm)						\
35 	do {								\
36 		memset((bm)->bm_bits, 0,				\
37 		       (bm)->bm_size * sizeof(bitmask_bits_t));		\
38 		(bm)->bm_nset = 0;					\
39 	} while (0)
40 
41 #define bitmask_init(bm) memset(bm, 0, sizeof((bm)[0]))
42 #define bitmask_nset(bm) ((bm)->bm_nset)
43 #define bitmask_max(bm) ((bm)->bm_nset * NBMBITS)
44 
45 #define __bitmask_expand(bm,n)					 	  \
46 	do {								  \
47 		size_t __n = n;						  \
48 		(bm)->bm_bits = mu_realloc((bm)->bm_bits,			  \
49 					 (__n) * sizeof(bitmask_bits_t)); \
50 		memset((bm)->bm_bits + (bm)->bm_size, 0,		  \
51 		       ((__n) - (bm)->bm_size) * sizeof(bitmask_bits_t)); \
52 		(bm)->bm_size = __n;					  \
53 	} while (0)
54 
55 #define bitmask_set(bm,n)						\
56 	do {								\
57 		unsigned num = BIT_WORD(n);				\
58 		if (num >= (bm)->bm_size)				\
59 			__bitmask_expand(bm, num+1);			\
60 		(bm)->bm_bits[num] |= BIT_MASK(n);			\
61 		(bm)->bm_nset++;					\
62 	} while (0)
63 
64 #define bitmask_isset(bm,n)						\
65 	((BIT_WORD(n) < (bm)->bm_size)					\
66 	 && (bm)->bm_bits[BIT_WORD(n)] & BIT_MASK(n))
67 
68 #define bitmask_clr(bm,n)						\
69 	do {								\
70 		unsigned num = BIT_WORD(n);				\
71 		if (num < (bm)->bm_size) {				\
72 			(bm)->bm_bits[num] &= ~BIT_MASK(n);		\
73 			(bm)->bm_nset--;				\
74 		}							\
75 	} while (0)
76 
77 #define bitmask_merge(d,s)					\
78 	do {							\
79 		int __i;					\
80 		if ((s)->bm_size > (d)->bm_size)		\
81 			__bitmask_expand(d, (s)->bm_size);	\
82 		for (__i = 0; __i < (s)->bm_size; __i++)	\
83 			(d)->bm_bits[__i] |= (s)->bm_bits[__i];	\
84                 (d)->bm_nset += (s)->bm_nset;                   \
85 	} while (0)
86