Skip to content

Commit 793edb7

Browse files
authored
fix bitset_next_set_bits when called with non-word-aligned starts (#692)
* convert cbetset_unit to a real cmocka unit testing file * fix bitset_next_set_bits when called with non-word-aligned starts `bitset_next_set_bits` was returning incorrect values for bits set within the same word as the start position when the start position is not a multiple of 64. The values within the word would be reported as lower than they should be by (`*start % 64`). Instead, `bitset_next_set_bits` will now correctly always return absolute bit positions.
1 parent bfba029 commit 793edb7

File tree

2 files changed

+61
-28
lines changed

2 files changed

+61
-28
lines changed

include/roaring/bitset/bitset.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,8 @@ inline size_t bitset_next_set_bits(const bitset_t *bitset, size_t *buffer,
236236
return 0; // nothing more to iterate over
237237
}
238238
uint64_t w = bitset->array[x];
239-
w >>= (*startfrom & 63);
239+
// unset low bits inside the word less than *startfrom
240+
w &= ~((UINT64_C(1) << (*startfrom & 63)) - 1);
240241
size_t howmany = 0;
241242
size_t base = x << 6;
242243
while (howmany < capacity) {

tests/cbitset_unit.c

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ int compute_cardinality(bitset_t *b) {
1414
return k;
1515
}
1616

17-
void test_iterate() {
17+
DEFINE_TEST(test_iterate) {
1818
bitset_t *b = bitset_create();
1919
for (int k = 0; k < 1000; ++k) bitset_set(b, 3 * k);
2020
assert_true(bitset_count(b) == 1000);
@@ -28,6 +28,34 @@ void test_iterate() {
2828
bitset_free(b);
2929
}
3030

31+
DEFINE_TEST(test_next_bits_iterate) {
32+
bitset_t *b = bitset_create();
33+
for (int i = 0; i < 100; i++) bitset_set(b, i);
34+
for (int i = 1000; i < 1100; i += 2) bitset_set(b, i);
35+
36+
// Use an odd, small buffer size
37+
size_t buffer[3];
38+
size_t howmany = 0;
39+
size_t i = 0;
40+
for (size_t startfrom = 0;
41+
(howmany = bitset_next_set_bits(
42+
b, buffer, sizeof(buffer) / sizeof(buffer[0]), &startfrom)) > 0;
43+
startfrom++) {
44+
for (size_t j = 0; j < howmany; j++) {
45+
size_t expected;
46+
if (i < 100) {
47+
expected = i;
48+
} else {
49+
expected = 1000 + 2 * (i - 100);
50+
}
51+
assert_int_equal(buffer[j], expected);
52+
++i;
53+
}
54+
}
55+
assert_int_equal(i, 150);
56+
bitset_free(b);
57+
}
58+
3159
bool increment(size_t value, void *param) {
3260
size_t k;
3361
memcpy(&k, param, sizeof(size_t));
@@ -37,7 +65,7 @@ bool increment(size_t value, void *param) {
3765
return true;
3866
}
3967

40-
void test_iterate2() {
68+
DEFINE_TEST(test_iterate2) {
4169
bitset_t *b = bitset_create();
4270
for (int k = 0; k < 1000; ++k) bitset_set(b, 3 * k);
4371
assert_true(compute_cardinality(b) == 1000);
@@ -48,7 +76,7 @@ void test_iterate2() {
4876
bitset_free(b);
4977
}
5078

51-
void test_construct() {
79+
DEFINE_TEST(test_construct) {
5280
bitset_t *b = bitset_create();
5381
for (int k = 0; k < 1000; ++k) bitset_set(b, 3 * k);
5482
assert_true(compute_cardinality(b) == 1000);
@@ -58,7 +86,7 @@ void test_construct() {
5886
bitset_free(b);
5987
}
6088

61-
void test_max_min() {
89+
DEFINE_TEST(test_max_min) {
6290
bitset_t *b = bitset_create();
6391
assert_true(bitset_empty(b));
6492
for (size_t k = 100; k < 1000; ++k) {
@@ -69,7 +97,7 @@ void test_max_min() {
6997
bitset_free(b);
7098
}
7199

72-
void test_shift_left() {
100+
DEFINE_TEST(test_shift_left) {
73101
for (size_t sh = 0; sh < 256; sh++) {
74102
bitset_t *b = bitset_create();
75103
int power = 3;
@@ -90,7 +118,7 @@ void test_shift_left() {
90118
}
91119
}
92120

93-
void test_set_to_val() {
121+
DEFINE_TEST(test_set_to_val) {
94122
bitset_t *b = bitset_create();
95123
bitset_set_to_value(b, 1, true);
96124
bitset_set_to_value(b, 1, false);
@@ -101,7 +129,7 @@ void test_set_to_val() {
101129
bitset_free(b);
102130
}
103131

104-
void test_shift_right() {
132+
DEFINE_TEST(test_shift_right) {
105133
for (size_t sh = 0; sh < 256; sh++) {
106134
bitset_t *b = bitset_create();
107135
int power = 3;
@@ -120,7 +148,7 @@ void test_shift_right() {
120148
}
121149
}
122150

123-
void test_union_intersection() {
151+
DEFINE_TEST(test_union_intersection) {
124152
bitset_t *b1 = bitset_create();
125153
bitset_t *b2 = bitset_create();
126154

@@ -148,7 +176,7 @@ void test_union_intersection() {
148176
bitset_free(b2);
149177
}
150178

151-
void test_counts() {
179+
DEFINE_TEST(test_counts) {
152180
bitset_t *b1 = bitset_create();
153181
bitset_t *b2 = bitset_create();
154182

@@ -165,7 +193,7 @@ void test_counts() {
165193
/* Creates 2 bitsets, one containing even numbers the other odds.
166194
Checks bitsets_disjoint() returns that they are disjoint, then sets a common
167195
bit between both sets and checks that they are no longer disjoint. */
168-
void test_disjoint() {
196+
DEFINE_TEST(test_disjoint) {
169197
bitset_t *evens = bitset_create();
170198
bitset_t *odds = bitset_create();
171199

@@ -190,7 +218,7 @@ void test_disjoint() {
190218
/* Creates 2 bitsets, one containing even numbers the other odds.
191219
Checks that bitsets_intersect() returns that they do not intersect, then sets
192220
a common bit and checks that they now intersect. */
193-
void test_intersects() {
221+
DEFINE_TEST(test_intersects) {
194222
bitset_t *evens = bitset_create();
195223
bitset_t *odds = bitset_create();
196224

@@ -215,7 +243,7 @@ void test_intersects() {
215243
contains the subset bits plus additional bits after the subset arraysize.
216244
Checks that the bitset_contains_all() returns false when checking if
217245
the superset contains all the subset bits, and true in the opposite case. */
218-
void test_contains_all_different_sizes() {
246+
DEFINE_TEST(test_contains_all_different_sizes) {
219247
const size_t superset_size = 10;
220248
const size_t subset_size = 5;
221249

@@ -240,7 +268,7 @@ void test_contains_all_different_sizes() {
240268
even bits set in the same range. Checks that the bitset_contains_all()
241269
returns true, then sets a single bit at 1001 in the prior subset and checks that
242270
bitset_contains_all() returns false. */
243-
void test_contains_all() {
271+
DEFINE_TEST(test_contains_all) {
244272
bitset_t *superset = bitset_create();
245273
bitset_t *subset = bitset_create();
246274

@@ -262,18 +290,22 @@ void test_contains_all() {
262290
}
263291

264292
int main() {
265-
test_set_to_val();
266-
test_construct();
267-
test_union_intersection();
268-
test_iterate();
269-
test_iterate2();
270-
test_max_min();
271-
test_counts();
272-
test_shift_right();
273-
test_shift_left();
274-
test_disjoint();
275-
test_intersects();
276-
test_contains_all();
277-
test_contains_all_different_sizes();
278-
printf("All asserts passed. Code is probably ok.\n");
293+
const struct CMUnitTest tests[] = {
294+
cmocka_unit_test(test_set_to_val),
295+
cmocka_unit_test(test_construct),
296+
cmocka_unit_test(test_union_intersection),
297+
cmocka_unit_test(test_iterate),
298+
cmocka_unit_test(test_iterate2),
299+
cmocka_unit_test(test_next_bits_iterate),
300+
cmocka_unit_test(test_max_min),
301+
cmocka_unit_test(test_counts),
302+
cmocka_unit_test(test_shift_right),
303+
cmocka_unit_test(test_shift_left),
304+
cmocka_unit_test(test_disjoint),
305+
cmocka_unit_test(test_intersects),
306+
cmocka_unit_test(test_contains_all),
307+
cmocka_unit_test(test_contains_all_different_sizes),
308+
};
309+
310+
return cmocka_run_group_tests(tests, NULL, NULL);
279311
}

0 commit comments

Comments
 (0)