23 RCSIDH(dcursor_h,
"$Id: 97e8e2cbdc04e98f106f8e70211cccd07ea8a77d $")
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);
212 out->iter =
in->iter;
213 out->iter_uctx =
in->iter_uctx;
221 out->mod_uctx = NULL;
243 cursor->at_end =
false;
266 void *
current = cursor->current;
268 while ((cursor->current = dcursor_next(cursor, cursor->iter, cursor->current))) {
305 return dcursor_next(cursor, cursor->peek, cursor->current);
324 return dcursor_next(cursor, NULL, cursor->current);
340 return cursor->current;
487 if (!cursor->
current)
return NULL;
494 if (i < 0)
return NULL;
690 #define fr_dcursor_iter_mod_init(_cursor, _list, _iter, _peek, _iter_uctx, _insert, _remove, _mod_uctx) \
691 _fr_dcursor_init(_cursor, \
699 IS_CONST(fr_dlist_head_t *, _list))
713 #define fr_dcursor_iter_init(_cursor, _head, _iter, _peek, _uctx) \
714 _fr_dcursor_init(_cursor, \
722 IS_CONST(fr_dlist_head_t *, _head))
732 #define fr_dcursor_init(_cursor, _head) \
733 _fr_dcursor_init(_cursor, \
741 IS_CONST(fr_dlist_head_t *, _head))
758 static inline CC_HINT(
nonnull(1,2))
766 .peek = peek ? peek :
iter,
767 .iter_uctx =
UNCONST(
void *, iter_uctx),
770 .mod_uctx =
UNCONST(
void *, mod_uctx),
788 #define fr_dcursor_reinit(_cursor, _head) \
789 _fr_dcursor_reinit(_cursor, \
791 IS_CONST(fr_dlist_head_t *, _head))
793 static inline CC_HINT(
nonnull(1,2))
797 cursor->current = NULL;
798 cursor->is_const = is_const;
827 talloc_set_name_const(
stack,
"fr_dcursor_stack_t");
843 #define FR_DCURSOR(_name) _name ## _dcursor_t
850 #define FR_DCURSOR_ITER(_name) _name ## _iter_t
857 #define FR_DCURSOR_EVAL(_name) _name ## _eval_t
864 #define FR_DCURSOR_INSERT(_name) _name ## _insert_t
871 #define FR_DCURSOR_REMOVE(_name) _name ## _remove_t
878 #define FR_DCURSOR_COPY(_name) _name ## _copy_t
894 #define FR_DCURSOR_DLIST_TYPES(_name, _list_name, _element_type) \
895 typedef struct { fr_dcursor_t dcursor; } FR_DCURSOR(_name); \
896 typedef _element_type *(*FR_DCURSOR_ITER(_name))(FR_DLIST_HEAD(_list_name) *list, _element_type *to_eval, void *uctx); \
897 typedef bool (*FR_DCURSOR_EVAL(_name))(_element_type const *item, void const *uctx); \
898 typedef int (*FR_DCURSOR_INSERT(_name))(FR_DLIST_HEAD(_list_name) *list, FR_DLIST_ENTRY(_list_name) *to_insert, void *uctx); \
899 typedef int (*FR_DCURSOR_REMOVE(_name))(FR_DLIST_HEAD(_list_name) *list, FR_DLIST_ENTRY(_list_name) *to_delete, void *uctx); \
900 typedef void (*FR_DCURSOR_COPY(_name))(FR_DCURSOR(_name) *out, FR_DCURSOR(_name) const *in);
911 #define FR_DCURSOR_FUNCS(_name, _list_name, _element_type) \
912 DIAG_OFF(unused-function) \
913 static inline CC_HINT(nonnull) _element_type *_name ## _init(FR_DCURSOR(_name) *dcursor, \
914 FR_DLIST_HEAD(_list_name) *head) \
915 { return (_element_type *)_fr_dcursor_init(&dcursor->dcursor, &head->head, \
916 NULL, NULL, NULL, NULL, NULL, NULL, \
917 IS_CONST(FR_DLIST_HEAD(_list_name) *, head)); } \
919 static inline CC_HINT(nonnull(1,2)) _element_type *_name ## _iter_init(FR_DCURSOR(_name) *dcursor, \
920 FR_DLIST_HEAD(_list_name) *head, \
921 FR_DCURSOR_ITER(_name) iter, \
922 FR_DCURSOR_ITER(_name) peek, \
923 void const *iter_uctx) \
924 { return (_element_type *)_fr_dcursor_init(&dcursor->dcursor, &head->head, \
925 (fr_dcursor_iter_t)iter, \
926 (fr_dcursor_iter_t)peek, \
929 IS_CONST(FR_DLIST_HEAD(_list_name) *, head)); } \
931 static inline CC_HINT(nonnull(1,2)) _element_type *_name ## _iter_mod_init(FR_DCURSOR(_name) *dcursor, \
932 FR_DLIST_HEAD(_list_name) *head, \
933 FR_DCURSOR_ITER(_name) iter, \
934 FR_DCURSOR_ITER(_name) peek, \
935 void const *iter_uctx, \
936 FR_DCURSOR_INSERT(_name) insert, \
937 FR_DCURSOR_REMOVE(_name) remove, \
938 void const *mod_uctx) \
939 { return (_element_type *)_fr_dcursor_init(&dcursor->dcursor, &head->head, \
940 (fr_dcursor_iter_t)iter, \
941 (fr_dcursor_iter_t)peek, \
943 (fr_dcursor_insert_t)insert, \
944 (fr_dcursor_remove_t)remove, \
946 IS_CONST(FR_DLIST_HEAD(_list_name) *, head)); } \
948 static inline CC_HINT(nonnull) _element_type *_name ## _current(FR_DCURSOR(_name) *dcursor) \
949 { return (_element_type *)fr_dcursor_current(&dcursor->dcursor); } \
951 static inline CC_HINT(nonnull) _element_type *_name ## _next_peek(FR_DCURSOR(_name) *dcursor) \
952 { return (_element_type *)fr_dcursor_next_peek(&dcursor->dcursor); } \
954 static inline CC_HINT(nonnull) _element_type *_name ## _list_next_peek(FR_DCURSOR(_name) *dcursor) \
955 { return (_element_type *)fr_dcursor_list_next_peek(&dcursor->dcursor); } \
957 static inline CC_HINT(nonnull) _element_type *_name ## _next(FR_DCURSOR(_name) *dcursor) \
958 { return (_element_type *)fr_dcursor_next(&dcursor->dcursor); } \
960 static inline CC_HINT(nonnull) void _name ## _copy(FR_DCURSOR(_name) *out, \
961 FR_DCURSOR(_name) const *in) \
962 { fr_dcursor_copy(&out->dcursor, &in->dcursor); } \
964 static inline CC_HINT(nonnull) _element_type *_name ## _head(FR_DCURSOR(_name) *dcursor) \
965 { return (_element_type *)fr_dcursor_head(&dcursor->dcursor); } \
967 static inline CC_HINT(nonnull) _element_type *_name ## _tail(FR_DCURSOR(_name) *dcursor) \
968 { return (_element_type *)fr_dcursor_tail(&dcursor->dcursor); } \
970 static inline CC_HINT(nonnull) _element_type *_name ## _set_current(FR_DCURSOR(_name) *dcursor, \
972 { return (_element_type *)fr_dcursor_set_current(&dcursor->dcursor, v); } \
974 static inline CC_HINT(nonnull) int _name ## _prepend(FR_DCURSOR(_name) *dcursor, \
976 { return fr_dcursor_prepend(&dcursor->dcursor, v); } \
978 static inline CC_HINT(nonnull) int _name ## _append(FR_DCURSOR(_name) *dcursor, \
980 { return fr_dcursor_append(&dcursor->dcursor, v); } \
982 static inline CC_HINT(nonnull) int _name ## _insert(FR_DCURSOR(_name) *dcursor, \
984 { return fr_dcursor_insert(&dcursor->dcursor, v); } \
986 static inline CC_HINT(nonnull) _element_type *_name ## _replace(FR_DCURSOR(_name) *dcursor, \
988 { return fr_dcursor_replace(&dcursor->dcursor, v); } \
990 static inline CC_HINT(nonnull) _element_type *_name ## _remove(FR_DCURSOR(_name) *dcursor) \
991 { return (_element_type *)fr_dcursor_remove(&dcursor->dcursor); } \
993 static inline CC_HINT(nonnull) void _name ## _merge(FR_DCURSOR(_name) *cursor, \
994 FR_DCURSOR(_name) *to_append) \
995 { fr_dcursor_merge(&cursor->dcursor, &to_append->dcursor); } \
997 static inline CC_HINT(nonnull) void _name ## _free_list(FR_DCURSOR(_name) *dcursor) \
998 { fr_dcursor_free_list(&dcursor->dcursor); } \
1000 static inline CC_HINT(nonnull) void _name ## _free_item(FR_DCURSOR(_name) *dcursor) \
1001 { fr_dcursor_free_item(&dcursor->dcursor); } \
1003 static inline CC_HINT(nonnull) _element_type *_name ## _intersect_head(FR_DCURSOR(_name) *a, \
1004 FR_DCURSOR(_name) *b) \
1005 { return (_element_type *)fr_dcursor_intersect_head(&a->dcursor, &b->dcursor); } \
1007 static inline CC_HINT(nonnull) _element_type *_name ## _intersect_next(FR_DCURSOR(_name) *a, \
1008 FR_DCURSOR(_name) *b) \
1009 { return (_element_type *)fr_dcursor_intersect_next(&a->dcursor, &b->dcursor); } \
1011 static inline CC_HINT(nonnull(1,2)) _element_type *_name ## _filter_head(FR_DCURSOR(_name) *dcursor, \
1012 FR_DCURSOR_EVAL(_name) eval, \
1014 { return (_element_type *)fr_dcursor_filter_head(&dcursor->dcursor, (fr_dcursor_eval_t)eval, uctx); } \
1016 static inline CC_HINT(nonnull(1,2)) _element_type *_name ## _filter_next(FR_DCURSOR(_name) *dcursor, \
1017 FR_DCURSOR_EVAL(_name) eval, \
1019 { return (_element_type *)fr_dcursor_filter_next(&dcursor->dcursor, (fr_dcursor_eval_t)eval, uctx); } \
1021 static inline CC_HINT(nonnull(1,2)) _element_type *_name ## _filter_current(FR_DCURSOR(_name) *dcursor, \
1022 FR_DCURSOR_EVAL(_name) eval, \
1024 { 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.
static void * fr_dcursor_remove(fr_dcursor_t *cursor)
Remove the current item.
fr_dcursor_iter_t iter
Iterator function.
uint8_t depth
Which cursor is currently in use.
static void * fr_dcursor_list_next_peek(fr_dcursor_t *cursor)
Returns the next list item without advancing the cursor.
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.
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.
return fr_dcursor_filter_next(cursor, eval, uctx)
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.
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.
bool at_end
We're at the end of the list.
bool(* fr_dcursor_eval_t)(void const *item, void const *uctx)
Type of evaluation functions to pass to the fr_dcursor_filter_*() functions.
static int fr_dcursor_insert(fr_dcursor_t *cursor, void *v)
Insert directly after the current item.
static void * fr_dcursor_next_peek(fr_dcursor_t *cursor)
Return the next iterator item without advancing the cursor.
void * mod_uctx
to pass to modification functions.
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_free_item(fr_dcursor_t *cursor)
talloc_free the current item
static void * fr_dcursor_set_current(fr_dcursor_t *cursor, void *item)
Set the cursor to a specified item.
fr_dcursor_insert_t insert
Callback function on insert.
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_free_list(fr_dcursor_t *cursor)
Free the current item and all items after it.
fr_dcursor_eval_t void const * uctx
void * current
The current item in the dlist.
void *(* fr_dcursor_iter_t)(fr_dlist_head_t *list, void *to_eval, void *uctx)
Callback for implementing custom iterators.
fr_dcursor_iter_t void * current
CC_NO_UBSAN(function) static inline void *dcursor_next(fr_dcursor_t *cursor
Internal function to get the next item.
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.
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 * 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_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
static void * fr_dcursor_replace(fr_dcursor_t *cursor, void *r)
Replace the current item.
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 fr_dcursor_stack_t * fr_dcursor_stack_alloc(TALLOC_CTX *ctx, uint8_t depth)
Allocate a stack of cursors for traversing trees.
fr_dcursor_copy_t copy
Copy dcursor state.
static void * fr_dcursor_head(fr_dcursor_t *cursor)
Rewind cursor to the start of the list.
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
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_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a 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 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 bool fr_dlist_empty(fr_dlist_head_t const *list_head)
Check whether a list has any items.
static void * fr_dlist_replace(fr_dlist_head_t *list_head, void *item, void *ptr)
Replace an item in a dlist.
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 int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the 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 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 uint8_t depth(fr_minmax_heap_index_t i)
static size_t char ** out