From 8d45509d687f45249b46d7eceafef3dbca332876 Mon Sep 17 00:00:00 2001 From: Bailey Thompson Date: Sun, 9 Jun 2019 00:30:30 -0400 Subject: [PATCH] Forward list optimization (#53) Add a tail pointer which is either NULL or points to the back of the list. This improves the performance when adding to the back of the list many times in a row. --- src/forward_list.c | 19 ++++++++++++++----- src/list.c | 5 ++--- tst/forward_list.c | 20 ++++++++++++++++++++ 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/forward_list.c b/src/forward_list.c index cbed266..fcc904b 100644 --- a/src/forward_list.c +++ b/src/forward_list.c @@ -28,6 +28,7 @@ struct internal_forward_list { size_t bytes_per_item; int item_count; struct node *head; + struct node *tail; }; struct node { @@ -57,6 +58,7 @@ forward_list forward_list_init(const size_t data_size) init->bytes_per_item = data_size; init->item_count = 0; init->head = NULL; + init->tail = NULL; return init; } @@ -113,9 +115,15 @@ static struct node *forward_list_get_node_at(forward_list me, const int index) { struct node *traverse = me->head; int i; + if (me->tail && index == me->item_count - 1) { + return me->tail; + } for (i = 0; i < index; i++) { traverse = traverse->next; } + if (!traverse->next) { + me->tail = traverse; + } return traverse; } @@ -175,6 +183,9 @@ int forward_list_add_at(forward_list me, const int index, void *const data) struct node *const traverse = forward_list_get_node_at(me, index - 1); add->next = traverse->next; traverse->next = add; + if (!add->next) { + me->tail = add; + } } me->item_count++; return 0; @@ -238,17 +249,15 @@ int forward_list_remove_at(forward_list me, const int index) me->head = temp->next; free(temp->data); free(temp); - } else if (index == me->item_count - 1) { - struct node *const traverse = forward_list_get_node_at(me, index - 1); - free(traverse->next->data); - free(traverse->next); - traverse->next = NULL; } else { struct node *const traverse = forward_list_get_node_at(me, index - 1); struct node *const backup = traverse->next; traverse->next = traverse->next->next; free(backup->data); free(backup); + if (!backup->next) { + me->tail = NULL; + } } me->item_count--; return 0; diff --git a/src/list.c b/src/list.c index abbd4b4..617774a 100644 --- a/src/list.c +++ b/src/list.c @@ -140,11 +140,10 @@ static struct node *list_get_node_from_tail(list me, const int index) */ static struct node *list_get_node_at(list me, const int index) { - if (index <= me->item_count / 2) { + if (index < me->item_count / 2) { return list_get_node_from_head(me, index); - } else { - return list_get_node_from_tail(me, index); } + return list_get_node_from_tail(me, index); } /** diff --git a/tst/forward_list.c b/tst/forward_list.c index bada179..a2937ce 100644 --- a/tst/forward_list.c +++ b/tst/forward_list.c @@ -150,6 +150,25 @@ static void test_basic(void) assert(!forward_list_destroy(me)); } +static void test_add_back(void) +{ + int i; + forward_list me = forward_list_init(sizeof(int)); + assert(me); + for (i = 1; i < 10000; i++) { + int get = 0xdeadbeef; + forward_list_add_last(me, &i); + forward_list_get_last(&get, me); + assert(get == i); + if (i % 5 == 0) { + forward_list_remove_last(me); + forward_list_get_last(&get, me); + assert(get == i - 1); + } + } + assert(!forward_list_destroy(me)); +} + static void test_init_out_of_memory(void) { fail_malloc = 1; @@ -264,6 +283,7 @@ void test_forward_list(void) { test_invalid_init(); test_basic(); + test_add_back(); test_init_out_of_memory(); test_add_first_out_of_memory(); test_add_at_out_of_memory();