24 RCSIDH(dlist_h,
"$Id: a500692c3d1e629036eb246a3aae2ae4c3715e1d $")
30 #include <freeradius-devel/build.h>
31 #include <freeradius-devel/missing.h>
32 #include <freeradius-devel/util/debug.h>
33 #include <freeradius-devel/util/misc.h>
34 #include <freeradius-devel/util/talloc.h>
65 static_assert(
sizeof(
unsigned int) >= 4,
"Unsigned integer too small on this platform");
75 #define FR_DLIST_ENTRY_INITIALISER(_entry) { .next = &_entry, .prev = &_entry }
85 #define FR_DLIST_HEAD_INITIALISER(_head) { .entry = FR_DLIST_ENTRY_INITIALISER((_head).entry) }
94 #define fr_dlist_foreach(_list_head, _type, _iter) \
95 for (_type *_iter = fr_dlist_head(_list_head); _iter; _iter = fr_dlist_next(_list_head, _iter))
108 #define fr_dlist_foreach_safe(_list_head, _type, _iter) \
111 fr_dlist_t _tmp ## _iter; \
112 for (_iter = fr_dlist_head(_list_head), \
113 _tmp ## _iter = fr_dlist_head(_list_head) ? *fr_dlist_item_to_entry((_list_head)->offset, fr_dlist_head(_list_head)) : (fr_dlist_t){ .prev = NULL, .next = NULL }; \
115 _iter = _tmp ## _iter.next && (_tmp ## _iter.next != &(_list_head)->entry) ? fr_dlist_entry_to_item((_list_head)->offset, _tmp ## _iter.next) : NULL, \
116 _tmp ## _iter = _tmp ## _iter.next && (_tmp ## _iter.next != &(_list_head)->entry) ? *_tmp ## _iter.next : (fr_dlist_t){ .prev = NULL, .next = NULL })
132 return (
void *)(((uintptr_t) entry) - offset);
165 if (((entry->
prev == entry) && (entry->
next == entry)) ||
166 ((entry->
prev == NULL) && (entry->
next == NULL)))
return false;
178 to_link->
prev = entry;
181 entry->
next = to_link;
191 to_link->
next = entry;
194 entry->
prev = to_link;
260 #define fr_dlist_init(_head, _type, _field) \
261 _Generic((((_type *)0)->_field), fr_dlist_t: _fr_dlist_init(_head, offsetof(_type, _field), NULL))
275 #define fr_dlist_talloc_init(_head, _type, _field) \
276 _Generic((((_type *)0)->_field), fr_dlist_t: _fr_dlist_init(_head, offsetof(_type, _field), #_type))
286 list_head->
offset = offset;
304 #define CHECK_ELEMENT_COUNT(_head, _add) \
305 if (unlikely((_head)->num_elements > (UINT_MAX - (_add)))) do { \
306 fr_strerror_const("Maximum elements in list"); \
345 #ifndef TALLOC_GET_TYPE_ABORT_NOOP
346 if (list_head->
type) ptr = _talloc_get_type_abort(ptr, list_head->
type, __location__);
357 head->next->prev = entry;
385 #ifndef TALLOC_GET_TYPE_ABORT_NOOP
386 if (list_head->
type) ptr = _talloc_get_type_abort(ptr, list_head->
type, __location__);
397 head->prev->next = entry;
420 #ifndef TALLOC_GET_TYPE_ABORT_NOOP
421 if (list_head->type) ptr = _talloc_get_type_abort(ptr, list_head->type, __location__);
426 pos_entry = &(list_head->entry);
436 list_head->num_elements++;
456 #ifndef TALLOC_GET_TYPE_ABORT_NOOP
457 if (list_head->type) ptr = _talloc_get_type_abort(ptr, list_head->type, __location__);
462 pos_entry = &(list_head->entry);
472 list_head->num_elements++;
490 if (
head->next ==
head)
return NULL;
519 if (!
head->prev && !
head->next)
return false;
535 if (
head->prev ==
head)
return NULL;
562 #ifndef TALLOC_GET_TYPE_ABORT_NOOP
563 if (list_head->type) ptr = _talloc_get_type_abort(ptr, list_head->type, __location__);
566 head = &(list_head->entry);
568 if (entry->
next ==
head)
return NULL;
569 if (!entry->
next)
return NULL;
595 #ifndef TALLOC_GET_TYPE_ABORT_NOOP
596 if (list_head->type) ptr = _talloc_get_type_abort(ptr, list_head->type, __location__);
600 head = &(list_head->entry);
602 if (entry->
prev ==
head)
return NULL;
646 #ifndef TALLOC_GET_TYPE_ABORT_NOOP
647 if (list_head->type) (void)_talloc_get_type_abort(ptr, list_head->type, __location__);
653 head = &(list_head->entry);
658 list_head->num_elements--;
660 if (prev ==
head)
return NULL;
711 if (!
item || !ptr)
return NULL;
713 #ifndef TALLOC_GET_TYPE_ABORT_NOOP
714 if (list_head->
type) (void)_talloc_get_type_abort(ptr, list_head->
type, __location__);
734 #ifndef TALLOC_GET_TYPE_ABORT_NOOP
739 if (!list_head->
type)
return;
746 item = _talloc_get_type_abort(
item, list_head->
type, __location__);
755 #define fr_dlist_verify(_head) _fr_dlist_verify(__FILE__, __LINE__, _head)
770 #ifdef WITH_VERIFY_PTR
819 #ifdef WITH_VERIFY_PTR
941 return head->num_elements;
965 if (!*source || !entry->
next) {
1004 void *result = NULL;
1015 if (cmp(*a, *b) <= 0) {
1027 result_entry->
next = next_entry;
1046 if (!*ptr || (!entry->
next))
return;
1115 #define FR_DLIST_ENTRY(_name) _name ## _entry_t
1122 #define FR_DLIST_HEAD(_name) _name ## _head_t
1129 #define FR_DLIST_TYPES(_name) \
1130 typedef struct { fr_dlist_t entry; } FR_DLIST_ENTRY(_name); \
1131 typedef struct { fr_dlist_head_t head; } FR_DLIST_HEAD(_name); \
1139 #define FR_DLIST_TYPEDEFS(_name, _head, _entry) \
1140 typedef FR_DLIST_HEAD(_name) _head; \
1141 typedef FR_DLIST_ENTRY(_name) _entry;
1152 #define FR_DLIST_FUNCS(_name, _element_type, _element_entry) \
1153 DIAG_OFF(unused-function) \
1154 _Static_assert(IS_FIELD_COMPATIBLE(_element_type, _element_entry, FR_DLIST_ENTRY(_name)) == 1, "Bad dlist entry field type");\
1155 static inline fr_dlist_head_t *_name ## _dlist_head(FR_DLIST_HEAD(_name) const *list) \
1156 { return UNCONST(fr_dlist_head_t *, &list->head); } \
1158 static inline fr_dlist_t *_name ## _dlist_entry(FR_DLIST_ENTRY(_name) const *entry) \
1159 { return UNCONST(fr_dlist_t *, &entry->entry ); } \
1161 static inline void _name ## _entry_init(_element_type *entry) \
1163 _Generic((&entry->_element_entry), \
1164 FR_DLIST_ENTRY(_name) *: fr_dlist_entry_init(UNCONST(fr_dlist_t *, &entry->_element_entry.entry)), \
1165 FR_DLIST_ENTRY(_name) const *: fr_dlist_noop()\
1169 static inline void _name ## _init(FR_DLIST_HEAD(_name) *list) \
1170 { _fr_dlist_init(&list->head, offsetof(_element_type, _element_entry), NULL); } \
1172 static inline void _name ## _talloc_init(FR_DLIST_HEAD(_name) *list) \
1173 { _fr_dlist_init(&list->head, offsetof(_element_type, _element_entry), #_element_type); } \
1175 static inline void _name ## _clear(FR_DLIST_HEAD(_name) *list) \
1176 { fr_dlist_clear(&list->head); } \
1178 static inline bool _name ## _in_list(FR_DLIST_HEAD(_name) *list, _element_type *ptr) \
1179 { return fr_dlist_in_list(&list->head, ptr); } \
1181 static inline int _name ## _insert_head(FR_DLIST_HEAD(_name) *list, _element_type *ptr) \
1182 { return fr_dlist_insert_head(&list->head, ptr); } \
1184 static inline int _name ## _insert_tail(FR_DLIST_HEAD(_name) *list, _element_type *ptr) \
1185 { return fr_dlist_insert_tail(&list->head, ptr); } \
1187 static inline int _name ## _insert_after(FR_DLIST_HEAD(_name) *list, _element_type *pos, _element_type *ptr) \
1188 { return fr_dlist_insert_after(&list->head, pos, ptr); } \
1190 static inline int _name ## _insert_before(FR_DLIST_HEAD(_name) *list, _element_type *pos, _element_type *ptr) \
1191 { return fr_dlist_insert_before(&list->head, pos, ptr); } \
1193 static inline _element_type *_name ## _head(FR_DLIST_HEAD(_name) const *list) \
1194 { return fr_dlist_head(&list->head); } \
1196 static inline bool _name ## _empty(FR_DLIST_HEAD(_name) const *list) \
1197 { return fr_dlist_empty(&list->head); } \
1199 static inline bool _name ## _initialised(FR_DLIST_HEAD(_name) const *list) \
1200 { return fr_dlist_initialised(&list->head); } \
1202 static inline _element_type *_name ## _tail(FR_DLIST_HEAD(_name) const *list) \
1203 { return fr_dlist_tail(&list->head); } \
1205 static inline _element_type *_name ## _next(FR_DLIST_HEAD(_name) const *list, _element_type const *ptr) \
1206 { return fr_dlist_next(&list->head, ptr); } \
1208 static inline _element_type *_name ## _prev(FR_DLIST_HEAD(_name) const *list, _element_type const *ptr) \
1209 { return fr_dlist_prev(&list->head, ptr); } \
1211 static inline _element_type *_name ## _remove(FR_DLIST_HEAD(_name) *list, _element_type *ptr) \
1212 { return fr_dlist_remove(&list->head, ptr); } \
1214 static inline _element_type *_name ## _pop_head(FR_DLIST_HEAD(_name) *list) \
1215 { return fr_dlist_pop_head(&list->head); } \
1217 static inline _element_type *_name ## _pop_tail(FR_DLIST_HEAD(_name) *list) \
1218 { return fr_dlist_pop_tail(&list->head); } \
1220 static inline _element_type *_name ## _replace(FR_DLIST_HEAD(_name) *list, _element_type *item, _element_type *ptr) \
1221 { return fr_dlist_replace(&list->head, item, ptr); } \
1223 static inline void _##_name ## _verify(char const *file, int line, FR_DLIST_HEAD(_name) const *list_head) \
1224 { _fr_dlist_verify(file, line, UNCONST(fr_dlist_head_t *, &list_head->head)); } \
1226 static inline int _name ## _move(FR_DLIST_HEAD(_name) *dst, FR_DLIST_HEAD(_name) *src) \
1227 { return fr_dlist_move(&dst->head, &src->head); } \
1229 static inline int _name ## _move_head(FR_DLIST_HEAD(_name) *dst, FR_DLIST_HEAD(_name) *src) \
1230 { return fr_dlist_move_head(&dst->head, &src->head); } \
1232 static inline void _name ## _talloc_free_head(FR_DLIST_HEAD(_name) *list) \
1233 { fr_dlist_talloc_free_head(&list->head); } \
1235 static inline void _name ## _talloc_free_tail(FR_DLIST_HEAD(_name) *list) \
1236 { fr_dlist_talloc_free_tail(&list->head); } \
1238 static inline _element_type * _name ## _talloc_free_item(FR_DLIST_HEAD(_name) *list, _element_type *ptr) \
1239 {return fr_dlist_talloc_free_item(&list->head, ptr); } \
1241 static inline void _name ## _talloc_free(FR_DLIST_HEAD(_name) *list) \
1242 { fr_dlist_talloc_free(&list->head); } \
1244 static inline void _name ## _talloc_free_to_tail(FR_DLIST_HEAD(_name) *list, _element_type *ptr) \
1245 { fr_dlist_talloc_free_to_tail(&list->head, ptr); } \
1247 static inline void _name ## _talloc_reverse_free(FR_DLIST_HEAD(_name) *list) \
1248 { fr_dlist_talloc_reverse_free(&list->head); } \
1250 static inline unsigned int _name ## _num_elements(FR_DLIST_HEAD(_name) const *list) \
1251 { return fr_dlist_num_elements(&list->head); } \
1253 static inline void _name ## _sort(FR_DLIST_HEAD(_name) *list, fr_cmp_t cmp) \
1254 { fr_dlist_sort(&list->head, cmp); } \
1255 DIAG_ON(unused-function)
#define static_assert
For systems with an old version libc, define static_assert.
#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.
static void fr_dlist_entry_link_before(fr_dlist_t *entry, fr_dlist_t *to_link)
Link in a single entry before the current entry.
static void * fr_dlist_pop_head(fr_dlist_head_t *list_head)
Remove the head item in a 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_verify(char const *file, int line, fr_dlist_head_t const *list_head)
Check all items in the list are valid.
static void fr_dlist_talloc_free_head(fr_dlist_head_t *list_head)
Free the first item in the list.
static void * fr_dlist_talloc_free_item(fr_dlist_head_t *list_head, void *ptr)
Free the item specified.
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 bool fr_dlist_entry_in_list(fr_dlist_t const *entry)
Check if a list entry is part of a list.
static void fr_dlist_talloc_free_to_tail(fr_dlist_head_t *head, void *ptr)
Free items in a doubly linked list (with talloc)
static void fr_dlist_talloc_free(fr_dlist_head_t *head)
Free all items in a doubly linked list (with talloc)
static void * fr_dlist_pop_tail(fr_dlist_head_t *list_head)
Remove the tail item in a 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 bool fr_dlist_in_list(fr_dlist_head_t *list_head, void *ptr)
Check if a list entry is part of a 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_talloc_free_tail(fr_dlist_head_t *list_head)
Free the last item in the list.
static void fr_dlist_entry_replace(fr_dlist_t *entry, fr_dlist_t *replacement)
Replace one entry with another.
static void * fr_dlist_entry_to_item(size_t offset, fr_dlist_t const *entry)
Get the item from a fr_dlist_t.
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_init(fr_dlist_head_t *list_head, size_t offset, char const *type)
Initialise common fields in a dlist.
unsigned int num_elements
Number of elements contained within the 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_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_noop(void)
static void fr_dlist_entry_move(fr_dlist_t *dst, fr_dlist_t *src)
Link in a sublist before the current entry.
fr_dlist_t entry
Struct holding the head and tail of the list.
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
static void fr_dlist_entry_link_after(fr_dlist_t *entry, fr_dlist_t *to_link)
Link in a single entry after the current entry.
static void * fr_dlist_prev(fr_dlist_head_t const *list_head, void const *ptr)
Get the previous item in a list.
static void fr_dlist_talloc_reverse_free(fr_dlist_head_t *head)
Free all items in a doubly linked list from the tail backwards.
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 fr_dlist_t * fr_dlist_item_to_entry(size_t offset, void const *item)
Find the dlist pointers within a list item.
#define CHECK_ELEMENT_COUNT(_head, _add)
Verify we're not going to overflow the element count.
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