23RCSIDH(dcursor_h,
"$Id: a252937864fd50fa2ecc9f6a16baf3a72b2ae0a2 $")
29#include <freeradius-devel/build.h>
30#include <freeradius-devel/missing.h>
31#include <freeradius-devel/util/dlist.h>
32#include <freeradius-devel/util/talloc.h>
117#ifndef TALLOC_GET_TYPE_ABORT_NOOP
118#define VALIDATE(_item) do { if (cursor->dlist->type && (_item)) _talloc_get_type_abort(_item, cursor->dlist->type, __location__); } while (0)
120#define VALIDATE(_item)
157 if (cursor->at_end)
return NULL;
167 if (cursor->at_end)
return NULL;
169 next = iter(cursor->dlist, NULL, cursor->iter_uctx);
178 next = iter(cursor->dlist,
current, cursor->iter_uctx);
212 out->iter =
in->iter;
213 out->iter_uctx =
in->iter_uctx;
221 out->mod_uctx = NULL;
243 cursor->at_end =
false;
267 void *
current = cursor->current;
269 while ((cursor->current =
dcursor_next(cursor, cursor->iter, cursor->current))) {
307 return dcursor_next(cursor, cursor->peek, cursor->current);
342 return cursor->current;
489 if (!cursor->
current)
return NULL;
496 if (i < 0)
return NULL;
553 }
while (
item && !eval(
item, uctx));
694#define fr_dcursor_iter_mod_init(_cursor, _list, _iter, _peek, _iter_uctx, _insert, _remove, _mod_uctx) \
695 _fr_dcursor_init(_cursor, \
703 IS_CONST(fr_dlist_head_t *, _list))
717#define fr_dcursor_iter_init(_cursor, _head, _iter, _peek, _uctx) \
718 _fr_dcursor_init(_cursor, \
726 IS_CONST(fr_dlist_head_t *, _head))
736#define fr_dcursor_init(_cursor, _head) \
737 _fr_dcursor_init(_cursor, \
745 IS_CONST(fr_dlist_head_t *, _head))
762static inline CC_HINT(
nonnull(1,2))
770 .peek = peek ? peek : iter,
771 .iter_uctx =
UNCONST(
void *, iter_uctx),
774 .mod_uctx =
UNCONST(
void *, mod_uctx),
792#define fr_dcursor_reinit(_cursor, _head) \
793 _fr_dcursor_reinit(_cursor, \
795 IS_CONST(fr_dlist_head_t *, _head))
797static inline CC_HINT(
nonnull(1,2))
801 cursor->current = NULL;
802 cursor->is_const = is_const;
833 talloc_set_name_const(
stack,
"fr_dcursor_stack_t");
849#define FR_DCURSOR(_name) _name ## _dcursor_t
856#define FR_DCURSOR_ITER(_name) _name ## _iter_t
863#define FR_DCURSOR_EVAL(_name) _name ## _eval_t
870#define FR_DCURSOR_INSERT(_name) _name ## _insert_t
877#define FR_DCURSOR_REMOVE(_name) _name ## _remove_t
884#define FR_DCURSOR_COPY(_name) _name ## _copy_t
900#define FR_DCURSOR_DLIST_TYPES(_name, _list_name, _element_type) \
901 typedef struct { fr_dcursor_t dcursor; } FR_DCURSOR(_name); \
902 typedef _element_type *(*FR_DCURSOR_ITER(_name))(FR_DLIST_HEAD(_list_name) *list, _element_type *to_eval, void *uctx); \
903 typedef bool (*FR_DCURSOR_EVAL(_name))(_element_type const *item, void const *uctx); \
904 typedef int (*FR_DCURSOR_INSERT(_name))(FR_DLIST_HEAD(_list_name) *list, FR_DLIST_ENTRY(_list_name) *to_insert, void *uctx); \
905 typedef int (*FR_DCURSOR_REMOVE(_name))(FR_DLIST_HEAD(_list_name) *list, FR_DLIST_ENTRY(_list_name) *to_delete, void *uctx); \
906 typedef void (*FR_DCURSOR_COPY(_name))(FR_DCURSOR(_name) *out, FR_DCURSOR(_name) const *in);
917#define FR_DCURSOR_FUNCS(_name, _list_name, _element_type) \
918DIAG_OFF(unused-function) \
919 static inline CC_HINT(nonnull) _element_type *_name ## _init(FR_DCURSOR(_name) *dcursor, \
920 FR_DLIST_HEAD(_list_name) *head) \
921 { return (_element_type *)_fr_dcursor_init(&dcursor->dcursor, &head->head, \
922 NULL, NULL, NULL, NULL, NULL, NULL, \
923 IS_CONST(FR_DLIST_HEAD(_list_name) *, head)); } \
925 static inline CC_HINT(nonnull(1,2)) _element_type *_name ## _iter_init(FR_DCURSOR(_name) *dcursor, \
926 FR_DLIST_HEAD(_list_name) *head, \
927 FR_DCURSOR_ITER(_name) iter, \
928 FR_DCURSOR_ITER(_name) peek, \
929 void const *iter_uctx) \
930 { return (_element_type *)_fr_dcursor_init(&dcursor->dcursor, &head->head, \
931 (fr_dcursor_iter_t)iter, \
932 (fr_dcursor_iter_t)peek, \
935 IS_CONST(FR_DLIST_HEAD(_list_name) *, head)); } \
937 static inline CC_HINT(nonnull(1,2)) _element_type *_name ## _iter_mod_init(FR_DCURSOR(_name) *dcursor, \
938 FR_DLIST_HEAD(_list_name) *head, \
939 FR_DCURSOR_ITER(_name) iter, \
940 FR_DCURSOR_ITER(_name) peek, \
941 void const *iter_uctx, \
942 FR_DCURSOR_INSERT(_name) insert, \
943 FR_DCURSOR_REMOVE(_name) remove, \
944 void const *mod_uctx) \
945 { return (_element_type *)_fr_dcursor_init(&dcursor->dcursor, &head->head, \
946 (fr_dcursor_iter_t)iter, \
947 (fr_dcursor_iter_t)peek, \
949 (fr_dcursor_insert_t)insert, \
950 (fr_dcursor_remove_t)remove, \
952 IS_CONST(FR_DLIST_HEAD(_list_name) *, head)); } \
954 static inline CC_HINT(nonnull) _element_type *_name ## _current(FR_DCURSOR(_name) *dcursor) \
955 { return (_element_type *)fr_dcursor_current(&dcursor->dcursor); } \
957 static inline CC_HINT(nonnull) _element_type *_name ## _next_peek(FR_DCURSOR(_name) *dcursor) \
958 { return (_element_type *)fr_dcursor_next_peek(&dcursor->dcursor); } \
960 static inline CC_HINT(nonnull) _element_type *_name ## _list_next_peek(FR_DCURSOR(_name) *dcursor) \
961 { return (_element_type *)fr_dcursor_list_next_peek(&dcursor->dcursor); } \
963 static inline CC_HINT(nonnull) _element_type *_name ## _next(FR_DCURSOR(_name) *dcursor) \
964 { return (_element_type *)fr_dcursor_next(&dcursor->dcursor); } \
966 static inline CC_HINT(nonnull) void _name ## _copy(FR_DCURSOR(_name) *out, \
967 FR_DCURSOR(_name) const *in) \
968 { fr_dcursor_copy(&out->dcursor, &in->dcursor); } \
970 static inline CC_HINT(nonnull) _element_type *_name ## _head(FR_DCURSOR(_name) *dcursor) \
971 { return (_element_type *)fr_dcursor_head(&dcursor->dcursor); } \
973 static inline CC_HINT(nonnull) _element_type *_name ## _tail(FR_DCURSOR(_name) *dcursor) \
974 { return (_element_type *)fr_dcursor_tail(&dcursor->dcursor); } \
976 static inline CC_HINT(nonnull) _element_type *_name ## _set_current(FR_DCURSOR(_name) *dcursor, \
978 { return (_element_type *)fr_dcursor_set_current(&dcursor->dcursor, v); } \
980 static inline CC_HINT(nonnull) int _name ## _prepend(FR_DCURSOR(_name) *dcursor, \
982 { return fr_dcursor_prepend(&dcursor->dcursor, v); } \
984 static inline CC_HINT(nonnull) int _name ## _append(FR_DCURSOR(_name) *dcursor, \
986 { return fr_dcursor_append(&dcursor->dcursor, v); } \
988 static inline CC_HINT(nonnull) int _name ## _insert(FR_DCURSOR(_name) *dcursor, \
990 { return fr_dcursor_insert(&dcursor->dcursor, v); } \
992 static inline CC_HINT(nonnull) _element_type *_name ## _replace(FR_DCURSOR(_name) *dcursor, \
994 { return fr_dcursor_replace(&dcursor->dcursor, v); } \
996 static inline CC_HINT(nonnull) _element_type *_name ## _remove(FR_DCURSOR(_name) *dcursor) \
997 { return (_element_type *)fr_dcursor_remove(&dcursor->dcursor); } \
999 static inline CC_HINT(nonnull) void _name ## _merge(FR_DCURSOR(_name) *cursor, \
1000 FR_DCURSOR(_name) *to_append) \
1001 { fr_dcursor_merge(&cursor->dcursor, &to_append->dcursor); } \
1003 static inline CC_HINT(nonnull) void _name ## _free_list(FR_DCURSOR(_name) *dcursor) \
1004 { fr_dcursor_free_list(&dcursor->dcursor); } \
1006 static inline CC_HINT(nonnull) void _name ## _free_item(FR_DCURSOR(_name) *dcursor) \
1007 { fr_dcursor_free_item(&dcursor->dcursor); } \
1009 static inline CC_HINT(nonnull) _element_type *_name ## _intersect_head(FR_DCURSOR(_name) *a, \
1010 FR_DCURSOR(_name) *b) \
1011 { return (_element_type *)fr_dcursor_intersect_head(&a->dcursor, &b->dcursor); } \
1013 static inline CC_HINT(nonnull) _element_type *_name ## _intersect_next(FR_DCURSOR(_name) *a, \
1014 FR_DCURSOR(_name) *b) \
1015 { return (_element_type *)fr_dcursor_intersect_next(&a->dcursor, &b->dcursor); } \
1017 static inline CC_HINT(nonnull(1,2)) _element_type *_name ## _filter_head(FR_DCURSOR(_name) *dcursor, \
1018 FR_DCURSOR_EVAL(_name) eval, \
1020 { return (_element_type *)fr_dcursor_filter_head(&dcursor->dcursor, (fr_dcursor_eval_t)eval, uctx); } \
1022 static inline CC_HINT(nonnull(1,2)) _element_type *_name ## _filter_next(FR_DCURSOR(_name) *dcursor, \
1023 FR_DCURSOR_EVAL(_name) eval, \
1025 { return (_element_type *)fr_dcursor_filter_next(&dcursor->dcursor, (fr_dcursor_eval_t)eval, uctx); } \
1027 static inline CC_HINT(nonnull(1,2)) _element_type *_name ## _filter_current(FR_DCURSOR(_name) *dcursor, \
1028 FR_DCURSOR_EVAL(_name) eval, \
1030 { return (_element_type *)fr_dcursor_filter_current(&dcursor->dcursor, (fr_dcursor_eval_t)eval, uctx); }
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
#define CC_NO_UBSAN(_sanitize)
fr_dcursor_iter_t iter
Iterator function.
uint8_t depth
Which cursor is currently in use.
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
static void * fr_dcursor_filter_current(fr_dcursor_t *cursor, fr_dcursor_eval_t eval, void const *uctx)
Return the next item, starting with the current item, that satisfies an evaluation function.
int(* fr_dcursor_remove_t)(fr_dlist_head_t *list, void *to_delete, void *uctx)
Callback for performing additional actions on removal.
void(* fr_dcursor_copy_t)(fr_dcursor_t *out, fr_dcursor_t const *in)
Copy callback for duplicating complex dcursor state.
void * fr_dcursor_intersect_head(fr_dcursor_t *a, fr_dcursor_t *b)
Return the first item matching the iterator in cursor a and cursor b.
static void * fr_dcursor_filter_head(fr_dcursor_t *cursor, fr_dcursor_eval_t eval, void const *uctx)
Return the first item that satisfies an evaluation function.
static void * fr_dcursor_list_next_peek(fr_dcursor_t *cursor)
Returns the next list item without advancing the cursor.
fr_dcursor_remove_t remove
Callback function on delete.
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
static void fr_dcursor_copy(fr_dcursor_t *out, fr_dcursor_t const *in)
Copy cursor parameters and state.
void * fr_dcursor_intersect_next(fr_dcursor_t *a, fr_dcursor_t *b)
Return the next item matching the iterator in cursor a and cursor b.
static void fr_dcursor_merge(fr_dcursor_t *cursor, fr_dcursor_t *to_append)
Moves items from one cursor to another.
static void * fr_dcursor_tail(fr_dcursor_t *cursor)
Wind cursor to the tail item in the list.
static void * fr_dcursor_next_peek(fr_dcursor_t *cursor)
Return the next iterator item without advancing the cursor.
bool at_end
We're at the end of the list.
static void * dcursor_next(fr_dcursor_t *cursor, fr_dcursor_iter_t iter, void *current)
Internal function to get the next item.
static fr_dcursor_stack_t * fr_dcursor_stack_alloc(TALLOC_CTX *ctx, uint8_t depth)
Allocate a stack of cursors for traversing trees.
bool(* fr_dcursor_eval_t)(void const *item, void const *uctx)
Type of evaluation functions to pass to the fr_dcursor_filter_*() functions.
static void * fr_dcursor_replace(fr_dcursor_t *cursor, void *r)
Replace the current item.
static int fr_dcursor_insert(fr_dcursor_t *cursor, void *v)
Insert directly after the current item.
void * mod_uctx
to pass to modification functions.
static void * fr_dcursor_set_current(fr_dcursor_t *cursor, void *item)
Set the cursor to a specified item.
static void * fr_dcursor_filter_next(fr_dcursor_t *cursor, fr_dcursor_eval_t eval, void const *uctx)
Return the next item, skipping the current item, that satisfies an evaluation function.
static void fr_dcursor_free_item(fr_dcursor_t *cursor)
talloc_free the current item
fr_dcursor_insert_t insert
Callback function on insert.
void *(* fr_dcursor_iter_t)(fr_dlist_head_t *list, void *to_eval, void *uctx)
Callback for implementing custom iterators.
struct fr_dcursor_s fr_dcursor_t
int(* fr_dcursor_insert_t)(fr_dlist_head_t *list, void *to_insert, void *uctx)
Callback for performing additional actions on insert.
static void * fr_dcursor_remove(fr_dcursor_t *cursor)
Remove the current item.
static void fr_dcursor_free_list(fr_dcursor_t *cursor)
Free the current item and all items after it.
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
static void * fr_dcursor_head(fr_dcursor_t *cursor)
Rewind cursor to the start of the list.
void * current
The current item in the dlist.
fr_dlist_head_t * dlist
Head of the doubly linked list being iterated over.
static int fr_dcursor_prepend(fr_dcursor_t *cursor, void *v)
Insert a single item at the start of the list.
void * iter_uctx
to pass to iterator function.
static void _fr_dcursor_list_reinit(fr_dcursor_t *cursor, fr_dlist_head_t const *head, bool is_const)
fr_dcursor_iter_t peek
Distinct "peek" function.
static void fr_dcursor_copy_iter(fr_dcursor_t *out, fr_dcursor_t const *in)
Copy a read-only iterator from a parent to a child cursor.
static void * dcursor_current_set(fr_dcursor_t *cursor, void *current)
If current is set to a NULL pointer, we record that fact.
static void * _fr_dcursor_init(fr_dcursor_t *cursor, fr_dlist_head_t const *head, 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)
Setup a cursor to iterate over attribute items in dlists.
fr_dcursor_copy_t copy
Copy dcursor state.
bool is_const
The list we're iterating over is immutable.
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
static bool fr_dlist_in_list(fr_dlist_head_t *list_head, void *ptr)
Check if a list entry is part of a list.
static bool fr_dlist_empty(fr_dlist_head_t const *list_head)
Check whether a list has any items.
static void * fr_dlist_tail(fr_dlist_head_t const *list_head)
Return the TAIL item of a list or NULL if the list is empty.
static void * fr_dlist_replace(fr_dlist_head_t *list_head, void *item, void *ptr)
Replace an item in a dlist.
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
static int fr_dlist_insert_head(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the head of a list.
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
static int fr_dlist_insert_after(fr_dlist_head_t *list_head, void *pos, void *ptr)
Insert an item after an item already in the list.
Head of a doubly linked list.
static char * stack[MAX_STACK]
static void * item(fr_lst_t const *lst, fr_lst_index_t idx)
static uint8_t depth(fr_minmax_heap_index_t i)
static rc_request_t * current
static size_t char ** out