]> git.corax.cc Git - mwm/commitdiff
loop: Add cyclic list type
authorMatthias Kruk <m@m10k.eu>
Mon, 3 May 2021 21:18:24 +0000 (06:18 +0900)
committerMatthias Kruk <m@m10k.eu>
Mon, 3 May 2021 21:18:24 +0000 (06:18 +0900)
Since we will often cycle through monitors, workspaces, and clients, it
would be beneficial to have a data structure that assists with that.
This commit adds the loop type, which implements a cyclic doubly-linked
list.

loop.c [new file with mode: 0644]
loop.h [new file with mode: 0644]

diff --git a/loop.c b/loop.c
new file mode 100644 (file)
index 0000000..19379cd
--- /dev/null
+++ b/loop.c
@@ -0,0 +1,150 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "loop.h"
+
+struct loop {
+        struct loop *prev;
+        struct loop *next;
+        void *data;
+};
+
+int loop_append(struct loop **loop, void *data)
+{
+       struct loop *new;
+
+       if(!loop) {
+               return(-EINVAL);
+       }
+
+       new = malloc(sizeof(*new));
+
+       if(!new) {
+               return(-ENOMEM);
+       }
+
+       new->data = data;
+       new->prev = new;
+       new->next = new;
+
+        if(*loop) {
+               new->prev = (*loop)->prev;
+               (*loop)->prev = new;
+               new->prev->next = new;
+               new->next = *loop;
+       } else {
+               *loop = new;
+       }
+
+       return(0);
+}
+
+int loop_prepend(struct loop **loop, void *data)
+{
+       struct loop *new;
+
+       if(!loop) {
+               return(-EINVAL);
+       }
+
+       new = malloc(sizeof(*new));
+
+       if(!new) {
+               return(-ENOMEM);
+       }
+
+       new->data = data;
+       new->prev = new;
+       new->next = new;
+
+       if(*loop) {
+               new->prev = (*loop)->prev;
+               (*loop)->prev = new;
+               new->prev->next = new;
+               new->next = *loop;
+       }
+
+       *loop = new;
+
+       return(0);
+}
+
+int loop_remove(struct loop **loop, void *data)
+{
+       struct loop *elem;
+
+       if(!loop) {
+               return(-EINVAL);
+       }
+
+       if(loop_find(loop, NULL, data, (void**)&elem) < 0) {
+               return(-ENOENT);
+       }
+
+       elem->next->prev = elem->prev;
+       elem->prev->next = elem->next;
+
+       if(*loop == elem) {
+               if(elem == elem->prev) {
+                       *loop = NULL;
+               } else {
+                       *loop = elem->prev;
+               }
+       }
+
+       free(elem);
+
+       return(0);
+}
+
+int _cmp_ptr(void *left, void *right)
+{
+       return(left == right);
+}
+
+int loop_find(struct loop **loop, int (*cmp)(void*, void*), void *data, void **dst)
+{
+       struct loop *cur;
+
+       if(!loop) {
+               return(-EINVAL);
+       }
+
+       if(!*loop) {
+               return(-ENOENT);
+       }
+
+       if(!cmp) {
+               cmp = _cmp_ptr;
+       }
+       cur = *loop;
+
+        do {
+                if(cmp(cur->data, data) == 0) {
+                       *dst = data;
+                       return(0);
+                }
+
+                cur = cur->next;
+        } while(cur != *loop);
+
+       return(-ENOENT);
+}
+
+int loop_free(struct loop **loop)
+{
+       if(!loop) {
+               return(-EINVAL);
+       }
+
+       while(*loop) {
+               struct loop *next;
+
+               next = (*loop)->next;
+               free(*loop);
+
+               *loop = (*loop == next) ? NULL : next;
+       }
+
+       return(0);
+}
diff --git a/loop.h b/loop.h
new file mode 100644 (file)
index 0000000..fa9de76
--- /dev/null
+++ b/loop.h
@@ -0,0 +1,12 @@
+#ifndef MWM_LOOP_H
+#define MWM_LOOP_H 1
+
+struct loop;
+
+int loop_append(struct loop **loop, void *data);
+int loop_prepend(struct loop **loop, void *data);
+int loop_remove(struct loop **loop, void *data);
+int loop_find(struct loop **loop, int(*cmp)(void*, void*), void *data, void **dst);
+int loop_free(struct loop **loop);
+
+#endif /* MWM_LOOP_H */