linked list

This commit is contained in:
Benedek László 2024-04-15 18:54:16 +02:00
parent 6e2fae213a
commit 1f0a022cc7
5 changed files with 305 additions and 0 deletions

View File

@ -0,0 +1,55 @@
#ifndef CEX_CONTAINERS_linked_list_t_H
#define CEX_CONTAINERS_linked_list_t_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
typedef struct linked_list_node_t {
struct linked_list_node_t* prev;
struct linked_list_node_t* next;
void* data;
} linked_list_node_t;
typedef struct {
linked_list_node_t* first;
size_t length;
size_t data_size;
} linked_list_t;
typedef int64_t index_t;
typedef void (*list_iterator_t)(index_t index, void* data, void* arg);
typedef bool (*list_filter_t)(index_t index, const void* data, void* arg);
linked_list_t LL_create(size_t data_size);
linked_list_t LL_from_array(size_t data_size, void* array, index_t length);
linked_list_t LL_copy(linked_list_t* list);
void* LL_to_array(linked_list_t* list);
void LL_destroy(linked_list_t* list);
void* LL_insert(linked_list_t* list, index_t index);
void* LL_insert_value(linked_list_t* list, index_t index, const void* data);
void* LL_add(linked_list_t* list);
void* LL_add_value(linked_list_t* list, const void* data);
void LL_remove(linked_list_t* list, index_t index);
void* LL_get(linked_list_t* list, index_t index);
void LL_set(linked_list_t* list, index_t index, const void* data);
void LL_iterate(linked_list_t* list, list_iterator_t func, void* arg);
void LL_iterate_range(linked_list_t* list, list_iterator_t func, void* arg, index_t from, index_t to);
void LL_ITER_COPY(index_t _, void* data, void* list);
void LL_ITER_SUM(index_t _, void* data, void* result);
void LL_ITER_PRINT(index_t i, void* data, void* _);
linked_list_t LL_filter(linked_list_t* list, list_filter_t func, void* arg);
linked_list_t LL_filter_range(linked_list_t* list, list_filter_t func, void* arg, index_t from, index_t to);
#endif

View File

