]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Fix various issues with dcursor that would prevent them from working correctly with...
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sat, 8 Jan 2022 00:29:54 +0000 (16:29 -0800)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sat, 8 Jan 2022 00:30:09 +0000 (16:30 -0800)
src/lib/io/schedule.c
src/lib/util/dcursor.c
src/lib/util/dcursor.h
src/lib/util/dcursor_tests.c
src/lib/util/pair.c

index 0faf3b08dfeb4534a39ade9553b5f010a1785038..8a938c00174d57afac4fd24867fb7579683d7a6c 100644 (file)
@@ -222,8 +222,8 @@ static void *fr_schedule_worker_thread(void *arg)
         *      Add this worker to all network threads.
         */
        for (sn = fr_dlist_head(&sc->networks);
-              sn != NULL;
-              sn = fr_dlist_next(&sc->networks, sn)) {
+            sn != NULL;
+            sn = fr_dlist_next(&sc->networks, sn)) {
                (void) fr_network_worker_add(sn->nr, sw->worker);
        }
 
index 5d425d2157b79b9b3d30b526be2a9a6e41c10ff2..b54fca9beb8aca1564ba60ac5304ac4c59cf4c59 100644 (file)
@@ -63,6 +63,8 @@ void *fr_dcursor_intersect_head(fr_dcursor_t *a, fr_dcursor_t *b)
  * If a and b are not currently set to the same item, b will be reset,
  * and wound to the item before a's current item.
  *
+ * The purpose of this function is to return items that match both iterators.
+ *
  * @note Both cursors must operate on the same list of items.
  *
  * @param[in] a                First cursor.
