24RCSIDH(dlist_h,
"$Id: 0bdcadc52c9cf5936638fcde276ee1c1776d4828 $")
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>
65static_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) }
98#define fr_dlist_foreach(_list_head, _type, _iter) \
99 for (_type *JOIN(_next,_iter), *_iter = fr_dlist_head(_list_head); JOIN(_next,_iter) = fr_dlist_next(_list_head, _iter), _iter != NULL; _iter = JOIN(_next,_iter))
114 return (
void *)(((uintptr_t) entry) - offset);
147 if (((entry->
prev == entry) && (entry->
next == entry)) ||
148 ((entry->
prev == NULL) && (entry->
next == NULL)))
return false;
160 to_link->
prev = entry;
163 entry->
next = to_link;
173 to_link->
next = entry;
176 entry->
prev = to_link;
242#define fr_dlist_init(_head, _type, _field) \
243 _Generic((((_type *)0)->_field), fr_dlist_t: _fr_dlist_init(_head, offsetof(_type, _field), NULL))
257#define fr_dlist_talloc_init(_head, _type, _field) \
258 _Generic((((_type *)0)->_field), fr_dlist_t: _fr_dlist_init(_head, offsetof(_type, _field), #_type))
268 list_head->
offset = offset;
286#define CHECK_ELEMENT_COUNT(_head, _add) \
287 if (unlikely((_head)->num_elements > (UINT_MAX - (_add)))) do { \
288 fr_strerror_const("Maximum elements in list"); \
327#ifndef TALLOC_GET_TYPE_ABORT_NOOP
367#ifndef TALLOC_GET_TYPE_ABORT_NOOP
402#ifndef TALLOC_GET_TYPE_ABORT_NOOP
408 pos_entry = &(list_head->entry);
418 list_head->num_elements++;
438#ifndef TALLOC_GET_TYPE_ABORT_NOOP
444 pos_entry = &(list_head->entry);
454 list_head->num_elements++;
472 if (
head->next ==
head)
return NULL;
501 if (!
head->prev && !
head->next)
return false;
517 if (
head->prev ==
head)
return NULL;
544#ifndef TALLOC_GET_TYPE_ABORT_NOOP
548 head = &(list_head->entry);
550 if (entry->
next ==
head)
return NULL;
551 if (!entry->
next)
return NULL;
577#ifndef TALLOC_GET_TYPE_ABORT_NOOP
582 head = &(list_head->entry);
584 if (entry->
prev ==
head)
return NULL;
628#ifndef TALLOC_GET_TYPE_ABORT_NOOP
635 head = &(list_head->entry);
640 list_head->num_elements--;
642 if (prev ==
head)
return NULL;
693 if (!
item || !ptr)
return NULL;
695#ifndef TALLOC_GET_TYPE_ABORT_NOOP
716#ifndef TALLOC_GET_TYPE_ABORT_NOOP
721 if (!list_head->
type)
return;
737#define fr_dlist_verify(_head) _fr_dlist_verify(__FILE__, __LINE__, _head)
752#ifdef WITH_VERIFY_PTR
801#ifdef WITH_VERIFY_PTR
923 return head->num_elements;
947 if (!*source || !entry->
next) {
1030 result_entry->
next = next_entry;
1054 if (!*ptr || (!entry->
next))
return 0;
1087#ifdef __clang_analyzer__
1136#define FR_DLIST_ENTRY(_name) _name ## _entry_t
1143#define FR_DLIST_HEAD(_name) _name ## _head_t
1150#define FR_DLIST_TYPES(_name) \
1151 typedef struct { fr_dlist_t entry; } FR_DLIST_ENTRY(_name); \
1152 typedef struct { fr_dlist_head_t head; } FR_DLIST_HEAD(_name); \
1160#define FR_DLIST_TYPEDEFS(_name, _head, _entry) \
1161 typedef FR_DLIST_HEAD(_name) _head; \
1162 typedef FR_DLIST_ENTRY(_name) _entry;
1173#define FR_DLIST_FUNCS(_name, _element_type, _element_entry) \
1174DIAG_OFF(unused-function) \
1175 _Static_assert(IS_FIELD_COMPATIBLE(_element_type, _element_entry, FR_DLIST_ENTRY(_name)) == 1, "Bad dlist entry field type");\
1176 static inline fr_dlist_head_t *_name ## _dlist_head(FR_DLIST_HEAD(_name) const *list) \
1177 { return UNCONST(fr_dlist_head_t *, &list->head); } \
1179 static inline fr_dlist_t *_name ## _dlist_entry(FR_DLIST_ENTRY(_name) const *entry) \
1180 { return UNCONST(fr_dlist_t *, &entry->entry ); } \
1182 static inline void _name ## _entry_init(_element_type *entry) \
1184 _Generic((&entry->_element_entry), \
1185 FR_DLIST_ENTRY(_name) *: fr_dlist_entry_init(UNCONST(fr_dlist_t *, &entry->_element_entry.entry)), \
1186 FR_DLIST_ENTRY(_name) const *: fr_dlist_noop()\
1190 static inline void _name ## _init(FR_DLIST_HEAD(_name) *list) \
1191 { _fr_dlist_init(&list->head, offsetof(_element_type, _element_entry), NULL); } \
1193 static inline void _name ## _talloc_init(FR_DLIST_HEAD(_name) *list) \
1194 { _fr_dlist_init(&list->head, offsetof(_element_type, _element_entry), #_element_type); } \
1196 static inline void _name ## _clear(FR_DLIST_HEAD(_name) *list) \
1197 { fr_dlist_clear(&list->head); } \
1199 static inline bool _name ## _in_list(FR_DLIST_HEAD(_name) *list, _element_type *ptr) \
1200 { return fr_dlist_in_list(&list->head, ptr); } \
1202 static inline int _name ## _insert_head(FR_DLIST_HEAD(_name) *list, _element_type *ptr) \
1203 { return fr_dlist_insert_head(&list->head, ptr); } \
1205 static inline int _name ## _insert_tail(FR_DLIST_HEAD(_name) *list, _element_type *ptr) \
1206 { return fr_dlist_insert_tail(&list->head, ptr); } \
1208 static inline int _name ## _insert_after(FR_DLIST_HEAD(_name) *list, _element_type *pos, _element_type *ptr) \
1209 { return fr_dlist_insert_after(&list->head, pos, ptr); } \
1211 static inline int _name ## _insert_before(FR_DLIST_HEAD(_name) *list, _element_type *pos, _element_type *ptr) \
1212 { return fr_dlist_insert_before(&list->head, pos, ptr); } \
1214 static inline _element_type *_name ## _head(FR_DLIST_HEAD(_name) const *list) \
1215 { return fr_dlist_head(&list->head); } \
1217 static inline bool _name ## _empty(FR_DLIST_HEAD(_name) const *list) \
1218 { return fr_dlist_empty(&list->head); } \
1220 static inline bool _name ## _initialised(FR_DLIST_HEAD(_name) const *list) \
1221 { return fr_dlist_initialised(&list->head); } \
1223 static inline _element_type *_name ## _tail(FR_DLIST_HEAD(_name) const *list) \
1224 { return fr_dlist_tail(&list->head); } \
1226 static inline _element_type *_name ## _next(FR_DLIST_HEAD(_name) const *list, _element_type const *ptr) \
1227 { return fr_dlist_next(&list->head, ptr); } \
1229 static inline _element_type *_name ## _prev(FR_DLIST_HEAD(_name) const *list, _element_type const *ptr) \
1230 { return fr_dlist_prev(&list->head, ptr); } \
1232 static inline _element_type *_name ## _remove(FR_DLIST_HEAD(_name) *list, _element_type *ptr) \
1233 { return fr_dlist_remove(&list->head, ptr); } \
1235 static inline _element_type *_name ## _pop_head(FR_DLIST_HEAD(_name) *list) \
1236 { return fr_dlist_pop_head(&list->head); } \
1238 static inline _element_type *_name ## _pop_tail(FR_DLIST_HEAD(_name) *list) \
1239 { return fr_dlist_pop_tail(&list->head); } \
1241 static inline _element_type *_name ## _replace(FR_DLIST_HEAD(_name) *list, _element_type *item, _element_type *ptr) \
1242 { return fr_dlist_replace(&list->head, item, ptr); } \
1244 static inline void _##_name ## _verify(char const *file, int line, FR_DLIST_HEAD(_name) const *list_head) \
1245 { _fr_dlist_verify(file, line, UNCONST(fr_dlist_head_t *, &list_head->head)); } \
1247 static inline int _name ## _move(FR_DLIST_HEAD(_name) *dst, FR_DLIST_HEAD(_name) *src) \
1248 { return fr_dlist_move(&dst->head, &src->head); } \
1250 static inline int _name ## _move_head(FR_DLIST_HEAD(_name) *dst, FR_DLIST_HEAD(_name) *src) \
1251 { return fr_dlist_move_head(&dst->head, &src->head); } \
1253 static inline void _name ## _talloc_free_head(FR_DLIST_HEAD(_name) *list) \
1254 { fr_dlist_talloc_free_head(&list->head); } \
1256 static inline void _name ## _talloc_free_tail(FR_DLIST_HEAD(_name) *list) \
1257 { fr_dlist_talloc_free_tail(&list->head); } \
1259 static inline _element_type * _name ## _talloc_free_item(FR_DLIST_HEAD(_name) *list, _element_type *ptr) \
1260 {return fr_dlist_talloc_free_item(&list->head, ptr); } \
1262 static inline void _name ## _talloc_free(FR_DLIST_HEAD(_name) *list) \
1263 { fr_dlist_talloc_free(&list->head); } \
1265 static inline void _name ## _talloc_free_to_tail(FR_DLIST_HEAD(_name) *list, _element_type *ptr) \
1266 { fr_dlist_talloc_free_to_tail(&list->head, ptr); } \
1268 static inline void _name ## _talloc_reverse_free(FR_DLIST_HEAD(_name) *list) \
1269 { fr_dlist_talloc_reverse_free(&list->head); } \
1271 static inline unsigned int _name ## _num_elements(FR_DLIST_HEAD(_name) const *list) \
1272 { return fr_dlist_num_elements(&list->head); } \
1274 static inline int _name ## _sort(FR_DLIST_HEAD(_name) *list, fr_cmp_t cmp) \
1275 { return fr_dlist_sort(&list->head, cmp); } \
1276DIAG_ON(unused-function)
fr_cmp_ret_t
Result of an ordering comparison.
@ CMP_ERR
comparison failed
#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_entry_link_before(fr_dlist_t *entry, fr_dlist_t *to_link)
Link in a single entry before the current entry.
static int fr_dlist_sort_merge(void **merged, fr_dlist_head_t *head, void **a, void **b, fr_cmp_t cmp)
Merge phase of a merge sort of a dlist.
static fr_dlist_t * fr_dlist_item_to_entry(size_t offset, void const *item)
Find the dlist pointers within a list item.
static int fr_dlist_sort(fr_dlist_head_t *list, fr_cmp_t cmp)
Sort a dlist using merge sort.
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_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_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the 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 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 int fr_dlist_talloc_free_head(fr_dlist_head_t *list_head)
Free the first item in the 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_verify(NDEBUG_UNUSED char const *file, NDEBUG_UNUSED int line, fr_dlist_head_t const *list_head)
Check all items in the list are valid.
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 void * fr_dlist_prev(fr_dlist_head_t const *list_head, void const *ptr)
Get the previous 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_entry_to_item(size_t offset, fr_dlist_t const *entry)
Get the item from a fr_dlist_t.
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
static bool fr_dlist_empty(fr_dlist_head_t const *list_head)
Check whether a list has any items.
static void * fr_dlist_pop_tail(fr_dlist_head_t *list_head)
Remove the tail item in a list.
static void * fr_dlist_pop_head(fr_dlist_head_t *list_head)
Remove the head item in 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 void fr_dlist_entry_replace(fr_dlist_t *entry, fr_dlist_t *replacement)
Replace one entry with another.
static void * fr_dlist_talloc_free_item(fr_dlist_head_t *list_head, void *ptr)
Free the item specified.
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_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_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_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.
#define CHECK_ELEMENT_COUNT(_head, _add)
Verify we're not going to overflow the element count.
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.
static bool fr_dlist_initialised(fr_dlist_head_t const *list_head)
Check if the list head is initialised.
static int fr_dlist_recursive_sort(fr_dlist_head_t *head, void **ptr, fr_cmp_t cmp)
Recursive sort routine for dlist.
static int fr_dlist_talloc_free_tail(fr_dlist_head_t *list_head)
Free the last item in the list.
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.
static void * item(fr_lst_t const *lst, fr_lst_index_t idx)
void * _talloc_get_type_abort(const void *ptr, const char *name, const char *location)
fr_cmp_ret_t(* fr_cmp_t)(void const *a, void const *b)
fr_aka_sim_id_type_t type