Initial commit

This commit is contained in:
William Brawner 2024-11-17 22:16:17 -07:00
commit 6fa8c4a110
Signed by: wbrawner
GPG key ID: 8FF12381C6C90D35
6 changed files with 225 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
build
.cache

10
Makefile Normal file
View file

@ -0,0 +1,10 @@
BUILDDIR="build"
all: configure
meson compile -C $(BUILDDIR)
configure:
meson setup $(BUILDDIR)
test: configure
meson test -vC $(BUILDDIR)

View file

@ -0,0 +1,43 @@
struct dll_node {
struct dll_node *previous;
struct dll_node *next;
char *value;
};
typedef struct dll_node dll_node;
typedef struct {
struct dll_node *head;
} dll_list;
/**
* Allocates a new (empty) doubly linked list
*/
dll_list *dll_list_new();
/**
* Frees the memory used by a list, including all of its child nodes
*/
void dll_list_free(dll_list *list);
/**
* Inserts a given node at the given index of the given list. If index is -1
* or is greater than the size of the list, then the node will be inserted at the end of the list
*/
void dll_list_insert(dll_list *list, dll_node *node, int index);
/**
* Appends a node to the end of a given list
*/
void dll_list_append(dll_list *list, dll_node *node) {
dll_list_insert(list, node, -1);
}
// TODO: find and delete operations on list
dll_node *dll_node_new(char *value);
/**
* Frees the memory for a given node, returning a pointer to the next node, if any
*/
dll_node *dll_node_free(dll_node *node);

5
meson.build Normal file
View file

@ -0,0 +1,5 @@
project('clox', 'c')
incdir = include_directories('include')
dll_lib = library('dll', 'src/doubly-linked-list.c', include_directories: incdir)
dll_test = executable('dll_test', 'test/dll.c', include_directories: incdir, link_with: dll_lib)
test('doubly-linked list tests', dll_test)

72
src/doubly-linked-list.c Normal file
View file

@ -0,0 +1,72 @@
#include "doubly-linked-list.h"
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
dll_list *dll_list_new() {
dll_list *list = malloc(sizeof(dll_list));
list->head = NULL;
return list;
}
void dll_list_free(dll_list *list) {
dll_node *current_node = list->head;
while (current_node != NULL) {
current_node = dll_node_free(current_node);
}
free(list);
}
void dll_list_insert(dll_list *list, dll_node *node, int index) {
if (list->head == NULL) {
list->head = node;
return;
}
if (index == 0) {
dll_node *old_head = list->head;
list->head = node;
node->next = old_head;
return;
}
int current_index = 0;
dll_node *current_node = list->head;
while (current_node->next != NULL) {
current_index++;
if (index > -1 && index == current_index) {
break;
}
current_node = current_node->next;
}
dll_node *next_node = current_node->next;
if (next_node != NULL) {
next_node->previous = node;
node->next = next_node;
}
node->previous = current_node;
current_node->next = node;
}
dll_node *dll_node_new(char *value) {
dll_node *node = malloc(sizeof(dll_node));
node->previous = NULL;
node->next = NULL;
int value_length = strlen(value) * sizeof(char);
value_length++; // pad for null byte
node->value = malloc(value_length);
strcpy(node->value, value);
node->value[value_length - 1] = '\0';
return node;
}
dll_node *dll_node_free(dll_node *node) {
dll_node *next = node->next;
free(node->value);
node->previous = NULL;
node->next = NULL;
free(node);
return next;
}

93
test/dll.c Normal file
View file

@ -0,0 +1,93 @@
#include "doubly-linked-list.h"
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
dll_list *list = NULL;
dll_node *head = NULL;
char *list_string = NULL;
#define ASSERT_STR_EQ(expected, actual) \
{ \
if (strcmp(expected, actual) != 0) { \
fprintf(stderr, \
"strings don't match. expected: \"%s\", actual: \"%s\"\n", \
expected, actual); \
cleanup(); \
return 1; \
} \
}
char *list_to_string(dll_list *list) {
char *list_string = malloc(sizeof(char));
list_string[0] = '\0';
dll_node *current_node = list->head;
while (current_node != NULL) {
// TODO: There's probably a better way to do this. Find it
int list_string_length = strlen(list_string);
int new_length = list_string_length + strlen(current_node->value) + 1;
if (current_node->previous != NULL) {
new_length += 2; // Add space for another ", "
}
char *new_list_string = realloc(list_string, new_length);
if (new_list_string == NULL) {
fprintf(stderr, "error: failed to reallocate memory for list string\n");
return NULL;
} else {
list_string = new_list_string;
}
if (list_string_length > 0 && current_node->previous != NULL) {
strcpy(&list_string[list_string_length], ", ");
list_string_length += 2;
}
strcpy(&list_string[list_string_length], current_node->value);
list_string[new_length - 1] = '\0';
current_node = current_node->next;
}
return list_string;
}
void cleanup() {
if (list != NULL) {
dll_list_free(list);
list = NULL;
}
if (head != NULL) {
dll_node_free(head);
head = NULL;
}
if (list_string != NULL) {
free(list_string);
list_string = NULL;
}
}
int main(int argc, char **argv) {
list = dll_list_new();
dll_node *head = dll_node_new("0");
dll_list_append(list, head);
head = NULL;
// TODO: Extract test utilities to shared file
list_string = list_to_string(list);
ASSERT_STR_EQ("0", list_string);
dll_node *third = dll_node_new("2");
dll_list_insert(list, third, 2);
free(list_string);
list_string = list_to_string(list);
ASSERT_STR_EQ("0, 2", list_string);
dll_node *second = dll_node_new("1");
dll_list_insert(list, second, 1);
free(list_string);
list_string = list_to_string(list);
ASSERT_STR_EQ("0, 1, 2", list_string);
cleanup();
return 0;
}