]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
cursor: Add intersection functions
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 2 Apr 2020 15:06:00 +0000 (09:06 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 2 Apr 2020 15:08:51 +0000 (09:08 -0600)
src/lib/util/cursor.c
src/lib/util/cursor.h

index 994d922984dc22f0cced2c1d3205928365da3711..5be7d695a5040b81c5300bbe57da4f9ccbbe3c8f 100644 (file)
@@ -33,7 +33,7 @@ RCSID("$Id$")
 
 #define NEXT_PTR(_v) ((void **)(((uint8_t *)(_v)) + cursor->offset))
 
-/** Internal function to get the next attribute
+/** Internal function to get the next item
  *
  * @param[in,out] prev attribute to the one we returned.  May be NULL.
  * @param[in] cursor   to operate on.
@@ -402,6 +402,88 @@ void fr_cursor_merge(fr_cursor_t *cursor, fr_cursor_t *to_append)
        }
 }
 
+/** Return the first item matching the iterator in cursor a and cursor b
+ *
+ * @param[in] a                First cursor.
+ * @param[in] b                Second cursor.
+ * @return item at the start of the list.
+ */
+void *fr_cursor_intersect_head(fr_cursor_t *a, fr_cursor_t *b)
+{
+       void *a_item, *b_item;
+
+       a_item = fr_cursor_head(a);
+       b_item = fr_cursor_head(b);
+
+       if (a_item == b_item) return a_item;
+
+       return fr_cursor_intersect_next(a, b);
+}
+
+/** Return the next item matching the iterator in cursor a and cursor b
+ *
+ * @param[in] a                First cursor.
+ * @param[in] b                Second cursor.
+ * @return next item in the list.
+ */
+void *fr_cursor_intersect_next(fr_cursor_t *a, fr_cursor_t *b)
+{
+       fr_cursor_iter_t b_iter;
+
+       /*
+        *      If either of the iterators lack an iterator
+        *      just use cursor_next...
+        */
+       if (!a->iter) return fr_cursor_next(b);
+       if (!b->iter) return fr_cursor_next(a);
+
+       /*
+        *      Both have iterators...
+        */
+       b_iter = b->iter;
+
+       /*
+        *      Use a's iterator to select the item to
+        *      check.
+        */
+       while ((a->current = cursor_next(&a->prev, a, a->current))) {
+               b->iter = NULL;         /* Disable B's iterator */
+
+               /*
+                *      Find a in b (the slow way *sigh*)
+                */
+               while ((b->current = cursor_next(&b->prev, b, b->current)) && (b->current != a->prev));
+
+               /*
+                *      No more items...
+                */
+               if (!b->current) {
+                       fr_cursor_copy(a, b);
+                       return NULL;
+               }
+
+               /*
+                *      We're now one item before the item
+                *      returned by a, see if b's iterator
+                *      returns the same item as a's.
+                */
+                b->iter = b_iter;
+                b->current = cursor_next(&b->prev, b, b->current);
+
+               /*
+                *      Matched, we're done...
+                */
+               if (a->current == b->current) return a->current;
+
+               /*
+                *      Reset b's position to a's and try again.
+                */
+               fr_cursor_copy(b, a);
+       }
+
+       return NULL;
+}
+
 /** Remove the current item
  *
  * The current item will be set to the one after the item
index 99b82fae69a636088a27f5f203d1acc1c94551d4..559c7af1183e4d86f0c692a907c56efb479d6556 100644 (file)
@@ -83,6 +83,10 @@ void fr_cursor_insert(fr_cursor_t *cursor, void *v) CC_HINT(nonnull);
 
 void fr_cursor_merge(fr_cursor_t *cursor, fr_cursor_t *to_append) CC_HINT(nonnull);
 
+void *fr_cursor_intersect_head(fr_cursor_t *a, fr_cursor_t *b) CC_HINT(nonnull);
+
+void *fr_cursor_intersect_next(fr_cursor_t *a, fr_cursor_t *b) CC_HINT(nonnull);
+
 void *fr_cursor_remove(fr_cursor_t *cursor) CC_HINT(nonnull);
 
 void *fr_cursor_replace(fr_cursor_t *cursor, void *r) CC_HINT(nonnull);