Reduce calls to malloc in list (#77)

Reduce the number of malloc calls in list. Improves efficiency by 15%.
This commit is contained in:
Bailey Thompson
2020-08-10 03:00:48 -04:00
committed by GitHub
parent 94e5530996
commit c74b0c4caf
4 changed files with 138 additions and 137 deletions

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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);
}