mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 18:27:21 +00:00
lib: add DECLARE_DLIST (double-linked list)
Turns out we need one of these. Same API as DECLARE_LIST, but deleting random items is much faster. Signed-off-by: David Lamparter <equinox@diac24.net>
This commit is contained in:
parent
01734da376
commit
fdad523b54
@ -19,6 +19,8 @@ For unsorted lists, the following implementations exist:
|
|||||||
|
|
||||||
- single-linked list with tail pointer (e.g. STAILQ in BSD)
|
- single-linked list with tail pointer (e.g. STAILQ in BSD)
|
||||||
|
|
||||||
|
- double-linked list
|
||||||
|
|
||||||
- atomic single-linked list with tail pointer
|
- atomic single-linked list with tail pointer
|
||||||
|
|
||||||
|
|
||||||
@ -70,6 +72,7 @@ Available types:
|
|||||||
|
|
||||||
DECLARE_LIST
|
DECLARE_LIST
|
||||||
DECLARE_ATOMLIST
|
DECLARE_ATOMLIST
|
||||||
|
DECLARE_DLIST
|
||||||
|
|
||||||
DECLARE_SORTLIST_UNIQ
|
DECLARE_SORTLIST_UNIQ
|
||||||
DECLARE_SORTLIST_NONUNIQ
|
DECLARE_SORTLIST_NONUNIQ
|
||||||
@ -313,8 +316,8 @@ are several functions exposed to insert data:
|
|||||||
|
|
||||||
.. c:function:: DECLARE_XXX(Z, type, field)
|
.. c:function:: DECLARE_XXX(Z, type, field)
|
||||||
|
|
||||||
:param listtype XXX: ``LIST`` or ``ATOMLIST`` to select a data structure
|
:param listtype XXX: ``LIST``, ``DLIST`` or ``ATOMLIST`` to select a data
|
||||||
implementation.
|
structure implementation.
|
||||||
:param token Z: Gives the name prefix that is used for the functions
|
:param token Z: Gives the name prefix that is used for the functions
|
||||||
created for this instantiation. ``DECLARE_XXX(foo, ...)``
|
created for this instantiation. ``DECLARE_XXX(foo, ...)``
|
||||||
gives ``struct foo_item``, ``foo_add_head()``, ``foo_count()``, etc. Note
|
gives ``struct foo_item``, ``foo_add_head()``, ``foo_count()``, etc. Note
|
||||||
|
101
lib/typesafe.h
101
lib/typesafe.h
@ -151,6 +151,107 @@ macro_pure size_t prefix ## _count(struct prefix##_head *h) \
|
|||||||
} \
|
} \
|
||||||
/* ... */
|
/* ... */
|
||||||
|
|
||||||
|
/* don't use these structs directly */
|
||||||
|
struct dlist_item {
|
||||||
|
struct dlist_item *next;
|
||||||
|
struct dlist_item *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dlist_head {
|
||||||
|
struct dlist_item hitem;
|
||||||
|
size_t count;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void typesafe_dlist_add(struct dlist_head *head,
|
||||||
|
struct dlist_item *prev, struct dlist_item *item)
|
||||||
|
{
|
||||||
|
item->next = prev->next;
|
||||||
|
item->next->prev = item;
|
||||||
|
item->prev = prev;
|
||||||
|
prev->next = item;
|
||||||
|
head->count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* double-linked list, for fast item deletion
|
||||||
|
*/
|
||||||
|
#define PREDECL_DLIST(prefix) \
|
||||||
|
struct prefix ## _head { struct dlist_head dh; }; \
|
||||||
|
struct prefix ## _item { struct dlist_item di; };
|
||||||
|
|
||||||
|
#define INIT_DLIST(var) { .dh = { \
|
||||||
|
.hitem = { &var.dh.hitem, &var.dh.hitem }, }, }
|
||||||
|
|
||||||
|
#define DECLARE_DLIST(prefix, type, field) \
|
||||||
|
\
|
||||||
|
macro_inline void prefix ## _init(struct prefix##_head *h) \
|
||||||
|
{ \
|
||||||
|
memset(h, 0, sizeof(*h)); \
|
||||||
|
h->dh.hitem.prev = &h->dh.hitem; \
|
||||||
|
h->dh.hitem.next = &h->dh.hitem; \
|
||||||
|
} \
|
||||||
|
macro_inline void prefix ## _fini(struct prefix##_head *h) \
|
||||||
|
{ \
|
||||||
|
memset(h, 0, sizeof(*h)); \
|
||||||
|
} \
|
||||||
|
macro_inline void prefix ## _add_head(struct prefix##_head *h, type *item) \
|
||||||
|
{ \
|
||||||
|
typesafe_dlist_add(&h->dh, &h->dh.hitem, &item->field.di); \
|
||||||
|
} \
|
||||||
|
macro_inline void prefix ## _add_tail(struct prefix##_head *h, type *item) \
|
||||||
|
{ \
|
||||||
|
typesafe_dlist_add(&h->dh, h->dh.hitem.prev, &item->field.di); \
|
||||||
|
} \
|
||||||
|
macro_inline void prefix ## _add_after(struct prefix##_head *h, \
|
||||||
|
type *after, type *item) \
|
||||||
|
{ \
|
||||||
|
struct dlist_item *prev; \
|
||||||
|
prev = after ? &after->field.di : &h->dh.hitem; \
|
||||||
|
typesafe_dlist_add(&h->dh, prev, &item->field.di); \
|
||||||
|
} \
|
||||||
|
macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \
|
||||||
|
{ \
|
||||||
|
struct dlist_item *ditem = &item->field.di; \
|
||||||
|
ditem->prev->next = ditem->next; \
|
||||||
|
ditem->next->prev = ditem->prev; \
|
||||||
|
h->dh.count--; \
|
||||||
|
ditem->prev = ditem->next = NULL; \
|
||||||
|
} \
|
||||||
|
macro_inline type *prefix ## _pop(struct prefix##_head *h) \
|
||||||
|
{ \
|
||||||
|
struct dlist_item *ditem = h->dh.hitem.next; \
|
||||||
|
if (ditem == &h->dh.hitem) \
|
||||||
|
return NULL; \
|
||||||
|
ditem->prev->next = ditem->next; \
|
||||||
|
ditem->next->prev = ditem->prev; \
|
||||||
|
h->dh.count--; \
|
||||||
|
return container_of(ditem, type, field.di); \
|
||||||
|
} \
|
||||||
|
macro_pure type *prefix ## _first(struct prefix##_head *h) \
|
||||||
|
{ \
|
||||||
|
struct dlist_item *ditem = h->dh.hitem.next; \
|
||||||
|
if (ditem == &h->dh.hitem) \
|
||||||
|
return NULL; \
|
||||||
|
return container_of(ditem, type, field.di); \
|
||||||
|
} \
|
||||||
|
macro_pure type *prefix ## _next(struct prefix##_head * h, type *item) \
|
||||||
|
{ \
|
||||||
|
struct dlist_item *ditem = &item->field.di; \
|
||||||
|
if (ditem->next == &h->dh.hitem) \
|
||||||
|
return NULL; \
|
||||||
|
return container_of(ditem->next, type, field.di); \
|
||||||
|
} \
|
||||||
|
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
|
||||||
|
{ \
|
||||||
|
if (!item) \
|
||||||
|
return NULL; \
|
||||||
|
return prefix ## _next(h, item); \
|
||||||
|
} \
|
||||||
|
macro_pure size_t prefix ## _count(struct prefix##_head *h) \
|
||||||
|
{ \
|
||||||
|
return h->dh.count; \
|
||||||
|
} \
|
||||||
|
/* ... */
|
||||||
|
|
||||||
/* single-linked list, sorted.
|
/* single-linked list, sorted.
|
||||||
* can be used as priority queue with add / pop
|
* can be used as priority queue with add / pop
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user