]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: use sentinel for single-linked lists
authorDavid Lamparter <equinox@opensourcerouting.org>
Wed, 29 Sep 2021 20:15:11 +0000 (22:15 +0200)
committerDavid Lamparter <equinox@opensourcerouting.org>
Tue, 19 Oct 2021 12:55:39 +0000 (14:55 +0200)
Using a non-NULL sentinel allows distinguishing between "end of list"
and "item not on any list".  It's a compare either way, just the value
is different.

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
lib/typesafe.c
lib/typesafe.h

index f886c5bdf6fefd3925135d324ee7d858579934bc..f90b59daf0c3a1548093a5793eca9b39b53e41e2 100644 (file)
@@ -29,18 +29,20 @@ DEFINE_MTYPE_STATIC(LIB, TYPEDHASH_BUCKET, "Typed-hash bucket");
 DEFINE_MTYPE_STATIC(LIB, SKIPLIST_OFLOW, "Skiplist overflow");
 DEFINE_MTYPE_STATIC(LIB, HEAP_ARRAY, "Typed-heap array");
 
+struct slist_item typesafe_slist_sentinel = { NULL };
+
 bool typesafe_list_member(const struct slist_head *head,
                          const struct slist_item *item)
 {
        struct slist_item *fromhead = head->first;
        struct slist_item **fromnext = (struct slist_item **)&item->next;
 
-       while (fromhead) {
+       while (fromhead != _SLIST_LAST) {
                if (fromhead == item || fromnext == head->last_next)
                        return true;
 
                fromhead = fromhead->next;
-               if (!*fromnext)
+               if (!*fromnext || *fromnext == _SLIST_LAST)
                        break;
                fromnext = &(*fromnext)->next;
        }
index ecf7d10eb1a9a5b48445d89eaa454ee65bc48f05..b03934b9649484e18ae6cce9ceec3aaefaf358f4 100644 (file)
@@ -132,6 +132,10 @@ struct slist_head {
        size_t count;
 };
 
+/* this replaces NULL as the value for ->next on the last item. */
+extern struct slist_item typesafe_slist_sentinel;
+#define _SLIST_LAST &typesafe_slist_sentinel
+
 static inline void typesafe_list_add(struct slist_head *head,
                struct slist_item **pos, struct slist_item *item)
 {
@@ -165,6 +169,7 @@ MACRO_REQUIRE_SEMICOLON() /* end */
 macro_inline void prefix ## _init(struct prefix##_head *h)                     \
 {                                                                              \
        memset(h, 0, sizeof(*h));                                              \
+       h->sh.first = _SLIST_LAST;                                             \
        h->sh.last_next = &h->sh.first;                                        \
 }                                                                              \
 macro_inline void prefix ## _fini(struct prefix##_head *h)                     \
@@ -190,13 +195,13 @@ macro_inline void prefix ## _add_after(struct prefix##_head *h,                \
 macro_inline type *prefix ## _del(struct prefix##_head *h, type *item)         \
 {                                                                              \
        struct slist_item **iter = &h->sh.first;                               \
-       while (*iter && *iter != &item->field.si)                              \
+       while (*iter != _SLIST_LAST && *iter != &item->field.si)               \
                iter = &(*iter)->next;                                         \
-       if (!*iter)                                                            \
+       if (*iter == _SLIST_LAST)                                              \
                return NULL;                                                   \
        h->sh.count--;                                                         \
        *iter = item->field.si.next;                                           \
-       if (!item->field.si.next)                                              \
+       if (item->field.si.next == _SLIST_LAST)                                \
                h->sh.last_next = iter;                                        \
        item->field.si.next = NULL;                                            \
        return item;                                                           \
@@ -204,11 +209,11 @@ macro_inline type *prefix ## _del(struct prefix##_head *h, type *item)         \
 macro_inline type *prefix ## _pop(struct prefix##_head *h)                     \
 {                                                                              \
        struct slist_item *sitem = h->sh.first;                                \
-       if (!sitem)                                                            \
+       if (sitem == _SLIST_LAST)                                              \
                return NULL;                                                   \
        h->sh.count--;                                                         \
        h->sh.first = sitem->next;                                             \
-       if (h->sh.first == NULL)                                               \
+       if (h->sh.first == _SLIST_LAST)                                        \
                h->sh.last_next = &h->sh.first;                                \
        sitem->next = NULL;                                                    \
        return container_of(sitem, type, field.si);                            \
@@ -226,13 +231,17 @@ macro_inline void prefix ## _swap_all(struct prefix##_head *a,                 \
 }                                                                              \
 macro_pure const type *prefix ## _const_first(const struct prefix##_head *h)   \
 {                                                                              \
-       return container_of_null(h->sh.first, type, field.si);                 \
+       if (h->sh.first != _SLIST_LAST)                                        \
+               return container_of(h->sh.first, type, field.si);              \
+       return NULL;                                                           \
 }                                                                              \
 macro_pure const type *prefix ## _const_next(const struct prefix##_head *h,    \
                                             const type *item)                 \
 {                                                                              \
        const struct slist_item *sitem = &item->field.si;                      \
-       return container_of_null(sitem->next, type, field.si);                 \
+       if (sitem->next != _SLIST_LAST)                                        \
+               return container_of(sitem->next, type, field.si);              \
+       return NULL;                                                           \
 }                                                                              \
 TYPESAFE_FIRST_NEXT(prefix, type)                                              \
 macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item)     \
@@ -241,7 +250,9 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item)     \
        if (!item)                                                             \
                return NULL;                                                   \
        sitem = &item->field.si;                                               \
-       return container_of_null(sitem->next, type, field.si);                 \
+       if (sitem->next != _SLIST_LAST)                                        \
+               return container_of(sitem->next, type, field.si);              \
+       return NULL;                                                           \
 }                                                                              \
 macro_pure size_t prefix ## _count(const struct prefix##_head *h)              \
 {                                                                              \