@ -0,0 +1,195 @@
#include <cex/containers/linked_list.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
linked_list_node_t* step(linked_list_node_t* node, index_t amount, size_t length) {
amount %= length;
if (amount > 0) {
while (amount != 0) {
amount--;
node = node->next;
}
} else {
while (amount != 0) {
amount++;
node = node->prev;
}
}
return node;
}
linked_list_t LL_create(size_t data_size) {
linked_list_t list = {.data_size = data_size, .first = NULL, .length = 0};
return list;
}
linked_list_t LL_from_array(size_t data_size, void* array, index_t length) {
linked_list_t list = LL_create(data_size);
for (index_t i = 0; i < length; i++) {
LL_add_value(&list, array + (data_size * i));
}
return list;
}
void* LL_to_array(linked_list_t* list) {
void* array = malloc(list->data_size * list->length);
linked_list_node_t* node = list->first;
for (index_t i = 0; i < list->length; i++) {
memcpy(array + (i * list->data_size), node->data, list->data_size);
node = node->next;
}
return array;
}
linked_list_t LL_copy(linked_list_t* list) {
linked_list_t result = LL_create(list->data_size);
LL_iterate(list, LL_ITER_COPY, &result);
return result;
}
void LL_destroy(linked_list_t* list) {
linked_list_node_t* node = list->first->prev;
list->first->prev = NULL;
while (node != NULL) {
if (node->data != NULL)
free(node->data);
linked_list_node_t* follwing = node->prev;
free(node);
node = follwing;
}
list->first = NULL;
list->length = 0;
}
void* LL_add(linked_list_t* list) {
return LL_insert(list, list->length);
}
void* LL_add_value(linked_list_t* list, const void* data) {
return LL_insert_value(list, list->length, data);
}
void* LL_insert(linked_list_t* list, index_t index) {
linked_list_node_t* node = (linked_list_node_t*)malloc(sizeof(linked_list_node_t));
if (list->data_size != 0)
node->data = malloc(list->data_size);
else
node->data = NULL;
linked_list_node_t* prev;
linked_list_node_t* next;
if (list->length == 0) {
prev = node;
next = node;
list->first = node;
} else if (index == 0) {
prev = list->first->prev;
next = list->first;
list->first = node;
} else {
index = index > 0 ? index - 1 : index;
prev = step(list->first, index, list->length);
next = prev->next;
}
// prev -> node -> next
prev->next = node;
node->prev = prev;
next->prev = node;
node->next = next;
list->length++;
return node->data;
}
void* LL_insert_value(linked_list_t* list, index_t index, const void* data) {
void* node_data = LL_insert(list, index);
memcpy(node_data, data, list->data_size);
return node_data;
}
void LL_remove(linked_list_t* list, index_t index) {
if (list->length == 1) {
if (list->first->data != NULL)
free(list->first->data);
free(list->first);
list->length--;
return;
}
linked_list_node_t* node = step(list->first, index, list->length);
node->prev = node->next;
node->next = node->prev;
if (node->data != NULL)
free(node->data);
free(node);
}
void* LL_get(linked_list_t* list, index_t index) {
return step(list->first, index, list->length)->data;
}
void LL_set(linked_list_t* list, index_t index, const void* data) {
memcpy(step(list->first, index, list->length)->data, data, list->data_size);
}
void LL_iterate_range(linked_list_t* list, list_iterator_t func, void* arg, index_t from, index_t to) {
linked_list_node_t* node = step(list->first, from, list->length);
for (index_t i = from; i < to; i++) {
func(i, node->data, arg);
node = node->next;
}
}
void LL_iterate(linked_list_t* list, list_iterator_t func, void* arg) {
LL_iterate_range(list, func, arg, 0, list->length);
}
linked_list_t LL_filter_range(linked_list_t* list, list_filter_t func, void* arg, index_t from, index_t to) {
linked_list_node_t* node = step(list->first, from, list->length);
linked_list_t result = LL_create(list->data_size);
for (index_t i = from; i < to; i++) {
if (func(i, node->data, arg)) {
LL_add_value(&result, node->data);
}
node = node->next;
}
return result;
}
linked_list_t LL_filter(linked_list_t* list, list_filter_t func, void* arg) {
return LL_filter_range(list, func, arg, 0, list->length);
}
void LL_ITER_COPY(index_t _, void* data, void* list) {
LL_add_value((linked_list_t*)list, data);
}
void LL_ITER_SUM(index_t _, void* data, void* result) {
*(int64_t*)result += *(int64_t*)data;
}
void LL_ITER_PRINT(index_t i, void* data, void* _) {
printf("#%ld: %ld\n", i, *(int64_t*)data);
}

View File

@ -0,0 +1,4 @@
#include <cex/test/assert.h>
#include <stddef.h>
test_result_t test_linked_list();

View File

@ -0,0 +1,45 @@
#include <cex/containers/linked_list.h>
#include <cex/test/assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
TEST(linked_list)
LABEL("create")
linked_list_t list = LL_create(sizeof(uint64_t));
ASSERT_EQ("data size set", list.data_size, sizeof(uint64_t))
ASSERT_EQ("length = 0", list.length, 0)
ASSERT_EQ("first = NULL", list.first, NULL)
LABEL("add")
int64_t num = 69;
LL_add_value(&list, &num);
ASSERT_EQ("length = 1", list.length, 1)
ASSERT_NEQ("first = NULL", list.first, NULL)
ASSERT_EQ("next = first", list.first->next, list.first)
ASSERT_EQ("prev = first", list.first->prev, list.first)
ASSERT_EQ("*data = num", *(int64_t*)list.first->data, num)
LABEL("destroy")
LL_destroy(&list);
ASSERT_EQ("length = 0", list.length, 0)
ASSERT_EQ("first = NULL", list.first, NULL)
LABEL("from array")
uint64_t array[10] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
list = LL_from_array(sizeof(uint64_t), array, 10);
LABEL("iterate")
LL_iterate(&list, LL_ITER_PRINT, NULL);
LABEL("to array")
uint64_t* result_array = LL_to_array(&list);
for (index_t i = 0; i < 10; i++) {
ASSERT_EQ("=", array[i], result_array[i]);
}
free(result_array);
LL_destroy(&list);
END_TEST

6
test/src/main.c Normal file
View File

@ -0,0 +1,6 @@
#include <cex/containers/test_linked_list.h>
#include <cex/test/assert.h>
PROJECT("cex")
RUN_TEST(linked_list)
END_PROJECT