* [PATCH 1/2] uintset: Add l_uintset_intersect
@ 2019-03-07 0:17 Tim Kourt
2019-03-07 0:17 ` [PATCH 2/2] unit: Add l_uintset_intersect tests Tim Kourt
2019-03-07 16:11 ` [PATCH 1/2] uintset: Add l_uintset_intersect Denis Kenzior
0 siblings, 2 replies; 7+ messages in thread
From: Tim Kourt @ 2019-03-07 0:17 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 2167 bytes --]
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(+)
diff --git a/ell/uintset.c b/ell/uintset.c
index 3f20098..60a9822 100644
--- a/ell/uintset.c
+++ b/ell/uintset.c
@@ -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;
+}
diff --git a/ell/uintset.h b/ell/uintset.h
index dd03cd7..c05a21b 100644
--- a/ell/uintset.h
+++ b/ell/uintset.h
@@ -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
--
2.13.6
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/2] unit: Add l_uintset_intersect tests
2019-03-07 0:17 [PATCH 1/2] uintset: Add l_uintset_intersect Tim Kourt
@ 2019-03-07 0:17 ` Tim Kourt
2019-03-07 16:13 ` Denis Kenzior
2019-03-07 16:11 ` [PATCH 1/2] uintset: Add l_uintset_intersect Denis Kenzior
1 sibling, 1 reply; 7+ messages in thread
From: Tim Kourt @ 2019-03-07 0:17 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 3332 bytes --]
---
unit/test-uintset.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 91 insertions(+)
diff --git a/unit/test-uintset.c b/unit/test-uintset.c
index 4488cd9..9bd455c 100644
--- a/unit/test-uintset.c
+++ b/unit/test-uintset.c
@@ -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();
}
--
2.13.6
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] uintset: Add l_uintset_intersect
2019-03-07 0:17 [PATCH 1/2] uintset: Add l_uintset_intersect Tim Kourt
2019-03-07 0:17 ` [PATCH 2/2] unit: Add l_uintset_intersect tests Tim Kourt
@ 2019-03-07 16:11 ` Denis Kenzior
1 sibling, 0 replies; 7+ messages in thread
From: Denis Kenzior @ 2019-03-07 16:11 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 559 bytes --]
On 03/06/2019 06:17 PM, Tim Kourt wrote:
> 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
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] unit: Add l_uintset_intersect tests
2019-03-07 0:17 ` [PATCH 2/2] unit: Add l_uintset_intersect tests Tim Kourt
@ 2019-03-07 16:13 ` Denis Kenzior
0 siblings, 0 replies; 7+ messages in thread
From: Denis Kenzior @ 2019-03-07 16:13 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 3844 bytes --]
Hi Tim,
On 03/06/2019 06:17 PM, Tim Kourt wrote:
> ---
> unit/test-uintset.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 91 insertions(+)
>
> diff --git a/unit/test-uintset.c b/unit/test-uintset.c
> index 4488cd9..9bd455c 100644
> --- a/unit/test-uintset.c
> +++ b/unit/test-uintset.c
> @@ -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
> +{
> + 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 };
These should be static const
> +
> +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
> +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);
Nitpick, but you have 'test 1' and then 'test2'. Be consistent :)
>
> return l_test_run();
> }
>
Regards,
-Denis
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] uintset: Add l_uintset_intersect
2019-03-05 20:35 Tim Kourt
2019-03-05 21:12 ` Andrew Zaborowski
@ 2019-03-05 21:47 ` Denis Kenzior
1 sibling, 0 replies; 7+ messages in thread
From: Denis Kenzior @ 2019-03-05 21:47 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 1716 bytes --]
Hi Tim,
On 03/05/2019 02:35 PM, Tim Kourt wrote:
> l_uintset_intersect computes the intersection of two sets.
> In addition, it introduces find_next_bit(…) that is used to
> efficiently loop through the set bits in the set and may have
> multiple implication in the future.
implications or applications? If it is the first, that sounds ominous...
> ---
> ell/uintset.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ell/uintset.h | 3 ++
> 2 files changed, 99 insertions(+)
>
<snip>
> +
> +/**
> + * l_uintset_intersect:
> + * @set_a: The set of numbers
> + * @set_b: The set of numbers
> + *
> + * Returns: A newly allocated l_uintset object containing intersection of
> + * @set_a and @set_b. If @set_a and @set_b cannot be intersected 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 min;
> + uint32_t max;
> + unsigned int bit_a;
> + unsigned int bit_b;
> +
> + if (unlikely(!set_a) || unlikely(!set_b))
> + return NULL;
> +
> + if (set_a->max < set_b->min || set_b->max < set_a->min)
> + return NULL;
So honestly I would implement a fast version which works for sets where
min and max are the same. This is really what you want anyway for the
scan_freq_set stuff, right? That should be a very simple bitwise and
operation...
I'm not completely sure of the utility of this more generalized
intersect operation that you have implemented here. Do you foresee a
need for something like this?
Regards,
-Denis
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] uintset: Add l_uintset_intersect
2019-03-05 20:35 Tim Kourt
@ 2019-03-05 21:12 ` Andrew Zaborowski
2019-03-05 21:47 ` Denis Kenzior
1 sibling, 0 replies; 7+ messages in thread
From: Andrew Zaborowski @ 2019-03-05 21:12 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 4661 bytes --]
Hi Tim,
On Tue, 5 Mar 2019 at 21:35, Tim Kourt <tim.a.kourt@linux.intel.com> wrote:
> l_uintset_intersect computes the intersection of two sets.
> In addition, it introduces find_next_bit(…) that is used to
> efficiently loop through the set bits in the set and may have
> multiple implication in the future.
> ---
> ell/uintset.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ell/uintset.h | 3 ++
> 2 files changed, 99 insertions(+)
>
> diff --git a/ell/uintset.c b/ell/uintset.c
> index 1d96e68..6b657b8 100644
> --- a/ell/uintset.c
> +++ b/ell/uintset.c
> @@ -122,6 +122,49 @@ static unsigned long find_last_bit(const unsigned long *addr, unsigned int size)
> return size;
> }
>
> +static unsigned long find_next_bit(const unsigned long *addr,
> + unsigned long size,
> + unsigned long bit)
> +{
> + unsigned long mask;
> + unsigned long offset;
> +
> + if (bit >= size)
> + return size;
> +
> + addr += bit / BITS_PER_LONG;
> + offset = bit % BITS_PER_LONG;
> + bit -= offset;
> +
> + if (offset) {
> + mask = *addr & ~(~0UL >> (BITS_PER_LONG - offset));
> + if (mask)
> + return bit + __ffs(mask);
> +
> + bit += BITS_PER_LONG;
> + addr++;
> + }
> +
> + for (size -= bit; size >= BITS_PER_LONG;
> + size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {
> + if (!*addr)
> + continue;
> +
> + return bit + __ffs(*addr);
> + }
> +
> + if (!size)
> + return bit;
> +
> + mask = *addr & (~0UL >> (BITS_PER_LONG - size));
> + if (mask)
> + bit += __ffs(mask);
> + else
> + bit += size;
> +
> + return bit;
> +}
> +
> struct l_uintset {
> unsigned long *bits;
> uint16_t size;
> @@ -404,3 +447,56 @@ LIB_EXPORT uint32_t l_uintset_find_min(struct l_uintset *set)
>
> return bit + set->min;
> }
> +
> +/**
> + * l_uintset_intersect:
> + * @set_a: The set of numbers
> + * @set_b: The set of numbers
> + *
> + * Returns: A newly allocated l_uintset object containing intersection of
> + * @set_a and @set_b. If @set_a and @set_b cannot be intersected 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 min;
> + uint32_t max;
> + unsigned int bit_a;
> + unsigned int bit_b;
> +
> + if (unlikely(!set_a) || unlikely(!set_b))
> + return NULL;
> +
> + if (set_a->max < set_b->min || set_b->max < set_a->min)
> + return NULL;
> +
> + min = set_a->min <= set_b->min ? set_a->min : set_b->min;
So this basically does min = MIN(set_a->min, set_b->min) but could
safely do MAX(...).
> + max = set_a->max >= set_b->max ? set_a->max : set_b->max;
> +
> + intersection = l_uintset_new_from_range(min, max);
> +
> + bit_a = find_first_bit(set_a->bits, set_a->size);
> + bit_b = find_first_bit(set_b->bits, set_b->size);
> +
> + while (bit_a < set_a->size && bit_b < set_b->size) {
> + if (set_a->min + bit_a < set_b->min + bit_b) {
> + bit_a = find_next_bit(set_a->bits, set_a->size,
> + bit_a + 1);
> + continue;
> + }
> +
> + if (set_a->min + bit_a > set_b->min + bit_b) {
> + bit_b = find_next_bit(set_b->bits, set_b->size,
> + bit_b + 1);
> + continue;
> + }
> +
> + l_uintset_put(intersection, set_a->min + bit_a);
> + bit_a = find_next_bit(set_a->bits, set_a->size, bit_a + 1);
> + bit_b = find_next_bit(set_b->bits, set_b->size, bit_b + 1);
> + }
Here you could also assign entire words in intersection->bits (with
some shifting required) and skip to the next non-zero word afterwards
although that wouldn't even be much faster than just assigning 0 by
&ing the words from set_a and set_b.
Best regards
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/2] uintset: Add l_uintset_intersect
@ 2019-03-05 20:35 Tim Kourt
2019-03-05 21:12 ` Andrew Zaborowski
2019-03-05 21:47 ` Denis Kenzior
0 siblings, 2 replies; 7+ messages in thread
From: Tim Kourt @ 2019-03-05 20:35 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 3673 bytes --]
l_uintset_intersect computes the intersection of two sets.
In addition, it introduces find_next_bit(…) that is used to
efficiently loop through the set bits in the set and may have
multiple implication in the future.
---
ell/uintset.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ell/uintset.h | 3 ++
2 files changed, 99 insertions(+)
diff --git a/ell/uintset.c b/ell/uintset.c
index 1d96e68..6b657b8 100644
--- a/ell/uintset.c
+++ b/ell/uintset.c
@@ -122,6 +122,49 @@ static unsigned long find_last_bit(const unsigned long *addr, unsigned int size)
return size;
}
+static unsigned long find_next_bit(const unsigned long *addr,
+ unsigned long size,
+ unsigned long bit)
+{
+ unsigned long mask;
+ unsigned long offset;
+
+ if (bit >= size)
+ return size;
+
+ addr += bit / BITS_PER_LONG;
+ offset = bit % BITS_PER_LONG;
+ bit -= offset;
+
+ if (offset) {
+ mask = *addr & ~(~0UL >> (BITS_PER_LONG - offset));
+ if (mask)
+ return bit + __ffs(mask);
+
+ bit += BITS_PER_LONG;
+ addr++;
+ }
+
+ for (size -= bit; size >= BITS_PER_LONG;
+ size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {
+ if (!*addr)
+ continue;
+
+ return bit + __ffs(*addr);
+ }
+
+ if (!size)
+ return bit;
+
+ mask = *addr & (~0UL >> (BITS_PER_LONG - size));
+ if (mask)
+ bit += __ffs(mask);
+ else
+ bit += size;
+
+ return bit;
+}
+
struct l_uintset {
unsigned long *bits;
uint16_t size;
@@ -404,3 +447,56 @@ LIB_EXPORT uint32_t l_uintset_find_min(struct l_uintset *set)
return bit + set->min;
}
+
+/**
+ * l_uintset_intersect:
+ * @set_a: The set of numbers
+ * @set_b: The set of numbers
+ *
+ * Returns: A newly allocated l_uintset object containing intersection of
+ * @set_a and @set_b. If @set_a and @set_b cannot be intersected 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 min;
+ uint32_t max;
+ unsigned int bit_a;
+ unsigned int bit_b;
+
+ if (unlikely(!set_a) || unlikely(!set_b))
+ return NULL;
+
+ if (set_a->max < set_b->min || set_b->max < set_a->min)
+ return NULL;
+
+ min = set_a->min <= set_b->min ? set_a->min : set_b->min;
+ max = set_a->max >= set_b->max ? set_a->max : set_b->max;
+
+ intersection = l_uintset_new_from_range(min, max);
+
+ bit_a = find_first_bit(set_a->bits, set_a->size);
+ bit_b = find_first_bit(set_b->bits, set_b->size);
+
+ while (bit_a < set_a->size && bit_b < set_b->size) {
+ if (set_a->min + bit_a < set_b->min + bit_b) {
+ bit_a = find_next_bit(set_a->bits, set_a->size,
+ bit_a + 1);
+ continue;
+ }
+
+ if (set_a->min + bit_a > set_b->min + bit_b) {
+ bit_b = find_next_bit(set_b->bits, set_b->size,
+ bit_b + 1);
+ continue;
+ }
+
+ l_uintset_put(intersection, set_a->min + bit_a);
+ bit_a = find_next_bit(set_a->bits, set_a->size, bit_a + 1);
+ bit_b = find_next_bit(set_b->bits, set_b->size, bit_b + 1);
+ }
+
+ return intersection;
+}
diff --git a/ell/uintset.h b/ell/uintset.h
index 474c5e4..9986086 100644
--- a/ell/uintset.h
+++ b/ell/uintset.h
@@ -50,6 +50,9 @@ uint32_t l_uintset_find_min(struct l_uintset *set);
uint32_t l_uintset_find_unused_min(struct l_uintset *set);
uint32_t l_uintset_find_unused(struct l_uintset *set, uint32_t start);
+struct l_uintset *l_uintset_intersect(const struct l_uintset *set_a,
+ const struct l_uintset *set_b);
+
#ifdef __cplusplus
}
#endif
--
2.13.6
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2019-03-07 16:13 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-07 0:17 [PATCH 1/2] uintset: Add l_uintset_intersect Tim Kourt
2019-03-07 0:17 ` [PATCH 2/2] unit: Add l_uintset_intersect tests Tim Kourt
2019-03-07 16:13 ` Denis Kenzior
2019-03-07 16:11 ` [PATCH 1/2] uintset: Add l_uintset_intersect Denis Kenzior
-- strict thread matches above, loose matches on Subject: below --
2019-03-05 20:35 Tim Kourt
2019-03-05 21:12 ` Andrew Zaborowski
2019-03-05 21:47 ` Denis Kenzior
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.