#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.
* - 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.
* - -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.
* - -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
* - 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.
#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.
* - 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
* 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;
}
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
*
* @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
* 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
*
* @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
*
* @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
*
* @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
*
* @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
*
* @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;
}
*
* @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
*/
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;
}
fr_dlist_insert_tail(cursor->dlist, v);
+ cursor->at_end = false; /* Can't be at the end if we just inserted something */
+
return 0;
}
*
* @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;
}
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.
*/
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;
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;
/*
* 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;
}
/** 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, \
* @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, \
NULL, \
NULL, \
NULL, \
+ NULL, \
IS_CONST(fr_dlist_head_t *, _head))
/** Setup a cursor to iterate over attribute items in dlists
* @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.
*/
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,
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.
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);
}
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)
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)
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)
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));
}
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)
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)
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)
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)
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)
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)
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)
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)
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)
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);
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);
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);
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);
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);
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);
*/
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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));
}
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));
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);
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));
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);
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);
* 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);
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));
}
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));
}
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));
}
*/
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));
}
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));
}
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);
}
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));
}
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));
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);
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);
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);
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);
}
*/
{ "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 },