summaryrefslogtreecommitdiffstats
path: root/lib/typesafe.c
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@diac24.net>2019-05-12 12:05:14 +0200
committerDavid Lamparter <equinox@diac24.net>2019-05-21 05:18:16 +0200
commit01734da376d0ed6ce355f27e4d19b5496f8ae94f (patch)
tree2a72a8f261537e9a562cde365bcc1ac683010822 /lib/typesafe.c
parentMerge pull request #4362 from donaldsharp/more_more_less (diff)
downloadfrr-01734da376d0ed6ce355f27e4d19b5496f8ae94f.tar.xz
frr-01734da376d0ed6ce355f27e4d19b5496f8ae94f.zip
lib: add dedicated pop() to DECLARE_SKIPLIST
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>
Diffstat (limited to 'lib/typesafe.c')
-rw-r--r--lib/typesafe.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/lib/typesafe.c b/lib/typesafe.c
index bd269e9b5..4b07c482e 100644
--- a/lib/typesafe.c
+++ b/lib/typesafe.c
@@ -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;
+}