All of lore.kernel.org
 help / color / mirror / Atom feed
* [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 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.