set(SimpleArchiver_SOURCES
src/main.c
src/parser.c
+ src/data_structures/linked_list.c
)
add_compile_options(
endif()
add_executable(simplearchiver ${SimpleArchiver_SOURCES})
+
+add_executable(test_datastructures
+ src/data_structures/test.c
+ src/data_structures/linked_list.c
+)
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})))
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}