@@ -73,76 +75,51 @@ void *fr_dcursor_intersect_head(fr_dcursor_t *a, fr_dcursor_t *b)
  */
 void *fr_dcursor_intersect_next(fr_dcursor_t *a, fr_dcursor_t *b)
 {
-       fr_dcursor_iter_t       b_iter;
-       void                    *b_uctx;
+       void *a_next, *b_next;
 
        if (unlikely(a->dlist != b->dlist)) return NULL;
 
        /*
-        *      If either of the iterators lack an iterator
-        *      just use cursor_next...
+        *      If either of the cursors lack an iterator
+        *      just use cursor_next... i.e. return items
+        *      from the list that's actually filtered.
         */
        if (!a->iter) return fr_dcursor_next(b);
        if (!b->iter) return fr_dcursor_next(a);
 
-       /*
-        *      Both have iterators...
-        */
-       b_iter = b->iter;
-       b_uctx = b->iter_uctx;
-
        /*
         *      Deal with the case where the two iterators
         *      are out of sync.
         */
-       if (a->current != b->current) {
-               fr_dcursor_head(b);     /* reset */
+       if (a->current == b->current) {
+               a_next = fr_dcursor_next(a);
+               b_next = fr_dcursor_next(b);
+
+               /*
+                *      Fast path...
+                */
+               if (a_next == b_next) return a_next;
        } else {
-               a->current = dcursor_next(a, a->current);
-               a->prev = fr_dlist_prev(a->dlist, a->current);
+               a_next = fr_dcursor_next(a);
        }
 
+       if (!a_next) return NULL;
+
        /*
-        *      Use a's iterator to select the item to
-        *      check.
+        *      b_next doesn't match a_next, we don't know
+        *      if b is ahead or behind a, so we rewind
+        *      b, and compare every item to see if it
+        *      matches a.
+        *
+        *      This is slow and inefficient, but there's
+        *      nothing else we can do for stateful
+        *      iterators.
         */
        do {
-               void *a_prev = fr_dcursor_list_prev_peek(a);
-               b->iter = NULL;         /* Disable b's iterator */
-
-               /*
-                *      Find a in b (the slow way *sigh*)
-                */
-               while ((b->current = dcursor_next(b, b->current)) && (b->current != a_prev));
-
-               /*
-                *      No more items...
-                */
-               if (!b->current) {
-                       fr_dcursor_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 = dcursor_next(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_dcursor_copy(b, a);
-               b->iter = b_iter;
-               b->iter_uctx = b_uctx;
-       } while ((a->current = dcursor_next(a, a->current)));
+               for (b_next = fr_dcursor_head(b);
+                    b_next;
+                    b_next = fr_dcursor_next(b)) if (a_next == b_next) return b_next;
+       } while ((a_next = fr_dcursor_next(a)));
 
        return NULL;
 }
index 382c409c1521cd404ca1ca1dd06085f4e40929b8..8a05b0096cd52bab45c32291c5c7d68916bc8d5e 100644 (file)
@@ -34,6 +34,8 @@ extern "C" {
 #include <stddef.h>
 #include <stdbool.h>
 
+typedef struct fr_dcursor_s fr_dcursor_t;
+
 /** Callback for implementing custom iterators
  *
  * @param[in] list     head of the dlist.
@@ -46,6 +48,7 @@ extern "C" {
  *     - NULL if no more matching attributes were found.
  */
 typedef void *(*fr_dcursor_iter_t)(fr_dlist_head_t *list, void *to_eval, void *uctx);
+
 /** Callback for performing additional actions on insert
  *
  * @param[in] list     head of the dlist.
@@ -56,6 +59,7 @@ typedef void *(*fr_dcursor_iter_t)(fr_dlist_head_t *list, void *to_eval, void *u
  *     - -1 on failure.
  */
 typedef int (*fr_dcursor_insert_t)(fr_dlist_head_t *list, void *to_insert, void *uctx);
+
 /** Callback for performing additional actions on removal
  *
  * @param[in] list     head of the dlist.
@@ -66,6 +70,14 @@ typedef int (*fr_dcursor_insert_t)(fr_dlist_head_t *list, void *to_insert, void
  *     - -1 on failure.
  */
 typedef int (*fr_dcursor_remove_t)(fr_dlist_head_t *list, void *to_delete, void *uctx);
+
+/** Copy callback for duplicating complex dcursor state
+ *
+ * @param[out] out     dcursor to copy to.
+ * @param[in] in       dcursor to copy from.
+ */
+typedef void (*fr_dcursor_copy_t)(fr_dcursor_t *out, fr_dcursor_t const *in);
+
 /** Type of evaluation functions to pass to the fr_dcursor_filter_*() functions.
  *
  * @param[in] item     the item to be evaluated
@@ -75,17 +87,25 @@ typedef int (*fr_dcursor_remove_t)(fr_dlist_head_t *list, void *to_delete, void
  *     - false if the evaluation function is not satisfied.
  */
 typedef bool (*fr_dcursor_eval_t)(void const *item, void const *uctx);
-typedef struct {
+
+struct fr_dcursor_s {
        fr_dlist_head_t         *dlist;         //!< Head of the doubly linked list being iterated over.
        void                    *current;       //!< The current item in the dlist.
-       void                    *prev;          //!< The previous item in the dlist.
+
        fr_dcursor_iter_t       iter;           //!< Iterator function.
+       fr_dcursor_iter_t       peek;           //!< Distinct "peek" function.  This is sometimes necessary
+                                               ///< for iterators with complex state.
        void                    *iter_uctx;     //!< to pass to iterator function.
+
        fr_dcursor_insert_t     insert;         //!< Callback function on insert.
        fr_dcursor_remove_t     remove;         //!< Callback function on delete.
        void                    *mod_uctx;      //!< to pass to modification functions.
+
+       fr_dcursor_copy_t       copy;           //!< Copy dcursor state.
+
        bool                    is_const;       //!< The list we're iterating over is immutable.
-} fr_dcursor_t;
+       bool                    at_end;         //!< We're at the end of the list.
+};
 
 typedef struct {
        uint8_t                 depth;          //!< Which cursor is currently in use.
@@ -98,6 +118,20 @@ typedef struct {
 #define VALIDATE(_item)
 #endif
 
+/** If current is set to a NULL pointer, we record that fact
+ *
+ * This stops us jumping back to the start of the dlist.
+ */
+static inline void *dcursor_current_set(fr_dcursor_t *cursor, void *current)
+{
+       VALIDATE(current);
+
+       cursor->at_end = (current == NULL);
+       cursor->current = current;
+
+       return current;
+}
+
 /** Internal function to get the next item
  *
  * @param[in] cursor   to operate on.
@@ -106,29 +140,27 @@ typedef struct {
  *     - The next attribute.
  *     - NULL if no more attributes.
  */
-static inline void *dcursor_next(fr_dcursor_t *cursor, void *current)
+static inline void *dcursor_next(fr_dcursor_t *cursor, fr_dcursor_iter_t iter, void *current)
 {
        void *next;
 
        /*
-        *      First time next has been called
+        *      First time next has been called, or potentially
+        *      another call after we hit the end of the list.
         */
        if (!current) {
-               if (fr_dlist_empty(cursor->dlist)) return NULL;
-               if (cursor->prev) return NULL;                                  /* At tail of the list */
-               if (!cursor->iter) return (fr_dlist_head(cursor->dlist));       /* Fast path without custom iter */
+               if (cursor->at_end) return NULL;                                /* At tail of the list */
+
+               if (!iter) return (fr_dlist_head(cursor->dlist));               /* Fast path without custom iter */
 
                current = fr_dlist_head(cursor->dlist);
-               next = cursor->iter(cursor->dlist, current, cursor->iter_uctx);
+               next = iter(cursor->dlist, current, cursor->iter_uctx);
                VALIDATE(next);
                return next;
        }
-
        VALIDATE(current);
 
-       if (!cursor->iter) {
-               return fr_dlist_next(cursor->dlist, current);                   /* Fast path without custom iter */
-       }
+       if (!iter) return fr_dlist_next(cursor->dlist, current);                /* Fast path without custom iter */
 
        /*
         *      Pre-advance current
@@ -140,8 +172,9 @@ static inline void *dcursor_next(fr_dcursor_t *cursor, void *current)
         *      The iterator can just return what it was passed for curr
         *      if it just wants to advance by one.
         */
-       next = cursor->iter(cursor->dlist, next, cursor->iter_uctx);
+       next = iter(cursor->dlist, next, cursor->iter_uctx);
        VALIDATE(next);
+
        return next;
 }
 
@@ -155,6 +188,8 @@ static inline void *dcursor_next(fr_dcursor_t *cursor, void *current)
 static inline void fr_dcursor_copy(fr_dcursor_t *out, fr_dcursor_t const *in)
 {
        memcpy(out, in, sizeof(*out));
+
+       if (in->copy) fr_dcursor_copy(out, in);
 }
 
 /** Rewind cursor to the start of the list
@@ -164,11 +199,9 @@ static inline void fr_dcursor_copy(fr_dcursor_t *out, fr_dcursor_t const *in)
  *
  * @hidecallergraph
  */
+CC_HINT(nonnull)
 static inline void *fr_dcursor_head(fr_dcursor_t *cursor)
 {
-       if (unlikely(!cursor)) return NULL;
-
-       cursor->prev = NULL;
        /*
         *      If we have a custom iterator, the dlist attribute
         *      may not be in the subset the iterator would
@@ -176,15 +209,12 @@ static inline void *fr_dcursor_head(fr_dcursor_t *cursor)
         *      dcursor_next figure it out.
         */
        if (cursor->iter) {
-               cursor->current = dcursor_next(cursor, NULL);
-               return cursor->current;
-       }
-
-       cursor->current = fr_dlist_head(cursor->dlist);
+               cursor->at_end = false; /* reset the flag, else next will just return NULL */
 
-       VALIDATE(cursor->current);
+               return dcursor_current_set(cursor, dcursor_next(cursor, cursor->iter, NULL));
+       }
 
-       return cursor->current;
+       return dcursor_current_set(cursor, fr_dlist_head(cursor->dlist));
 }
 
 /** Wind cursor to the tail item in the list
@@ -194,20 +224,24 @@ static inline void *fr_dcursor_head(fr_dcursor_t *cursor)
  *
  * @hidecallergraph
  */
+CC_HINT(nonnull)
 static inline void *fr_dcursor_tail(fr_dcursor_t *cursor)
 {
-       if (!cursor || fr_dlist_empty(cursor->dlist)) return NULL;
+       /*
+        *      Keep calling next on the custom iterator
+        *      until we hit the end of the list.
+        */
+       if (cursor->iter) {
+               void *current = cursor->current;
 
-       cursor->current = fr_dlist_tail(cursor->dlist);
-       if (cursor->current) {
-               cursor->prev = fr_dlist_prev(cursor->dlist, cursor->current);
-       } else {
-               cursor->prev = NULL;
-       }
+               while ((cursor->current = dcursor_next(cursor, cursor->iter, cursor->current))) {
+                       current = cursor->current;
+               }
 
-       VALIDATE(cursor->current);
+               return dcursor_current_set(cursor, current);
+       }
 
-       return cursor->current;
+       return dcursor_current_set(cursor, fr_dlist_tail(cursor->dlist));
 }
 
 /** Advanced the cursor to the next item
@@ -219,16 +253,10 @@ static inline void *fr_dcursor_tail(fr_dcursor_t *cursor)
  *
  * @hidecallergraph
  */
-static inline void * fr_dcursor_next(fr_dcursor_t *cursor)
+CC_HINT(nonnull)
+static inline void *fr_dcursor_next(fr_dcursor_t *cursor)
 {
-       if (!cursor || fr_dlist_empty(cursor->dlist)) return NULL;
-       cursor->current = dcursor_next(cursor, cursor->current);
-
-       cursor->prev = fr_dlist_prev(cursor->dlist, cursor->current);
-
-       VALIDATE(cursor->current);
-
-       return cursor->current;
+       return dcursor_current_set(cursor, dcursor_next(cursor, cursor->iter, cursor->current));
 }
 
 /** Return the next iterator item without advancing the cursor
@@ -240,9 +268,10 @@ static inline void * fr_dcursor_next(fr_dcursor_t *cursor)
  *
  * @hidecallergraph
  */
+CC_HINT(nonnull)
 static inline void *fr_dcursor_next_peek(fr_dcursor_t *cursor)
 {
-       return dcursor_next(cursor, cursor->current);
+       return dcursor_next(cursor, cursor->peek, cursor->current);
 }
 
 /** Returns the next list item without advancing the cursor
@@ -258,36 +287,10 @@ static inline void *fr_dcursor_next_peek(fr_dcursor_t *cursor)
  *
  * @hidecallergraph
  */
+CC_HINT(nonnull)
 static inline void *fr_dcursor_list_next_peek(fr_dcursor_t *cursor)
 {
-       if (!cursor || !cursor->current) return NULL;
-
-       return fr_dlist_next(cursor->dlist, cursor->current);
-}
-
-/** Returns the previous list item without rewinding the cursor
- *
- * @note This returns the previous item in the list, which may not be the
- *      previous 'current' value.
- *
- * @param[in] cursor to operator on.
- * @return
- *     - Previous item.
- *     - NULL if no previous item available.
- *
- * @hidecallergraph
- */
-static inline void *fr_dcursor_list_prev_peek(fr_dcursor_t *cursor)
-{
-       if (unlikely(!cursor)) return NULL;
-
-       /*
-        *      If cursor->current is not set then there's no prev.
-        *      fr_dlist_prev would return the tail
-        */
-       if (!cursor->prev) return NULL;
-
-       return fr_dlist_prev(cursor->dlist, cursor->current);
+       return dcursor_next(cursor, NULL, cursor->current);
 }
 
 /** Return the item the cursor current points to
@@ -299,12 +302,10 @@ static inline void *fr_dcursor_list_prev_peek(fr_dcursor_t *cursor)
  *
  * @hidecallergraph
  */
+CC_HINT(nonnull)
 static inline void *fr_dcursor_current(fr_dcursor_t *cursor)
 {
-       if (unlikely(!cursor)) return NULL;
-
        VALIDATE(cursor->current);
-
        return cursor->current;
 }
 
@@ -318,24 +319,15 @@ static inline void *fr_dcursor_current(fr_dcursor_t *cursor)
  *
  * @hidecallergraph
  */
-static inline void * fr_dcursor_set_current(fr_dcursor_t *cursor, void *item)
+static inline void *fr_dcursor_set_current(fr_dcursor_t *cursor, void *item)
 {
        if (!fr_cond_assert_msg(!cursor->is_const, "attempting to modify const list")) return NULL;
 
-       if (fr_dlist_empty(cursor->dlist)) return NULL;
-       if (!item) return NULL;
-
-       VALIDATE(item);
-
-       /*
-        *      Item must be in the dlist
-        */
-       if (!fr_dlist_in_list(cursor->dlist, item)) return NULL;
-
-       cursor->current = item;
-       cursor->prev = fr_dlist_prev(cursor->dlist, item);
+       if (!item ||
+           !fr_dlist_in_list(cursor->dlist, item) ||
+           (cursor->iter && !cursor->iter(cursor->dlist, item, cursor->iter_uctx))) return NULL;
 
-       return cursor->current;
+       return dcursor_current_set(cursor, item);
 }
 
 /** Insert a single item at the start of the list
@@ -365,15 +357,6 @@ static inline int fr_dcursor_prepend(fr_dcursor_t *cursor, void *v)
         */
        fr_dlist_insert_head(cursor->dlist, v);
 
-       /*
-        *      Set previous if the cursor was already set but not
-        *      prev - this will be if there was only one item in the
-        *      list
-        */
-       if (cursor->current && !cursor->prev) {
-               cursor->prev = v;
-       }
-
        return 0;
 }
 
@@ -401,6 +384,8 @@ static inline int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
 
        fr_dlist_insert_tail(cursor->dlist, v);
 
+       cursor->at_end = false; /* Can't be at the end if we just inserted something */
+
        return 0;
 }
 
@@ -461,35 +446,23 @@ static inline int fr_dcursor_insert(fr_dcursor_t *cursor, void *v)
  *
  * @hidecallergraph
  */
-static inline void * fr_dcursor_remove(fr_dcursor_t *cursor)
+static inline void *fr_dcursor_remove(fr_dcursor_t *cursor)
 {
-       void *v, *p;
+       void *v;
 
        if (!fr_cond_assert_msg(!cursor->is_const, "attempting to modify const list")) return NULL;
 
        if (!cursor->current) return NULL;                      /* don't do anything fancy, it's just a noop */
 
        v = cursor->current;
-
        VALIDATE(v);
 
-       if (cursor->remove) if (cursor->remove(cursor->dlist, v, cursor->mod_uctx) < 0) return NULL;
+       if (cursor->remove && (cursor->remove(cursor->dlist, v, cursor->mod_uctx) < 0)) return NULL;
 
-       p = fr_dcursor_list_prev_peek(cursor);
-       fr_dlist_remove(cursor->dlist, v);
+       dcursor_current_set(cursor, dcursor_next(cursor, cursor->iter, v));
 
-       if (fr_dlist_head(cursor->dlist) == v) {
-               cursor->current = NULL;
-               cursor->prev = NULL;
-       } else {
-               cursor->current = p;
-               cursor->prev = p;
-       }
+       fr_dlist_remove(cursor->dlist, v);
 
-       /*
-        *      Advance the cursor to the next item after the one which we just removed.
-        */
-       cursor->current = dcursor_next(cursor, cursor->current);
        return v;
 }
 
@@ -517,9 +490,9 @@ static inline void fr_dcursor_merge(fr_dcursor_t *cursor, fr_dcursor_t *to_appen
        p = cursor->current;
        while ((v = fr_dcursor_remove(to_append))) {
                fr_dcursor_insert(cursor, v);
-               cursor->current = v;
+               dcursor_current_set(cursor, v);
        }
-       cursor->current = p;
+       dcursor_current_set(cursor, p);
 }
 
 /** Return the next item, skipping the current item, that satisfies an evaluation function.
@@ -602,7 +575,7 @@ void *fr_dcursor_intersect_next(fr_dcursor_t *a, fr_dcursor_t *b) CC_HINT(nonnul
  */
 static inline void *fr_dcursor_replace(fr_dcursor_t *cursor, void *r)
 {
-       void *v, *p;
+       void *v;
 
        if (!fr_cond_assert_msg(!cursor->is_const, "attempting to modify const list")) return NULL;
 
@@ -626,8 +599,6 @@ static inline void *fr_dcursor_replace(fr_dcursor_t *cursor, void *r)
                fr_dcursor_append(cursor, r);
                return NULL;
        }
-       p = fr_dcursor_list_prev_peek(cursor);
-       VALIDATE(p);
 
        if (cursor->remove) if (cursor->remove(cursor->dlist, v, cursor->mod_uctx) < 0) return NULL;
 
@@ -636,15 +607,11 @@ static inline void *fr_dcursor_replace(fr_dcursor_t *cursor, void *r)
        /*
         *      Fixup current pointer.
         */
-       cursor->current = p;
-
-       /*
-        *      re-advance the cursor.
-        *
-        *      This ensures if the iterator skips the item
-        *      we just replaced, it doesn't become current.
-        */
-       fr_dcursor_next(cursor);
+       if (cursor->iter) {
+               dcursor_current_set(cursor, cursor->iter(cursor->dlist, r, cursor->iter_uctx)); /* Verify r matches */
+       } else {
+               dcursor_current_set(cursor, r);                 /* Current becomes replacement */
+       }
 
        return v;
 }
@@ -673,19 +640,21 @@ static inline void fr_dcursor_free_list(fr_dcursor_t *cursor)
 
 /** Initialise a cursor with a custom iterator
  *
- * @param[in] _cursor  to initialise.
- * @param[in] _head    of item list.
- * @param[in] _iter    function.
- * @param[in] _uctx    _iter function _uctx.
+ * @param[in] _cursor          to initialise.
+ * @param[in] _head            of item list.
+ * @param[in] _iter            function.
+ * @param[in] _peek            function.  If NULL _iter will be used for peeking.
+ * @param[in] _iter_uctx       _iter function _uctx.
  * @return
  *     - NULL if _head does not point to any items, or the iterator matches no items
  *       in the current list.
  *     - The first item returned by the iterator.
  */
-#define fr_dcursor_iter_mod_init(_cursor, _list, _iter, _iter_uctx, _insert, _remove, _mod_uctx) \
+#define fr_dcursor_iter_mod_init(_cursor, _list, _iter, _peek, _iter_uctx, _insert, _remove, _mod_uctx) \
        _fr_dcursor_init(_cursor, \
                         _list, \
                         _iter, \
+                        _peek, \
                         _iter_uctx, \
                         _insert, \
                         _remove, \
@@ -697,16 +666,18 @@ static inline void fr_dcursor_free_list(fr_dcursor_t *cursor)
  * @param[in] _cursor  to initialise.
  * @param[in] _head    of item list.
  * @param[in] _iter    function.
+ * @param[in] _peek    function.  If NULL _iter will be used for peeking.
  * @param[in] _uctx    _iter function _uctx.
  * @return
  *     - NULL if _head does not point to any items, or the iterator matches no items
  *       in the current list.
  *     - The first item returned by the iterator.
  */
-#define fr_dcursor_iter_init(_cursor, _head, _iter, _uctx) \
+#define fr_dcursor_iter_init(_cursor, _head, _iter, _peek, _uctx) \
        _fr_dcursor_init(_cursor, \
                         _head, \
                         _iter, \
+                        _peek, \
                         _uctx, \
                         NULL, \
                         NULL, \
@@ -729,6 +700,7 @@ static inline void fr_dcursor_free_list(fr_dcursor_t *cursor)
                         NULL, \
                         NULL, \
                         NULL, \
+                        NULL, \
                         IS_CONST(fr_dlist_head_t *, _head))
 
 /** Setup a cursor to iterate over attribute items in dlists
@@ -736,6 +708,7 @@ static inline void fr_dcursor_free_list(fr_dcursor_t *cursor)
  * @param[in] cursor   Where to initialise the cursor (uses existing structure).
  * @param[in] head     of dlist.
  * @param[in] iter     Iterator callback.
+ * @param[in] peek     Iterator callback that should not modify iterator state.
  * @param[in] iter_uctx        to pass to iterator function.
  * @param[in] insert   Callback for inserts.
  * @param[in] remove   Callback for removals.
@@ -747,12 +720,13 @@ static inline void fr_dcursor_free_list(fr_dcursor_t *cursor)
  */
 static inline CC_HINT(nonnull(1,2))
 void *_fr_dcursor_init(fr_dcursor_t *cursor, fr_dlist_head_t const *head,
-                      fr_dcursor_iter_t iter, void const *iter_uctx,
+                      fr_dcursor_iter_t iter, fr_dcursor_iter_t peek, void const *iter_uctx,
                       fr_dcursor_insert_t insert, fr_dcursor_remove_t remove, void const *mod_uctx, bool is_const)
 {
        *cursor = (fr_dcursor_t){
                .dlist = UNCONST(fr_dlist_head_t *, head),
                .iter = iter,
+               .peek = peek ? peek : iter,
                .iter_uctx = UNCONST(void *, iter_uctx),
                .insert = insert,
                .remove = remove,
@@ -764,6 +738,27 @@ void *_fr_dcursor_init(fr_dcursor_t *cursor, fr_dlist_head_t const *head,
        return NULL;
 }
 
+/** re-initialise a cursor, changing its list
+ *
+ * @param[in] _cursor  to re-initialise.
+ * @param[in] _head    of item list.
+ * @return
+ *     - NULL if _head does not point to any items.
+ *     - The first item in the list.
+ */
+#define fr_dcursor_reinit(_cursor, _head) \
+       _fr_dcursor_reinit(_cursor, \
+                          _head, \
+                          IS_CONST(fr_dlist_head_t *, _head))
+
+static inline CC_HINT(nonnull(1,2))
+void _fr_dcursor_list_reinit(fr_dcursor_t *cursor, fr_dlist_head_t const *head, bool is_const)
+{
+       cursor->dlist = UNCONST(fr_dlist_head_t *, head);
+       cursor->current = NULL;
+       cursor->is_const = is_const;
+}
+
 /** talloc_free the current item
  *
  * @param[in] cursor   to free items from.
index a286e3d3f40b397a776ea3eb511489dca636525a..cfdaeb3f71d708ba182285bc644aa86edc868010 100644 (file)
@@ -36,11 +36,10 @@ static void test_init_null_item(void)
 
        test_list_init(&list);
 
-       item_p = fr_dcursor_iter_init(&cursor, &list.head, test_iter, &cursor);
+       item_p = fr_dcursor_iter_init(&cursor, &list.head, test_iter, NULL, &cursor);
        TEST_CHECK(!item_p);
        TEST_CHECK((cursor.dlist) == &list.head);
        TEST_CHECK(!fr_dcursor_current(&cursor));
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
        TEST_CHECK(!fr_dcursor_list_next_peek(&cursor));
        TEST_CHECK(cursor.iter_uctx == &cursor);
 }
@@ -59,7 +58,6 @@ static void test_init_1i_start(void)
        TEST_CHECK(item_p == &item1);
        TEST_CHECK((cursor.dlist) == &list.head);
        TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
 }
 
 static void test_init_2i_start(void)
@@ -77,7 +75,6 @@ static void test_init_2i_start(void)
        item_p = fr_dcursor_init(&cursor, &list.head);
        TEST_CHECK(item_p == &item1);
        TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
 }
 
 static void test_next(void)
@@ -99,7 +96,6 @@ static void test_next(void)
        TEST_CHECK(item_p == &item2);
        TEST_CHECK(fr_dcursor_current(&cursor) == &item2);
        TEST_CHECK(!fr_dcursor_next_peek(&cursor));
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item1);
 }
 
 static void test_next_wrap(void)
@@ -118,13 +114,11 @@ static void test_next_wrap(void)
        fr_dcursor_next(&cursor);
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(!item_p);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item2);
        TEST_CHECK(!fr_dcursor_current(&cursor));
        TEST_CHECK(!fr_dcursor_next_peek(&cursor));
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(!item_p);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item2);
        TEST_CHECK(!fr_dcursor_current(&cursor));
        TEST_CHECK(!fr_dcursor_next_peek(&cursor));
 }
@@ -159,7 +153,58 @@ static void test_dcursor_head(void)
        fr_dcursor_init(&cursor, &list.head);
        item_p = fr_dcursor_head(&cursor);
        TEST_CHECK(item_p == &item1);
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
+}
+
+static void test_dcursor_head_reset(void)
+{
+       fr_dcursor_t            cursor;
+       test_item_t             item1 = { "item1", { NULL, NULL } };
+       test_item_t             item2 = { "item2", { NULL, NULL } };
+       test_item_t             *item_p;
+       test_item_list_t        list;
+
+       test_list_init(&list);
+       fr_dlist_insert_tail(&list.head, &item1);
+       fr_dlist_insert_tail(&list.head, &item2);
+
+       fr_dcursor_init(&cursor, &list.head);
+
+       item_p = fr_dcursor_head(&cursor);
+       TEST_CHECK(item_p == &item1);
+
+       item_p = fr_dcursor_next(&cursor);
+       TEST_CHECK(item_p == &item2);
+
+       item_p = fr_dcursor_next(&cursor);
+       TEST_CHECK(item_p == NULL);
+
+       item_p = fr_dcursor_head(&cursor);
+       TEST_CHECK(item_p == &item1);
+}
+
+static void test_dcursor_iter_head_reset(void)
+{
+       fr_dcursor_t            cursor;
+       test_item_t             item1 = { "item1", { NULL, NULL } };
+       test_item_t             item2 = { "item2", { NULL, NULL } };
+       test_item_t             *item_p;
+       test_item_list_t        list;
+
+       test_list_init(&list);
+       fr_dlist_insert_tail(&list.head, &item1);
+       fr_dlist_insert_tail(&list.head, &item2);
+
+       item_p = fr_dcursor_iter_init(&cursor, &list.head, test_iter, NULL, &cursor);
+       TEST_CHECK(item_p == &item1);
+
+       item_p = fr_dcursor_next(&cursor);
+       TEST_CHECK(item_p == &item2);
+
+       item_p = fr_dcursor_next(&cursor);
+       TEST_CHECK(item_p == NULL);
+
+       item_p = fr_dcursor_head(&cursor);
+       TEST_CHECK(item_p == &item1);
 }
 
 static void test_dcursor_head_after_next(void)
@@ -180,7 +225,6 @@ static void test_dcursor_head_after_next(void)
        fr_dcursor_next(&cursor);
        item_p = fr_dcursor_head(&cursor);
        TEST_CHECK(item_p == &item1);
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
 }
 
 static void test_dcursor_tail(void)
@@ -201,7 +245,6 @@ static void test_dcursor_tail(void)
        fr_dcursor_next(&cursor);
        item_p = fr_dcursor_tail(&cursor);
        TEST_CHECK(item_p == &item3);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item2);
 }
 
 static void test_dcursor_head_after_tail(void)
@@ -222,7 +265,6 @@ static void test_dcursor_head_after_tail(void)
        fr_dcursor_tail(&cursor);
        item_p = fr_dcursor_head(&cursor);
        TEST_CHECK(item_p == &item1);
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
 }
 
 static void test_dcursor_wrap_after_tail(void)
@@ -243,11 +285,9 @@ static void test_dcursor_wrap_after_tail(void)
        fr_dcursor_tail(&cursor);
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(!item_p);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item3);
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(!item_p);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item3);
 }
 
 static void test_dcursor_append_empty(void)
@@ -265,7 +305,6 @@ static void test_dcursor_append_empty(void)
        item_p = fr_dcursor_current(&cursor);
        TEST_CHECK(!item_p);
        TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item1);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == NULL);
 }
 
 static void test_dcursor_append_empty_3(void)
@@ -306,7 +345,6 @@ static void test_dcursor_prepend_empty(void)
        item_p = fr_dcursor_current(&cursor);
        TEST_CHECK(!item_p);
        TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item1);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == NULL);
 }
 
 static void test_dcursor_insert_into_empty(void)
@@ -324,7 +362,6 @@ static void test_dcursor_insert_into_empty(void)
        item_p = fr_dcursor_current(&cursor);
        TEST_CHECK(!item_p);
        TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item1);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == NULL);
 }
 
 static void test_dcursor_insert_into_empty_3(void)
@@ -365,7 +402,6 @@ static void test_dcursor_replace_in_empty(void)
        item_p = fr_dcursor_current(&cursor);
        TEST_CHECK(!item_p);
        TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item1);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == NULL);
 }
 
 static void test_dcursor_prepend_1i_start(void)
@@ -384,11 +420,9 @@ static void test_dcursor_prepend_1i_start(void)
 
        TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
        TEST_CHECK(!fr_dcursor_next_peek(&cursor));
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item2);       /* Inserted before item 1 */
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(!item_p);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item1);
 
        item_p = fr_dcursor_head(&cursor);
        TEST_CHECK(item_p == &item2);
@@ -413,11 +447,9 @@ static void test_dcursor_append_1i_start(void)
 
        TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
        TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item2);
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(item_p == &item2);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item1);
 
        item_p = fr_dcursor_head(&cursor);
        TEST_CHECK(item_p == &item1);
@@ -442,11 +474,9 @@ static void test_dcursor_insert_1i_start(void)
 
        TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
        TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item2);
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(item_p == &item2);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item1);
 
        item_p = fr_dcursor_head(&cursor);
        TEST_CHECK(item_p == &item1);
