Skip to content

Commit

Permalink
Merge pull request #4 from mischathompson/master
Browse files Browse the repository at this point in the history
Add bitset comparison functions: disjoint, intersect, contains all
  • Loading branch information
lemire authored Jun 11, 2019
2 parents d252583 + d8d5161 commit 2d22c9a
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 0 deletions.
10 changes: 10 additions & 0 deletions include/bitset.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,16 @@ void bitset_inplace_intersection(bitset_t * restrict b1, const bitset_t * restri
size_t bitset_intersection_count(const bitset_t * restrict b1, const bitset_t * restrict b2);


/* returns true if the bitsets contain no common elements */
bool bitsets_disjoint(const bitset_t * b1, const bitset_t * b2);

/* returns true if the bitsets contain any common elements */
bool bitsets_intersect(const bitset_t * b1, const bitset_t * b2);

/* returns true if b1 contains all of the set bits of b2 */
bool bitset_contains_all(const bitset_t * b1, const bitset_t * b2);


/* compute the difference in-place (to b1), to generate a new bitset first call bitset_copy */
void bitset_inplace_difference(bitset_t * restrict b1, const bitset_t * restrict b2);

Expand Down
56 changes: 56 additions & 0 deletions src/bitset.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,62 @@ size_t bitset_maximum(const bitset_t *bitset) {
return 0;
}

/* Returns true if bitsets share no common elements, false otherwise.
*
* Performs early-out if common element found. */
bool bitsets_disjoint(const bitset_t * b1, const bitset_t * b2) {
size_t minlength = b1->arraysize < b2->arraysize ? b1->arraysize : b2->arraysize;

for(size_t k = 0; k < minlength; k++) {
if((b1->array[k] & b2->array[k]) != 0)
return false;
}
return true;
}


/* Returns true if bitsets contain at least 1 common element, false if they are
* disjoint.
*
* Performs early-out if common element found. */
bool bitsets_intersect(const bitset_t * b1, const bitset_t * b2) {
size_t minlength = b1->arraysize < b2->arraysize ? b1->arraysize : b2->arraysize;

for(size_t k = 0; k < minlength; k++) {
if((b1->array[k] & b2->array[k]) != 0)
return true;
}
return false;
}

/* Returns true if b has any bits set in or after b->array[starting_loc]. */
static bool any_bits_set(const bitset_t * b, size_t starting_loc) {
if(starting_loc >= b->arraysize) {
return false;
}
for(size_t k = starting_loc; k < b->arraysize; k++) {
if(b->array[k] != 0)
return false;
}
return true;
}

/* Returns true if b1 has all of b2's bits set.
*
* Performs early out if a bit is found in b2 that is not found in b1. */
bool bitset_contains_all(const bitset_t * b1, const bitset_t * b2) {
for(size_t k = 0; k < b1->arraysize; k++) {
if((b1->array[k] & b2->array[k]) != b2->array[k]) {
return false;
}
}
if(b2->arraysize > b1->arraysize) {
/* Need to check if b2 has any bits set beyond b1's array */
return !any_bits_set(b2, b1->arraysize);
}
return true;
}

size_t bitset_union_count(const bitset_t *restrict b1, const bitset_t * restrict b2) {
size_t answer = 0;
size_t minlength = b1->arraysize < b2->arraysize ? b1->arraysize : b2->arraysize;
Expand Down
79 changes: 79 additions & 0 deletions tests/unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,82 @@ void test_counts() {
bitset_free(b2);
}

/* Creates 2 bitsets, one containing even numbers the other odds.
Checks bitsets_disjoint() returns that they are disjoint, then sets a common
bit between both sets and checks that they are no longer disjoint. */
void test_disjoint() {
bitset_t * evens = bitset_create();
bitset_t * odds = bitset_create();

for(int i = 0; i < 1000; i++) {
if(i % 2 == 0)
bitset_set(evens, i);
else
bitset_set(odds, i);
}

assert(bitsets_disjoint(evens, odds));

bitset_set(evens, 501);
bitset_set(odds, 501);

assert(!bitsets_disjoint(evens, odds));

bitset_free(evens);
bitset_free(odds);
}

/* Creates 2 bitsets, one containing even numbers the other odds.
Checks that bitsets_intersect() returns that they do not intersect, then sets
a common bit and checks that they now intersect. */
void test_intersects() {
bitset_t * evens = bitset_create();
bitset_t * odds = bitset_create();

for(int i = 0; i < 1000; i++) {
if(i % 2 == 0)
bitset_set(evens, i);
else
bitset_set(odds, i);
}

assert(!bitsets_intersect(evens, odds));

bitset_set(evens, 1001);
bitset_set(odds, 1001);

assert(bitsets_intersect(evens, odds));

bitset_free(evens);
bitset_free(odds);
}

/* Creates 2 bitsets, one with all bits from 0->1000 set, the other with only
even bits set in the same range. Checks that the bitset_contains_all()
returns true, then sets a single bit at 1001 in the prior subset and checks that
bitset_contains_all() returns false. */
void test_contains_all() {
bitset_t * superset = bitset_create();
bitset_t * subset = bitset_create();

for(int i = 0; i < 1000; i++) {
bitset_set(superset, i);
if(i % 2 == 0)
bitset_set(subset, i);
}

assert(bitset_contains_all(superset, subset));
assert(!bitset_contains_all(subset, superset));

bitset_set(subset, 1001);

assert(!bitset_contains_all(superset, subset));
assert(!bitset_contains_all(subset, superset));

bitset_free(superset);
bitset_free(subset);
}


int main() {
test_construct();
Expand All @@ -148,5 +224,8 @@ int main() {
test_counts();
test_shift_right();
test_shift_left();
test_disjoint();
test_intersects();
test_contains_all();
printf("All asserts passed. Code is probably ok.\n");
}

0 comments on commit 2d22c9a

Please sign in to comment.