mirror of
https://github.com/bkthomps/Containers.git
synced 2025-11-16 04:24:47 +00:00
Rewrite deque (#72)
The deque is now 40% faster and the code is much cleaner.
This commit is contained in:
360
src/deque.c
360
src/deque.c
@@ -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
|
||||
@@ -24,19 +24,16 @@
|
||||
#include <errno.h>
|
||||
#include "include/deque.h"
|
||||
|
||||
static const int BLOCK_SIZE = 8;
|
||||
static const size_t BLOCK_SIZE = 1024;
|
||||
static const size_t INITIAL_BLOCK_COUNT = 8;
|
||||
static const double RESIZE_RATIO = 1.5;
|
||||
|
||||
struct internal_deque {
|
||||
size_t data_size;
|
||||
int start_index;
|
||||
int end_index;
|
||||
int block_count;
|
||||
struct node *block;
|
||||
};
|
||||
|
||||
struct node {
|
||||
void *data;
|
||||
size_t start_index;
|
||||
size_t end_index;
|
||||
size_t block_count;
|
||||
char **data;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -51,7 +48,7 @@ struct node {
|
||||
deque deque_init(const size_t data_size)
|
||||
{
|
||||
struct internal_deque *init;
|
||||
struct node *block;
|
||||
char *block;
|
||||
if (data_size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -60,21 +57,21 @@ deque deque_init(const size_t data_size)
|
||||
return NULL;
|
||||
}
|
||||
init->data_size = data_size;
|
||||
init->start_index = BLOCK_SIZE / 2;
|
||||
init->end_index = init->start_index + 1;
|
||||
init->block_count = 1;
|
||||
init->block = malloc(sizeof(struct node));
|
||||
if (!init->block) {
|
||||
init->start_index = BLOCK_SIZE * INITIAL_BLOCK_COUNT / 2;
|
||||
init->end_index = init->start_index;
|
||||
init->block_count = INITIAL_BLOCK_COUNT;
|
||||
init->data = calloc(init->block_count, sizeof(char *));
|
||||
if (!init->data) {
|
||||
free(init);
|
||||
return NULL;
|
||||
}
|
||||
block = init->block;
|
||||
block->data = malloc(BLOCK_SIZE * init->data_size);
|
||||
if (!block->data) {
|
||||
free(init->block);
|
||||
block = malloc(BLOCK_SIZE * init->data_size);
|
||||
if (!block) {
|
||||
free(init->data);
|
||||
free(init);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(init->data + init->start_index / BLOCK_SIZE, &block, sizeof(char *));
|
||||
return init;
|
||||
}
|
||||
|
||||
@@ -87,9 +84,9 @@ deque deque_init(const size_t data_size)
|
||||
*
|
||||
* @return the size of the deque
|
||||
*/
|
||||
int deque_size(deque me)
|
||||
size_t deque_size(deque me)
|
||||
{
|
||||
return me->end_index - me->start_index - 1;
|
||||
return me->end_index - me->start_index;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,34 +112,32 @@ int deque_is_empty(deque me)
|
||||
*/
|
||||
int deque_trim(deque me)
|
||||
{
|
||||
int i;
|
||||
/* The start and end blocks are written like this because in C89 */
|
||||
/* negative integer division and modulo are implementation-defined. */
|
||||
const int start_block =
|
||||
me->start_index == -1 ? 0 : me->start_index / BLOCK_SIZE;
|
||||
const int end_block =
|
||||
me->end_index == 0 ? 0 : (me->end_index - 1) / BLOCK_SIZE;
|
||||
const int new_block_count = end_block - start_block + 1;
|
||||
void *const new_block = malloc(new_block_count * sizeof(struct node));
|
||||
if (!new_block) {
|
||||
size_t i;
|
||||
const size_t start_block_index = me->start_index / BLOCK_SIZE;
|
||||
const size_t end_block_index = deque_is_empty(me) ? start_block_index :
|
||||
(me->end_index - 1) / BLOCK_SIZE;
|
||||
const size_t updated_block_count = end_block_index - start_block_index + 1;
|
||||
char **updated_data = malloc(updated_block_count * sizeof(char *));
|
||||
if (!updated_data) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
for (i = 0; i < start_block; i++) {
|
||||
const struct node block_item = me->block[i];
|
||||
free(block_item.data);
|
||||
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 = end_block + 1; i < me->block_count; i++) {
|
||||
const struct node block_item = me->block[i];
|
||||
free(block_item.data);
|
||||
for (i = end_block_index + 1; i < me->block_count; i++) {
|
||||
char *block;
|
||||
memcpy(&block, me->data + i, sizeof(char *));
|
||||
free(block);
|
||||
}
|
||||
memcpy(new_block,
|
||||
&me->block[start_block],
|
||||
new_block_count * sizeof(struct node));
|
||||
free(me->block);
|
||||
me->block = new_block;
|
||||
me->block_count = new_block_count;
|
||||
me->start_index -= start_block * BLOCK_SIZE;
|
||||
me->end_index -= start_block * BLOCK_SIZE;
|
||||
free(me->data);
|
||||
me->start_index -= start_block_index * BLOCK_SIZE;
|
||||
me->end_index -= start_block_index * BLOCK_SIZE;
|
||||
me->block_count = updated_block_count;
|
||||
me->data = updated_data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -159,9 +154,31 @@ int deque_trim(deque me)
|
||||
*/
|
||||
void deque_copy_to_array(void *const arr, deque me)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < deque_size(me); i++) {
|
||||
deque_get_at((char *) arr + i * me->data_size, me, i);
|
||||
char *block;
|
||||
size_t i;
|
||||
size_t size_offset;
|
||||
const size_t start_block_index = me->start_index / BLOCK_SIZE;
|
||||
const size_t start_inner_index = me->start_index % BLOCK_SIZE;
|
||||
const size_t end_block_index = (me->end_index - 1) / BLOCK_SIZE;
|
||||
const size_t end_inner_index = (me->end_index - 1) % BLOCK_SIZE;
|
||||
const size_t first_block_length =
|
||||
BLOCK_SIZE - start_inner_index < deque_size(me)
|
||||
? BLOCK_SIZE - start_inner_index : deque_size(me);
|
||||
if (deque_is_empty(me)) {
|
||||
return;
|
||||
}
|
||||
size_offset = first_block_length * me->data_size;
|
||||
memcpy(&block, me->data + start_block_index, sizeof(char *));
|
||||
memcpy(arr, block + start_inner_index * me->data_size, size_offset);
|
||||
for (i = start_block_index + 1; i < end_block_index; i++) {
|
||||
memcpy(&block, me->data + i, sizeof(char *));
|
||||
memcpy((char *) arr + size_offset, block, BLOCK_SIZE * me->data_size);
|
||||
size_offset += BLOCK_SIZE * me->data_size;
|
||||
}
|
||||
if (end_block_index != start_block_index) {
|
||||
memcpy(&block, me->data + end_block_index, sizeof(char *));
|
||||
memcpy((char *) arr + size_offset, block,
|
||||
(end_inner_index + 1) * me->data_size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,54 +197,43 @@ void deque_copy_to_array(void *const arr, deque me)
|
||||
*/
|
||||
int deque_push_front(deque me, void *const data)
|
||||
{
|
||||
struct node block_item;
|
||||
int block_index;
|
||||
int inner_index;
|
||||
if (me->start_index == -1) {
|
||||
block_index = -1;
|
||||
inner_index = BLOCK_SIZE - 1;
|
||||
} else {
|
||||
block_index = me->start_index / BLOCK_SIZE;
|
||||
inner_index = me->start_index % BLOCK_SIZE;
|
||||
}
|
||||
if (inner_index == BLOCK_SIZE - 1) {
|
||||
struct node *block_item_reference;
|
||||
if (block_index == -1) {
|
||||
int i;
|
||||
const int old_block_count = me->block_count;
|
||||
const int new_block_count =
|
||||
(int) (RESIZE_RATIO * me->block_count) + 1;
|
||||
const int added_blocks = new_block_count - old_block_count;
|
||||
void *temp = realloc(me->block,
|
||||
new_block_count * sizeof(struct node));
|
||||
if (!temp) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
me->block = temp;
|
||||
me->block_count = new_block_count;
|
||||
memmove(&me->block[added_blocks],
|
||||
me->block,
|
||||
old_block_count * sizeof(struct node));
|
||||
block_index = added_blocks - 1;
|
||||
me->start_index += added_blocks * BLOCK_SIZE;
|
||||
me->end_index += added_blocks * BLOCK_SIZE;
|
||||
for (i = 0; i < added_blocks; i++) {
|
||||
struct node *const block_item_copy = &me->block[i];
|
||||
block_item_copy->data = NULL;
|
||||
}
|
||||
}
|
||||
block_item_reference = &me->block[block_index];
|
||||
if (!block_item_reference->data) {
|
||||
block_item_reference->data = malloc(BLOCK_SIZE * me->data_size);
|
||||
if (!block_item_reference->data) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (me->start_index == 0) {
|
||||
const size_t updated_block_count =
|
||||
(size_t) (me->block_count * RESIZE_RATIO) + 1;
|
||||
const size_t added_blocks = updated_block_count - me->block_count;
|
||||
char **temp = realloc(me->data, updated_block_count * sizeof(char *));
|
||||
if (!temp) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
memmove(temp + added_blocks, temp, me->block_count * sizeof(char *));
|
||||
memset(temp, 0, added_blocks * sizeof(char *));
|
||||
me->data = temp;
|
||||
me->block_count += added_blocks;
|
||||
me->start_index += added_blocks * BLOCK_SIZE;
|
||||
me->end_index += added_blocks * BLOCK_SIZE;
|
||||
}
|
||||
block_item = me->block[block_index];
|
||||
memcpy((char *) block_item.data + inner_index * me->data_size, data,
|
||||
me->data_size);
|
||||
if (me->start_index % BLOCK_SIZE == 0) {
|
||||
char *block;
|
||||
const size_t previous_block_index = me->start_index / BLOCK_SIZE - 1;
|
||||
memcpy(&block, me->data + previous_block_index, sizeof(char *));
|
||||
if (block) {
|
||||
goto copy_element;
|
||||
}
|
||||
block = malloc(BLOCK_SIZE * me->data_size);
|
||||
if (!block) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy(me->data + previous_block_index, &block, sizeof(char *));
|
||||
}
|
||||
copy_element:
|
||||
me->start_index--;
|
||||
{
|
||||
char *block;
|
||||
const size_t block_index = me->start_index / BLOCK_SIZE;
|
||||
const size_t inner_index = me->start_index % BLOCK_SIZE;
|
||||
memcpy(&block, me->data + block_index, sizeof(char *));
|
||||
memcpy(block + inner_index * me->data_size, data, me->data_size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -246,38 +252,39 @@ int deque_push_front(deque me, void *const data)
|
||||
*/
|
||||
int deque_push_back(deque me, void *const data)
|
||||
{
|
||||
struct node block_item;
|
||||
const int block_index = me->end_index / BLOCK_SIZE;
|
||||
const int inner_index = me->end_index % BLOCK_SIZE;
|
||||
if (inner_index == 0) {
|
||||
struct node *block_item_reference;
|
||||
if (block_index == me->block_count) {
|
||||
int i;
|
||||
const int new_block_count =
|
||||
(int) (RESIZE_RATIO * me->block_count) + 1;
|
||||
void *temp = realloc(me->block,
|
||||
new_block_count * sizeof(struct node));
|
||||
if (!temp) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
me->block = temp;
|
||||
me->block_count = new_block_count;
|
||||
for (i = block_index; i < me->block_count; i++) {
|
||||
struct node *const block_item_copy = &me->block[i];
|
||||
block_item_copy->data = NULL;
|
||||
}
|
||||
}
|
||||
block_item_reference = &me->block[block_index];
|
||||
if (!block_item_reference->data) {
|
||||
block_item_reference->data = malloc(BLOCK_SIZE * me->data_size);
|
||||
if (!block_item_reference->data) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (me->end_index == me->block_count * BLOCK_SIZE) {
|
||||
const size_t updated_block_count =
|
||||
(size_t) (me->block_count * RESIZE_RATIO) + 1;
|
||||
const size_t added_blocks = updated_block_count - me->block_count;
|
||||
char **temp = realloc(me->data, updated_block_count * sizeof(char *));
|
||||
if (!temp) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(temp + me->block_count, 0, added_blocks * sizeof(char *));
|
||||
me->data = temp;
|
||||
me->block_count += added_blocks;
|
||||
}
|
||||
if (me->end_index % BLOCK_SIZE == 0) {
|
||||
char *block;
|
||||
const size_t tentative_block_index = me->end_index / BLOCK_SIZE;
|
||||
memcpy(&block, me->data + tentative_block_index, sizeof(char *));
|
||||
if (block) {
|
||||
goto copy_element;
|
||||
}
|
||||
block = malloc(BLOCK_SIZE * me->data_size);
|
||||
if (!block) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy(me->data + tentative_block_index, &block, sizeof(char *));
|
||||
}
|
||||
copy_element:
|
||||
{
|
||||
char *block;
|
||||
const size_t block_index = me->end_index / BLOCK_SIZE;
|
||||
const size_t inner_index = me->end_index % BLOCK_SIZE;
|
||||
memcpy(&block, me->data + block_index, sizeof(char *));
|
||||
memcpy(block + inner_index * me->data_size, data, me->data_size);
|
||||
}
|
||||
block_item = me->block[block_index];
|
||||
memcpy((char *) block_item.data + inner_index * me->data_size, data,
|
||||
me->data_size);
|
||||
me->end_index++;
|
||||
return 0;
|
||||
}
|
||||
@@ -298,18 +305,15 @@ int deque_push_back(deque me, void *const data)
|
||||
*/
|
||||
int deque_pop_front(void *const data, deque me)
|
||||
{
|
||||
int block_index;
|
||||
int inner_index;
|
||||
struct node block_item;
|
||||
char *block;
|
||||
const size_t block_index = me->start_index / BLOCK_SIZE;
|
||||
const size_t inner_index = me->start_index % BLOCK_SIZE;
|
||||
if (deque_is_empty(me)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(&block, me->data + block_index, sizeof(char *));
|
||||
memcpy(data, block + inner_index * me->data_size, me->data_size);
|
||||
me->start_index++;
|
||||
block_index = me->start_index / BLOCK_SIZE;
|
||||
inner_index = me->start_index % BLOCK_SIZE;
|
||||
block_item = me->block[block_index];
|
||||
memcpy(data, (char *) block_item.data + inner_index * me->data_size,
|
||||
me->data_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -329,18 +333,15 @@ int deque_pop_front(void *const data, deque me)
|
||||
*/
|
||||
int deque_pop_back(void *const data, deque me)
|
||||
{
|
||||
int block_index;
|
||||
int inner_index;
|
||||
struct node block_item;
|
||||
char *block;
|
||||
const size_t block_index = (me->end_index - 1) / BLOCK_SIZE;
|
||||
const size_t inner_index = (me->end_index - 1) % BLOCK_SIZE;
|
||||
if (deque_is_empty(me)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(&block, me->data + block_index, sizeof(char *));
|
||||
memcpy(data, block + inner_index * me->data_size, me->data_size);
|
||||
me->end_index--;
|
||||
block_index = me->end_index / BLOCK_SIZE;
|
||||
inner_index = me->end_index % BLOCK_SIZE;
|
||||
block_item = me->block[block_index];
|
||||
memcpy(data, (char *) block_item.data + inner_index * me->data_size,
|
||||
me->data_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -376,20 +377,16 @@ int deque_set_first(deque me, void *const data)
|
||||
* @return 0 if no error
|
||||
* @return -EINVAL if invalid argument
|
||||
*/
|
||||
int deque_set_at(deque me, int index, void *const data)
|
||||
int deque_set_at(deque me, size_t index, void *const data)
|
||||
{
|
||||
int block_index;
|
||||
int inner_index;
|
||||
struct node block_item;
|
||||
if (index < 0 || index >= deque_size(me)) {
|
||||
char *block;
|
||||
const size_t block_index = (index + me->start_index) / BLOCK_SIZE;
|
||||
const size_t inner_index = (index + me->start_index) % BLOCK_SIZE;
|
||||
if (index >= deque_size(me)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
index += me->start_index + 1;
|
||||
block_index = index / BLOCK_SIZE;
|
||||
inner_index = index % BLOCK_SIZE;
|
||||
block_item = me->block[block_index];
|
||||
memcpy((char *) block_item.data + inner_index * me->data_size, data,
|
||||
me->data_size);
|
||||
memcpy(&block, me->data + block_index, sizeof(char *));
|
||||
memcpy(block + inner_index * me->data_size, data, me->data_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -443,20 +440,16 @@ int deque_get_first(void *const data, deque me)
|
||||
* @return 0 if no error
|
||||
* @return -EINVAL if invalid argument
|
||||
*/
|
||||
int deque_get_at(void *const data, deque me, int index)
|
||||
int deque_get_at(void *const data, deque me, size_t index)
|
||||
{
|
||||
int block_index;
|
||||
int inner_index;
|
||||
struct node block_item;
|
||||
if (index < 0 || index >= deque_size(me)) {
|
||||
char *block;
|
||||
const size_t block_index = (index + me->start_index) / BLOCK_SIZE;
|
||||
const size_t inner_index = (index + me->start_index) % BLOCK_SIZE;
|
||||
if (index >= deque_size(me)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
index += me->start_index + 1;
|
||||
block_index = index / BLOCK_SIZE;
|
||||
inner_index = index % BLOCK_SIZE;
|
||||
block_item = me->block[block_index];
|
||||
memcpy(data, (char *) block_item.data + inner_index * me->data_size,
|
||||
me->data_size);
|
||||
memcpy(&block, me->data + block_index, sizeof(char *));
|
||||
memcpy(data, block + inner_index * me->data_size, me->data_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -488,29 +481,29 @@ int deque_get_last(void *const data, deque me)
|
||||
*/
|
||||
int deque_clear(deque me)
|
||||
{
|
||||
void *temp_block_data;
|
||||
int i;
|
||||
struct node *block;
|
||||
struct node *const temp_block = malloc(sizeof(struct node));
|
||||
if (!temp_block) {
|
||||
size_t i;
|
||||
char *updated_block;
|
||||
char **updated_data = calloc(INITIAL_BLOCK_COUNT, sizeof(char *));
|
||||
if (!updated_data) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
temp_block_data = malloc(BLOCK_SIZE * me->data_size);
|
||||
if (!temp_block_data) {
|
||||
free(temp_block);
|
||||
updated_block = malloc(BLOCK_SIZE * me->data_size);
|
||||
if (!updated_block) {
|
||||
free(updated_data);
|
||||
return -ENOMEM;
|
||||
}
|
||||
for (i = 0; i < me->block_count; i++) {
|
||||
const struct node block_item = me->block[i];
|
||||
free(block_item.data);
|
||||
char *block;
|
||||
memcpy(&block, me->data + i, sizeof(char *));
|
||||
free(block);
|
||||
}
|
||||
free(me->block);
|
||||
me->start_index = BLOCK_SIZE / 2;
|
||||
me->end_index = me->start_index + 1;
|
||||
me->block_count = 1;
|
||||
me->block = temp_block;
|
||||
block = me->block;
|
||||
block->data = temp_block_data;
|
||||
free(me->data);
|
||||
me->start_index = BLOCK_SIZE * INITIAL_BLOCK_COUNT / 2;
|
||||
me->end_index = me->start_index;
|
||||
me->block_count = INITIAL_BLOCK_COUNT;
|
||||
me->data = updated_data;
|
||||
memcpy(me->data + me->start_index / BLOCK_SIZE, &updated_block,
|
||||
sizeof(char *));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -524,12 +517,13 @@ int deque_clear(deque me)
|
||||
*/
|
||||
deque deque_destroy(deque me)
|
||||
{
|
||||
int i;
|
||||
size_t i;
|
||||
for (i = 0; i < me->block_count; i++) {
|
||||
const struct node block_item = me->block[i];
|
||||
free(block_item.data);
|
||||
char *block;
|
||||
memcpy(&block, me->data + i, sizeof(char *));
|
||||
free(block);
|
||||
}
|
||||
free(me->block);
|
||||
free(me->data);
|
||||
free(me);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -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,7 +34,7 @@ typedef struct internal_deque *deque;
|
||||
deque deque_init(size_t data_size);
|
||||
|
||||
/* Utility */
|
||||
int deque_size(deque me);
|
||||
size_t deque_size(deque me);
|
||||
int deque_is_empty(deque me);
|
||||
int deque_trim(deque me);
|
||||
void deque_copy_to_array(void *arr, deque me);
|
||||
@@ -49,12 +49,12 @@ int deque_pop_back(void *data, deque me);
|
||||
|
||||
/* Setting */
|
||||
int deque_set_first(deque me, void *data);
|
||||
int deque_set_at(deque me, int index, void *data);
|
||||
int deque_set_at(deque me, size_t index, void *data);
|
||||
int deque_set_last(deque me, void *data);
|
||||
|
||||
/* Getting */
|
||||
int deque_get_first(void *data, deque me);
|
||||
int deque_get_at(void *data, deque me, int index);
|
||||
int deque_get_at(void *data, deque me, size_t index);
|
||||
int deque_get_last(void *data, deque me);
|
||||
|
||||
/* Ending */
|
||||
|
||||
145
tst/deque.c
145
tst/deque.c
@@ -15,7 +15,7 @@ static void test_copy(deque me)
|
||||
int i;
|
||||
for (i = 0; i < 10; i++) {
|
||||
deque_push_front(me, &val[i]);
|
||||
get = 0;
|
||||
get = 0xfacade;
|
||||
deque_get_first(&get, me);
|
||||
assert(get == val[i]);
|
||||
}
|
||||
@@ -23,12 +23,12 @@ static void test_copy(deque me)
|
||||
assert(!deque_is_empty(me));
|
||||
deque_copy_to_array(get_arr, me);
|
||||
for (i = 0; i < 10; i++) {
|
||||
get = 0;
|
||||
get = 0xfacade;
|
||||
deque_get_at(&get, me, i);
|
||||
assert(get == val[9 - i]);
|
||||
assert(get_arr[i] == val[9 - i]);
|
||||
}
|
||||
get = 5;
|
||||
get = 0xfacade;
|
||||
deque_trim(me);
|
||||
for (i = 0; i < 7; i++) {
|
||||
deque_pop_back(&get, me);
|
||||
@@ -37,6 +37,9 @@ static void test_copy(deque me)
|
||||
deque_copy_to_array(trimmed, me);
|
||||
assert(deque_size(me) == 3);
|
||||
for (i = 0; i < 3; i++) {
|
||||
get = 0xfacade;
|
||||
deque_get_at(&get, me, i);
|
||||
assert(get == 10 - i);
|
||||
assert(10 - i == trimmed[i]);
|
||||
}
|
||||
}
|
||||
@@ -136,25 +139,118 @@ static void test_trim(void)
|
||||
{
|
||||
deque me = deque_init(sizeof(int));
|
||||
int i;
|
||||
assert(deque_is_empty(me));
|
||||
deque_trim(me);
|
||||
assert(deque_is_empty(me));
|
||||
for (i = 0; i < 100; i++) {
|
||||
int get;
|
||||
deque_push_back(me, &i);
|
||||
deque_pop_front(&get, me);
|
||||
}
|
||||
assert(deque_is_empty(me));
|
||||
deque_trim(me);
|
||||
assert(deque_is_empty(me));
|
||||
for (i = 0; i < 100; i++) {
|
||||
deque_push_back(me, &i);
|
||||
}
|
||||
for (i = 0; i < 100; i++) {
|
||||
int get = 0xfacade;
|
||||
deque_get_at(&get, me, i);
|
||||
}
|
||||
assert(deque_size(me) == 100);
|
||||
deque_trim(me);
|
||||
assert(deque_size(me) == 100);
|
||||
deque_destroy(me);
|
||||
}
|
||||
|
||||
static void test_stress(void)
|
||||
{
|
||||
int i;
|
||||
deque me = deque_init(sizeof(int));
|
||||
for (i = -1000; i < 1000; i++) {
|
||||
int val = 7 * i;
|
||||
deque_push_back(me, &val);
|
||||
}
|
||||
assert(deque_size(me) == 2000);
|
||||
for (i = -1000; i < 1000; i++) {
|
||||
int get = 0xfacade;
|
||||
deque_get_at(&get, me, i + 1000);
|
||||
assert(get == 7 * i);
|
||||
}
|
||||
assert(deque_size(me) == 2000);
|
||||
deque_clear(me);
|
||||
assert(deque_size(me) == 0);
|
||||
assert(deque_is_empty(me));
|
||||
for (i = -1000; i < 1000; i++) {
|
||||
int val = 7 * i;
|
||||
deque_push_front(me, &val);
|
||||
}
|
||||
assert(deque_size(me) == 2000);
|
||||
for (i = -1000; i < 1000; i++) {
|
||||
int get = 0xfacade;
|
||||
deque_get_at(&get, me, i + 1000);
|
||||
assert(get == -7 * (i + 1));
|
||||
}
|
||||
assert(deque_size(me) == 2000);
|
||||
deque_destroy(me);
|
||||
}
|
||||
|
||||
static void test_array_copy(void)
|
||||
{
|
||||
size_t i = 0xfacade;
|
||||
size_t arr_sz = 9000;
|
||||
size_t arr[9000] = {0};
|
||||
deque me = deque_init(sizeof *arr);
|
||||
assert(sizeof arr / sizeof *arr == arr_sz);
|
||||
deque_copy_to_array(&i, me);
|
||||
assert(i == 0xfacade);
|
||||
for (i = 0; i < arr_sz; i++) {
|
||||
deque_push_back(me, &i);
|
||||
}
|
||||
for (i = 0; i < arr_sz; i++) {
|
||||
size_t get = 0xfacade;
|
||||
deque_get_at(&get, me, i);
|
||||
assert(get == i);
|
||||
}
|
||||
deque_copy_to_array(&arr, me);
|
||||
for (i = 0; i < arr_sz; i++) {
|
||||
assert(arr[i] == i);
|
||||
}
|
||||
deque_clear(me);
|
||||
i = 0xfacade;
|
||||
deque_copy_to_array(&i, me);
|
||||
assert(i == 0xfacade);
|
||||
for (i = 0; i < arr_sz; i++) {
|
||||
deque_push_front(me, &i);
|
||||
}
|
||||
deque_copy_to_array(&arr, me);
|
||||
for (i = 0; i < arr_sz; i++) {
|
||||
assert(arr[i] == arr_sz - i - 1);
|
||||
}
|
||||
for (i = 0; i < arr_sz / 2; i++) {
|
||||
size_t get = 0xfacade;
|
||||
deque_pop_front(&get, me);
|
||||
assert(get == arr_sz - i - 1);
|
||||
}
|
||||
for (i = 0; i < arr_sz / 2; i++) {
|
||||
size_t get = 0xfacade;
|
||||
deque_push_front(me, &i);
|
||||
deque_get_first(&get, me);
|
||||
assert(get == i);
|
||||
}
|
||||
deque_destroy(me);
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
@@ -184,24 +280,14 @@ static void test_push_front_out_of_memory(void)
|
||||
{
|
||||
deque me = deque_init(sizeof(int));
|
||||
int i;
|
||||
for (i = 0; i < 5; i++) {
|
||||
assert(deque_push_front(me, &i) == 0);
|
||||
for (i = 0; i < 4096; i++) {
|
||||
deque_push_front(me, &i);
|
||||
}
|
||||
assert(deque_size(me) == 5);
|
||||
fail_realloc = 1;
|
||||
assert(deque_push_front(me, &i) == -ENOMEM);
|
||||
assert(deque_size(me) == 5);
|
||||
for (i = 0; i < 5; i++) {
|
||||
int get = 0xfacade;
|
||||
deque_get_at(&get, me, i);
|
||||
}
|
||||
delay_fail_realloc = 1;
|
||||
fail_malloc = 1;
|
||||
assert(deque_push_front(me, &i) == -ENOMEM);
|
||||
assert(deque_size(me) == 5);
|
||||
for (i = 0; i < 5; i++) {
|
||||
int get = 0xfacade;
|
||||
deque_get_at(&get, me, i);
|
||||
}
|
||||
assert(!deque_destroy(me));
|
||||
}
|
||||
#endif
|
||||
@@ -211,24 +297,14 @@ static void test_push_back_out_of_memory(void)
|
||||
{
|
||||
deque me = deque_init(sizeof(int));
|
||||
int i;
|
||||
for (i = 0; i < 3; i++) {
|
||||
assert(deque_push_back(me, &i) == 0);
|
||||
for (i = 0; i < 4096; i++) {
|
||||
deque_push_back(me, &i);
|
||||
}
|
||||
assert(deque_size(me) == 3);
|
||||
fail_realloc = 1;
|
||||
assert(deque_push_back(me, &i) == -ENOMEM);
|
||||
assert(deque_size(me) == 3);
|
||||
for (i = 0; i < 3; i++) {
|
||||
int get = 0xfacade;
|
||||
deque_get_at(&get, me, i);
|
||||
}
|
||||
delay_fail_realloc = 1;
|
||||
fail_malloc = 1;
|
||||
assert(deque_push_back(me, &i) == -ENOMEM);
|
||||
assert(deque_size(me) == 3);
|
||||
for (i = 0; i < 3; i++) {
|
||||
int get = 0xfacade;
|
||||
deque_get_at(&get, me, i);
|
||||
}
|
||||
assert(!deque_destroy(me));
|
||||
}
|
||||
#endif
|
||||
@@ -242,7 +318,7 @@ static void test_clear_out_of_memory(void)
|
||||
deque_push_back(me, &i);
|
||||
}
|
||||
assert(deque_size(me) == 32);
|
||||
fail_malloc = 1;
|
||||
fail_calloc = 1;
|
||||
assert(deque_clear(me) == -ENOMEM);
|
||||
for (i = 0; i < 32; i++) {
|
||||
int get = 0xfacade;
|
||||
@@ -251,7 +327,6 @@ 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;
|
||||
@@ -328,6 +403,8 @@ void test_deque(void)
|
||||
test_invalid_init();
|
||||
test_basic();
|
||||
test_trim();
|
||||
test_stress();
|
||||
test_array_copy();
|
||||
#if STUB_MALLOC
|
||||
test_init_out_of_memory();
|
||||
test_trim_out_of_memory();
|
||||
|
||||
@@ -104,14 +104,8 @@ static void test_init_out_of_memory(void)
|
||||
{
|
||||
fail_malloc = 1;
|
||||
assert(!queue_init(sizeof(int)));
|
||||
fail_malloc = 1;
|
||||
delay_fail_malloc = 1;
|
||||
assert(!queue_init(sizeof(int)));
|
||||
fail_malloc = 1;
|
||||
delay_fail_malloc = 2;
|
||||
assert(!queue_init(sizeof(int)));
|
||||
fail_malloc = 1;
|
||||
delay_fail_malloc = 3;
|
||||
assert(!queue_init(sizeof(int)));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -72,14 +72,8 @@ static void test_init_out_of_memory(void)
|
||||
{
|
||||
fail_malloc = 1;
|
||||
assert(!stack_init(sizeof(int)));
|
||||
fail_malloc = 1;
|
||||
delay_fail_malloc = 1;
|
||||
assert(!stack_init(sizeof(int)));
|
||||
fail_malloc = 1;
|
||||
delay_fail_malloc = 2;
|
||||
assert(!stack_init(sizeof(int)));
|
||||
fail_malloc = 1;
|
||||
delay_fail_malloc = 3;
|
||||
assert(!stack_init(sizeof(int)));
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user