@@ -473,8 +503,6 @@ static void test_dcursor_replace_1i_start(void)
        item_p = fr_dcursor_current(&cursor);
        TEST_CHECK(item_p == &item2);
 
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
-
        item_p = fr_dcursor_head(&cursor);
        TEST_CHECK(item_p == &item2);
 
@@ -500,15 +528,12 @@ static void test_dcursor_prepend_2i_start(void)
 
        TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
        TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item2);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item3);
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(item_p == &item2);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item1);
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(!item_p);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item2);
 
        item_p = fr_dcursor_head(&cursor);
        TEST_CHECK(item_p == &item3);
@@ -535,11 +560,9 @@ static void test_dcursor_append_2i_start(void)
 
        TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
        TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item2);
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(item_p == &item2);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item1);
 
        item_p = fr_dcursor_head(&cursor);
        TEST_CHECK(item_p == &item1);
@@ -573,15 +596,12 @@ static void test_dcursor_insert_2i_start(void)
         */
        TEST_CHECK(fr_dcursor_current(&cursor) == &item1);
        TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item3);
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(item_p == &item3);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item1);
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(item_p == &item2);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item3);
 
        item_p = fr_dcursor_head(&cursor);
        TEST_CHECK(item_p == &item1);
@@ -616,8 +636,6 @@ static void test_dcursor_replace_2i_start(void)
        item_p = fr_dcursor_current(&cursor);
        TEST_CHECK(item_p == &item3);
 
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
-
        item_p = fr_dcursor_head(&cursor);
        TEST_CHECK(item_p == &item3);
 
