Skip to contentSkip to conversation

uintset: Add l_uintset_intersect

PATCH Applied Tim Kourt 2 participants 4 messages Mar 7, 2019

lore
Share & tools
lore

Tim Kourt

author
#0 lore raw

PATCH 1/2 uintset: Add l_uintset_intersect

l_uintset_intersect computes the intersection of two sets of an equal base.

---
 ell/uintset.c | 37 +++++++++++++++++++++++++++++++++++++
 ell/uintset.h |  3 +++
 2 files changed, 40 insertions(+)
ell/uintset.c +37 -0
index 3f20098..60a9822 100644
@@ -469,3 +469,40 @@ LIB_EXPORT void l_uintset_foreach(struct l_uintset *set,
 			bit = find_next_bit(set->bits, set->size, bit + 1))
 		function(set->min + bit, user_data);
 }
+
+/**
+ * l_uintset_intersect:
+ * @set_a: The set of numbers
+ * @set_b: The set of numbers
+ *
+ * Intersects the two sets of numbers of an equal base, e.g.:
+ * l_uintset_get_min(set_a) must be equal to l_uintset_get_min(set_b) and
+ * l_uintset_get_max(set_a) must be equal to l_uintset_get_max(set_b)
+ *
+ * Returns: A newly allocated l_uintset object containing the intersection of
+ * @set_a and @set_b. If the bases are not equal returns NULL. If either @set_a
+ * or @set_b is NULL returns NULL.
+ **/
+LIB_EXPORT struct l_uintset *l_uintset_intersect(const struct l_uintset *set_a,
+						const struct l_uintset *set_b)
+{
+	struct l_uintset *intersection;
+	uint32_t offset;
+	uint32_t offset_max;
+
+	if (unlikely(!set_a || !set_b))
+		return NULL;
+
+	if (unlikely(set_a->min != set_b->min || set_a->max != set_b->max))
+		return NULL;
+
+	intersection = l_uintset_new_from_range(set_a->min, set_a->max);
+
+	offset_max = (set_a->size + BITS_PER_LONG - 1) / BITS_PER_LONG;
+
+	for (offset = 0; offset < offset_max; offset++)
+		intersection->bits[offset] =
+				set_a->bits[offset] & set_b->bits[offset];
+
+	return intersection;
+}
ell/uintset.h +3 -0
index dd03cd7..c05a21b 100644
@@ -55,6 +55,9 @@ uint32_t l_uintset_find_unused(struct l_uintset *set, uint32_t start);
 void l_uintset_foreach(struct l_uintset *set,
 			l_uintset_foreach_func_t function, void *user_data);
 
+struct l_uintset *l_uintset_intersect(const struct l_uintset *set_a,
+						const struct l_uintset *set_b);
+
 #ifdef __cplusplus
 }
 #endif
Signature · 1 line
2.13.6
author
#1 lore raw

PATCH 2/2 unit: Add l_uintset_intersect tests

---
 unit/test-uintset.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 91 insertions(+)
unit/test-uintset.c +91 -0
index 4488cd9..9bd455c 100644
@@ -262,6 +262,91 @@ static void test_uintset_foreach(const void *data)
 	l_uintset_free(check);
 }
 
