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