@@ -646,15 +664,12 @@ static void test_dcursor_prepend_3i_mid(void)
 
        TEST_CHECK(fr_dcursor_current(&cursor) == &item2);
        TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item3);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item1);
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(item_p == &item3);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item2);
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(!item_p);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item3);
 
        item_p = fr_dcursor_head(&cursor);
        TEST_CHECK(item_p == &item4);
@@ -684,11 +699,9 @@ static void test_dcursor_append_3i_mid(void)
 
        TEST_CHECK(fr_dcursor_current(&cursor) == &item2);
        TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item3);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item1);
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(item_p == &item3);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item2);
 
        item_p = fr_dcursor_head(&cursor);
        TEST_CHECK(item_p == &item1);
@@ -718,15 +731,12 @@ static void test_dcursor_insert_3i_mid(void)
 
        TEST_CHECK(fr_dcursor_current(&cursor) == &item2);
        TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item4);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item1);
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(item_p == &item4);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item2);
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(item_p == &item3);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item4);
 
        item_p = fr_dcursor_head(&cursor);
        TEST_CHECK(item_p == &item1);
@@ -758,7 +768,6 @@ static void test_dcursor_replace_3i_mid(void)
        item_p = fr_dcursor_current(&cursor);
        TEST_CHECK(item_p == &item4);
 
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item1);
        TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item3);
 
        item_p = fr_dcursor_head(&cursor);
