Initial commit
This commit is contained in:
commit
6fa8c4a110
6 changed files with 225 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
build
|
||||||
|
.cache
|
10
Makefile
Normal file
10
Makefile
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
BUILDDIR="build"
|
||||||
|
|
||||||
|
all: configure
|
||||||
|
meson compile -C $(BUILDDIR)
|
||||||
|
|
||||||
|
configure:
|
||||||
|
meson setup $(BUILDDIR)
|
||||||
|
|
||||||
|
test: configure
|
||||||
|
meson test -vC $(BUILDDIR)
|
43
include/doubly-linked-list.h
Normal file
43
include/doubly-linked-list.h
Normal 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
5
meson.build
Normal 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
72
src/doubly-linked-list.c
Normal 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
93
test/dll.c
Normal 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;
|
||||||
|
}
|
Loading…
Reference in a new issue