xref: /netbsd-src/external/bsd/jemalloc/dist/test/unit/fb.c (revision 7bdf38e5b7a28439665f2fdeff81e36913eef7dd)
1*7bdf38e5Schristos #include "test/jemalloc_test.h"
2*7bdf38e5Schristos 
3*7bdf38e5Schristos #include "jemalloc/internal/fb.h"
4*7bdf38e5Schristos #include "test/nbits.h"
5*7bdf38e5Schristos 
6*7bdf38e5Schristos static void
7*7bdf38e5Schristos do_test_init(size_t nbits) {
8*7bdf38e5Schristos 	size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t);
9*7bdf38e5Schristos 	fb_group_t *fb = malloc(sz);
10*7bdf38e5Schristos 	/* Junk fb's contents. */
11*7bdf38e5Schristos 	memset(fb, 99, sz);
12*7bdf38e5Schristos 	fb_init(fb, nbits);
13*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
14*7bdf38e5Schristos 		expect_false(fb_get(fb, nbits, i),
15*7bdf38e5Schristos 		    "bitmap should start empty");
16*7bdf38e5Schristos 	}
17*7bdf38e5Schristos 	free(fb);
18*7bdf38e5Schristos }
19*7bdf38e5Schristos 
20*7bdf38e5Schristos TEST_BEGIN(test_fb_init) {
21*7bdf38e5Schristos #define NB(nbits) \
22*7bdf38e5Schristos 	do_test_init(nbits);
23*7bdf38e5Schristos 	NBITS_TAB
24*7bdf38e5Schristos #undef NB
25*7bdf38e5Schristos }
26*7bdf38e5Schristos TEST_END
27*7bdf38e5Schristos 
28*7bdf38e5Schristos static void
29*7bdf38e5Schristos do_test_get_set_unset(size_t nbits) {
30*7bdf38e5Schristos 	size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t);
31*7bdf38e5Schristos 	fb_group_t *fb = malloc(sz);
32*7bdf38e5Schristos 	fb_init(fb, nbits);
33*7bdf38e5Schristos 	/* Set the bits divisible by 3. */
34*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
35*7bdf38e5Schristos 		if (i % 3 == 0) {
36*7bdf38e5Schristos 			fb_set(fb, nbits, i);
37*7bdf38e5Schristos 		}
38*7bdf38e5Schristos 	}
39*7bdf38e5Schristos 	/* Check them. */
40*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
41*7bdf38e5Schristos 		expect_b_eq(i % 3 == 0, fb_get(fb, nbits, i),
42*7bdf38e5Schristos 		    "Unexpected bit at position %zu", i);
43*7bdf38e5Schristos 	}
44*7bdf38e5Schristos 	/* Unset those divisible by 5. */
45*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
46*7bdf38e5Schristos 		if (i % 5 == 0) {
47*7bdf38e5Schristos 			fb_unset(fb, nbits, i);
48*7bdf38e5Schristos 		}
49*7bdf38e5Schristos 	}
50*7bdf38e5Schristos 	/* Check them. */
51*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
52*7bdf38e5Schristos 		expect_b_eq(i % 3 == 0 && i % 5 != 0, fb_get(fb, nbits, i),
53*7bdf38e5Schristos 		    "Unexpected bit at position %zu", i);
54*7bdf38e5Schristos 	}
55*7bdf38e5Schristos 	free(fb);
56*7bdf38e5Schristos }
57*7bdf38e5Schristos 
58*7bdf38e5Schristos TEST_BEGIN(test_get_set_unset) {
59*7bdf38e5Schristos #define NB(nbits) \
60*7bdf38e5Schristos 	do_test_get_set_unset(nbits);
61*7bdf38e5Schristos 	NBITS_TAB
62*7bdf38e5Schristos #undef NB
63*7bdf38e5Schristos }
64*7bdf38e5Schristos TEST_END
65*7bdf38e5Schristos 
66*7bdf38e5Schristos static ssize_t
67*7bdf38e5Schristos find_3_5_compute(ssize_t i, size_t nbits, bool bit, bool forward) {
68*7bdf38e5Schristos 	for(; i < (ssize_t)nbits && i >= 0; i += (forward ? 1 : -1)) {
69*7bdf38e5Schristos 		bool expected_bit = i % 3 == 0 || i % 5 == 0;
70*7bdf38e5Schristos 		if (expected_bit == bit) {
71*7bdf38e5Schristos 			return i;
72*7bdf38e5Schristos 		}
73*7bdf38e5Schristos 	}
74*7bdf38e5Schristos 	return forward ? (ssize_t)nbits : (ssize_t)-1;
75*7bdf38e5Schristos }
76*7bdf38e5Schristos 
77*7bdf38e5Schristos static void
78*7bdf38e5Schristos do_test_search_simple(size_t nbits) {
79*7bdf38e5Schristos 	size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t);
80*7bdf38e5Schristos 	fb_group_t *fb = malloc(sz);
81*7bdf38e5Schristos 	fb_init(fb, nbits);
82*7bdf38e5Schristos 
83*7bdf38e5Schristos 	/* We pick multiples of 3 or 5. */
84*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
85*7bdf38e5Schristos 		if (i % 3 == 0) {
86*7bdf38e5Schristos 			fb_set(fb, nbits, i);
87*7bdf38e5Schristos 		}
88*7bdf38e5Schristos 		/* This tests double-setting a little, too. */
89*7bdf38e5Schristos 		if (i % 5 == 0) {
90*7bdf38e5Schristos 			fb_set(fb, nbits, i);
91*7bdf38e5Schristos 		}
92*7bdf38e5Schristos 	}
93*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
94*7bdf38e5Schristos 		size_t ffs_compute = find_3_5_compute(i, nbits, true, true);
95*7bdf38e5Schristos 		size_t ffs_search = fb_ffs(fb, nbits, i);
96*7bdf38e5Schristos 		expect_zu_eq(ffs_compute, ffs_search, "ffs mismatch at %zu", i);
97*7bdf38e5Schristos 
98*7bdf38e5Schristos 		ssize_t fls_compute = find_3_5_compute(i, nbits, true, false);
99*7bdf38e5Schristos 		size_t fls_search = fb_fls(fb, nbits, i);
100*7bdf38e5Schristos 		expect_zu_eq(fls_compute, fls_search, "fls mismatch at %zu", i);
101*7bdf38e5Schristos 
102*7bdf38e5Schristos 		size_t ffu_compute = find_3_5_compute(i, nbits, false, true);
103*7bdf38e5Schristos 		size_t ffu_search = fb_ffu(fb, nbits, i);
104*7bdf38e5Schristos 		expect_zu_eq(ffu_compute, ffu_search, "ffu mismatch at %zu", i);
105*7bdf38e5Schristos 
106*7bdf38e5Schristos 		size_t flu_compute = find_3_5_compute(i, nbits, false, false);
107*7bdf38e5Schristos 		size_t flu_search = fb_flu(fb, nbits, i);
108*7bdf38e5Schristos 		expect_zu_eq(flu_compute, flu_search, "flu mismatch at %zu", i);
109*7bdf38e5Schristos 	}
110*7bdf38e5Schristos 
111*7bdf38e5Schristos 	free(fb);
112*7bdf38e5Schristos }
113*7bdf38e5Schristos 
114*7bdf38e5Schristos TEST_BEGIN(test_search_simple) {
115*7bdf38e5Schristos #define NB(nbits) \
116*7bdf38e5Schristos 	do_test_search_simple(nbits);
117*7bdf38e5Schristos 	NBITS_TAB
118*7bdf38e5Schristos #undef NB
119*7bdf38e5Schristos }
120*7bdf38e5Schristos TEST_END
121*7bdf38e5Schristos 
122*7bdf38e5Schristos static void
123*7bdf38e5Schristos expect_exhaustive_results(fb_group_t *mostly_full, fb_group_t *mostly_empty,
124*7bdf38e5Schristos     size_t nbits, size_t special_bit, size_t position) {
125*7bdf38e5Schristos 	if (position < special_bit) {
126*7bdf38e5Schristos 		expect_zu_eq(special_bit, fb_ffs(mostly_empty, nbits, position),
127*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
128*7bdf38e5Schristos 		expect_zd_eq(-1, fb_fls(mostly_empty, nbits, position),
129*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
130*7bdf38e5Schristos 		expect_zu_eq(position, fb_ffu(mostly_empty, nbits, position),
131*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
132*7bdf38e5Schristos 		expect_zd_eq(position, fb_flu(mostly_empty, nbits, position),
133*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
134*7bdf38e5Schristos 
135*7bdf38e5Schristos 		expect_zu_eq(position, fb_ffs(mostly_full, nbits, position),
136*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
137*7bdf38e5Schristos 		expect_zd_eq(position, fb_fls(mostly_full, nbits, position),
138*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
139*7bdf38e5Schristos 		expect_zu_eq(special_bit, fb_ffu(mostly_full, nbits, position),
140*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
141*7bdf38e5Schristos 		expect_zd_eq(-1, fb_flu(mostly_full, nbits, position),
142*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
143*7bdf38e5Schristos 	} else if (position == special_bit) {
144*7bdf38e5Schristos 		expect_zu_eq(special_bit, fb_ffs(mostly_empty, nbits, position),
145*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
146*7bdf38e5Schristos 		expect_zd_eq(special_bit, fb_fls(mostly_empty, nbits, position),
147*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
148*7bdf38e5Schristos 		expect_zu_eq(position + 1, fb_ffu(mostly_empty, nbits, position),
149*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
150*7bdf38e5Schristos 		expect_zd_eq(position - 1, fb_flu(mostly_empty, nbits,
151*7bdf38e5Schristos 		    position), "mismatch at %zu, %zu", position, special_bit);
152*7bdf38e5Schristos 
153*7bdf38e5Schristos 		expect_zu_eq(position + 1, fb_ffs(mostly_full, nbits, position),
154*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
155*7bdf38e5Schristos 		expect_zd_eq(position - 1, fb_fls(mostly_full, nbits,
156*7bdf38e5Schristos 		    position), "mismatch at %zu, %zu", position, special_bit);
157*7bdf38e5Schristos 		expect_zu_eq(position, fb_ffu(mostly_full, nbits, position),
158*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
159*7bdf38e5Schristos 		expect_zd_eq(position, fb_flu(mostly_full, nbits, position),
160*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
161*7bdf38e5Schristos 	} else {
162*7bdf38e5Schristos 		/* position > special_bit. */
163*7bdf38e5Schristos 		expect_zu_eq(nbits, fb_ffs(mostly_empty, nbits, position),
164*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
165*7bdf38e5Schristos 		expect_zd_eq(special_bit, fb_fls(mostly_empty, nbits,
166*7bdf38e5Schristos 		    position), "mismatch at %zu, %zu", position, special_bit);
167*7bdf38e5Schristos 		expect_zu_eq(position, fb_ffu(mostly_empty, nbits, position),
168*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
169*7bdf38e5Schristos 		expect_zd_eq(position, fb_flu(mostly_empty, nbits, position),
170*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
171*7bdf38e5Schristos 
172*7bdf38e5Schristos 		expect_zu_eq(position, fb_ffs(mostly_full, nbits, position),
173*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
174*7bdf38e5Schristos 		expect_zd_eq(position, fb_fls(mostly_full, nbits, position),
175*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
176*7bdf38e5Schristos 		expect_zu_eq(nbits, fb_ffu(mostly_full, nbits, position),
177*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
178*7bdf38e5Schristos 		expect_zd_eq(special_bit, fb_flu(mostly_full, nbits, position),
179*7bdf38e5Schristos 		    "mismatch at %zu, %zu", position, special_bit);
180*7bdf38e5Schristos 	}
181*7bdf38e5Schristos }
182*7bdf38e5Schristos 
183*7bdf38e5Schristos static void
184*7bdf38e5Schristos do_test_search_exhaustive(size_t nbits) {
185*7bdf38e5Schristos 	/* This test is quadratic; let's not get too big. */
186*7bdf38e5Schristos 	if (nbits > 1000) {
187*7bdf38e5Schristos 		return;
188*7bdf38e5Schristos 	}
189*7bdf38e5Schristos 	size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t);
190*7bdf38e5Schristos 	fb_group_t *empty = malloc(sz);
191*7bdf38e5Schristos 	fb_init(empty, nbits);
192*7bdf38e5Schristos 	fb_group_t *full = malloc(sz);
193*7bdf38e5Schristos 	fb_init(full, nbits);
194*7bdf38e5Schristos 	fb_set_range(full, nbits, 0, nbits);
195*7bdf38e5Schristos 
196*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
197*7bdf38e5Schristos 		fb_set(empty, nbits, i);
198*7bdf38e5Schristos 		fb_unset(full, nbits, i);
199*7bdf38e5Schristos 
200*7bdf38e5Schristos 		for (size_t j = 0; j < nbits; j++) {
201*7bdf38e5Schristos 			expect_exhaustive_results(full, empty, nbits, i, j);
202*7bdf38e5Schristos 		}
203*7bdf38e5Schristos 		fb_unset(empty, nbits, i);
204*7bdf38e5Schristos 		fb_set(full, nbits, i);
205*7bdf38e5Schristos 	}
206*7bdf38e5Schristos 
207*7bdf38e5Schristos 	free(empty);
208*7bdf38e5Schristos 	free(full);
209*7bdf38e5Schristos }
210*7bdf38e5Schristos 
211*7bdf38e5Schristos TEST_BEGIN(test_search_exhaustive) {
212*7bdf38e5Schristos #define NB(nbits) \
213*7bdf38e5Schristos 	do_test_search_exhaustive(nbits);
214*7bdf38e5Schristos 	NBITS_TAB
215*7bdf38e5Schristos #undef NB
216*7bdf38e5Schristos }
217*7bdf38e5Schristos TEST_END
218*7bdf38e5Schristos 
219*7bdf38e5Schristos TEST_BEGIN(test_range_simple) {
220*7bdf38e5Schristos 	/*
221*7bdf38e5Schristos 	 * Just pick a constant big enough to have nontrivial middle sizes, and
222*7bdf38e5Schristos 	 * big enough that usages of things like weirdnum (below) near the
223*7bdf38e5Schristos 	 * beginning fit comfortably into the beginning of the bitmap.
224*7bdf38e5Schristos 	 */
225*7bdf38e5Schristos 	size_t nbits = 64 * 10;
226*7bdf38e5Schristos 	size_t ngroups = FB_NGROUPS(nbits);
227*7bdf38e5Schristos 	fb_group_t *fb = malloc(sizeof(fb_group_t) * ngroups);
228*7bdf38e5Schristos 	fb_init(fb, nbits);
229*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
230*7bdf38e5Schristos 		if (i % 2 == 0) {
231*7bdf38e5Schristos 			fb_set_range(fb, nbits, i, 1);
232*7bdf38e5Schristos 		}
233*7bdf38e5Schristos 	}
234*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
235*7bdf38e5Schristos 		expect_b_eq(i % 2 == 0, fb_get(fb, nbits, i),
236*7bdf38e5Schristos 		    "mismatch at position %zu", i);
237*7bdf38e5Schristos 	}
238*7bdf38e5Schristos 	fb_set_range(fb, nbits, 0, nbits / 2);
239*7bdf38e5Schristos 	fb_unset_range(fb, nbits, nbits / 2, nbits / 2);
240*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
241*7bdf38e5Schristos 		expect_b_eq(i < nbits / 2, fb_get(fb, nbits, i),
242*7bdf38e5Schristos 		    "mismatch at position %zu", i);
243*7bdf38e5Schristos 	}
244*7bdf38e5Schristos 
245*7bdf38e5Schristos 	static const size_t weirdnum = 7;
246*7bdf38e5Schristos 	fb_set_range(fb, nbits, 0, nbits);
247*7bdf38e5Schristos 	fb_unset_range(fb, nbits, weirdnum, FB_GROUP_BITS + weirdnum);
248*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
249*7bdf38e5Schristos 		expect_b_eq(7 <= i && i <= 2 * weirdnum + FB_GROUP_BITS - 1,
250*7bdf38e5Schristos 		    !fb_get(fb, nbits, i), "mismatch at position %zu", i);
251*7bdf38e5Schristos 	}
252*7bdf38e5Schristos 	free(fb);
253*7bdf38e5Schristos }
254*7bdf38e5Schristos TEST_END
255*7bdf38e5Schristos 
256*7bdf38e5Schristos static void
257*7bdf38e5Schristos do_test_empty_full_exhaustive(size_t nbits) {
258*7bdf38e5Schristos 	size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t);
259*7bdf38e5Schristos 	fb_group_t *empty = malloc(sz);
260*7bdf38e5Schristos 	fb_init(empty, nbits);
261*7bdf38e5Schristos 	fb_group_t *full = malloc(sz);
262*7bdf38e5Schristos 	fb_init(full, nbits);
263*7bdf38e5Schristos 	fb_set_range(full, nbits, 0, nbits);
264*7bdf38e5Schristos 
265*7bdf38e5Schristos 	expect_true(fb_full(full, nbits), "");
266*7bdf38e5Schristos 	expect_false(fb_empty(full, nbits), "");
267*7bdf38e5Schristos 	expect_false(fb_full(empty, nbits), "");
268*7bdf38e5Schristos 	expect_true(fb_empty(empty, nbits), "");
269*7bdf38e5Schristos 
270*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
271*7bdf38e5Schristos 		fb_set(empty, nbits, i);
272*7bdf38e5Schristos 		fb_unset(full, nbits, i);
273*7bdf38e5Schristos 
274*7bdf38e5Schristos 		expect_false(fb_empty(empty, nbits), "error at bit %zu", i);
275*7bdf38e5Schristos 		if (nbits != 1) {
276*7bdf38e5Schristos 			expect_false(fb_full(empty, nbits),
277*7bdf38e5Schristos 			    "error at bit %zu", i);
278*7bdf38e5Schristos 			expect_false(fb_empty(full, nbits),
279*7bdf38e5Schristos 			    "error at bit %zu", i);
280*7bdf38e5Schristos 		} else {
281*7bdf38e5Schristos 			expect_true(fb_full(empty, nbits),
282*7bdf38e5Schristos 			    "error at bit %zu", i);
283*7bdf38e5Schristos 			expect_true(fb_empty(full, nbits),
284*7bdf38e5Schristos 			    "error at bit %zu", i);
285*7bdf38e5Schristos 		}
286*7bdf38e5Schristos 		expect_false(fb_full(full, nbits), "error at bit %zu", i);
287*7bdf38e5Schristos 
288*7bdf38e5Schristos 		fb_unset(empty, nbits, i);
289*7bdf38e5Schristos 		fb_set(full, nbits, i);
290*7bdf38e5Schristos 	}
291*7bdf38e5Schristos 
292*7bdf38e5Schristos 	free(empty);
293*7bdf38e5Schristos 	free(full);
294*7bdf38e5Schristos }
295*7bdf38e5Schristos 
296*7bdf38e5Schristos TEST_BEGIN(test_empty_full) {
297*7bdf38e5Schristos #define NB(nbits) \
298*7bdf38e5Schristos 	do_test_empty_full_exhaustive(nbits);
299*7bdf38e5Schristos 	NBITS_TAB
300*7bdf38e5Schristos #undef NB
301*7bdf38e5Schristos }
302*7bdf38e5Schristos TEST_END
303*7bdf38e5Schristos 
304*7bdf38e5Schristos /*
305*7bdf38e5Schristos  * This tests both iter_range and the longest range functionality, which is
306*7bdf38e5Schristos  * built closely on top of it.
307*7bdf38e5Schristos  */
308*7bdf38e5Schristos TEST_BEGIN(test_iter_range_simple) {
309*7bdf38e5Schristos 	size_t set_limit = 30;
310*7bdf38e5Schristos 	size_t nbits = 100;
311*7bdf38e5Schristos 	fb_group_t fb[FB_NGROUPS(100)];
312*7bdf38e5Schristos 
313*7bdf38e5Schristos 	fb_init(fb, nbits);
314*7bdf38e5Schristos 
315*7bdf38e5Schristos 	/*
316*7bdf38e5Schristos 	 * Failing to initialize these can lead to build failures with -Wall;
317*7bdf38e5Schristos 	 * the compiler can't prove that they're set.
318*7bdf38e5Schristos 	 */
319*7bdf38e5Schristos 	size_t begin = (size_t)-1;
320*7bdf38e5Schristos 	size_t len = (size_t)-1;
321*7bdf38e5Schristos 	bool result;
322*7bdf38e5Schristos 
323*7bdf38e5Schristos 	/* A set of checks with only the first set_limit bits *set*. */
324*7bdf38e5Schristos 	fb_set_range(fb, nbits, 0, set_limit);
325*7bdf38e5Schristos 	expect_zu_eq(set_limit, fb_srange_longest(fb, nbits),
326*7bdf38e5Schristos 	    "Incorrect longest set range");
327*7bdf38e5Schristos 	expect_zu_eq(nbits - set_limit, fb_urange_longest(fb, nbits),
328*7bdf38e5Schristos 	    "Incorrect longest unset range");
329*7bdf38e5Schristos 	for (size_t i = 0; i < set_limit; i++) {
330*7bdf38e5Schristos 		result = fb_srange_iter(fb, nbits, i, &begin, &len);
331*7bdf38e5Schristos 		expect_true(result, "Should have found a range at %zu", i);
332*7bdf38e5Schristos 		expect_zu_eq(i, begin, "Incorrect begin at %zu", i);
333*7bdf38e5Schristos 		expect_zu_eq(set_limit - i, len, "Incorrect len at %zu", i);
334*7bdf38e5Schristos 
335*7bdf38e5Schristos 		result = fb_urange_iter(fb, nbits, i, &begin, &len);
336*7bdf38e5Schristos 		expect_true(result, "Should have found a range at %zu", i);
337*7bdf38e5Schristos 		expect_zu_eq(set_limit, begin, "Incorrect begin at %zu", i);
338*7bdf38e5Schristos 		expect_zu_eq(nbits - set_limit, len, "Incorrect len at %zu", i);
339*7bdf38e5Schristos 
340*7bdf38e5Schristos 		result = fb_srange_riter(fb, nbits, i, &begin, &len);
341*7bdf38e5Schristos 		expect_true(result, "Should have found a range at %zu", i);
342*7bdf38e5Schristos 		expect_zu_eq(0, begin, "Incorrect begin at %zu", i);
343*7bdf38e5Schristos 		expect_zu_eq(i + 1, len, "Incorrect len at %zu", i);
344*7bdf38e5Schristos 
345*7bdf38e5Schristos 		result = fb_urange_riter(fb, nbits, i, &begin, &len);
346*7bdf38e5Schristos 		expect_false(result, "Should not have found a range at %zu", i);
347*7bdf38e5Schristos 	}
348*7bdf38e5Schristos 	for (size_t i = set_limit; i < nbits; i++) {
349*7bdf38e5Schristos 		result = fb_srange_iter(fb, nbits, i, &begin, &len);
350*7bdf38e5Schristos 		expect_false(result, "Should not have found a range at %zu", i);
351*7bdf38e5Schristos 
352*7bdf38e5Schristos 		result = fb_urange_iter(fb, nbits, i, &begin, &len);
353*7bdf38e5Schristos 		expect_true(result, "Should have found a range at %zu", i);
354*7bdf38e5Schristos 		expect_zu_eq(i, begin, "Incorrect begin at %zu", i);
355*7bdf38e5Schristos 		expect_zu_eq(nbits - i, len, "Incorrect len at %zu", i);
356*7bdf38e5Schristos 
357*7bdf38e5Schristos 		result = fb_srange_riter(fb, nbits, i, &begin, &len);
358*7bdf38e5Schristos 		expect_true(result, "Should have found a range at %zu", i);
359*7bdf38e5Schristos 		expect_zu_eq(0, begin, "Incorrect begin at %zu", i);
360*7bdf38e5Schristos 		expect_zu_eq(set_limit, len, "Incorrect len at %zu", i);
361*7bdf38e5Schristos 
362*7bdf38e5Schristos 		result = fb_urange_riter(fb, nbits, i, &begin, &len);
363*7bdf38e5Schristos 		expect_true(result, "Should have found a range at %zu", i);
364*7bdf38e5Schristos 		expect_zu_eq(set_limit, begin, "Incorrect begin at %zu", i);
365*7bdf38e5Schristos 		expect_zu_eq(i - set_limit + 1, len, "Incorrect len at %zu", i);
366*7bdf38e5Schristos 	}
367*7bdf38e5Schristos 
368*7bdf38e5Schristos 	/* A set of checks with only the first set_limit bits *unset*. */
369*7bdf38e5Schristos 	fb_unset_range(fb, nbits, 0, set_limit);
370*7bdf38e5Schristos 	fb_set_range(fb, nbits, set_limit, nbits - set_limit);
371*7bdf38e5Schristos 	expect_zu_eq(nbits - set_limit, fb_srange_longest(fb, nbits),
372*7bdf38e5Schristos 	    "Incorrect longest set range");
373*7bdf38e5Schristos 	expect_zu_eq(set_limit, fb_urange_longest(fb, nbits),
374*7bdf38e5Schristos 	    "Incorrect longest unset range");
375*7bdf38e5Schristos 	for (size_t i = 0; i < set_limit; i++) {
376*7bdf38e5Schristos 		result = fb_srange_iter(fb, nbits, i, &begin, &len);
377*7bdf38e5Schristos 		expect_true(result, "Should have found a range at %zu", i);
378*7bdf38e5Schristos 		expect_zu_eq(set_limit, begin, "Incorrect begin at %zu", i);
379*7bdf38e5Schristos 		expect_zu_eq(nbits - set_limit, len, "Incorrect len at %zu", i);
380*7bdf38e5Schristos 
381*7bdf38e5Schristos 		result = fb_urange_iter(fb, nbits, i, &begin, &len);
382*7bdf38e5Schristos 		expect_true(result, "Should have found a range at %zu", i);
383*7bdf38e5Schristos 		expect_zu_eq(i, begin, "Incorrect begin at %zu", i);
384*7bdf38e5Schristos 		expect_zu_eq(set_limit - i, len, "Incorrect len at %zu", i);
385*7bdf38e5Schristos 
386*7bdf38e5Schristos 		result = fb_srange_riter(fb, nbits, i, &begin, &len);
387*7bdf38e5Schristos 		expect_false(result, "Should not have found a range at %zu", i);
388*7bdf38e5Schristos 
389*7bdf38e5Schristos 		result = fb_urange_riter(fb, nbits, i, &begin, &len);
390*7bdf38e5Schristos 		expect_true(result, "Should not have found a range at %zu", i);
391*7bdf38e5Schristos 		expect_zu_eq(0, begin, "Incorrect begin at %zu", i);
392*7bdf38e5Schristos 		expect_zu_eq(i + 1, len, "Incorrect len at %zu", i);
393*7bdf38e5Schristos 	}
394*7bdf38e5Schristos 	for (size_t i = set_limit; i < nbits; i++) {
395*7bdf38e5Schristos 		result = fb_srange_iter(fb, nbits, i, &begin, &len);
396*7bdf38e5Schristos 		expect_true(result, "Should have found a range at %zu", i);
397*7bdf38e5Schristos 		expect_zu_eq(i, begin, "Incorrect begin at %zu", i);
398*7bdf38e5Schristos 		expect_zu_eq(nbits - i, len, "Incorrect len at %zu", i);
399*7bdf38e5Schristos 
400*7bdf38e5Schristos 		result = fb_urange_iter(fb, nbits, i, &begin, &len);
401*7bdf38e5Schristos 		expect_false(result, "Should not have found a range at %zu", i);
402*7bdf38e5Schristos 
403*7bdf38e5Schristos 		result = fb_srange_riter(fb, nbits, i, &begin, &len);
404*7bdf38e5Schristos 		expect_true(result, "Should have found a range at %zu", i);
405*7bdf38e5Schristos 		expect_zu_eq(set_limit, begin, "Incorrect begin at %zu", i);
406*7bdf38e5Schristos 		expect_zu_eq(i - set_limit + 1, len, "Incorrect len at %zu", i);
407*7bdf38e5Schristos 
408*7bdf38e5Schristos 		result = fb_urange_riter(fb, nbits, i, &begin, &len);
409*7bdf38e5Schristos 		expect_true(result, "Should have found a range at %zu", i);
410*7bdf38e5Schristos 		expect_zu_eq(0, begin, "Incorrect begin at %zu", i);
411*7bdf38e5Schristos 		expect_zu_eq(set_limit, len, "Incorrect len at %zu", i);
412*7bdf38e5Schristos 	}
413*7bdf38e5Schristos 
414*7bdf38e5Schristos }
415*7bdf38e5Schristos TEST_END
416*7bdf38e5Schristos 
417*7bdf38e5Schristos /*
418*7bdf38e5Schristos  * Doing this bit-by-bit is too slow for a real implementation, but for testing
419*7bdf38e5Schristos  * code, it's easy to get right.  In the exhaustive tests, we'll compare the
420*7bdf38e5Schristos  * (fast but tricky) real implementation against the (slow but simple) testing
421*7bdf38e5Schristos  * one.
422*7bdf38e5Schristos  */
423*7bdf38e5Schristos static bool
424*7bdf38e5Schristos fb_iter_simple(fb_group_t *fb, size_t nbits, size_t start, size_t *r_begin,
425*7bdf38e5Schristos     size_t *r_len, bool val, bool forward) {
426*7bdf38e5Schristos 	ssize_t stride = (forward ? (ssize_t)1 : (ssize_t)-1);
427*7bdf38e5Schristos 	ssize_t range_begin = (ssize_t)start;
428*7bdf38e5Schristos 	for (; range_begin != (ssize_t)nbits && range_begin != -1;
429*7bdf38e5Schristos 	    range_begin += stride) {
430*7bdf38e5Schristos 		if (fb_get(fb, nbits, range_begin) == val) {
431*7bdf38e5Schristos 			ssize_t range_end = range_begin;
432*7bdf38e5Schristos 			for (; range_end != (ssize_t)nbits && range_end != -1;
433*7bdf38e5Schristos 			    range_end += stride) {
434*7bdf38e5Schristos 				if (fb_get(fb, nbits, range_end) != val) {
435*7bdf38e5Schristos 					break;
436*7bdf38e5Schristos 				}
437*7bdf38e5Schristos 			}
438*7bdf38e5Schristos 			if (forward) {
439*7bdf38e5Schristos 				*r_begin = range_begin;
440*7bdf38e5Schristos 				*r_len = range_end - range_begin;
441*7bdf38e5Schristos 			} else {
442*7bdf38e5Schristos 				*r_begin = range_end + 1;
443*7bdf38e5Schristos 				*r_len = range_begin - range_end;
444*7bdf38e5Schristos 			}
445*7bdf38e5Schristos 			return true;
446*7bdf38e5Schristos 		}
447*7bdf38e5Schristos 	}
448*7bdf38e5Schristos 	return false;
449*7bdf38e5Schristos }
450*7bdf38e5Schristos 
451*7bdf38e5Schristos /* Similar, but for finding longest ranges. */
452*7bdf38e5Schristos static size_t
453*7bdf38e5Schristos fb_range_longest_simple(fb_group_t *fb, size_t nbits, bool val) {
454*7bdf38e5Schristos 	size_t longest_so_far = 0;
455*7bdf38e5Schristos 	for (size_t begin = 0; begin < nbits; begin++) {
456*7bdf38e5Schristos 		if (fb_get(fb, nbits, begin) != val) {
457*7bdf38e5Schristos 			continue;
458*7bdf38e5Schristos 		}
459*7bdf38e5Schristos 		size_t end = begin + 1;
460*7bdf38e5Schristos 		for (; end < nbits; end++) {
461*7bdf38e5Schristos 			if (fb_get(fb, nbits, end) != val) {
462*7bdf38e5Schristos 				break;
463*7bdf38e5Schristos 			}
464*7bdf38e5Schristos 		}
465*7bdf38e5Schristos 		if (end - begin > longest_so_far) {
466*7bdf38e5Schristos 			longest_so_far = end - begin;
467*7bdf38e5Schristos 		}
468*7bdf38e5Schristos 	}
469*7bdf38e5Schristos 	return longest_so_far;
470*7bdf38e5Schristos }
471*7bdf38e5Schristos 
472*7bdf38e5Schristos static void
473*7bdf38e5Schristos expect_iter_results_at(fb_group_t *fb, size_t nbits, size_t pos,
474*7bdf38e5Schristos     bool val, bool forward) {
475*7bdf38e5Schristos 	bool iter_res;
476*7bdf38e5Schristos 	size_t iter_begin JEMALLOC_CC_SILENCE_INIT(0);
477*7bdf38e5Schristos 	size_t iter_len JEMALLOC_CC_SILENCE_INIT(0);
478*7bdf38e5Schristos 	if (val) {
479*7bdf38e5Schristos 		if (forward) {
480*7bdf38e5Schristos 			iter_res = fb_srange_iter(fb, nbits, pos,
481*7bdf38e5Schristos 			    &iter_begin, &iter_len);
482*7bdf38e5Schristos 		} else {
483*7bdf38e5Schristos 			iter_res = fb_srange_riter(fb, nbits, pos,
484*7bdf38e5Schristos 			    &iter_begin, &iter_len);
485*7bdf38e5Schristos 		}
486*7bdf38e5Schristos 	} else {
487*7bdf38e5Schristos 		if (forward) {
488*7bdf38e5Schristos 			iter_res = fb_urange_iter(fb, nbits, pos,
489*7bdf38e5Schristos 			    &iter_begin, &iter_len);
490*7bdf38e5Schristos 		} else {
491*7bdf38e5Schristos 			iter_res = fb_urange_riter(fb, nbits, pos,
492*7bdf38e5Schristos 			    &iter_begin, &iter_len);
493*7bdf38e5Schristos 		}
494*7bdf38e5Schristos 	}
495*7bdf38e5Schristos 
496*7bdf38e5Schristos 	bool simple_iter_res;
497*7bdf38e5Schristos 	/*
498*7bdf38e5Schristos 	 * These are dead stores, but the compiler can't always figure that out
499*7bdf38e5Schristos 	 * statically, and warns on the uninitialized variable.
500*7bdf38e5Schristos 	 */
501*7bdf38e5Schristos 	size_t simple_iter_begin = 0;
502*7bdf38e5Schristos 	size_t simple_iter_len = 0;
503*7bdf38e5Schristos 	simple_iter_res = fb_iter_simple(fb, nbits, pos, &simple_iter_begin,
504*7bdf38e5Schristos 	    &simple_iter_len, val, forward);
505*7bdf38e5Schristos 
506*7bdf38e5Schristos 	expect_b_eq(iter_res, simple_iter_res, "Result mismatch at %zu", pos);
507*7bdf38e5Schristos 	if (iter_res && simple_iter_res) {
508*7bdf38e5Schristos 		assert_zu_eq(iter_begin, simple_iter_begin,
509*7bdf38e5Schristos 		    "Begin mismatch at %zu", pos);
510*7bdf38e5Schristos 		expect_zu_eq(iter_len, simple_iter_len,
511*7bdf38e5Schristos 		    "Length mismatch at %zu", pos);
512*7bdf38e5Schristos 	}
513*7bdf38e5Schristos }
514*7bdf38e5Schristos 
515*7bdf38e5Schristos static void
516*7bdf38e5Schristos expect_iter_results(fb_group_t *fb, size_t nbits) {
517*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
518*7bdf38e5Schristos 		expect_iter_results_at(fb, nbits, i, false, false);
519*7bdf38e5Schristos 		expect_iter_results_at(fb, nbits, i, false, true);
520*7bdf38e5Schristos 		expect_iter_results_at(fb, nbits, i, true, false);
521*7bdf38e5Schristos 		expect_iter_results_at(fb, nbits, i, true, true);
522*7bdf38e5Schristos 	}
523*7bdf38e5Schristos 	expect_zu_eq(fb_range_longest_simple(fb, nbits, true),
524*7bdf38e5Schristos 	    fb_srange_longest(fb, nbits), "Longest range mismatch");
525*7bdf38e5Schristos 	expect_zu_eq(fb_range_longest_simple(fb, nbits, false),
526*7bdf38e5Schristos 	    fb_urange_longest(fb, nbits), "Longest range mismatch");
527*7bdf38e5Schristos }
528*7bdf38e5Schristos 
529*7bdf38e5Schristos static void
530*7bdf38e5Schristos set_pattern_3(fb_group_t *fb, size_t nbits, bool zero_val) {
531*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
532*7bdf38e5Schristos 		if ((i % 6 < 3 && zero_val) || (i % 6 >= 3 && !zero_val)) {
533*7bdf38e5Schristos 			fb_set(fb, nbits, i);
534*7bdf38e5Schristos 		} else {
535*7bdf38e5Schristos 			fb_unset(fb, nbits, i);
536*7bdf38e5Schristos 		}
537*7bdf38e5Schristos 	}
538*7bdf38e5Schristos }
539*7bdf38e5Schristos 
540*7bdf38e5Schristos static void
541*7bdf38e5Schristos do_test_iter_range_exhaustive(size_t nbits) {
542*7bdf38e5Schristos 	/* This test is also pretty slow. */
543*7bdf38e5Schristos 	if (nbits > 1000) {
544*7bdf38e5Schristos 		return;
545*7bdf38e5Schristos 	}
546*7bdf38e5Schristos 	size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t);
547*7bdf38e5Schristos 	fb_group_t *fb = malloc(sz);
548*7bdf38e5Schristos 	fb_init(fb, nbits);
549*7bdf38e5Schristos 
550*7bdf38e5Schristos 	set_pattern_3(fb, nbits, /* zero_val */ true);
551*7bdf38e5Schristos 	expect_iter_results(fb, nbits);
552*7bdf38e5Schristos 
553*7bdf38e5Schristos 	set_pattern_3(fb, nbits, /* zero_val */ false);
554*7bdf38e5Schristos 	expect_iter_results(fb, nbits);
555*7bdf38e5Schristos 
556*7bdf38e5Schristos 	fb_set_range(fb, nbits, 0, nbits);
557*7bdf38e5Schristos 	fb_unset_range(fb, nbits, 0, nbits / 2 == 0 ? 1 : nbits / 2);
558*7bdf38e5Schristos 	expect_iter_results(fb, nbits);
559*7bdf38e5Schristos 
560*7bdf38e5Schristos 	fb_unset_range(fb, nbits, 0, nbits);
561*7bdf38e5Schristos 	fb_set_range(fb, nbits, 0, nbits / 2 == 0 ? 1: nbits / 2);
562*7bdf38e5Schristos 	expect_iter_results(fb, nbits);
563*7bdf38e5Schristos 
564*7bdf38e5Schristos 	free(fb);
565*7bdf38e5Schristos }
566*7bdf38e5Schristos 
567*7bdf38e5Schristos /*
568*7bdf38e5Schristos  * Like test_iter_range_simple, this tests both iteration and longest-range
569*7bdf38e5Schristos  * computation.
570*7bdf38e5Schristos  */
571*7bdf38e5Schristos TEST_BEGIN(test_iter_range_exhaustive) {
572*7bdf38e5Schristos #define NB(nbits) \
573*7bdf38e5Schristos 	do_test_iter_range_exhaustive(nbits);
574*7bdf38e5Schristos 	NBITS_TAB
575*7bdf38e5Schristos #undef NB
576*7bdf38e5Schristos }
577*7bdf38e5Schristos TEST_END
578*7bdf38e5Schristos 
579*7bdf38e5Schristos /*
580*7bdf38e5Schristos  * If all set bits in the bitmap are contiguous, in [set_start, set_end),
581*7bdf38e5Schristos  * returns the number of set bits in [scount_start, scount_end).
582*7bdf38e5Schristos  */
583*7bdf38e5Schristos static size_t
584*7bdf38e5Schristos scount_contiguous(size_t set_start, size_t set_end, size_t scount_start,
585*7bdf38e5Schristos     size_t scount_end) {
586*7bdf38e5Schristos 	/* No overlap. */
587*7bdf38e5Schristos 	if (set_end <= scount_start || scount_end <= set_start) {
588*7bdf38e5Schristos 		return 0;
589*7bdf38e5Schristos 	}
590*7bdf38e5Schristos 	/* set range contains scount range */
591*7bdf38e5Schristos 	if (set_start <= scount_start && set_end >= scount_end) {
592*7bdf38e5Schristos 		return scount_end - scount_start;
593*7bdf38e5Schristos 	}
594*7bdf38e5Schristos 	/* scount range contains set range. */
595*7bdf38e5Schristos 	if (scount_start <= set_start && scount_end >= set_end) {
596*7bdf38e5Schristos 		return set_end - set_start;
597*7bdf38e5Schristos 	}
598*7bdf38e5Schristos 	/* Partial overlap, with set range starting first. */
599*7bdf38e5Schristos 	if (set_start < scount_start && set_end < scount_end) {
600*7bdf38e5Schristos 		return set_end - scount_start;
601*7bdf38e5Schristos 	}
602*7bdf38e5Schristos 	/* Partial overlap, with scount range starting first. */
603*7bdf38e5Schristos 	if (scount_start < set_start && scount_end < set_end) {
604*7bdf38e5Schristos 		return scount_end - set_start;
605*7bdf38e5Schristos 	}
606*7bdf38e5Schristos 	/*
607*7bdf38e5Schristos 	 * Trigger an assert failure; the above list should have been
608*7bdf38e5Schristos 	 * exhaustive.
609*7bdf38e5Schristos 	 */
610*7bdf38e5Schristos 	unreachable();
611*7bdf38e5Schristos }
612*7bdf38e5Schristos 
613*7bdf38e5Schristos static size_t
614*7bdf38e5Schristos ucount_contiguous(size_t set_start, size_t set_end, size_t ucount_start,
615*7bdf38e5Schristos     size_t ucount_end) {
616*7bdf38e5Schristos 	/* No overlap. */
617*7bdf38e5Schristos 	if (set_end <= ucount_start || ucount_end <= set_start) {
618*7bdf38e5Schristos 		return ucount_end - ucount_start;
619*7bdf38e5Schristos 	}
620*7bdf38e5Schristos 	/* set range contains ucount range */
621*7bdf38e5Schristos 	if (set_start <= ucount_start && set_end >= ucount_end) {
622*7bdf38e5Schristos 		return 0;
623*7bdf38e5Schristos 	}
624*7bdf38e5Schristos 	/* ucount range contains set range. */
625*7bdf38e5Schristos 	if (ucount_start <= set_start && ucount_end >= set_end) {
626*7bdf38e5Schristos 		return (ucount_end - ucount_start) - (set_end - set_start);
627*7bdf38e5Schristos 	}
628*7bdf38e5Schristos 	/* Partial overlap, with set range starting first. */
629*7bdf38e5Schristos 	if (set_start < ucount_start && set_end < ucount_end) {
630*7bdf38e5Schristos 		return ucount_end - set_end;
631*7bdf38e5Schristos 	}
632*7bdf38e5Schristos 	/* Partial overlap, with ucount range starting first. */
633*7bdf38e5Schristos 	if (ucount_start < set_start && ucount_end < set_end) {
634*7bdf38e5Schristos 		return set_start - ucount_start;
635*7bdf38e5Schristos 	}
636*7bdf38e5Schristos 	/*
637*7bdf38e5Schristos 	 * Trigger an assert failure; the above list should have been
638*7bdf38e5Schristos 	 * exhaustive.
639*7bdf38e5Schristos 	 */
640*7bdf38e5Schristos 	unreachable();
641*7bdf38e5Schristos }
642*7bdf38e5Schristos 
643*7bdf38e5Schristos static void
644*7bdf38e5Schristos expect_count_match_contiguous(fb_group_t *fb, size_t nbits, size_t set_start,
645*7bdf38e5Schristos     size_t set_end) {
646*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
647*7bdf38e5Schristos 		for (size_t j = i + 1; j <= nbits; j++) {
648*7bdf38e5Schristos 			size_t cnt = j - i;
649*7bdf38e5Schristos 			size_t scount_expected = scount_contiguous(set_start,
650*7bdf38e5Schristos 			    set_end, i, j);
651*7bdf38e5Schristos 			size_t scount_computed = fb_scount(fb, nbits, i, cnt);
652*7bdf38e5Schristos 			expect_zu_eq(scount_expected, scount_computed,
653*7bdf38e5Schristos 			    "fb_scount error with nbits=%zu, start=%zu, "
654*7bdf38e5Schristos 			    "cnt=%zu, with bits set in [%zu, %zu)",
655*7bdf38e5Schristos 			    nbits, i, cnt, set_start, set_end);
656*7bdf38e5Schristos 
657*7bdf38e5Schristos 			size_t ucount_expected = ucount_contiguous(set_start,
658*7bdf38e5Schristos 			    set_end, i, j);
659*7bdf38e5Schristos 			size_t ucount_computed = fb_ucount(fb, nbits, i, cnt);
660*7bdf38e5Schristos 			assert_zu_eq(ucount_expected, ucount_computed,
661*7bdf38e5Schristos 			    "fb_ucount error with nbits=%zu, start=%zu, "
662*7bdf38e5Schristos 			    "cnt=%zu, with bits set in [%zu, %zu)",
663*7bdf38e5Schristos 			    nbits, i, cnt, set_start, set_end);
664*7bdf38e5Schristos 
665*7bdf38e5Schristos 		}
666*7bdf38e5Schristos 	}
667*7bdf38e5Schristos }
668*7bdf38e5Schristos 
669*7bdf38e5Schristos static void
670*7bdf38e5Schristos do_test_count_contiguous(size_t nbits) {
671*7bdf38e5Schristos 	size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t);
672*7bdf38e5Schristos 	fb_group_t *fb = malloc(sz);
673*7bdf38e5Schristos 
674*7bdf38e5Schristos 	fb_init(fb, nbits);
675*7bdf38e5Schristos 
676*7bdf38e5Schristos 	expect_count_match_contiguous(fb, nbits, 0, 0);
677*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
678*7bdf38e5Schristos 		fb_set(fb, nbits, i);
679*7bdf38e5Schristos 		expect_count_match_contiguous(fb, nbits, 0, i + 1);
680*7bdf38e5Schristos 	}
681*7bdf38e5Schristos 
682*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
683*7bdf38e5Schristos 		fb_unset(fb, nbits, i);
684*7bdf38e5Schristos 		expect_count_match_contiguous(fb, nbits, i + 1, nbits);
685*7bdf38e5Schristos 	}
686*7bdf38e5Schristos 
687*7bdf38e5Schristos 	free(fb);
688*7bdf38e5Schristos }
689*7bdf38e5Schristos 
690*7bdf38e5Schristos TEST_BEGIN(test_count_contiguous_simple) {
691*7bdf38e5Schristos 	enum {nbits = 300};
692*7bdf38e5Schristos 	fb_group_t fb[FB_NGROUPS(nbits)];
693*7bdf38e5Schristos 	fb_init(fb, nbits);
694*7bdf38e5Schristos 	/* Just an arbitrary number. */
695*7bdf38e5Schristos 	size_t start = 23;
696*7bdf38e5Schristos 
697*7bdf38e5Schristos 	fb_set_range(fb, nbits, start, 30 - start);
698*7bdf38e5Schristos 	expect_count_match_contiguous(fb, nbits, start, 30);
699*7bdf38e5Schristos 
700*7bdf38e5Schristos 	fb_set_range(fb, nbits, start, 40 - start);
701*7bdf38e5Schristos 	expect_count_match_contiguous(fb, nbits, start, 40);
702*7bdf38e5Schristos 
703*7bdf38e5Schristos 	fb_set_range(fb, nbits, start, 70 - start);
704*7bdf38e5Schristos 	expect_count_match_contiguous(fb, nbits, start, 70);
705*7bdf38e5Schristos 
706*7bdf38e5Schristos 	fb_set_range(fb, nbits, start, 120 - start);
707*7bdf38e5Schristos 	expect_count_match_contiguous(fb, nbits, start, 120);
708*7bdf38e5Schristos 
709*7bdf38e5Schristos 	fb_set_range(fb, nbits, start, 150 - start);
710*7bdf38e5Schristos 	expect_count_match_contiguous(fb, nbits, start, 150);
711*7bdf38e5Schristos 
712*7bdf38e5Schristos 	fb_set_range(fb, nbits, start, 200 - start);
713*7bdf38e5Schristos 	expect_count_match_contiguous(fb, nbits, start, 200);
714*7bdf38e5Schristos 
715*7bdf38e5Schristos 	fb_set_range(fb, nbits, start, 290 - start);
716*7bdf38e5Schristos 	expect_count_match_contiguous(fb, nbits, start, 290);
717*7bdf38e5Schristos }
718*7bdf38e5Schristos TEST_END
719*7bdf38e5Schristos 
720*7bdf38e5Schristos TEST_BEGIN(test_count_contiguous) {
721*7bdf38e5Schristos #define NB(nbits) \
722*7bdf38e5Schristos 	/* This test is *particularly* slow in debug builds. */ \
723*7bdf38e5Schristos 	if ((!config_debug && nbits < 300) || nbits < 150) { \
724*7bdf38e5Schristos 		do_test_count_contiguous(nbits); \
725*7bdf38e5Schristos 	}
726*7bdf38e5Schristos 	NBITS_TAB
727*7bdf38e5Schristos #undef NB
728*7bdf38e5Schristos }
729*7bdf38e5Schristos TEST_END
730*7bdf38e5Schristos 
731*7bdf38e5Schristos static void
732*7bdf38e5Schristos expect_count_match_alternating(fb_group_t *fb_even, fb_group_t *fb_odd,
733*7bdf38e5Schristos     size_t nbits) {
734*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
735*7bdf38e5Schristos 		for (size_t j = i + 1; j <= nbits; j++) {
736*7bdf38e5Schristos 			size_t cnt = j - i;
737*7bdf38e5Schristos 			size_t odd_scount = cnt / 2
738*7bdf38e5Schristos 			    + (size_t)(cnt % 2 == 1 && i % 2 == 1);
739*7bdf38e5Schristos 			size_t odd_scount_computed = fb_scount(fb_odd, nbits,
740*7bdf38e5Schristos 			    i, j - i);
741*7bdf38e5Schristos 			assert_zu_eq(odd_scount, odd_scount_computed,
742*7bdf38e5Schristos 			    "fb_scount error with nbits=%zu, start=%zu, "
743*7bdf38e5Schristos 			    "cnt=%zu, with alternating bits set.",
744*7bdf38e5Schristos 			    nbits, i, j - i);
745*7bdf38e5Schristos 
746*7bdf38e5Schristos 			size_t odd_ucount = cnt / 2
747*7bdf38e5Schristos 			    + (size_t)(cnt % 2 == 1 && i % 2 == 0);
748*7bdf38e5Schristos 			size_t odd_ucount_computed = fb_ucount(fb_odd, nbits,
749*7bdf38e5Schristos 			    i, j - i);
750*7bdf38e5Schristos 			assert_zu_eq(odd_ucount, odd_ucount_computed,
751*7bdf38e5Schristos 			    "fb_ucount error with nbits=%zu, start=%zu, "
752*7bdf38e5Schristos 			    "cnt=%zu, with alternating bits set.",
753*7bdf38e5Schristos 			    nbits, i, j - i);
754*7bdf38e5Schristos 
755*7bdf38e5Schristos 			size_t even_scount = cnt / 2
756*7bdf38e5Schristos 			    + (size_t)(cnt % 2 == 1 && i % 2 == 0);
757*7bdf38e5Schristos 			size_t even_scount_computed = fb_scount(fb_even, nbits,
758*7bdf38e5Schristos 			    i, j - i);
759*7bdf38e5Schristos 			assert_zu_eq(even_scount, even_scount_computed,
760*7bdf38e5Schristos 			    "fb_scount error with nbits=%zu, start=%zu, "
761*7bdf38e5Schristos 			    "cnt=%zu, with alternating bits set.",
762*7bdf38e5Schristos 			    nbits, i, j - i);
763*7bdf38e5Schristos 
764*7bdf38e5Schristos 			size_t even_ucount = cnt / 2
765*7bdf38e5Schristos 			    + (size_t)(cnt % 2 == 1 && i % 2 == 1);
766*7bdf38e5Schristos 			size_t even_ucount_computed = fb_ucount(fb_even, nbits,
767*7bdf38e5Schristos 			    i, j - i);
768*7bdf38e5Schristos 			assert_zu_eq(even_ucount, even_ucount_computed,
769*7bdf38e5Schristos 			    "fb_ucount error with nbits=%zu, start=%zu, "
770*7bdf38e5Schristos 			    "cnt=%zu, with alternating bits set.",
771*7bdf38e5Schristos 			    nbits, i, j - i);
772*7bdf38e5Schristos 		}
773*7bdf38e5Schristos 	}
774*7bdf38e5Schristos }
775*7bdf38e5Schristos 
776*7bdf38e5Schristos static void
777*7bdf38e5Schristos do_test_count_alternating(size_t nbits) {
778*7bdf38e5Schristos 	if (nbits > 1000) {
779*7bdf38e5Schristos 		return;
780*7bdf38e5Schristos 	}
781*7bdf38e5Schristos 	size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t);
782*7bdf38e5Schristos 	fb_group_t *fb_even = malloc(sz);
783*7bdf38e5Schristos 	fb_group_t *fb_odd = malloc(sz);
784*7bdf38e5Schristos 
785*7bdf38e5Schristos 	fb_init(fb_even, nbits);
786*7bdf38e5Schristos 	fb_init(fb_odd, nbits);
787*7bdf38e5Schristos 
788*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
789*7bdf38e5Schristos 		if (i % 2 == 0) {
790*7bdf38e5Schristos 			fb_set(fb_even, nbits, i);
791*7bdf38e5Schristos 		} else {
792*7bdf38e5Schristos 			fb_set(fb_odd, nbits, i);
793*7bdf38e5Schristos 		}
794*7bdf38e5Schristos 	}
795*7bdf38e5Schristos 
796*7bdf38e5Schristos 	expect_count_match_alternating(fb_even, fb_odd, nbits);
797*7bdf38e5Schristos 
798*7bdf38e5Schristos 	free(fb_even);
799*7bdf38e5Schristos 	free(fb_odd);
800*7bdf38e5Schristos }
801*7bdf38e5Schristos 
802*7bdf38e5Schristos TEST_BEGIN(test_count_alternating) {
803*7bdf38e5Schristos #define NB(nbits) \
804*7bdf38e5Schristos 	do_test_count_alternating(nbits);
805*7bdf38e5Schristos 	NBITS_TAB
806*7bdf38e5Schristos #undef NB
807*7bdf38e5Schristos }
808*7bdf38e5Schristos TEST_END
809*7bdf38e5Schristos 
810*7bdf38e5Schristos static void
811*7bdf38e5Schristos do_test_bit_op(size_t nbits, bool (*op)(bool a, bool b),
812*7bdf38e5Schristos     void (*fb_op)(fb_group_t *dst, fb_group_t *src1, fb_group_t *src2, size_t nbits)) {
813*7bdf38e5Schristos 	size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t);
814*7bdf38e5Schristos 	fb_group_t *fb1 = malloc(sz);
815*7bdf38e5Schristos 	fb_group_t *fb2 = malloc(sz);
816*7bdf38e5Schristos 	fb_group_t *fb_result = malloc(sz);
817*7bdf38e5Schristos 	fb_init(fb1, nbits);
818*7bdf38e5Schristos 	fb_init(fb2, nbits);
819*7bdf38e5Schristos 	fb_init(fb_result, nbits);
820*7bdf38e5Schristos 
821*7bdf38e5Schristos 	/* Just two random numbers. */
822*7bdf38e5Schristos 	const uint64_t prng_init1 = (uint64_t)0X4E9A9DE6A35691CDULL;
823*7bdf38e5Schristos 	const uint64_t prng_init2 = (uint64_t)0X7856E396B063C36EULL;
824*7bdf38e5Schristos 
825*7bdf38e5Schristos 	uint64_t prng1 = prng_init1;
826*7bdf38e5Schristos 	uint64_t prng2 = prng_init2;
827*7bdf38e5Schristos 
828*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
829*7bdf38e5Schristos 		bool bit1 = ((prng1 & (1ULL << (i % 64))) != 0);
830*7bdf38e5Schristos 		bool bit2 = ((prng2 & (1ULL << (i % 64))) != 0);
831*7bdf38e5Schristos 
832*7bdf38e5Schristos 		if (bit1) {
833*7bdf38e5Schristos 			fb_set(fb1, nbits, i);
834*7bdf38e5Schristos 		}
835*7bdf38e5Schristos 		if (bit2) {
836*7bdf38e5Schristos 			fb_set(fb2, nbits, i);
837*7bdf38e5Schristos 		}
838*7bdf38e5Schristos 
839*7bdf38e5Schristos 		if (i % 64 == 0) {
840*7bdf38e5Schristos 			prng1 = prng_state_next_u64(prng1);
841*7bdf38e5Schristos 			prng2 = prng_state_next_u64(prng2);
842*7bdf38e5Schristos 		}
843*7bdf38e5Schristos 	}
844*7bdf38e5Schristos 
845*7bdf38e5Schristos 	fb_op(fb_result, fb1, fb2, nbits);
846*7bdf38e5Schristos 
847*7bdf38e5Schristos 	/* Reset the prngs to replay them. */
848*7bdf38e5Schristos 	prng1 = prng_init1;
849*7bdf38e5Schristos 	prng2 = prng_init2;
850*7bdf38e5Schristos 
851*7bdf38e5Schristos 	for (size_t i = 0; i < nbits; i++) {
852*7bdf38e5Schristos 		bool bit1 = ((prng1 & (1ULL << (i % 64))) != 0);
853*7bdf38e5Schristos 		bool bit2 = ((prng2 & (1ULL << (i % 64))) != 0);
854*7bdf38e5Schristos 
855*7bdf38e5Schristos 		/* Original bitmaps shouldn't change. */
856*7bdf38e5Schristos 		expect_b_eq(bit1, fb_get(fb1, nbits, i), "difference at bit %zu", i);
857*7bdf38e5Schristos 		expect_b_eq(bit2, fb_get(fb2, nbits, i), "difference at bit %zu", i);
858*7bdf38e5Schristos 
859*7bdf38e5Schristos 		/* New one should be bitwise and. */
860*7bdf38e5Schristos 		expect_b_eq(op(bit1, bit2), fb_get(fb_result, nbits, i),
861*7bdf38e5Schristos 		    "difference at bit %zu", i);
862*7bdf38e5Schristos 
863*7bdf38e5Schristos 		/* Update the same way we did last time. */
864*7bdf38e5Schristos 		if (i % 64 == 0) {
865*7bdf38e5Schristos 			prng1 = prng_state_next_u64(prng1);
866*7bdf38e5Schristos 			prng2 = prng_state_next_u64(prng2);
867*7bdf38e5Schristos 		}
868*7bdf38e5Schristos 	}
869*7bdf38e5Schristos 
870*7bdf38e5Schristos 	free(fb1);
871*7bdf38e5Schristos 	free(fb2);
872*7bdf38e5Schristos 	free(fb_result);
873*7bdf38e5Schristos }
874*7bdf38e5Schristos 
875*7bdf38e5Schristos static bool
876*7bdf38e5Schristos binary_and(bool a, bool b) {
877*7bdf38e5Schristos 	return a & b;
878*7bdf38e5Schristos }
879*7bdf38e5Schristos 
880*7bdf38e5Schristos static void
881*7bdf38e5Schristos do_test_bit_and(size_t nbits) {
882*7bdf38e5Schristos 	do_test_bit_op(nbits, &binary_and, &fb_bit_and);
883*7bdf38e5Schristos }
884*7bdf38e5Schristos 
885*7bdf38e5Schristos TEST_BEGIN(test_bit_and) {
886*7bdf38e5Schristos #define NB(nbits) \
887*7bdf38e5Schristos 	do_test_bit_and(nbits);
888*7bdf38e5Schristos 	NBITS_TAB
889*7bdf38e5Schristos #undef NB
890*7bdf38e5Schristos }
891*7bdf38e5Schristos TEST_END
892*7bdf38e5Schristos 
893*7bdf38e5Schristos static bool
894*7bdf38e5Schristos binary_or(bool a, bool b) {
895*7bdf38e5Schristos 	return a | b;
896*7bdf38e5Schristos }
897*7bdf38e5Schristos 
898*7bdf38e5Schristos static void
899*7bdf38e5Schristos do_test_bit_or(size_t nbits) {
900*7bdf38e5Schristos 	do_test_bit_op(nbits, &binary_or, &fb_bit_or);
901*7bdf38e5Schristos }
902*7bdf38e5Schristos 
903*7bdf38e5Schristos TEST_BEGIN(test_bit_or) {
904*7bdf38e5Schristos #define NB(nbits) \
905*7bdf38e5Schristos 	do_test_bit_or(nbits);
906*7bdf38e5Schristos 	NBITS_TAB
907*7bdf38e5Schristos #undef NB
908*7bdf38e5Schristos }
909*7bdf38e5Schristos TEST_END
910*7bdf38e5Schristos 
911*7bdf38e5Schristos static bool
912*7bdf38e5Schristos binary_not(bool a, bool b) {
913*7bdf38e5Schristos 	(void)b;
914*7bdf38e5Schristos 	return !a;
915*7bdf38e5Schristos }
916*7bdf38e5Schristos 
917*7bdf38e5Schristos static void
918*7bdf38e5Schristos fb_bit_not_shim(fb_group_t *dst, fb_group_t *src1, fb_group_t *src2,
919*7bdf38e5Schristos     size_t nbits) {
920*7bdf38e5Schristos 	(void)src2;
921*7bdf38e5Schristos 	fb_bit_not(dst, src1, nbits);
922*7bdf38e5Schristos }
923*7bdf38e5Schristos 
924*7bdf38e5Schristos static void
925*7bdf38e5Schristos do_test_bit_not(size_t nbits) {
926*7bdf38e5Schristos 	do_test_bit_op(nbits, &binary_not, &fb_bit_not_shim);
927*7bdf38e5Schristos }
928*7bdf38e5Schristos 
929*7bdf38e5Schristos TEST_BEGIN(test_bit_not) {
930*7bdf38e5Schristos #define NB(nbits) \
931*7bdf38e5Schristos 	do_test_bit_not(nbits);
932*7bdf38e5Schristos 	NBITS_TAB
933*7bdf38e5Schristos #undef NB
934*7bdf38e5Schristos }
935*7bdf38e5Schristos TEST_END
936*7bdf38e5Schristos 
937*7bdf38e5Schristos int
938*7bdf38e5Schristos main(void) {
939*7bdf38e5Schristos 	return test_no_reentrancy(
940*7bdf38e5Schristos 	    test_fb_init,
941*7bdf38e5Schristos 	    test_get_set_unset,
942*7bdf38e5Schristos 	    test_search_simple,
943*7bdf38e5Schristos 	    test_search_exhaustive,
944*7bdf38e5Schristos 	    test_range_simple,
945*7bdf38e5Schristos 	    test_empty_full,
946*7bdf38e5Schristos 	    test_iter_range_simple,
947*7bdf38e5Schristos 	    test_iter_range_exhaustive,
948*7bdf38e5Schristos 	    test_count_contiguous_simple,
949*7bdf38e5Schristos 	    test_count_contiguous,
950*7bdf38e5Schristos 	    test_count_alternating,
951*7bdf38e5Schristos 	    test_bit_and,
952*7bdf38e5Schristos 	    test_bit_or,
953*7bdf38e5Schristos 	    test_bit_not);
954*7bdf38e5Schristos }
955