@@ -790,11 +799,9 @@ static void test_dcursor_prepend_3i_end(void)
 
        TEST_CHECK(fr_dcursor_current(&cursor) == &item3);
        TEST_CHECK(!fr_dcursor_next_peek(&cursor));
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item2);
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(!item_p);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item3);
 
        item_p = fr_dcursor_head(&cursor);
        TEST_CHECK(item_p == &item4);
@@ -825,11 +832,9 @@ static void test_dcursor_append_3i_end(void)
 
        TEST_CHECK(fr_dcursor_current(&cursor) == &item3);
        TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item4);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item2);
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(item_p == &item4);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item3);
 
        item_p = fr_dcursor_head(&cursor);
        TEST_CHECK(item_p == &item1);
@@ -860,15 +865,12 @@ static void test_dcursor_insert_3i_end(void)
 
        TEST_CHECK(fr_dcursor_current(&cursor) == &item3);
        TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item4);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item2);
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(item_p == &item4);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item3);
 
        item_p = fr_dcursor_next(&cursor);
        TEST_CHECK(!item_p);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item4);
 
        item_p = fr_dcursor_head(&cursor);
        TEST_CHECK(item_p == &item1);
@@ -901,7 +903,6 @@ static void test_dcursor_replace_3i_end(void)
        item_p = fr_dcursor_current(&cursor);
        TEST_CHECK(item_p == &item4);
 
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item2);
        TEST_CHECK(!fr_dcursor_next_peek(&cursor));
 
        item_p = fr_dcursor_head(&cursor);
