summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorDimitri Staessens <dimitri@ouroboros.rocks>2026-02-15 12:26:04 +0100
committerSander Vrijders <sander@ouroboros.rocks>2026-02-18 07:58:21 +0100
commit760e17f142eb5cc0f594f1383ae68bb63bebe9ee (patch)
treefe0734604c3546421df5bb9ed880ec42e779a980 /include
parent471700175766f5a7f0b2449e1fe320ee78e9e2af (diff)
downloadouroboros-760e17f142eb5cc0f594f1383ae68bb63bebe9ee.tar.gz
ouroboros-760e17f142eb5cc0f594f1383ae68bb63bebe9ee.zip
lib: Add struct llist for lists tracking len
The DHT uses a struct {struct list_head, size_t len} pattern, which is also useful in the registry and other places. Having a struct llist (defined in list.h) with consistent macros for addition/deletion etc removes a lot of duplication and boilerplate and reduces the risk of inconsistent updates. The list management is now a macro-only implementation. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
Diffstat (limited to 'include')
-rw-r--r--include/ouroboros/list.h93
1 files changed, 84 insertions, 9 deletions
diff --git a/include/ouroboros/list.h b/include/ouroboros/list.h
index a00cfe61..26138b28 100644
--- a/include/ouroboros/list.h
+++ b/include/ouroboros/list.h
@@ -33,6 +33,11 @@ struct list_head {
struct list_head * prv;
};
+struct llist {
+ struct list_head list;
+ size_t len;
+};
+
#define list_entry(ptr, type, mbr) \
((type *)((uint8_t *)(ptr) - offsetof(type, mbr)))
@@ -48,19 +53,89 @@ struct list_head {
#define list_for_each_safe(p, t, h) \
for (p = (h)->nxt, t = p->nxt; p != (h); p = t, t = p->nxt)
-void list_head_init(struct list_head * h);
+#define list_head_init(h) do { \
+ (h)->nxt = (h); \
+ (h)->prv = (h); \
+} while (0)
+
+#define __list_add(_n, _prv, _nxt) do { \
+ struct list_head * __nxt = (_nxt); \
+ struct list_head * __prv = (_prv); \
+ struct list_head * __n = (_n); \
+ __nxt->prv = __n; \
+ __n->nxt = __nxt; \
+ __n->prv = __prv; \
+ __prv->nxt = __n; \
+} while (0)
+
+#define __list_del(_prv, _nxt) do { \
+ struct list_head * __nxt = (_nxt); \
+ struct list_head * __prv = (_prv); \
+ __nxt->prv = __prv; \
+ __prv->nxt = __nxt; \
+} while (0)
+
+#define list_add(n, h) do { \
+ __list_add(n, h, (h)->nxt); \
+} while (0)
+
+#define list_add_tail(n, h) do { \
+ __list_add(n, (h)->prv, h); \
+} while (0)
+
+#define list_del(e) do { \
+ __list_del((e)->prv, (e)->nxt); \
+ (e)->nxt = (e)->prv = (e); \
+} while (0)
+
+#define list_move(n, h) do { \
+ __list_del((n)->prv, (n)->nxt); \
+ __list_add(n, h, (h)->nxt); \
+} while (0)
+
+#define list_is_empty(h) ((h)->nxt == (h))
+
+#define llist_init(l) do { \
+ list_head_init(&(l)->list); \
+ (l)->len = 0; \
+} while (0)
+
+#define llist_add(e, l) do { \
+ list_add(e, &(l)->list); \
+ (l)->len++; \
+} while (0)
+
+#define llist_add_tail(e, l) do { \
+ list_add_tail(e, &(l)->list); \
+ (l)->len++; \
+} while (0)
+
+#define llist_add_at(e, pos, l) do { \
+ list_add(e, pos); \
+ (l)->len++; \
+} while (0)
+
+#define llist_add_tail_at(e, pos, l) do { \
+ list_add_tail(e, pos); \
+ (l)->len++; \
+} while (0)
+
+#define llist_del(e, l) do { \
+ list_del(e); \
+ (l)->len--; \
+} while (0)
-void list_add(struct list_head * e,
- struct list_head * h);
+#define llist_is_empty(l) ((l)->len == 0)
-void list_add_tail(struct list_head * e,
- struct list_head * h);
+#define llist_first_entry(l, type, mbr) \
+ list_first_entry(&(l)->list, type, mbr)
-void list_del(struct list_head * e);
+#define llist_last_entry(l, type, mbr) \
+ list_last_entry(&(l)->list, type, mbr)
-void list_move(struct list_head * dst,
- struct list_head * src);
+#define llist_for_each(p, l) list_for_each(p, &(l)->list)
-bool list_is_empty(const struct list_head * h);
+#define llist_for_each_safe(p, t, l) \
+ list_for_each_safe(p, t, &(l)->list)
#endif /* OUROBOROS_LIB_LIST_H */