+static void test_uintset_intersect_1(const void *data)
+{
+	struct l_uintset *set_a;
+	struct l_uintset *set_b;
+
+	assert(!l_uintset_intersect(NULL, NULL));
+
+	set_a = l_uintset_new_from_range(0, 5);
+	assert(!l_uintset_intersect(NULL, set_a));
+	assert(!l_uintset_intersect(set_a, NULL));
+
+	set_b = l_uintset_new_from_range(4, 10);
+	assert(!l_uintset_intersect(set_a, set_b));
+
+	l_uintset_free(set_a);
+	l_uintset_free(set_b);
+}
+
+struct uintset_data {
+	uint32_t min;
+	uint32_t max;
+	uint32_t *vals;
+	uint32_t size;
+};
+
+struct uintset_intersect_data {
+	const struct uintset_data set_a;
+	const struct uintset_data set_b;
+	const struct uintset_data set_r;
+};
+
+uint32_t vals1[] = { 1, 2, 3 };
+uint32_t vals2[] = { 3, 4};
+uint32_t vals3[] = { 3 };
+
+static const struct uintset_intersect_data intersect_data_1 = {
+	.set_a = { 0, 4, vals1, L_ARRAY_SIZE(vals1) },
+	.set_b = { 0, 4, vals2, L_ARRAY_SIZE(vals2) },
+	.set_r = { 0, 4, vals3, L_ARRAY_SIZE(vals3) },
+};
+
+uint32_t vals4[] = { 0, 1, 64, 127 };
+uint32_t vals5[] = { 1, 25, 64, 66, 127, 135 };
+uint32_t vals6[] = { 1, 64, 127 };
+
+static const struct uintset_intersect_data intersect_data_2 = {
+	.set_a = { 0, 191, vals4, L_ARRAY_SIZE(vals4) },
+	.set_b = { 0, 191, vals5, L_ARRAY_SIZE(vals5) },
+	.set_r = { 0, 191, vals6, L_ARRAY_SIZE(vals6) },
+};
+
+static void test_uintset_intersect_2(const void *user_data)
+{
+	const struct uintset_intersect_data *data = user_data;
+	struct l_uintset *set_a;
+	struct l_uintset *set_b;
+	struct l_uintset *set_r;
+	size_t i;
+
+	set_a = l_uintset_new_from_range(data->set_a.min, data->set_a.max);
+
+	for (i = 0; i < data->set_a.size; i++)
+		l_uintset_put(set_a, data->set_a.vals[i]);
+
+	set_b = l_uintset_new_from_range(data->set_b.min, data->set_b.max);
+
+	for (i = 0; i < data->set_b.size; i++)
+		l_uintset_put(set_b, data->set_b.vals[i]);
+
+	set_r = l_uintset_intersect(set_a, set_b);
+
+	assert(set_r);
+
+	for (i = 0; i < data->set_r.size; i++) {
+		assert(l_uintset_contains(set_r, data->set_r.vals[i]));
+		assert(l_uintset_take(set_r, data->set_r.vals[i]));
+	}
+
+	assert(l_uintset_find_max(set_r) == l_uintset_get_max(set_r) + 1);
+
+	l_uintset_free(set_a);
+	l_uintset_free(set_b);
+	l_uintset_free(set_r);
+}
+
 int main(int argc, char *argv[])
 {
 	l_test_init(&argc, &argv);
@@ -273,6 +358,12 @@ int main(int argc, char *argv[])
 	l_test_add("l_uintset for each tests", test_uintset_foreach, NULL);
 	l_test_add("l_uintset find unused tests", test_uintset_find_unused,
 							NULL);
+	l_test_add("l_uintset intersect sanity check", test_uintset_intersect_1,
+									NULL);
+	l_test_add("l_uintset intersect test 1", test_uintset_intersect_2,
+							&intersect_data_1);
+	l_test_add("l_uintset intersect test2", test_uintset_intersect_2,
+							&intersect_data_2);
 
 	return l_test_run();
 }
Signature · 1 line
2.13.6
#2 lore raw

Re: [PATCH 2/2] unit: Add l_uintset_intersect tests

Hi Tim,

unit/test-uintset.c static void test_uintset_foreach(const void *data) · line 265

Quoted 13 lines · Tim Kourt
---
  unit/test-uintset.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++
  1 file changed, 91 insertions(+)
unit/test-uintset.c +1 -0
index 4488cd9..9bd455c 100644
@@ -262,6 +262,91 @@ static void test_uintset_foreach(const void *data)
  	l_uintset_free(check);
  }
 
+static void test_uintset_intersect_1(const void *data)

Can this be a bit more descriptive, e.g. intersect_invalid, intersect_sanity, etc

Quoted 23 lines
unit/test-uintset.c +23 -0
+{
+	struct l_uintset *set_a;
+	struct l_uintset *set_b;
+
+	assert(!l_uintset_intersect(NULL, NULL));
+
+	set_a = l_uintset_new_from_range(0, 5);
+	assert(!l_uintset_intersect(NULL, set_a));
+	assert(!l_uintset_intersect(set_a, NULL));
+
+	set_b = l_uintset_new_from_range(4, 10);
+	assert(!l_uintset_intersect(set_a, set_b));
+
+	l_uintset_free(set_a);
+	l_uintset_free(set_b);
+}
+
+struct uintset_data {
+	uint32_t min;
+	uint32_t max;
+	uint32_t *vals;
+	uint32_t size;
+};

unit/test-uintset.c static void test_uintset_foreach(const void *data) · line 298