@@ -918,7 +919,7 @@ static void test_dcursor_remove_empty(void)
 
        test_list_init(&list);
 
-       _fr_dcursor_init(&cursor, (fr_dlist_head_t *)&list, test_iter, NULL, NULL, NULL, NULL, false);
+       _fr_dcursor_init(&cursor, (fr_dlist_head_t *)&list, test_iter, NULL, NULL, NULL, NULL, NULL, false);
        TEST_CHECK(!fr_dcursor_remove(&cursor));
 }
 
@@ -938,7 +939,6 @@ static void test_dcursor_remove_1i(void)
        TEST_CHECK(item_p == &item1);
 
        TEST_CHECK(!fr_dcursor_current(&cursor));
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
        TEST_CHECK(!fr_dcursor_next(&cursor));
        TEST_CHECK(!fr_dcursor_tail(&cursor));
        TEST_CHECK(!fr_dcursor_head(&cursor));
@@ -961,7 +961,6 @@ static void test_dcursor_remove_2i(void)
 
        TEST_CHECK(item_p == &item1);
        TEST_CHECK(fr_dcursor_current(&cursor) == &item2);
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
        TEST_CHECK(!fr_dcursor_next(&cursor));
        TEST_CHECK(fr_dcursor_tail(&cursor) == &item2);
        TEST_CHECK(fr_dcursor_head(&cursor) == &item2);
