24 RCSIDH(tlist_h,
"$Id: 5d6d3918a13b36a43049c5a0d32f9a3c2c3cbfea $")
30 #include <freeradius-devel/util/dlist.h>
41 #define tlist_type(_list) ((_list)->dlist_head.type)
138 #define fr_tlist_init(_head, _type, _field) \
139 _Generic((((_type *)0)->_field), fr_tlist_t: _fr_tlist_init(_head, offsetof(_type, _field), NULL))
153 #define fr_tlist_talloc_init(_head, _type, _field) \
154 _Generic((((_type *)0)->_field), fr_tlist_t: _fr_tlist_init(_head, offsetof(_type, _field), #_type))
179 #define fr_tlist_foreach_entry(_list_head, _iter) \
180 for (void *_iter = fr_dlist_head(&_list_head->dlist_head); _iter; _iter = fr_dlist_next(&_list_head->dlist_head, _iter))
319 if (!list_head)
return true;
488 #ifndef TALLOC_GET_TYPE_ABORT_NOOP
503 fr_assert_msg(entry->
list_head == list_head,
"CONSISTENCY CHECK FAILED %s[%i]: tlist entry %p has wrong parent",
513 "CONSISTENCY CHECK FAILED %s[%i]: tlist entry %p has different child type from parent",
520 # define FR_TLIST_VERIFY(_head) fr_tlist_verify(__FILE__, __LINE__, _head)
521 #elif !defined(NDEBUG)
522 # define FR_TLIST_VERIFY(_head) fr_assert(_head)
524 # define FR_TLIST_VERIFY(_head)
538 #ifdef WITH_VERIFY_PTR
576 #ifdef WITH_VERIFY_PTR
762 #define FR_TLIST_ENTRY(_name) _name ## _entry_t
769 #define FR_TLIST_HEAD(_name) _name ## _head_t
776 #define FR_TLIST_TYPES(_name) \
777 typedef struct { fr_tlist_t entry; } FR_TLIST_ENTRY(_name); \
778 typedef struct { fr_tlist_head_t head; } FR_TLIST_HEAD(_name); \
790 #define FR_TLIST_FUNCS(_name, _element_type, _element_entry) \
791 DIAG_OFF(unused-function) \
792 _Static_assert(IS_FIELD_COMPATIBLE(_element_type, _element_entry, FR_TLIST_ENTRY(_name)) == 1, "Bad tlist entry field type");\
793 static inline fr_tlist_head_t *_name ## _list_head(FR_TLIST_HEAD(_name) const *list) \
794 { return UNCONST(fr_tlist_head_t *, &list->head); } \
796 static inline fr_dlist_head_t *_name ## _dlist_head(FR_TLIST_HEAD(_name) const *list) \
797 { return UNCONST(fr_dlist_head_t *, &list->head.dlist_head); } \
799 static inline void _name ## _entry_init(_element_type *entry) \
801 _Generic((&entry->_element_entry), \
802 FR_TLIST_ENTRY(_name) *: fr_tlist_entry_init(UNCONST(fr_tlist_t *, &entry->_element_entry.entry)), \
803 FR_TLIST_ENTRY(_name) const *: fr_tlist_noop()\
807 static inline void _name ## _init(FR_TLIST_HEAD(_name) *list) \
808 { _fr_tlist_init(&list->head, offsetof(_element_type, _element_entry), NULL); } \
810 static inline void _name ## _talloc_init(FR_TLIST_HEAD(_name) *list) \
811 { _fr_tlist_init(&list->head, offsetof(_element_type, _element_entry), #_element_type); } \
813 static inline void _name ## _clear(FR_TLIST_HEAD(_name) *list) \
814 { fr_tlist_clear(&list->head); } \
816 static inline bool _name ## _in_list(FR_TLIST_HEAD(_name) *list, _element_type *ptr) \
817 { return fr_tlist_in_list(&list->head, ptr); } \
819 static inline bool _name ## _in_a_list(_element_type *ptr) \
820 { return fr_tlist_entry_in_a_list(&ptr->_element_entry.entry); } \
822 static inline int _name ## _insert_head(FR_TLIST_HEAD(_name) *list, _element_type *ptr) \
823 { return fr_tlist_insert_head(&list->head, ptr); } \
825 static inline int _name ## _insert_tail(FR_TLIST_HEAD(_name) *list, _element_type *ptr) \
826 { return fr_tlist_insert_tail(&list->head, ptr); } \
828 static inline int _name ## _insert_after(FR_TLIST_HEAD(_name) *list, _element_type *pos, _element_type *ptr) \
829 { return fr_tlist_insert_after(&list->head, pos, ptr); } \
831 static inline int _name ## _insert_before(FR_TLIST_HEAD(_name) *list, _element_type *pos, _element_type *ptr) \
832 { return fr_tlist_insert_before(&list->head, pos, ptr); } \
834 static inline _element_type *_name ## _head(FR_TLIST_HEAD(_name) const *list) \
835 { return fr_tlist_head(&list->head); } \
837 static inline bool _name ## _empty(FR_TLIST_HEAD(_name) const *list) \
838 { return fr_tlist_empty(&list->head); } \
840 static inline bool _name ## _initialised(FR_TLIST_HEAD(_name) const *list) \
841 { return fr_tlist_initialised(&list->head); } \
843 static inline _element_type *_name ## _tail(FR_TLIST_HEAD(_name) const *list) \
844 { return fr_tlist_tail(&list->head); } \
846 static inline _element_type *_name ## _next(FR_TLIST_HEAD(_name) const *list, _element_type const *ptr) \
847 { return fr_tlist_next(&list->head, ptr); } \
849 static inline _element_type *_name ## _prev(FR_TLIST_HEAD(_name) const *list, _element_type const *ptr) \
850 { return fr_tlist_prev(&list->head, ptr); } \
852 static inline _element_type *_name ## _remove(FR_TLIST_HEAD(_name) *list, _element_type *ptr) \
853 { return fr_tlist_remove(&list->head, ptr); } \
855 static inline _element_type *_name ## _pop_head(FR_TLIST_HEAD(_name) *list) \
856 { return fr_tlist_pop_head(&list->head); } \
858 static inline _element_type *_name ## _pop_tail(FR_TLIST_HEAD(_name) *list) \
859 { return fr_tlist_pop_tail(&list->head); } \
861 static inline _element_type *_name ## _replace(FR_TLIST_HEAD(_name) *list, _element_type *item, _element_type *ptr) \
862 { return fr_tlist_replace(&list->head, item, ptr); } \
864 static inline int _name ## _move(FR_TLIST_HEAD(_name) *dst, FR_TLIST_HEAD(_name) *src) \
865 { return fr_tlist_move(&dst->head, &src->head); } \
867 static inline int _name ## _move_head(FR_TLIST_HEAD(_name) *dst, FR_TLIST_HEAD(_name) *src) \
868 { return fr_tlist_move_head(&dst->head, &src->head); } \
870 static inline void _name ## _talloc_free_head(FR_TLIST_HEAD(_name) *list) \
871 { fr_tlist_talloc_free_head(&list->head); } \
873 static inline void _name ## _talloc_free_tail(FR_TLIST_HEAD(_name) *list) \
874 { fr_tlist_talloc_free_tail(&list->head); } \
876 static inline void _name ## _talloc_free_item(FR_TLIST_HEAD(_name) *list, _element_type *ptr) \
877 { fr_tlist_talloc_free_item(&list->head, ptr); } \
879 static inline void _name ## _talloc_free(FR_TLIST_HEAD(_name) *list) \
880 { fr_tlist_talloc_free(&list->head); } \
882 static inline void _name ## _talloc_free_to_tail(FR_TLIST_HEAD(_name) *list, _element_type *ptr) \
883 { fr_tlist_talloc_free_to_tail(&list->head, ptr); } \
885 static inline void _name ## _talloc_reverse_free(FR_TLIST_HEAD(_name) *list) \
886 { fr_tlist_talloc_reverse_free(&list->head); } \
888 static inline unsigned int _name ## _num_elements(FR_TLIST_HEAD(_name) const *list) \
889 { return fr_tlist_num_elements(&list->head); } \
891 static inline void _name ## _sort(FR_TLIST_HEAD(_name) *list, fr_cmp_t cmp) \
892 { fr_tlist_sort(&list->head, cmp); } \
894 static inline FR_TLIST_HEAD(_name) *_name ## _parent(const _element_type *ptr) \
895 { return (FR_TLIST_HEAD(_name) *) (ptr->_element_entry.entry.list_head); } \
897 static inline FR_TLIST_HEAD(_name) *_name ## _children(_element_type *ptr) \
898 { return (FR_TLIST_HEAD(_name) *) (ptr->_element_entry.entry.children); } \
900 static inline void _name ## _talloc_init_children(_element_type *ptr, FR_TLIST_HEAD(_name) *children) \
901 { _name ## _talloc_init(children); ptr->_element_entry.entry.children = &children->head; } \
903 static inline void _name ## _add_children(_element_type *ptr, FR_TLIST_HEAD(_name) *children) \
904 { fr_tlist_add_children(&ptr->_element_entry.entry, &children->head); } \
906 static inline FR_TLIST_HEAD(_name) * _name ## _remove_children(_element_type *ptr) \
907 { return (FR_TLIST_HEAD(_name) *) fr_tlist_remove_children(&ptr->_element_entry.entry); } \
909 static inline void _name ## _set_head(fr_tlist_head_t *list, _element_type *ptr) \
910 { ptr->_element_entry.entry.list_head = list; }
917 if (!ptr || !list_head)
return NULL;
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
static void fr_dlist_sort(fr_dlist_head_t *list, fr_cmp_t cmp)
Sort a dlist using merge sort.
#define fr_dlist_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
static int fr_dlist_move_head(fr_dlist_head_t *list_dst, fr_dlist_head_t *list_src)
Merge two lists, inserting the source at the head of the destination.
unsigned int offset
Positive offset from start of structure to fr_dlist_t.
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
static void fr_dlist_sort_split(fr_dlist_head_t *head, void **source, void **front, void **back)
Split phase of a merge sort of a dlist.
static void fr_dlist_recursive_sort(fr_dlist_head_t *head, void **ptr, fr_cmp_t cmp)
Recursive sort routine for dlist.
static int fr_dlist_insert_before(fr_dlist_head_t *list_head, void *pos, void *ptr)
Insert an item before an item already in the list.
static void * fr_dlist_sort_merge(fr_dlist_head_t *head, void **a, void **b, fr_cmp_t cmp)
Merge phase of a merge sort of a dlist.
static void fr_dlist_entry_unlink(fr_dlist_t *entry)
Remove an item from the dlist when we don't have access to the head.
char const * type
of items contained within the list.
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
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 int fr_dlist_move(fr_dlist_head_t *list_dst, fr_dlist_head_t *list_src)
Merge two lists, inserting the source at the tail of the destination.
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
static void * fr_dlist_prev(fr_dlist_head_t const *list_head, void const *ptr)
Get the previous item in 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_entry_init(fr_dlist_t *entry)
Initialise a linked list without metadata.
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.
static bool fr_dlist_initialised(fr_dlist_head_t const *list_head)
Check if the list head is initialised.
static void fr_dlist_clear(fr_dlist_head_t *list_head)
Efficiently remove all elements in a dlist.
Head of a doubly linked list.
Entry in a doubly linked list.
int8_t(* fr_cmp_t)(void const *a, void const *b)
fr_aka_sim_id_type_t type
static void fr_tlist_entry_init(fr_tlist_t *entry)
Initialise a linked list without metadata.
static fr_tlist_head_t * fr_tlist_remove_children(fr_tlist_t *entry)
Remove a child tlist from a parent entry.
static void fr_tlist_talloc_free(fr_tlist_head_t *head)
Free all items in a doubly linked list (with talloc)
static void fr_tlist_talloc_free_to_tail(fr_tlist_head_t *head, void *ptr)
Free items in a doubly linked list (with talloc)
fr_tlist_t * parent
the parent entry which holds this list. May be NULL.
static void * fr_tlist_entry_to_item(fr_tlist_head_t const *list_head, fr_tlist_t const *entry)
Get the item from a fr_tlist_t.
static void * fr_tlist_replace(fr_tlist_head_t *list_head, void *item, void *ptr)
Replace an item in a dlist.
static fr_tlist_t * fr_tlist_item_to_entry(fr_tlist_head_t const *list_head, void const *item)
Find the tlist pointers within a list item.
static void fr_tlist_sort_split(fr_tlist_head_t *head, void **source, void **front, void **back)
Split phase of a merge sort of a dlist.
static void * fr_tlist_head(fr_tlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
static fr_tlist_head_t * fr_tlist_head_from_dlist(fr_dlist_head_t *dlist_head)
Get a fr_tlist_head_t from a fr_dlist_head_t.
static bool fr_tlist_empty(fr_tlist_head_t const *list_head)
Check whether a list has any items.
static void fr_tlist_talloc_free_tail(fr_tlist_head_t *list_head)
Free the last item in the list.
static void fr_tlist_talloc_free_head(fr_tlist_head_t *list_head)
Free the first item in the list.
static void * fr_tlist_pop_tail(fr_tlist_head_t *list_head)
Remove the tail item in a list.
static int fr_tlist_insert_tail(fr_tlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
static void * fr_tlist_pop_head(fr_tlist_head_t *list_head)
Remove the head item in a list.
fr_tlist_head_t * list_head
the list which holds this entry
static void fr_tlist_noop(void)
static void fr_tlist_sort(fr_tlist_head_t *list, fr_cmp_t cmp)
Sort a tlist using merge sort.
static void * fr_tlist_sort_merge(fr_tlist_head_t *head, void **a, void **b, fr_cmp_t cmp)
Merge phase of a merge sort of a dlist.
static void fr_tlist_verify(char const *file, int line, fr_tlist_head_t const *list_head)
Check all items in the list are valid.
static void fr_tlist_recursive_sort(fr_tlist_head_t *head, void **ptr, fr_cmp_t cmp)
Recursive sort routine for tlist.
static void * fr_tlist_talloc_free_item(fr_tlist_head_t *list_head, void *ptr)
Free the item specified.
#define fr_tlist_foreach_entry(_list_head, _iter)
Iterate over the contents of a list, only one level.
static void * fr_tlist_next(fr_tlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
static int fr_tlist_insert_before(fr_tlist_head_t *list_head, void *pos, void *ptr)
Insert an item after an item already in the list.
static int fr_tlist_insert_head(fr_tlist_head_t *list_head, void *ptr)
Insert an item into the head of a list.
static int fr_tlist_add_children(fr_tlist_t *entry, fr_tlist_head_t *children)
Add a pre-initialized child tlist to a parent entry.
fr_dlist_head_t dlist_head
static int fr_tlist_move(fr_tlist_head_t *list_dst, fr_tlist_head_t *list_src)
Merge two lists, inserting the source at the tail of the destination.
static unsigned int fr_tlist_num_elements(fr_tlist_head_t const *list_head)
Return the number of elements in the tlist.
static bool fr_tlist_entry_in_a_list(fr_tlist_t const *entry)
Check if a list entry is part of a list.
static void fr_tlist_init_children(fr_tlist_t *entry, fr_tlist_head_t *children)
Initialize a child tlist based on a parent entry.
static void * fr_tlist_parent(fr_tlist_head_t *list_head, void const *ptr)
static int fr_tlist_insert_after(fr_tlist_head_t *list_head, void *pos, void *ptr)
Insert an item after an item already in the list.
static int fr_tlist_move_head(fr_tlist_head_t *list_dst, fr_tlist_head_t *list_src)
Merge two lists, inserting the source at the head of the destination.
static void fr_tlist_entry_unlink(fr_tlist_t *entry)
static void fr_tlist_clear(fr_tlist_head_t *list_head)
Remove all elements in a tlist.
static void fr_tlist_talloc_reverse_free(fr_tlist_head_t *head)
Free all items in a doubly linked list from the tail backwards.
static void * fr_tlist_remove(fr_tlist_head_t *list_head, void *ptr)
Remove an item from the list.
static void _fr_tlist_init(fr_tlist_head_t *list_head, size_t offset, char const *type)
Initialise common fields in a tlist.
#define tlist_type(_list)
fr_tlist_head_t * children
any child list
static bool fr_tlist_in_list(fr_tlist_head_t *list_head, void *ptr)
Check if a list entry is part of a tlist.
fr_dlist_t dlist_entry
the doubly linked list of entries.
static void * fr_tlist_tail(fr_tlist_head_t const *list_head)
Return the TAIL item of a list or NULL if the list is empty.
static void * fr_tlist_prev(fr_tlist_head_t const *list_head, void const *ptr)
Get the previous item in a list.
static bool fr_tlist_initialised(fr_tlist_head_t const *list_head)
Check if the list head is initialised.