]> git.seodisparate.com - SimpleArchiver/commitdiff
Implement a linked list data structure
authorStephen Seo <seo.disparate@gmail.com>
Fri, 28 Jun 2024 04:54:38 +0000 (13:54 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Fri, 28 Jun 2024 04:54:38 +0000 (13:54 +0900)
CMakeLists.txt
cosmopolitan/Makefile
src/data_structures/linked_list.c [new file with mode: 0644]
src/data_structures/linked_list.h [new file with mode: 0644]
src/data_structures/test.c [new file with mode: 0644]

index 4645618b80558014be2538734c25f39e39b64d74..c720fa1825bb6e4c17d8fc3421777a0db5046812 100644 (file)
@@ -6,6 +6,7 @@ set(SimpleArchiver_VERSION 1.0)
 set(SimpleArchiver_SOURCES
     src/main.c
     src/parser.c
+    src/data_structures/linked_list.c
 )
 
 add_compile_options(
@@ -21,3 +22,8 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
 endif()
 
 add_executable(simplearchiver ${SimpleArchiver_SOURCES})
+
+add_executable(test_datastructures
+  src/data_structures/test.c
+  src/data_structures/linked_list.c
+)
index 9c6b0e962b1d5665998b745920660b968dd369b2..d81601f9e97c17ee6cd4702b167448bdfd1ac248 100644 (file)
@@ -5,10 +5,12 @@ OUTDIR = out
 
 SOURCES = \
                ../src/main.c \
-               ../src/parser.c
+               ../src/parser.c \
+               ../src/data_structures/linked_list.c
 
 HEADERS = \
-               ../src/parser.h
+               ../src/parser.h \
+               ../src/data_structures/linked_list.h
 
 OBJECTS = $(addprefix ${OBJDIR}/,$(subst ..,PREVDIR,$(patsubst %.c,%.c.o,${SOURCES})))
 
diff --git a/src/data_structures/linked_list.c b/src/data_structures/linked_list.c
new file mode 100644 (file)
index 0000000..e2af7b4
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2024 Stephen Seo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * `linked_list.c` is the source for a linked list data structure.
+ */
+
+#include "linked_list.h"
+
+#include <stdlib.h>
+
+SDArchiverLinkedList *simple_archiver_list_init(void) {
+  SDArchiverLinkedList *list = malloc(sizeof(SDArchiverLinkedList));
+
+  list->head = malloc(sizeof(SDArchiverLLNode));
+  list->tail = malloc(sizeof(SDArchiverLLNode));
+
+  list->head->next = list->tail;
+  list->head->prev = NULL;
+  list->head->data = NULL;
+  list->head->data_free_fn = NULL;
+
+  list->tail->next = NULL;
+  list->tail->prev = list->head;
+  list->tail->data = NULL;
+  list->tail->data_free_fn = NULL;
+
+  list->count = 0;
+
+  return list;
+}
+
+void simple_archiver_list_free(SDArchiverLinkedList **list) {
+  if (list && *list) {
+    SDArchiverLLNode *node = (*list)->head;
+    SDArchiverLLNode *prev;
+    while (node) {
+      prev = node;
+      node = node->next;
+      free(prev);
+      if (node && node->data) {
+        if (node->data_free_fn) {
+          node->data_free_fn(node->data);
+        } else {
+          free(node->data);
+        }
+      }
+    }
+
+    free(*list);
+    *list = NULL;
+  }
+}
+
+int simple_archiver_list_add(SDArchiverLinkedList *list, void *data,
+                             void (*data_free_fn)(void *)) {
+  if (!list) {
+    return 1;
+  }
+
+  SDArchiverLLNode *new_node = malloc(sizeof(SDArchiverLLNode));
+  new_node->data = data;
+  new_node->data_free_fn = data_free_fn;
+
+  new_node->next = list->tail;
+  new_node->prev = list->tail->prev;
+
+  list->tail->prev->next = new_node;
+  list->tail->prev = new_node;
+
+  ++list->count;
+
+  return 0;
+}
+
+int simple_archiver_list_remove(SDArchiverLinkedList *list,
+                                int (*data_check_fn)(void *)) {
+  if (!list) {
+    return 0;
+  }
+
+  int removed_count = 0;
+
+  SDArchiverLLNode *node = list->head;
+  int iter_removed = 0;
+  while (node) {
+    if (iter_removed == 0) {
+      node = node->next;
+    }
+    iter_removed = 0;
+    if (node && node != list->tail) {
+      if (data_check_fn(node->data) != 0) {
+        SDArchiverLLNode *temp = node->next;
+
+        if (node->data_free_fn) {
+          node->data_free_fn(node->data);
+        } else {
+          free(node->data);
+        }
+
+        node->prev->next = node->next;
+        node->next->prev = node->prev;
+        free(node);
+
+        node = temp;
+        iter_removed = 1;
+        ++removed_count;
+        --list->count;
+      }
+    }
+  }
+
+  return removed_count;
+}
+
+int simple_archiver_list_remove_once(SDArchiverLinkedList *list,
+                                     int (*data_check_fn)(void *)) {
+  if (!list) {
+    return 0;
+  }
+
+  SDArchiverLLNode *node = list->head;
+  while (node) {
+    node = node->next;
+    if (node && node != list->tail) {
+      if (data_check_fn(node->data) != 0) {
+        if (node->data_free_fn) {
+          node->data_free_fn(node->data);
+        } else {
+          free(node->data);
+        }
+
+        node->prev->next = node->next;
+        node->next->prev = node->prev;
+        free(node);
+
+        --list->count;
+
+        return 1;
+      }
+    }
+  }
+
+  return 0;
+}
+
+void *simple_archiver_list_get(SDArchiverLinkedList *list,
+                               int (*data_check_fn)(void *)) {
+  if (!list) {
+    return NULL;
+  }
+
+  SDArchiverLLNode *node = list->head;
+  while (node) {
+    node = node->next;
+    if (node && node != list->tail) {
+      if (data_check_fn(node->data) != 0) {
+        return node->data;
+      }
+    }
+  }
+
+  return NULL;
+}
diff --git a/src/data_structures/linked_list.h b/src/data_structures/linked_list.h
new file mode 100644 (file)
index 0000000..93609d5
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2024 Stephen Seo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * `linked_list.h` is the header for a linked list data structure.
+ */
+
+#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_DATA_STRUCTURE_LINKED_LIST_H_
+#define SEODISPARATE_COM_SIMPLE_ARCHIVER_DATA_STRUCTURE_LINKED_LIST_H_
+
+typedef struct SDArchiverLLNode {
+  struct SDArchiverLLNode *next;
+  struct SDArchiverLLNode *prev;
+  void *data;
+  void (*data_free_fn)(void *);
+} SDArchiverLLNode;
+
+typedef struct SDArchiverLinkedList {
+  SDArchiverLLNode *head;
+  SDArchiverLLNode *tail;
+  unsigned int count;
+} SDArchiverLinkedList;
+
+SDArchiverLinkedList *simple_archiver_list_init(void);
+void simple_archiver_list_free(SDArchiverLinkedList **list);
+
+/// Returns 0 on success.
+int simple_archiver_list_add(SDArchiverLinkedList *list, void *data,
+                             void (*data_free_fn)(void *));
+
+/// Returns number of removed items.
+/// data_check_fn must return non-zero if the data passed to it is to be
+/// removed.
+int simple_archiver_list_remove(SDArchiverLinkedList *list,
+                                int (*data_check_fn)(void *));
+
+/// Returns 1 on removed, 0 if not removed.
+/// data_check_fn must return non-zero if the data passed to it is to be
+/// removed.
+int simple_archiver_list_remove_once(SDArchiverLinkedList *list,
+                                     int (*data_check_fn)(void *));
+
+/// Returns non-null on success.
+/// data_check_fn must return non-zero if the data passed to it is to be
+/// returned.
+void *simple_archiver_list_get(SDArchiverLinkedList *list,
+                               int (*data_check_fn)(void *));
+
+#endif
diff --git a/src/data_structures/test.c b/src/data_structures/test.c
new file mode 100644 (file)
index 0000000..4121fb7
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2024 Stephen Seo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * `data_structures/test.c` is the source for testing data structure code.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "linked_list.h"
+
+static int checks_checked = 0;
+static int checks_passed = 0;
+
+#define CHECK_TRUE(x)                                             \
+  do {                                                            \
+    ++checks_checked;                                             \
+    if (!(x)) {                                                   \
+      printf("CHECK_TRUE at line %u failed: %s\n", __LINE__, #x); \
+    } else {                                                      \
+      ++checks_passed;                                            \
+    }                                                             \
+  } while (0);
+#define CHECK_FALSE(x)                                             \
+  do {                                                             \
+    ++checks_checked;                                              \
+    if (x) {                                                       \
+      printf("CHECK_FALSE at line %u failed: %s\n", __LINE__, #x); \
+    } else {                                                       \
+      ++checks_passed;                                             \
+    }                                                              \
+  } while (0);
+
+void no_free_fn(__attribute__((unused)) void *unused) { return; }
+
+int get_one_fn(void *data) { return strcmp(data, "one") == 0 ? 1 : 0; }
+
+int get_two_fn(void *data) { return strcmp(data, "two") == 0 ? 1 : 0; }
+
+int get_three_fn(void *data) { return strcmp(data, "three") == 0 ? 1 : 0; }
+
+int main(void) {
+  // Test LinkedList.
+  {
+    SDArchiverLinkedList *list = simple_archiver_list_init();
+
+    CHECK_TRUE(list->count == 0);
+
+    const char *one = "one";
+    const char *two = "two";
+    const char *three = "three";
+
+    simple_archiver_list_add(list, (void *)one, no_free_fn);
+
+    CHECK_TRUE(list->count == 1);
+
+    simple_archiver_list_add(list, (void *)two, no_free_fn);
+
+    CHECK_TRUE(list->count == 2);
+
+    simple_archiver_list_add(list, (void *)three, no_free_fn);
+
+    CHECK_TRUE(list->count == 3);
+
+    void *ptr = simple_archiver_list_get(list, get_one_fn);
+    CHECK_TRUE(ptr == one);
+
+    ptr = simple_archiver_list_get(list, get_two_fn);
+    CHECK_TRUE(ptr == two);
+
+    ptr = simple_archiver_list_get(list, get_three_fn);
+    CHECK_TRUE(ptr == three);
+
+    CHECK_TRUE(simple_archiver_list_remove(list, get_two_fn) == 1);
+    CHECK_TRUE(list->count == 2);
+    CHECK_TRUE(simple_archiver_list_get(list, get_two_fn) == NULL);
+
+    CHECK_TRUE(simple_archiver_list_remove_once(list, get_one_fn) == 1);
+    CHECK_TRUE(list->count == 1);
+    CHECK_TRUE(simple_archiver_list_get(list, get_one_fn) == NULL);
+
+    simple_archiver_list_free(&list);
+
+    CHECK_TRUE(list == NULL);
+  }
+
+  printf("Checks checked: %u\n", checks_checked);
+  printf("Checks passed:  %u\n", checks_passed);
+  return checks_passed == checks_checked ? 0 : 1;
+}