diff --git a/src/deque.c b/src/deque.c index 0a38c4a..8d9e710 100644 --- a/src/deque.c +++ b/src/deque.c @@ -34,6 +34,8 @@ struct internal_deque { size_t start_index; size_t end_index; size_t block_count; + size_t alloc_block_start; + size_t alloc_block_end; char **data; }; @@ -70,7 +72,9 @@ deque deque_init(const size_t data_size) init->block_size * BKTHOMPS_DEQUE_INITIAL_BLOCK_COUNT / 2; init->end_index = init->start_index; init->block_count = BKTHOMPS_DEQUE_INITIAL_BLOCK_COUNT; - init->data = calloc(init->block_count, sizeof(char *)); + init->alloc_block_start = init->start_index / init->block_size; + init->alloc_block_end = init->alloc_block_start; + init->data = malloc(init->block_count * sizeof(char *)); if (!init->data) { free(init); return NULL; @@ -81,8 +85,7 @@ deque deque_init(const size_t data_size) free(init); return NULL; } - memcpy(init->data + init->start_index / init->block_size, &block, - sizeof(char *)); + init->data[init->alloc_block_start] = block; return init; } @@ -134,20 +137,18 @@ bk_err deque_trim(deque me) } memcpy(updated_data, me->data + start_block_index, updated_block_count * sizeof(char *)); - for (i = 0; i < start_block_index; i++) { - char *block; - memcpy(&block, me->data + i, sizeof(char *)); - free(block); + for (i = me->alloc_block_start; i < start_block_index; i++) { + free(me->data[i]); } - for (i = end_block_index + 1; i < me->block_count; i++) { - char *block; - memcpy(&block, me->data + i, sizeof(char *)); - free(block); + for (i = end_block_index + 1; i <= me->alloc_block_end; i++) { + free(me->data[i]); } free(me->data); me->start_index -= start_block_index * me->block_size; me->end_index -= start_block_index * me->block_size; me->block_count = updated_block_count; + me->alloc_block_start = 0; + me->alloc_block_end = updated_block_count - 1; me->data = updated_data; return BK_OK; } @@ -235,18 +236,15 @@ bk_err deque_add_all(deque me, void *const arr, const size_t size) if (!temp) { return -BK_ENOMEM; } - memset(temp + me->block_count, 0, appended_blocks * sizeof(char *)); me->data = temp; me->block_count = new_block_count; } - for (i = block_index + 1; i <= block_index + needed_blocks; i++) { - if (me->data[i]) { - continue; - } + for (i = me->alloc_block_end + 1; i <= block_index + needed_blocks; i++) { me->data[i] = malloc(me->block_size * me->data_size); if (!me->data[i]) { return -BK_ENOMEM; } + me->alloc_block_end++; } offset = first_block_space * me->data_size; memcpy(me->data[block_index] + inner_index * me->data_size, arr, offset); @@ -307,23 +305,28 @@ bk_err deque_push_front(deque me, void *const data) return -BK_ENOMEM; } memmove(temp + added_blocks, temp, me->block_count * sizeof(char *)); - memset(temp, 0, added_blocks * sizeof(char *)); me->data = temp; me->block_count = new_block_count; me->start_index += added_blocks * me->block_size; me->end_index += added_blocks * me->block_size; + me->alloc_block_start += added_blocks; + me->alloc_block_end += added_blocks; } if (me->start_index % me->block_size == 0) { - char *block; - const size_t previous_block_index = - me->start_index / me->block_size - 1; - memcpy(&block, me->data + previous_block_index, sizeof(char *)); - if (!block) { - block = malloc(me->block_size * me->data_size); - if (!block) { - return -BK_ENOMEM; + const size_t add_block_index = me->start_index / me->block_size - 1; + if (add_block_index < me->alloc_block_start) { + const size_t end_block = (me->end_index - 1) / me->block_size; + if (end_block < me->alloc_block_end) { + me->data[add_block_index] = me->data[me->alloc_block_end]; + me->alloc_block_end--; + } else { + me->data[add_block_index] = + malloc(me->block_size * me->data_size); + if (!me->data[add_block_index]) { + return -BK_ENOMEM; + } } - memcpy(me->data + previous_block_index, &block, sizeof(char *)); + me->alloc_block_start--; } } me->start_index--; @@ -355,30 +358,32 @@ bk_err deque_push_back(deque me, void *const data) { if (me->end_index == me->block_count * me->block_size) { const size_t new_block_count = deque_get_new_block_count(me); - size_t added_blocks; char **temp; if (new_block_count == 0) { return -BK_ERANGE; } - added_blocks = new_block_count - me->block_count; temp = realloc(me->data, new_block_count * sizeof(char *)); if (!temp) { return -BK_ENOMEM; } - memset(temp + me->block_count, 0, added_blocks * sizeof(char *)); me->data = temp; me->block_count = new_block_count; } if (me->end_index % me->block_size == 0) { - char *block; - const size_t tentative_block_index = me->end_index / me->block_size; - memcpy(&block, me->data + tentative_block_index, sizeof(char *)); - if (!block) { - block = malloc(me->block_size * me->data_size); - if (!block) { - return -BK_ENOMEM; + const size_t add_block_index = me->end_index / me->block_size; + if (add_block_index > me->alloc_block_end) { + const size_t start_block = me->start_index / me->block_size; + if (start_block > me->alloc_block_start) { + me->data[add_block_index] = me->data[me->alloc_block_start]; + me->alloc_block_start++; + } else { + me->data[add_block_index] = + malloc(me->block_size * me->data_size); + if (!me->data[add_block_index]) { + return -BK_ENOMEM; + } } - memcpy(me->data + tentative_block_index, &block, sizeof(char *)); + me->alloc_block_end++; } } { @@ -586,8 +591,8 @@ bk_err deque_clear(deque me) { size_t i; char *updated_block; - char **updated_data = calloc(BKTHOMPS_DEQUE_INITIAL_BLOCK_COUNT, - sizeof(char *)); + char **updated_data = + malloc(BKTHOMPS_DEQUE_INITIAL_BLOCK_COUNT * sizeof(char *)); if (!updated_data) { return -BK_ENOMEM; } @@ -596,18 +601,17 @@ bk_err deque_clear(deque me) free(updated_data); return -BK_ENOMEM; } - for (i = 0; i < me->block_count; i++) { - char *block; - memcpy(&block, me->data + i, sizeof(char *)); - free(block); + for (i = me->alloc_block_start; i <= me->alloc_block_end; i++) { + free(me->data[i]); } free(me->data); me->start_index = me->block_size * BKTHOMPS_DEQUE_INITIAL_BLOCK_COUNT / 2; me->end_index = me->start_index; me->block_count = BKTHOMPS_DEQUE_INITIAL_BLOCK_COUNT; + me->alloc_block_start = me->start_index / me->block_size; + me->alloc_block_end = me->alloc_block_start; me->data = updated_data; - memcpy(me->data + me->start_index / me->block_size, &updated_block, - sizeof(char *)); + me->data[me->alloc_block_start] = updated_block; return BK_OK; } @@ -622,10 +626,8 @@ bk_err deque_clear(deque me) deque deque_destroy(deque me) { size_t i; - for (i = 0; i < me->block_count; i++) { - char *block; - memcpy(&block, me->data + i, sizeof(char *)); - free(block); + for (i = me->alloc_block_start; i <= me->alloc_block_end; i++) { + free(me->data[i]); } free(me->data); free(me); diff --git a/tst/test_deque.c b/tst/test_deque.c index 202c2ad..e526ed5 100644 --- a/tst/test_deque.c +++ b/tst/test_deque.c @@ -268,13 +268,14 @@ static void test_large_elements(void) #if STUB_MALLOC static void test_init_out_of_memory(void) { - fail_calloc = 1; - assert(!deque_init(sizeof(int))); fail_malloc = 1; assert(!deque_init(sizeof(int))); fail_malloc = 1; delay_fail_malloc = 1; assert(!deque_init(sizeof(int))); + fail_malloc = 1; + delay_fail_malloc = 2; + assert(!deque_init(sizeof(int))); } #endif @@ -342,7 +343,7 @@ static void test_clear_out_of_memory(void) deque_push_back(me, &i); } assert(deque_size(me) == 32); - fail_calloc = 1; + fail_malloc = 1; assert(deque_clear(me) == -ENOMEM); for (i = 0; i < 32; i++) { int get = 0xfacade; @@ -351,6 +352,7 @@ static void test_clear_out_of_memory(void) } assert(deque_size(me) == 32); fail_malloc = 1; + delay_fail_malloc = 1; assert(deque_clear(me) == -ENOMEM); for (i = 0; i < 32; i++) { int get = 0xfacade; @@ -461,7 +463,7 @@ static void test_big_object(void) assert(!deque_destroy(me)); } -void test_add_all(int big_arr_size) +static void test_add_all(int big_arr_size) { int i; double small_array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; @@ -489,7 +491,7 @@ void test_add_all(int big_arr_size) free(big_array); } -void test_add_all_failure(void) +static void test_add_all_failure(void) { const size_t big_arr_size = 2000; size_t i; @@ -529,6 +531,80 @@ void test_add_all_failure(void) free(big_array); } +static void test_block_reuse_forwards(void) +{ + size_t i; + size_t queue_size = 1500; + deque queue = deque_init(sizeof(double)); + for (i = 0; i < queue_size; i++) { + double d = i; + assert(deque_push_back(queue, &d) == BK_OK); + } + for (i = 0; i < queue_size; i++) { + double d = i; + double get; + assert(deque_push_back(queue, &d) == BK_OK); + assert(deque_pop_front(&get, queue) == BK_OK); + assert(get == d); + } + deque_destroy(queue); +} + +static void test_block_reuse_backwards(void) +{ + size_t i; + size_t queue_size = 1500; + deque queue = deque_init(sizeof(double)); + for (i = 0; i < queue_size; i++) { + double d = i; + assert(deque_push_front(queue, &d) == BK_OK); + } + for (i = 0; i < queue_size; i++) { + double d = i; + double get; + assert(deque_push_front(queue, &d) == BK_OK); + assert(deque_pop_back(&get, queue) == BK_OK); + assert(get == d); + } + deque_destroy(queue); +} + +static void test_trim_both_sides(void) +{ + int i; + deque me = deque_init(sizeof(int)); + for (i = 999; i >= 0; i--) { + assert(deque_push_front(me, &i) == BK_OK); + assert(deque_push_back(me, &i) == BK_OK); + } + assert(deque_size(me) == 2000); + assert(deque_trim(me) == BK_OK); + assert(deque_size(me) == 2000); + for (i = 0; i < 500; i++) { + int get = 0xfacade; + assert(deque_pop_front(&get, me) == BK_OK); + assert(get == i); + get = 0xfacade; + assert(deque_pop_back(&get, me) == BK_OK); + assert(get == i); + } + assert(deque_size(me) == 1000); + assert(deque_trim(me) == BK_OK); + assert(deque_size(me) == 1000); + for (i = 500; i < 1000; i++) { + int get = 0xfacade; + assert(deque_pop_front(&get, me) == BK_OK); + assert(get == i); + get = 0xfacade; + assert(deque_pop_back(&get, me) == BK_OK); + assert(get == i); + } + assert(deque_size(me) == 0); + assert(deque_trim(me) == BK_OK); + assert(deque_size(me) == 0); + deque_destroy(me); +} + void test_deque(void) { int i; @@ -555,4 +631,7 @@ void test_deque(void) test_add_all(i); } test_add_all_failure(); + test_block_reuse_forwards(); + test_block_reuse_backwards(); + test_trim_both_sides(); }