Add generic doubly-linked list implementation
authorJouni Malinen <j@w1.fi>
Sat, 19 Dec 2009 11:43:25 +0000 (13:43 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 19 Dec 2009 11:43:25 +0000 (13:43 +0200)
src/utils/list.h [new file with mode: 0644]
tests/.gitignore
tests/Makefile
tests/test-list.c [new file with mode: 0644]

diff --git a/src/utils/list.h b/src/utils/list.h
new file mode 100644 (file)
index 0000000..ed7c022
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Doubly-linked list
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef LIST_H
+#define LIST_H
+
+/**
+ * struct dl_list - Doubly-linked list
+ */
+struct dl_list {
+       struct dl_list *next;
+       struct dl_list *prev;
+};
+
+static inline void dl_list_init(struct dl_list *list)
+{
+       list->next = list;
+       list->prev = list;
+}
+
+static inline void dl_list_add(struct dl_list *list, struct dl_list *item)
+{
+       item->next = list->next;
+       item->prev = list;
+       list->next->prev = item;
+       list->next = item;
+}
+
+static inline void dl_list_add_tail(struct dl_list *list, struct dl_list *item)
+{
+       dl_list_add(list->prev, item);
+}
+
+static inline void dl_list_del(struct dl_list *item)
+{
+       item->next->prev = item->prev;
+       item->prev->next = item->next;
+       item->next = NULL;
+       item->prev = NULL;
+}
+
+static inline int dl_list_empty(struct dl_list *list)
+{
+       return list->next == list;
+}
+
+static inline unsigned int dl_list_len(struct dl_list *list)
+{
+       struct dl_list *item;
+       int count = 0;
+       for (item = list->next; item != list; item = item->next)
+               count++;
+       return count;
+}
+
+#ifndef offsetof
+#define offsetof(type, member) ((long) &((type *) 0)->member)
+#endif
+
+#define dl_list_entry(item, type, member) \
+       ((type *) ((char *) item - offsetof(type, member)))
+
+#define dl_list_first(list, type, member) \
+       (dl_list_empty((list)) ? NULL : \
+        dl_list_entry((list)->next, type, member))
+
+#define dl_list_for_each(item, list, type, member) \
+       for (item = dl_list_entry((list)->next, type, member); \
+            &item->member != (list); \
+            item = dl_list_entry(item->member.next, type, member))
+
+#define dl_list_for_each_safe(item, n, list, type, member) \
+       for (item = dl_list_entry((list)->next, type, member), \
+                    n = dl_list_entry(item->member.next, type, member); \
+            &item->member != (list); \
+            item = n, n = dl_list_entry(n->member.next, type, member))
+
+#endif /* LIST_H */
index 9c64aa6..5b992a3 100644 (file)
@@ -1,6 +1,7 @@
 test-aes
 test-asn1
 test-base64
+test-list
 test-md4
 test-md5
 test-milenage
index dcb9a2d..210a1b4 100644 (file)
@@ -1,5 +1,5 @@
 TESTS=test-base64 test-md4 test-md5 test-milenage test-ms_funcs test-sha1 \
-       test-sha256 test-aes test-asn1 test-x509 test-x509v3
+       test-sha256 test-aes test-asn1 test-x509 test-x509v3 test-list
 
 all: $(TESTS)
 
@@ -45,6 +45,9 @@ test-asn1: test-asn1.o $(LIBS)
 test-base64: test-base64.o $(LIBS)
        $(LDO) $(LDFLAGS) -o $@ $^
 
+test-list: test-list.o $(LIBS)
+       $(LDO) $(LDFLAGS) -o $@ $^
+
 test-md4: test-md4.o $(LIBS)
        $(LDO) $(LDFLAGS) -o $@ $^
 
@@ -72,6 +75,7 @@ test-x509v3: test-x509v3.o $(LIBS)
 
 run-tests: $(TESTS)
        ./test-aes
+       ./test-list
        ./test-md4
        ./test-md5
        ./test-milenage
diff --git a/tests/test-list.c b/tests/test-list.c
new file mode 100644 (file)
index 0000000..930ce41
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Doubly-linked list - test program
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/os.h"
+#include "utils/list.h"
+
+struct test {
+       struct dl_list list;
+       int value;
+};
+
+static void dump_list(struct dl_list *head)
+{
+       struct test *t;
+       printf("dump:");
+       dl_list_for_each(t, head, struct test, list)
+               printf(" %d", t->value);
+       printf(" (len=%d%s)\n", dl_list_len(head),
+              dl_list_empty(head) ? " empty" : "");
+}
+
+int main(int argc, char *argv[])
+{
+       struct dl_list head;
+       struct test *t, *tmp;
+       int i;
+
+       dl_list_init(&head);
+       dump_list(&head);
+
+       for (i = 0; i < 5; i++) {
+               t = os_zalloc(sizeof(*t));
+               if (t == NULL)
+                       return -1;
+               t->value = i;
+               dl_list_add(&head, &t->list);
+               dump_list(&head);
+       }
+
+       for (i = 10; i > 5; i--) {
+               t = os_zalloc(sizeof(*t));
+               if (t == NULL)
+                       return -1;
+               t->value = i;
+               dl_list_add_tail(&head, &t->list);
+               dump_list(&head);
+       }
+
+       i = 0;
+       dl_list_for_each(t, &head, struct test, list)
+               if (++i == 5)
+                       break;
+       printf("move: %d\n", t->value);
+       dl_list_del(&t->list);
+       dl_list_add(&head, &t->list);
+       dump_list(&head);
+
+       dl_list_for_each_safe(t, tmp, &head, struct test, list) {
+               printf("delete: %d\n", t->value);
+               dl_list_del(&t->list);
+               os_free(t);
+               dump_list(&head);
+       }
+
+       return 0;
+}