]> git.corax.cc Git - mwm/commitdiff
loop: Add convenience functions and a foreach function without data
authorMatthias Kruk <m@m10k.eu>
Tue, 18 May 2021 23:03:51 +0000 (08:03 +0900)
committerMatthias Kruk <m@m10k.eu>
Tue, 18 May 2021 23:03:51 +0000 (08:03 +0900)
This commit adds convenience functions to the loop data type that
allow the caller to find the elements that come before or after an
element in a loop.
This further adds functions to shift the position of an element in
the loop to the back or the front, and a foreach function that
passes only the element pointer to the callback (this is useful for
calling things like free() from the foreach function).

loop.c
loop.h

diff --git a/loop.c b/loop.c
index 50370d415c2384a858c1745c36734bc3b854ffe8..2f74943a10305d3c9b9c867a1534c5d782bc00fe 100644 (file)
--- a/loop.c
+++ b/loop.c
@@ -154,7 +154,29 @@ int loop_find(struct loop **loop, int (*cmp)(void*, void*),
        return(err);
 }
 
-int loop_foreach(struct loop **loop, int(*func)(void*, void*),
+int loop_foreach(struct loop **loop, void(*func)(void*))
+{
+       struct loop *cur;
+
+       if(!loop) {
+               return(-EINVAL);
+       }
+
+       if(!*loop) {
+               return(0);
+       }
+
+       cur = *loop;
+
+       do {
+               func(cur->data);
+               cur = cur->next;
+       } while(cur != *loop);
+
+       return(0);
+}
+
+int loop_foreach_with_data(struct loop **loop, int(*func)(void*, void*),
                 void *data)
 {
        struct loop *cur;
@@ -163,19 +185,19 @@ int loop_foreach(struct loop **loop, int(*func)(void*, void*),
                return(-EINVAL);
        }
 
+       if(!*loop) {
+               return(0);
+       }
+
        cur = *loop;
 
-       while(cur) {
+       do {
                if(func(cur->data, data) < 0) {
                        break;
                }
 
                cur = cur->next;
-
-               if(cur == *loop) {
-                       break;
-               }
-       }
+       } while(cur != *loop);
 
        return(0);
 }
@@ -276,3 +298,97 @@ int loop_get_length(struct loop **loop)
 
        return(length);
 }
+
+int loop_get_next(struct loop **loop, void *data, void **next)
+{
+       struct loop *iter;
+
+       if(!loop || !data || !next) {
+               return(-EINVAL);
+       }
+
+       if(__loop_find(loop, NULL, data, &iter) < 0) {
+               return(-ENOENT);
+       }
+
+       *next = iter->next->data;
+       return(0);
+}
+
+int loop_get_prev(struct loop **loop, void *data, void **prev)
+{
+       struct loop *iter;
+
+       if(!loop || !data || !prev) {
+               return(-EINVAL);
+       }
+
+       if(__loop_find(loop, NULL, data, &iter) < 0) {
+               return(-ENOENT);
+       }
+
+       *prev = iter->prev->data;
+       return(0);
+}
+
+int loop_shift_forwards(struct loop **loop, void *data)
+{
+       struct loop *iter;
+       struct loop *next;
+
+       if(!loop || !data) {
+               return(-EINVAL);
+       }
+
+       if(__loop_find(loop, NULL, data, &iter) < 0) {
+               return(-ENOENT);
+       }
+
+       next = iter->next;
+
+       iter->prev->next = next;
+       next->prev = iter->prev;
+       next->next->prev = iter;
+       iter->next = next->next;
+       iter->prev = next;
+       next->next = iter;
+
+       if(*loop == iter) {
+               *loop = iter->prev;
+       } else if(*loop == iter->prev) {
+               *loop = iter;
+       }
+
+       return(0);
+}
+
+int loop_shift_backwards(struct loop **loop, void *data)
+{
+       struct loop *iter;
+       struct loop *next;
+
+       if(!loop || !data) {
+               return(-EINVAL);
+       }
+
+       if(__loop_find(loop, NULL, data, &next) < 0) {
+               return(-ENOENT);
+       }
+
+       iter = next->prev;
+
+       iter->prev->next = next;
+       next->prev = iter->prev;
+       next->next->prev = iter;
+       iter->next = next->next;
+       iter->prev = next;
+       next->next = iter;
+
+       if(*loop == next) {
+               *loop = next->next;
+       } else if(*loop == next->next) {
+               *loop = next;
+       }
+
+       return(0);
+}
diff --git a/loop.h b/loop.h
index 746949b7e4c029efcebc7c3fb2ecc5a3d5277388..03a5cfc8e6cffdb134a08cb236c6119e0e069850 100644 (file)
--- a/loop.h
+++ b/loop.h
@@ -8,11 +8,16 @@ 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_foreach(struct loop **loop, int(*func)(void*, void*), void*);
+int loop_foreach(struct loop **loop, void(*func)(void*));
+int loop_foreach_with_data(struct loop **loop, int(*func)(void*, void*), void*);
 int loop_free(struct loop **loop);
 int loop_get_first(struct loop **loop, void**);
 int loop_get_last(struct loop **loop, void**);
 int loop_get_length(struct loop **loop);
+int loop_get_next(struct loop **loop, void *data, void **next);
+int loop_get_prev(struct loop **loop, void *data, void **next);
+int loop_shift_backwards(struct loop **loop, void *data);
+int loop_shift_forwards(struct loop **loop, void *data);
 
 loop_iter_t loop_get_iter(struct loop **loop);
 loop_iter_t loop_iter_get_next(loop_iter_t iter);