@@ -970,7 +969,6 @@ static void test_dcursor_remove_2i(void)
        TEST_CHECK(item_p == &item2);
 
        TEST_CHECK(!fr_dcursor_current(&cursor));
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
        TEST_CHECK(!fr_dcursor_next(&cursor));
        TEST_CHECK(!fr_dcursor_tail(&cursor));
        TEST_CHECK(!fr_dcursor_head(&cursor));
@@ -994,13 +992,11 @@ static void test_dcursor_remove_3i_start(void)
        item_p = fr_dcursor_remove(&cursor);
        TEST_CHECK(item_p == &item1);
        TEST_CHECK(fr_dcursor_current(&cursor) == &item2);
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
        TEST_CHECK(fr_dcursor_next_peek(&cursor) == &item3);
 
        item_p = fr_dcursor_remove(&cursor);
        TEST_CHECK(item_p == &item2);
        TEST_CHECK(fr_dcursor_current(&cursor) == &item3);
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
        TEST_CHECK(!fr_dcursor_next_peek(&cursor));
 
        item_p = fr_dcursor_remove(&cursor);
@@ -1030,7 +1026,6 @@ static void test_dcursor_remove_3i_mid(void)
        item_p = fr_dcursor_remove(&cursor);
        TEST_CHECK(item_p == &item2);
        TEST_CHECK(fr_dcursor_current(&cursor) == &item3);
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item1);
        TEST_CHECK(!fr_dcursor_next_peek(&cursor));
 
        item_p = fr_dcursor_remove(&cursor);
@@ -1043,7 +1038,6 @@ static void test_dcursor_remove_3i_mid(void)
         *      We don't implicitly start moving backwards.
         */
        TEST_CHECK(!fr_dcursor_current(&cursor));
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item1);
        TEST_CHECK(!fr_dcursor_next_peek(&cursor));
 
        item_p = fr_dcursor_remove(&cursor);
@@ -1073,14 +1067,12 @@ static void test_dcursor_remove_3i_end(void)
        item_p = fr_dcursor_remove(&cursor);
        TEST_CHECK(item_p == &item3);
        TEST_CHECK(!fr_dcursor_current(&cursor));
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item2);
        TEST_CHECK(!fr_dcursor_next_peek(&cursor));
 
        item_p = fr_dcursor_remove(&cursor);
        TEST_CHECK(!item_p);
 
        TEST_CHECK(!fr_dcursor_current(&cursor));
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor) == &item2);
        TEST_CHECK(!fr_dcursor_next_peek(&cursor));
 }
 
@@ -1148,7 +1140,6 @@ static void test_dcursor_merge_start_a_b(void)
        TEST_CHECK(!fr_dcursor_next(&cursor_a));
 
        TEST_CHECK(!fr_dcursor_current(&cursor_b));
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor_b));
        TEST_CHECK(!fr_dcursor_list_next_peek(&cursor_b));
 }
 
@@ -1211,7 +1202,6 @@ static void test_dcursor_merge_mid_a(void)
        TEST_CHECK(!fr_dcursor_next(&cursor_a));
 
        TEST_CHECK(!fr_dcursor_current(&cursor_b));
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor_b));
        TEST_CHECK(!fr_dcursor_list_next_peek(&cursor_b));
 }
 
@@ -1270,7 +1260,6 @@ static void test_dcursor_merge_end_a(void)
         */
        TEST_CHECK(!fr_dcursor_list_next_peek(&cursor_a));
        TEST_CHECK(!fr_dcursor_current(&cursor_b));
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor_b));
        TEST_CHECK(!fr_dcursor_list_next_peek(&cursor_b));
 }
 
@@ -1336,7 +1325,6 @@ static void test_dcursor_merge_mid_b(void)
        TEST_CHECK(!fr_dcursor_next(&cursor_a));
 
        TEST_CHECK(!fr_dcursor_current(&cursor_b));
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor_b) == &item1b);
        TEST_CHECK(!fr_dcursor_list_next_peek(&cursor_b));
 }
 
@@ -1400,7 +1388,6 @@ static void test_dcursor_merge_end_b(void)
        TEST_CHECK(!fr_dcursor_next(&cursor_a));
 
        TEST_CHECK(!fr_dcursor_current(&cursor_b));
-       TEST_CHECK(fr_dcursor_list_prev_peek(&cursor_b) == &item2b);
        TEST_CHECK(fr_dcursor_head(&cursor_b) == &item1b);
 }
 
