From 1774ab3041dad5196f9b2bfff2afd9f11812c852 Mon Sep 17 00:00:00 2001 From: mischathompson Date: Mon, 3 Jun 2019 14:08:56 -0700 Subject: [PATCH 1/4] Added bitsets_disjoint, bitsets_intersect, and bitset_contains_all functions along with appropriate unit tests --- include/bitset.h | 10 ++++++ src/bitset.c | 55 +++++++++++++++++++++++++++++++++ tests/unit.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+) diff --git a/include/bitset.h b/include/bitset.h index b7245d6..6abdf7e 100644 --- a/include/bitset.h +++ b/include/bitset.h @@ -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 * restrict b1, const bitset_t * restrict 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); diff --git a/src/bitset.c b/src/bitset.c index 94a0952..846ac07 100644 --- a/src/bitset.c +++ b/src/bitset.c @@ -189,6 +189,61 @@ 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 * restrict 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] & 0xFFFFFFFFFFFFFFFF) != 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 * restrict b1, const bitset_t * restrict 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) { + 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; diff --git a/tests/unit.c b/tests/unit.c index 87c8ec4..b5bcb69 100644 --- a/tests/unit.c +++ b/tests/unit.c @@ -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, 1001); + bitset_set(odds, 1001); + + 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(); @@ -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"); } From 68c2d19dfe5aa1e823115f26054ccee4b9e80300 Mon Sep 17 00:00:00 2001 From: mischathompson Date: Tue, 11 Jun 2019 11:44:28 -0700 Subject: [PATCH 2/4] Changed comment formatting and changed common bit in disjoint test to be a bit in the middle of the sets rather than at the end --- tests/unit.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/unit.c b/tests/unit.c index b5bcb69..dfe87aa 100644 --- a/tests/unit.c +++ b/tests/unit.c @@ -139,8 +139,8 @@ void test_counts() { } /* 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. */ +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(); @@ -154,8 +154,8 @@ void test_disjoint() { assert(bitsets_disjoint(evens, odds)); - bitset_set(evens, 1001); - bitset_set(odds, 1001); + bitset_set(evens, 501); + bitset_set(odds, 501); assert(!bitsets_disjoint(evens, odds)); @@ -164,8 +164,8 @@ void test_disjoint() { } /* 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. */ +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(); @@ -189,9 +189,9 @@ void test_intersects() { } /* 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. */ +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(); From 99386e2858679c194ee2a32160065af77c2f6fbe Mon Sep 17 00:00:00 2001 From: mischathompson Date: Tue, 11 Jun 2019 12:26:33 -0700 Subject: [PATCH 3/4] Removed unnecessary bitwise & and changed new code to be consistent with existing code style --- src/bitset.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/bitset.c b/src/bitset.c index 846ac07..4661814 100644 --- a/src/bitset.c +++ b/src/bitset.c @@ -195,8 +195,8 @@ size_t bitset_maximum(const bitset_t *bitset) { 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) + for(size_t k = 0; k < minlength; k++) { + if((b1->array[k] & b2->array[k]) != 0) return false; } return true; @@ -210,8 +210,8 @@ bool bitsets_disjoint(const bitset_t * b1, const bitset_t * b2) { 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) + for(size_t k = 0; k < minlength; k++) { + if((b1->array[k] & b2->array[k]) != 0) return true; } return false; @@ -219,11 +219,11 @@ bool bitsets_intersect(const bitset_t * b1, const bitset_t * b2) { /* Returns true if b has any bits set in or after b->array[starting_loc]. */ static bool any_bits_set(const bitset_t * restrict b, size_t starting_loc) { - if (starting_loc > b->arraysize) { + if(starting_loc >= b->arraysize) { return false; } - for (size_t k = starting_loc; k < b->arraysize; k++) { - if ((b->array[k] & 0xFFFFFFFFFFFFFFFF) != 0) + for(size_t k = starting_loc; k < b->arraysize; k++) { + if(b->array[k] != 0) return false; } return true; @@ -233,12 +233,13 @@ static bool any_bits_set(const bitset_t * restrict b, size_t starting_loc) { * * Performs early out if a bit is found in b2 that is not found in b1. */ bool bitset_contains_all(const bitset_t * restrict b1, const bitset_t * restrict b2) { - for (size_t k = 0; k < b1->arraysize; k++) { - if ((b1->array[k] & b2->array[k]) != b2->array[k]) { + 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) { + 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; From d8d516100063c39ca6a55897efdbb5cc6c903f0c Mon Sep 17 00:00:00 2001 From: mischathompson Date: Tue, 11 Jun 2019 15:44:39 -0700 Subject: [PATCH 4/4] Removed unnecessary 'restrict' keywords --- include/bitset.h | 2 +- src/bitset.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/bitset.h b/include/bitset.h index 6abdf7e..636d736 100644 --- a/include/bitset.h +++ b/include/bitset.h @@ -126,7 +126,7 @@ bool bitsets_disjoint(const bitset_t * b1, const bitset_t * b2); 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 * restrict b1, const bitset_t * restrict 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 */ diff --git a/src/bitset.c b/src/bitset.c index 4661814..3310bdf 100644 --- a/src/bitset.c +++ b/src/bitset.c @@ -218,7 +218,7 @@ bool bitsets_intersect(const bitset_t * b1, const bitset_t * b2) { } /* Returns true if b has any bits set in or after b->array[starting_loc]. */ -static bool any_bits_set(const bitset_t * restrict b, size_t starting_loc) { +static bool any_bits_set(const bitset_t * b, size_t starting_loc) { if(starting_loc >= b->arraysize) { return false; } @@ -232,7 +232,7 @@ static bool any_bits_set(const bitset_t * restrict b, size_t starting_loc) { /* 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 * restrict b1, const bitset_t * restrict b2) { +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;