Quoted 10 lines
unit/test-uintset.c +10 -0
+
+struct uintset_intersect_data {
+	const struct uintset_data set_a;
+	const struct uintset_data set_b;
+	const struct uintset_data set_r;
+};
+
+uint32_t vals1[] = { 1, 2, 3 };
+uint32_t vals2[] = { 3, 4};
+uint32_t vals3[] = { 3 };

These should be static const

unit/test-uintset.c static void test_uintset_foreach(const void *data) · line 309

Quoted 11 lines
unit/test-uintset.c +11 -0
+
+static const struct uintset_intersect_data intersect_data_1 = {
+	.set_a = { 0, 4, vals1, L_ARRAY_SIZE(vals1) },
+	.set_b = { 0, 4, vals2, L_ARRAY_SIZE(vals2) },
+	.set_r = { 0, 4, vals3, L_ARRAY_SIZE(vals3) },
+};
+
+uint32_t vals4[] = { 0, 1, 64, 127 };
+uint32_t vals5[] = { 1, 25, 64, 66, 127, 135 };
+uint32_t vals6[] = { 1, 64, 127 };
+

And these

Quoted 44 lines
unit/test-uintset.c +40 -0
+static const struct uintset_intersect_data intersect_data_2 = {
+	.set_a = { 0, 191, vals4, L_ARRAY_SIZE(vals4) },
+	.set_b = { 0, 191, vals5, L_ARRAY_SIZE(vals5) },
+	.set_r = { 0, 191, vals6, L_ARRAY_SIZE(vals6) },
+};
+
+static void test_uintset_intersect_2(const void *user_data)
+{
+	const struct uintset_intersect_data *data = user_data;
+	struct l_uintset *set_a;
+	struct l_uintset *set_b;
+	struct l_uintset *set_r;
+	size_t i;
+
+	set_a = l_uintset_new_from_range(data->set_a.min, data->set_a.max);
+
+	for (i = 0; i < data->set_a.size; i++)
+		l_uintset_put(set_a, data->set_a.vals[i]);
+
+	set_b = l_uintset_new_from_range(data->set_b.min, data->set_b.max);
+
+	for (i = 0; i < data->set_b.size; i++)
+		l_uintset_put(set_b, data->set_b.vals[i]);
+
+	set_r = l_uintset_intersect(set_a, set_b);
+
+	assert(set_r);
+
+	for (i = 0; i < data->set_r.size; i++) {
+		assert(l_uintset_contains(set_r, data->set_r.vals[i]));
+		assert(l_uintset_take(set_r, data->set_r.vals[i]));
+	}
+
+	assert(l_uintset_find_max(set_r) == l_uintset_get_max(set_r) + 1);
+
+	l_uintset_free(set_a);
+	l_uintset_free(set_b);
+	l_uintset_free(set_r);
+}
+
  int main(int argc, char *argv[])
  {
  	l_test_init(&argc, &argv);

unit/test-uintset.c int main(int argc, char *argv[]) · line 366

Quoted 9 lines
unit/test-uintset.c +6 -0
@@ -273,6 +358,12 @@ int main(int argc, char *argv[])
  	l_test_add("l_uintset for each tests", test_uintset_foreach, NULL);
  	l_test_add("l_uintset find unused tests", test_uintset_find_unused,
  							NULL);
+	l_test_add("l_uintset intersect sanity check", test_uintset_intersect_1,
+									NULL);
+	l_test_add("l_uintset intersect test 1", test_uintset_intersect_2,
+							&intersect_data_1);
+	l_test_add("l_uintset intersect test2", test_uintset_intersect_2,
+							&intersect_data_2);

Nitpick, but you have 'test 1' and then 'test2'. Be consistent :)

unit/test-uintset.c int main(int argc, char *argv[])

Quoted 4 lines
unit/test-uintset.c +0 -0
  	return l_test_run();
  }
 

Regards,
-Denis

#3 lore raw
In reply to Tim Kourt
Quoted 7 lines · Tim Kourt

l_uintset_intersect computes the intersection of two sets of an equal base.

---
  ell/uintset.c | 37 +++++++++++++++++++++++++++++++++++++
  ell/uintset.h |  3 +++
  2 files changed, 40 insertions(+)

Applied. But note that since you're adding a new public API, you should also add an entry to ell/ell.sym. This is a necessary manual step at the moment until Marcel fixes the build system to do this properly.

Anyhow, I fixed this for you in a follow-on commit.

Regards,
-Denis