From c74b0c4caf93d091d46508efb41ea772238a04ec Mon Sep 17 00:00:00 2001 From: Bailey Thompson Date: Mon, 10 Aug 2020 03:00:48 -0400 Subject: [PATCH] Reduce calls to malloc in list (#77) Reduce the number of malloc calls in list. Improves efficiency by 15%. --- containers.h | 20 +++--- src/include/list.h | 12 ++-- src/list.c | 161 ++++++++++++++++++++++----------------------- tst/list.c | 82 ++++++++++++----------- 4 files changed, 138 insertions(+), 137 deletions(-) diff --git a/containers.h b/containers.h index d5f6c26..312a3df 100644 --- a/containers.h +++ b/containers.h @@ -222,28 +222,28 @@ typedef struct internal_list *list; list list_init(size_t data_size); /* Utility */ -int list_size(list me); +size_t list_size(list me); int list_is_empty(list me); void list_copy_to_array(void *arr, list me); /* Adding */ int list_add_first(list me, void *data); -int list_add_at(list me, int index, void *data); +int list_add_at(list me, size_t index, void *data); int list_add_last(list me, void *data); /* Removing */ int list_remove_first(list me); -int list_remove_at(list me, int index); +int list_remove_at(list me, size_t index); int list_remove_last(list me); /* Setting */ int list_set_first(list me, void *data); -int list_set_at(list me, int index, void *data); +int list_set_at(list me, size_t index, void *data); int list_set_last(list me, void *data); /* Getting */ int list_get_first(void *data, list me); -int list_get_at(void *data, list me, int index); +int list_get_at(void *data, list me, size_t index); int list_get_last(void *data, list me); /* Ending */ @@ -337,28 +337,28 @@ typedef struct internal_forward_list *forward_list; forward_list forward_list_init(size_t data_size); /* Utility */ -int forward_list_size(forward_list me); +size_t forward_list_size(forward_list me); int forward_list_is_empty(forward_list me); void forward_list_copy_to_array(void *arr, forward_list me); /* Adding */ int forward_list_add_first(forward_list me, void *data); -int forward_list_add_at(forward_list me, int index, void *data); +int forward_list_add_at(forward_list me, size_t index, void *data); int forward_list_add_last(forward_list me, void *data); /* Removing */ int forward_list_remove_first(forward_list me); -int forward_list_remove_at(forward_list me, int index); +int forward_list_remove_at(forward_list me, size_t index); int forward_list_remove_last(forward_list me); /* Setting */ int forward_list_set_first(forward_list me, void *data); -int forward_list_set_at(forward_list me, int index, void *data); +int forward_list_set_at(forward_list me, size_t index, void *data); int forward_list_set_last(forward_list me, void *data); /* Getting */ int forward_list_get_first(void *data, forward_list me); -int forward_list_get_at(void *data, forward_list me, int index); +int forward_list_get_at(void *data, forward_list me, size_t index); int forward_list_get_last(void *data, forward_list me); /* Ending */ diff --git a/src/include/list.h b/src/include/list.h index d67d072..8c2e921 100644 --- a/src/include/list.h +++ b/src/include/list.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Bailey Thompson + * Copyright (c) 2017-2020 Bailey Thompson * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,28 +34,28 @@ typedef struct internal_list *list; list list_init(size_t data_size); /* Utility */ -int list_size(list me); +size_t list_size(list me); int list_is_empty(list me); void list_copy_to_array(void *arr, list me); /* Adding */ int list_add_first(list me, void *data); -int list_add_at(list me, int index, void *data); +int list_add_at(list me, size_t index, void *data); int list_add_last(list me, void *data); /* Removing */ int list_remove_first(list me); -int list_remove_at(list me, int index); +int list_remove_at(list me, size_t index); int list_remove_last(list me); /* Setting */ int list_set_first(list me, void *data); -int list_set_at(list me, int index, void *data); +int list_set_at(list me, size_t index, void *data); int list_set_last(list me, void *data); /* Getting */ int list_get_first(void *data, list me); -int list_get_at(void *data, list me, int index); +int list_get_at(void *data, list me, size_t index); int list_get_last(void *data, list me); /* Ending */ diff --git a/src/list.c b/src/list.c index 85d806b..eeb535a 100644 --- a/src/list.c +++ b/src/list.c @@ -26,16 +26,15 @@ struct internal_list { size_t bytes_per_item; - int item_count; - struct node *head; - struct node *tail; + size_t item_count; + char *head; + char *tail; }; -struct node { - struct node *prev; - void *data; - struct node *next; -}; +static const size_t ptr_size = sizeof(char *); +static const size_t node_next_ptr_offset = 0; +static const size_t node_prev_ptr_offset = sizeof(char *); +static const size_t node_data_ptr_offset = 2 * sizeof(char *); /** * Initializes a doubly-linked list. @@ -70,7 +69,7 @@ list list_init(const size_t data_size) * * @return the number of elements */ -int list_size(list me) +size_t list_size(list me) { return me->item_count; } @@ -100,24 +99,25 @@ int list_is_empty(list me) */ void list_copy_to_array(void *const arr, list me) { - struct node *traverse = me->head; - int offset = 0; + char *traverse = me->head; + size_t offset = 0; while (traverse) { - memcpy((char *) arr + offset, traverse->data, me->bytes_per_item); + memcpy((char *) arr + offset, traverse + node_data_ptr_offset, + me->bytes_per_item); + memcpy(&traverse, traverse + node_next_ptr_offset, ptr_size); offset += me->bytes_per_item; - traverse = traverse->next; } } /* * Gets the node at index starting from the head. */ -static struct node *list_get_node_from_head(list me, const int index) +static char *list_get_node_from_head(list me, const size_t index) { - struct node *traverse = me->head; - int i; + char *traverse = me->head; + size_t i; for (i = 0; i < index; i++) { - traverse = traverse->next; + memcpy(&traverse, traverse + node_next_ptr_offset, ptr_size); } return traverse; } @@ -125,12 +125,12 @@ static struct node *list_get_node_from_head(list me, const int index) /* * Gets the node at index starting from the tail. */ -static struct node *list_get_node_from_tail(list me, const int index) +static char *list_get_node_from_tail(list me, const size_t index) { - struct node *traverse = me->tail; - int i; + char *traverse = me->tail; + size_t i; for (i = me->item_count - 1; i > index; i--) { - traverse = traverse->prev; + memcpy(&traverse, traverse + node_prev_ptr_offset, ptr_size); } return traverse; } @@ -138,7 +138,7 @@ static struct node *list_get_node_from_tail(list me, const int index) /* * Gets the node at the specified index. */ -static struct node *list_get_node_at(list me, const int index) +static char *list_get_node_at(list me, const size_t index) { if (index < me->item_count / 2) { return list_get_node_from_head(me, index); @@ -179,45 +179,42 @@ int list_add_first(list me, void *const data) * @return -ENOMEM if out of memory * @return -EINVAL if invalid argument */ -int list_add_at(list me, const int index, void *const data) +int list_add_at(list me, const size_t index, void *const data) { - struct node *add; - if (index < 0 || index > me->item_count) { + char *node; + if (index > me->item_count) { return -EINVAL; } - add = malloc(sizeof(struct node)); - if (!add) { + node = malloc(2 * ptr_size + me->bytes_per_item); + if (!node) { return -ENOMEM; } - add->data = malloc(me->bytes_per_item); - if (!add->data) { - free(add); - return -ENOMEM; - } - memcpy(add->data, data, me->bytes_per_item); + memcpy(node + node_data_ptr_offset, data, me->bytes_per_item); if (!me->head) { - add->prev = NULL; - add->next = NULL; - me->head = add; - me->tail = add; + /* Relies on next and prev being the first two blocks. */ + memset(node, 0, 2 * ptr_size); + me->head = node; + me->tail = node; } else if (index == 0) { - struct node *const traverse = me->head; - traverse->prev = add; - add->prev = NULL; - add->next = traverse; - me->head = add; + char *traverse = me->head; + memcpy(traverse + node_prev_ptr_offset, &node, ptr_size); + memcpy(node + node_next_ptr_offset, &traverse, ptr_size); + memset(node + node_prev_ptr_offset, 0, ptr_size); + me->head = node; } else if (index == me->item_count) { - struct node *const traverse = me->tail; - traverse->next = add; - add->prev = traverse; - add->next = NULL; - me->tail = add; + char *traverse = me->tail; + memcpy(traverse + node_next_ptr_offset, &node, ptr_size); + memset(node + node_next_ptr_offset, 0, ptr_size); + memcpy(node + node_prev_ptr_offset, &traverse, ptr_size); + me->tail = node; } else { - struct node *const traverse = list_get_node_at(me, index); - add->prev = traverse->prev; - add->next = traverse; - traverse->prev->next = add; - traverse->prev = add; + char *traverse = list_get_node_at(me, index); + char *traverse_prev; + memcpy(&traverse_prev, traverse + node_prev_ptr_offset, ptr_size); + memcpy(node + node_prev_ptr_offset, &traverse_prev, ptr_size); + memcpy(node + node_next_ptr_offset, &traverse, ptr_size); + memcpy(traverse_prev + node_next_ptr_offset, &node, ptr_size); + memcpy(traverse + node_prev_ptr_offset, &node, ptr_size); } me->item_count++; return 0; @@ -241,14 +238,6 @@ int list_add_last(list me, void *const data) return list_add_at(me, me->item_count, data); } -/* - * Determines if the input is illegal. - */ -static int list_is_illegal_input(list me, const int index) -{ - return index < 0 || index >= me->item_count; -} - /** * Removes the first piece of data from the doubly-linked list. * @@ -271,10 +260,10 @@ int list_remove_first(list me) * @return 0 if no error * @return -EINVAL if invalid argument */ -int list_remove_at(list me, const int index) +int list_remove_at(list me, const size_t index) { - struct node *traverse; - if (list_is_illegal_input(me, index)) { + char *traverse; + if (index >= me->item_count) { return -EINVAL; } traverse = list_get_node_at(me, index); @@ -282,16 +271,23 @@ int list_remove_at(list me, const int index) me->head = NULL; me->tail = NULL; } else if (index == 0) { - traverse->next->prev = NULL; - me->head = traverse->next; + char *traverse_next; + memcpy(&traverse_next, traverse + node_next_ptr_offset, ptr_size); + memset(traverse_next + node_prev_ptr_offset, 0, ptr_size); + me->head = traverse_next; } else if (index == me->item_count - 1) { - traverse->prev->next = NULL; - me->tail = traverse->prev; + char *traverse_prev; + memcpy(&traverse_prev, traverse + node_prev_ptr_offset, ptr_size); + memset(traverse_prev + node_next_ptr_offset, 0, ptr_size); + me->tail = traverse_prev; } else { - traverse->prev->next = traverse->next; - traverse->next->prev = traverse->prev; + char *traverse_next; + char *traverse_prev; + memcpy(&traverse_next, traverse + node_next_ptr_offset, ptr_size); + memcpy(&traverse_prev, traverse + node_prev_ptr_offset, ptr_size); + memcpy(traverse_next + node_prev_ptr_offset, &traverse_prev, ptr_size); + memcpy(traverse_prev + node_next_ptr_offset, &traverse_next, ptr_size); } - free(traverse->data); free(traverse); me->item_count--; return 0; @@ -342,14 +338,14 @@ int list_set_first(list me, void *const data) * @return 0 if no error * @return -EINVAL if invalid argument */ -int list_set_at(list me, const int index, void *const data) +int list_set_at(list me, const size_t index, void *const data) { - struct node *traverse; - if (list_is_illegal_input(me, index)) { + char *traverse; + if (index >= me->item_count) { return -EINVAL; } traverse = list_get_node_at(me, index); - memcpy(traverse->data, data, me->bytes_per_item); + memcpy(traverse + node_data_ptr_offset, data, me->bytes_per_item); return 0; } @@ -405,14 +401,14 @@ int list_get_first(void *const data, list me) * @return 0 if no error * @return -EINVAL if invalid argument */ -int list_get_at(void *const data, list me, const int index) +int list_get_at(void *const data, list me, const size_t index) { - struct node *traverse; - if (list_is_illegal_input(me, index)) { + char *traverse; + if (index >= me->item_count) { return -EINVAL; } traverse = list_get_node_at(me, index); - memcpy(data, traverse->data, me->bytes_per_item); + memcpy(data, traverse + node_data_ptr_offset, me->bytes_per_item); return 0; } @@ -442,15 +438,14 @@ int list_get_last(void *const data, list me) */ void list_clear(list me) { - struct node *traverse = me->head; + char *traverse = me->head; while (traverse) { - struct node *const temp = traverse; - traverse = traverse->next; - free(temp->data); + char *temp = traverse; + memcpy(&traverse, traverse + node_next_ptr_offset, ptr_size); free(temp); } - me->head = NULL; me->item_count = 0; + me->head = NULL; me->tail = NULL; } diff --git a/tst/list.c b/tst/list.c index 12080d1..762d9b6 100644 --- a/tst/list.c +++ b/tst/list.c @@ -11,7 +11,7 @@ static void test_front(list me) int val[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int get_arr[10] = {0}; int get; - int i; + size_t i; assert(list_size(me) == 0); assert(list_is_empty(me)); for (i = 0; i < 10; i++) { @@ -176,15 +176,6 @@ static void test_add_first_out_of_memory(void) assert(list_get_at(&get, me, i) == 0); assert(get == 15 - i); } - fail_malloc = 1; - delay_fail_malloc = 1; - assert(list_add_first(me, &i) == -ENOMEM); - assert(list_size(me) == 16); - for (i = 0; i < 16; i++) { - int get = 0xfacade; - assert(list_get_at(&get, me, i) == 0); - assert(get == 15 - i); - } assert(!list_destroy(me)); } #endif @@ -218,21 +209,6 @@ static void test_add_at_out_of_memory(void) get = 0xfacade; assert(list_get_at(&get, me, 15) == 0); assert(get == 982); - fail_malloc = 1; - delay_fail_malloc = 1; - assert(list_add_at(me, 5, &i) == -ENOMEM); - assert(list_size(me) == 16); - get = 0xfacade; - assert(list_get_at(&get, me, 0) == 0); - assert(get == 157); - for (i = 1; i < 15; i++) { - get = 0xfacade; - assert(list_get_at(&get, me, i) == 0); - assert(get == i); - } - get = 0xfacade; - assert(list_get_at(&get, me, 15) == 0); - assert(get == 982); assert(!list_destroy(me)); } #endif @@ -255,22 +231,13 @@ static void test_add_last_out_of_memory(void) assert(list_get_at(&get, me, i) == 0); assert(get == i); } - fail_malloc = 1; - delay_fail_malloc = 1; - assert(list_add_last(me, &i) == -ENOMEM); - assert(list_size(me) == 16); - for (i = 0; i < 16; i++) { - int get = 0xfacade; - assert(list_get_at(&get, me, i) == 0); - assert(get == i); - } assert(!list_destroy(me)); } #endif void test_remove_all(void) { - int i; + size_t i; list me = list_init(sizeof(int)); for (i = 0; i < 100; i++) { list_add_first(me, &i); @@ -294,7 +261,7 @@ struct pair { int cur_cost; }; -static int test_puzzle(int start_node, int dest_node) +static int test_puzzle_forwards(int start_node, int dest_node) { list q = list_init(sizeof(struct pair)); struct pair cur; @@ -331,6 +298,43 @@ static int test_puzzle(int start_node, int dest_node) return -1; } +static int test_puzzle_backwards(int start_node, int dest_node) +{ + list q = list_init(sizeof(struct pair)); + struct pair cur; + cur.cur_node = start_node; + cur.cur_cost = 0; + assert(list_is_empty(q)); + list_add_first(q, &cur); + assert(list_size(q) == 1); + while (!list_is_empty(q)) { + int node; + int cost; + list_get_last(&cur, q); + list_remove_last(q); + node = cur.cur_node; + cost = cur.cur_cost; + if (node > 2 * dest_node || node < 1) { + continue; + } + if (node == dest_node) { + list_destroy(q); + return cost; + } + cur.cur_cost = cost + 1; + cur.cur_node = node - 1; + list_add_first(q, &cur); + assert(cur.cur_cost == cost + 1); + assert(cur.cur_node == node - 1); + cur.cur_node = 2 * node; + list_add_first(q, &cur); + assert(cur.cur_cost == cost + 1); + assert(cur.cur_node == 2 * node); + } + list_destroy(q); + return -1; +} + void test_list(void) { test_invalid_init(); @@ -342,6 +346,8 @@ void test_list(void) test_add_last_out_of_memory(); #endif test_remove_all(); - assert(test_puzzle(2, 5) == 4); - assert(test_puzzle(2, 10) == 5); + assert(test_puzzle_forwards(2, 5) == 4); + assert(test_puzzle_forwards(2, 10) == 5); + assert(test_puzzle_backwards(2, 5) == 4); + assert(test_puzzle_backwards(2, 10) == 5); }