From 38496b78838a6faea8b6c68a8b5d455e5181234f Mon Sep 17 00:00:00 2001
From: Bruce Cowan <bruce@bcowan.me.uk>
Date: Mon, 23 Dec 2019 13:34:37 +0000
Subject: [PATCH] More featureful linked list

---
 lib/types/array.h |  6 ++--
 lib/types/slist.c | 89 +++++++++++++++++++++++++++++++++++++++++++----
 lib/types/slist.h | 21 ++++++++---
 lib/types/types.h |  8 +++++
 src/list-test.c   | 42 ++++++++++++----------
 5 files changed, 133 insertions(+), 33 deletions(-)
 create mode 100644 lib/types/types.h

diff --git a/lib/types/array.h b/lib/types/array.h
index 44f0a7b..25c432a 100644
--- a/lib/types/array.h
+++ b/lib/types/array.h
@@ -22,11 +22,9 @@
 #include <stdbool.h>
 #include <stddef.h>
 
-typedef struct _Array Array;
+#include "types.h"
 
-typedef void   (*FreeFunc)    (void *element);
-typedef double (*ValueFunc)   (const void *element);
-typedef int    (*CompareFunc) (const void *a, const void *b);
+typedef struct _Array Array;
 
 // Fundamental functions
 Array * array_new         (FreeFunc    func);
diff --git a/lib/types/slist.c b/lib/types/slist.c
index 2bcbef4..a15cc63 100644
--- a/lib/types/slist.c
+++ b/lib/types/slist.c
@@ -7,17 +7,94 @@ SList *
 slist_prepend (SList *list,
                void  *data)
 {
-	SList *new = malloc (sizeof (SList));
-	new->data = data;
-	new->next = list;
+  SList *new = malloc (sizeof (SList));
+  new->data = data;
+  new->next = list;
 
-	return new;
+  return new;
+}
+
+SList *
+slist_find (SList      *list,
+            const void *data)
+{
+  for (SList *l = list; l; l = l->next)
+    {
+      if (l->data == data)
+        return l;
+    }
+
+  return NULL;
+}
+
+SList *
+slist_nth (SList *list,
+           int    idx)
+{
+  int i = 0;
+
+  for (SList *l = list; l; l = l->next)
+    {
+      if (i == idx)
+        return l;
+      i++;
+    }
+
+  return NULL;
+}
+
+void
+slist_foreach (SList      *list,
+               ForEachFunc func,
+               void       *user_data)
+{
+  for (SList *l = list; l; l = l->next)
+    func (l->data, user_data);
+}
+
+static inline void
+slist_free_one (SList   *list,
+                FreeFunc func)
+{
+  if (func)
+    func (list->data);
+
+  free (list);
+}
+
+SList *
+slist_remove (SList   *list,
+              void    *data,
+              FreeFunc func)
+{
+  if (!list)
+    return NULL;
+
+  // If the first element is the one we're looking for
+  if (list->data == data)
+    {
+      SList *head = list->next;
+      slist_free_one (list, func);
+      return head;
+    }
+
+  SList *prev = list;
+  for (SList *l = list; l; prev = l, l = l->next)
+    {
+      if (l->data == data)
+        {
+          prev->next = l->next;
+          slist_free_one (l, func);
+          break;
+        }
+    }
+
+  return list;
 }
 
 void
 slist_free_all (SList    *list,
                 FreeFunc  func)
 {
-    for (SList *l = list; l; l = l->next)
-        func (l);
+  slist_foreach (list, (ForEachFunc) slist_free_one, NULL);
 }
diff --git a/lib/types/slist.h b/lib/types/slist.h
index ae55f13..243a0b6 100644
--- a/lib/types/slist.h
+++ b/lib/types/slist.h
@@ -1,16 +1,27 @@
 #pragma once
 
-typedef void (*FreeFunc) (void *value);
+#include "types.h"
 
 typedef struct _SList SList;
 struct _SList
 {
-	void  *data;
-	SList *next;
+  void  *data;
+  SList *next;
 };
 
-SList * slist_prepend (SList *list,
-                       void  *data);
+SList * slist_prepend (SList      *list,
+                       void       *data);
 
+SList * slist_find    (SList      *slist,
+                       const void *data);
+SList * slist_nth     (SList      *slist,
+                       int         index);
+void    slist_foreach (SList      *list,
+                       ForEachFunc func,
+                       void       *user_data);
+
+SList * slist_remove   (SList   *list,
+                        void    *data,
+                        FreeFunc func);
 void    slist_free_all (SList   *list,
                         FreeFunc func);
diff --git a/lib/types/types.h b/lib/types/types.h
new file mode 100644
index 0000000..4db1954
--- /dev/null
+++ b/lib/types/types.h
@@ -0,0 +1,8 @@
+#pragma once
+
+typedef void   (*FreeFunc)    (void       *data);
+typedef void   (*ForEachFunc) (void       *data,
+                               void       *user_data);
+typedef double (*ValueFunc)   (const void *element);
+typedef int    (*CompareFunc) (const void *a,
+                               const void *b);
diff --git a/src/list-test.c b/src/list-test.c
index 98aad53..31333b5 100644
--- a/src/list-test.c
+++ b/src/list-test.c
@@ -1,4 +1,4 @@
-#include "slist.h"
+#include <slist.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -7,38 +7,44 @@
 static SList *
 add_data (SList *list)
 {
-    char buffer[128];
+  char buffer[128];
 
-    printf ("Input the data ");
-    scanf ("%s", buffer);
+  printf ("Input the data ");
+  scanf ("%s", buffer);
 
-    char *str = strdup (buffer);
-    return slist_prepend (list, str);
+  char *str = strdup (buffer);
+  return slist_prepend (list, str);
 }
 
 static void
 print_data (SList *list)
 {
-    SList *l;
+  SList *l;
 
-    for (l = list; l != NULL; l = l->next)
-    {
-        printf ("%s\n", (char *) l->data);
-    }
+  for (l = list; l; l = l->next)
+      printf ("%s\n", (char*) l->data);
 }
 
 int
-main (void)
+main(void)
 {
-    SList *list = NULL;
+  SList *list = NULL;
+
+  for (int i = 0; i < 3; i++)
+    {
+      list = add_data (list);
+      print_data (list);
+    }
 
-    while (1)
+  for (int i = 2; i >= 1; i--)
     {
-        list = add_data (list);
-        print_data (list);
+      void *el = slist_nth (list, i)->data;
+      list = slist_remove (list, el, NULL);
     }
+  puts ("After deletion: ");
+  print_data (list);
 
-    slist_free_all (list, free);
+  slist_free_all(list, NULL);
 
-    return 0;
+  return 0;
 }
-- 
GitLab