Implement linked list data structure.
This commit is contained in:
114
src/ll.c
Normal file
114
src/ll.c
Normal file
@@ -0,0 +1,114 @@
|
||||
#include "ll.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void ll_init(ll* ll) {
|
||||
ll->head = NULL;
|
||||
ll->tail = NULL;
|
||||
}
|
||||
void ll_free(ll* ll) {
|
||||
ll_node* head = ll->head;
|
||||
while (head) {
|
||||
ll_node* to_free = head;
|
||||
head = head->next;
|
||||
free(to_free);
|
||||
}
|
||||
ll->tail = NULL;
|
||||
ll->head = NULL;
|
||||
}
|
||||
|
||||
libds_result ll_append(ll* ll, void* data) {
|
||||
libds_result result = LIBDS_SUCCESS;
|
||||
ll_node** to_set = ll->head ? &ll->tail->next : &ll->head;
|
||||
ll_node* new_node = malloc(sizeof(*new_node));
|
||||
if (new_node) {
|
||||
new_node->next = NULL;
|
||||
new_node->prev = ll->tail;
|
||||
new_node->data = data;
|
||||
|
||||
*to_set = new_node;
|
||||
ll->tail = new_node;
|
||||
} else {
|
||||
result = LIBDS_MALLOC;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
libds_result ll_prepend(ll* ll, void* data) {
|
||||
libds_result result = LIBDS_SUCCESS;
|
||||
ll_node** to_set = ll->tail ? &ll->head->prev : &ll->tail;
|
||||
ll_node* new_node = malloc(sizeof(*new_node));
|
||||
if (new_node) {
|
||||
new_node->next = ll->head;
|
||||
new_node->prev = NULL;
|
||||
new_node->data = data;
|
||||
|
||||
*to_set = new_node;
|
||||
ll->head = new_node;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
void ll_remove(ll* ll, void* data) {
|
||||
ll_node* head = ll->head;
|
||||
while (head) {
|
||||
if (head->data == data) {
|
||||
ll_node* to_delete = head;
|
||||
|
||||
head = head->next;
|
||||
*(to_delete->prev ? &to_delete->prev->next : &ll->head) = to_delete->next;
|
||||
*(to_delete->next ? &to_delete->next->prev : &ll->tail) = to_delete->prev;
|
||||
free(to_delete);
|
||||
} else {
|
||||
head = head->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* ll_find(ll* ll, void* data, compare_func compare) {
|
||||
void* to_return = NULL;
|
||||
ll_node* head = ll->head;
|
||||
while (head && to_return == NULL) {
|
||||
if (compare(data, head->data)) {
|
||||
to_return = head->data;
|
||||
}
|
||||
}
|
||||
return to_return;
|
||||
}
|
||||
int ll_foreach(ll* ll, void* data, compare_func compare, foreach_func foreach,
|
||||
...) {
|
||||
int return_code = 0;
|
||||
ll_node* head = ll->head;
|
||||
va_list args;
|
||||
while (head && return_code == 0) {
|
||||
if (compare(data, head->data)) {
|
||||
va_start(args, foreach);
|
||||
return_code = foreach (head->data, args);
|
||||
va_end(args);
|
||||
}
|
||||
head = head->next;
|
||||
}
|
||||
return return_code;
|
||||
}
|
||||
|
||||
void* ll_head(ll* ll) { return ll->head ? ll->head->data : NULL; }
|
||||
void* ll_tail(ll* ll) { return ll->tail ? ll->tail->data : NULL; }
|
||||
void* ll_pophead(ll* ll) {
|
||||
void* to_return = NULL;
|
||||
if (ll->head) {
|
||||
ll_node* to_delete = ll->head;
|
||||
to_return = to_delete->data;
|
||||
*(to_delete->next ? &to_delete->next->prev : &ll->tail) = NULL;
|
||||
ll->head = to_delete->next;
|
||||
free(to_delete);
|
||||
}
|
||||
return to_return;
|
||||
}
|
||||
void* ll_poptail(ll* ll) {
|
||||
void* to_return = NULL;
|
||||
if (ll->tail) {
|
||||
ll_node* to_delete = ll->tail;
|
||||
to_return = to_delete->data;
|
||||
*(to_delete->prev ? &to_delete->prev->next : &ll->head) = NULL;
|
||||
ll->tail = to_delete->prev;
|
||||
free(to_delete);
|
||||
}
|
||||
return to_return;
|
||||
}
|
||||
108
src/main.c
108
src/main.c
@@ -3,6 +3,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "ht.h"
|
||||
#include "ll.h"
|
||||
#include "vec.h"
|
||||
|
||||
int _test_vec_foreach_func(void* data, va_list args) {
|
||||
@@ -145,9 +146,9 @@ int test_ht_foreach() {
|
||||
int return_code;
|
||||
int sum = 0;
|
||||
ht test_ht;
|
||||
ht_init(&test_ht);
|
||||
char* test_one = "one";
|
||||
char* test_two = "two";
|
||||
ht_init(&test_ht);
|
||||
ht_put(&test_ht, test_one, test_two);
|
||||
ht_put(&test_ht, test_two, test_one);
|
||||
ht_foreach(&test_ht, NULL, compare_always, _test_ht_foreach_func, &sum);
|
||||
@@ -156,6 +157,101 @@ int test_ht_foreach() {
|
||||
return return_code;
|
||||
}
|
||||
|
||||
int _test_ll_foreach_count(void* data, va_list args){
|
||||
(*va_arg(args, int*))++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_ll_basic() {
|
||||
ll test_ll;
|
||||
ll_init(&test_ll);
|
||||
ll_free(&test_ll);
|
||||
return 1;
|
||||
}
|
||||
int test_ll_append() {
|
||||
int return_code;
|
||||
ll test_ll;
|
||||
char* test_string = "test";
|
||||
ll_init(&test_ll);
|
||||
ll_append(&test_ll, test_string);
|
||||
return_code = test_ll.head->data == test_string && test_ll.tail->data == test_string;
|
||||
ll_free(&test_ll);
|
||||
return return_code;
|
||||
}
|
||||
int test_ll_prepend() {
|
||||
int return_code;
|
||||
ll test_ll;
|
||||
char* test_string = "test";
|
||||
ll_init(&test_ll);
|
||||
ll_prepend(&test_ll, test_string);
|
||||
return_code = test_ll.head->data == test_string && test_ll.tail->data == test_string;
|
||||
ll_free(&test_ll);
|
||||
return return_code;
|
||||
}
|
||||
int test_ll_remove() {
|
||||
int return_code;
|
||||
ll test_ll;
|
||||
char* test_string = "test";
|
||||
ll_init(&test_ll);
|
||||
ll_prepend(&test_ll, test_string);
|
||||
ll_prepend(&test_ll, test_string);
|
||||
ll_remove(&test_ll, test_string);
|
||||
return_code = test_ll.tail == NULL && test_ll.head == NULL;
|
||||
ll_free(&test_ll);
|
||||
return return_code;
|
||||
}
|
||||
int test_ll_find() {
|
||||
int return_code;
|
||||
ll test_ll;
|
||||
char* test_string = "test";
|
||||
ll_init(&test_ll);
|
||||
ll_prepend(&test_ll, test_string);
|
||||
return_code = ll_find(&test_ll, "test", _test_vec_find_string) == test_string;
|
||||
ll_free(&test_ll);
|
||||
return return_code;
|
||||
}
|
||||
int test_ll_foreach(){
|
||||
int return_code;
|
||||
int count = 0;
|
||||
ll test_ll;
|
||||
char* test_string = "test";
|
||||
ll_init(&test_ll);
|
||||
ll_append(&test_ll, test_string);
|
||||
ll_append(&test_ll, test_string);
|
||||
ll_foreach(&test_ll, NULL, compare_always, _test_ll_foreach_count, &count);
|
||||
return_code = count == 2;
|
||||
ll_free(&test_ll);
|
||||
return return_code;
|
||||
}
|
||||
int test_ll_pophead(){
|
||||
int return_code;
|
||||
ll test_ll;
|
||||
char* test_string_one = "test 1";
|
||||
char* test_string_two = "test 2";
|
||||
ll_init(&test_ll);
|
||||
ll_append(&test_ll, test_string_one);
|
||||
ll_append(&test_ll, test_string_two);
|
||||
return_code = ll_pophead(&test_ll) == test_string_one
|
||||
&& ll_head(&test_ll) == ll_tail(&test_ll)
|
||||
&& ll_head(&test_ll) == test_string_two;
|
||||
ll_free(&test_ll);
|
||||
return return_code;
|
||||
}
|
||||
int test_ll_poptail(){
|
||||
int return_code;
|
||||
ll test_ll;
|
||||
char* test_string_one = "test 1";
|
||||
char* test_string_two = "test 2";
|
||||
ll_init(&test_ll);
|
||||
ll_append(&test_ll, test_string_one);
|
||||
ll_append(&test_ll, test_string_two);
|
||||
return_code = ll_poptail(&test_ll) == test_string_two
|
||||
&& ll_head(&test_ll) == ll_tail(&test_ll)
|
||||
&& ll_head(&test_ll) == test_string_one;
|
||||
ll_free(&test_ll);
|
||||
return return_code;
|
||||
}
|
||||
|
||||
int run_test(char* test_name, int (*test_func)()) {
|
||||
int success = test_func();
|
||||
printf("Running test %-15s . . . ", test_name);
|
||||
@@ -164,18 +260,18 @@ int run_test(char* test_name, int (*test_func)()) {
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
char* test_names[11] = {"vec_basic", "vec_add", "vec_remove", "vec_find",
|
||||
char* test_names[19] = {"vec_basic", "vec_add", "vec_remove", "vec_find",
|
||||
"vec_foreach", "vec_index", "ht_basic", "ht_put",
|
||||
"ht_get", "ht_remove", "ht_foreach"};
|
||||
"ht_get", "ht_remove", "ht_foreach", "ll_basic", "ll_append", "ll_prepend", "ll_remove", "ll_find" , "ll_foreach", "ll_pophead", "ll_poptail"};
|
||||
|
||||
int (*test_functions[11])() = {
|
||||
int (*test_functions[19])() = {
|
||||
test_vec_basic, test_vec_add, test_vec_remove, test_vec_find,
|
||||
test_vec_foreach, test_vec_index, test_ht_basic, test_ht_put,
|
||||
test_ht_get, test_ht_remove, test_ht_foreach};
|
||||
test_ht_get, test_ht_remove, test_ht_foreach, test_ll_basic, test_ll_append, test_ll_prepend, test_ll_remove, test_ll_find, test_ll_foreach, test_ll_pophead, test_ll_poptail};
|
||||
|
||||
int test_index = 0;
|
||||
int result = 1;
|
||||
for (; test_index < 11 && result; test_index++) {
|
||||
for (; test_index < 19 && result; test_index++) {
|
||||
result = run_test(test_names[test_index], test_functions[test_index]);
|
||||
}
|
||||
return result ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
|
||||
Reference in New Issue
Block a user