@@ -1430,7 +1417,6 @@ static void test_dcursor_merge_with_empty(void)
        TEST_CHECK(fr_dcursor_next(&cursor_a) == &item3b);
 
        TEST_CHECK(!fr_dcursor_current(&cursor_b));
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor_b));
        TEST_CHECK(!fr_dcursor_list_next_peek(&cursor_b));
 }
 
@@ -1505,7 +1491,6 @@ static void test_dcursor_free(void)
        fr_dcursor_free_list(&cursor);
 
        TEST_CHECK(fr_dcursor_current(&cursor) == NULL);
-       TEST_CHECK(!fr_dcursor_list_prev_peek(&cursor));
        TEST_CHECK(!fr_dcursor_tail(&cursor));
        TEST_CHECK(!fr_dcursor_head(&cursor));
 
@@ -1595,7 +1580,7 @@ static void test_intersect_iterator_a(void)
        fr_dlist_insert_tail(&list.head, &item3);
        fr_dlist_insert_tail(&list.head, &item4);
 
-       fr_dcursor_iter_init(&cursor_a, &list.head, iter_name_check, &filter_a);
+       fr_dcursor_iter_init(&cursor_a, &list.head, iter_name_check, NULL, &filter_a);
        fr_dcursor_init(&cursor_b, &list.head);
 
        TEST_CHECK(fr_dcursor_intersect_head(&cursor_a, &cursor_b) == &item1);
@@ -1622,7 +1607,7 @@ static void test_intersect_iterator_b(void)
        fr_dlist_insert_tail(&list.head, &item4);
 
        fr_dcursor_init(&cursor_a, &list.head);
-       fr_dcursor_iter_init(&cursor_b, &list.head, iter_name_check, &filter_b);
+       fr_dcursor_iter_init(&cursor_b, &list.head, iter_name_check, NULL, &filter_b);
 
        TEST_CHECK(fr_dcursor_intersect_head(&cursor_a, &cursor_b) == &item1);
        TEST_CHECK(fr_dcursor_intersect_next(&cursor_a, &cursor_b) == &item3);
@@ -1649,8 +1634,8 @@ static void test_intersect_iterator_ab(void)
        fr_dlist_insert_tail(&list.head, &item4);
        fr_dlist_insert_tail(&list.head, &item5);
 
-       fr_dcursor_iter_init(&cursor_a, &list.head, iter_name_check, &filter_a);
-       fr_dcursor_iter_init(&cursor_b, &list.head, iter_name_check, &filter_b);
+       fr_dcursor_iter_init(&cursor_a, &list.head, iter_name_check, NULL, &filter_a);
+       fr_dcursor_iter_init(&cursor_b, &list.head, iter_name_check, NULL, &filter_b);
 
        TEST_CHECK(fr_dcursor_intersect_head(&cursor_a, &cursor_b) == &item1);
        TEST_CHECK(fr_dcursor_intersect_next(&cursor_a, &cursor_b) == &item3);
@@ -1679,8 +1664,8 @@ static void test_intersect_iterator_disjoint(void)
        fr_dlist_insert_tail(&list.head, &item4);
        fr_dlist_insert_tail(&list.head, &item5);
 
-       fr_dcursor_iter_init(&cursor_a, &list.head, iter_name_check, &filter_a);
-       fr_dcursor_iter_init(&cursor_b, &list.head, iter_name_check, &filter_b);
+       fr_dcursor_iter_init(&cursor_a, &list.head, iter_name_check, NULL, &filter_a);
+       fr_dcursor_iter_init(&cursor_b, &list.head, iter_name_check, NULL, &filter_b);
 
        TEST_CHECK(fr_dcursor_intersect_head(&cursor_a, &cursor_b) == NULL);
 }
@@ -1796,6 +1781,8 @@ TEST_LIST = {
         */
        { "head_tail_null",             test_dcursor_head_tail_null },
        { "head",                       test_dcursor_head },
+       { "head_reset",                 test_dcursor_head_reset },
+       { "head_iter_reset",            test_dcursor_iter_head_reset },
        { "head_after_next",            test_dcursor_head_after_next },
        { "tail",                       test_dcursor_tail },
        { "head_after_tail",            test_dcursor_head_after_tail },
index e8b3b4737d9cc99aaa68edae17a10e5c3638ec9e..8ddbb4adb303479e5c021de629150495833461b9 100644 (file)
@@ -841,7 +841,7 @@ fr_pair_t *_fr_pair_dcursor_iter_init(fr_dcursor_t *cursor, fr_pair_list_t const
                                      bool is_const)
 {
        return _fr_dcursor_init(cursor, fr_pair_order_list_list_head(&list->order),
-                               iter, uctx,
+                               iter, NULL, uctx,
                                _pair_list_dcursor_insert, _pair_list_dcursor_remove, list, is_const);
 }
 
@@ -862,7 +862,7 @@ fr_pair_t *_fr_pair_dcursor_init(fr_dcursor_t *cursor, fr_pair_list_t const *lis
                                 bool is_const)
 {
        return _fr_dcursor_init(cursor, fr_pair_order_list_list_head(&list->order),
-                               NULL, NULL,
+                               NULL, NULL, NULL,
                                _pair_list_dcursor_insert, _pair_list_dcursor_remove, list, is_const);
 }
 
@@ -882,7 +882,7 @@ fr_pair_t *_fr_pair_dcursor_by_da_init(fr_dcursor_t *cursor,
                                        bool is_const)
 {
        return _fr_dcursor_init(cursor, fr_pair_order_list_list_head(&list->order),
-                               fr_pair_iter_next_by_da, da,
+                               fr_pair_iter_next_by_da, NULL, da,
                                _pair_list_dcursor_insert, _pair_list_dcursor_remove, list, is_const);
 }
 
@@ -901,7 +901,7 @@ fr_pair_t *_fr_pair_dcursor_by_ancestor_init(fr_dcursor_t *cursor,
                                             bool is_const)
 {
        return _fr_dcursor_init(cursor, fr_pair_order_list_list_head(&list->order),
-                               fr_pair_iter_next_by_ancestor, da,
+                               fr_pair_iter_next_by_ancestor, NULL, da,
                                _pair_list_dcursor_insert, _pair_list_dcursor_remove, list, is_const);
 }