]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: add dedicated pop() to DECLARE_SKIPLIST
authorDavid Lamparter <equinox@diac24.net>
Sun, 12 May 2019 10:05:14 +0000 (12:05 +0200)
committerDavid Lamparter <equinox@diac24.net>
Tue, 21 May 2019 03:18:16 +0000 (05:18 +0200)
The skiplist code was previously falling back to the del() code path for
a pop() on a skiplist.  This is unneeded complexity, a pop() can be done
more efficiently.

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

index bd269e9b54e822acd7bb4bcf424299b473effc7b..4b07c482e8663a33daee8a4eeb6c34be6b618708 100644 (file)
@@ -375,3 +375,35 @@ void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item,
        }
        memset(item, 0, sizeof(*item));
 }
+
+struct sskip_item *typesafe_skiplist_pop(struct sskip_head *head)
+{
+       size_t level = SKIPLIST_MAXDEPTH;
+       struct sskip_item *prev = &head->hitem, *next, *item;
+
+       item = sl_level_get(prev, 0);
+       if (!item)
+               return NULL;
+
+       do {
+               level--;
+
+               next = sl_level_get(prev, level);
+               if (next != item)
+                       continue;
+
+               sl_level_set(prev, level, sl_level_get(item, level));
+       } while (level);
+
+       head->count--;
+
+       if ((uintptr_t)item->next[SKIPLIST_OVERFLOW] & 1) {
+               uintptr_t ptrval = (uintptr_t)item->next[SKIPLIST_OVERFLOW];
+               ptrval &= UINTPTR_MAX - 3;
+               struct sskip_overflow *oflow = (struct sskip_overflow *)ptrval;
+               XFREE(MTYPE_SKIPLIST_OFLOW, oflow);
+       }
+       memset(item, 0, sizeof(*item));
+
+       return item;
+}
index 94002da599c23ea4d66a3184bbc63486f2825cc3..c08a2220913101de81a1f501fcb9feb968e39295 100644 (file)
@@ -538,11 +538,8 @@ macro_inline void prefix ## _del(struct prefix##_head *h, type *item)          \
 }                                                                              \
 macro_inline type *prefix ## _pop(struct prefix##_head *h)                     \
 {                                                                              \
-       struct sskip_item *sitem = h->sh.hitem.next[0];                        \
-       if (!sitem)                                                            \
-               return NULL;                                                   \
-       typesafe_skiplist_del(&h->sh, sitem, cmpfn_uq);                        \
-       return container_of(sitem, type, field.si);                            \
+       struct sskip_item *sitem = typesafe_skiplist_pop(&h->sh);              \
+       return container_of_null(sitem, type, field.si);                       \
 }                                                                              \
 macro_pure type *prefix ## _first(struct prefix##_head *h)                     \
 {                                                                              \
@@ -636,6 +633,7 @@ extern void typesafe_skiplist_del(struct sskip_head *head,
                struct sskip_item *item, int (*cmpfn)(
                        const struct sskip_item *a,
                        const struct sskip_item *b));
+extern struct sskip_item *typesafe_skiplist_pop(struct sskip_head *head);
 
 /* this needs to stay at the end because both files include each other.
  * the resolved order is typesafe.h before typerb.h