mirror of
https://github.com/bkthomps/Containers.git
synced 2025-11-16 12:34:47 +00:00
Add deque development version
This is a development version which contains the core of the deque, without the documentation, and still containing debug code.
This commit is contained in:
255
src/deque.c
Normal file
255
src/deque.c
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (c) 2017 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
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
#include "deque.h"
|
||||
|
||||
const int BLOCK_SIZE = 8;
|
||||
|
||||
struct _deque {
|
||||
size_t data_size;
|
||||
int start_index;
|
||||
int end_index;
|
||||
int block_count;
|
||||
struct node *block;
|
||||
};
|
||||
|
||||
struct node {
|
||||
void *data;
|
||||
};
|
||||
|
||||
static void deque_DEBUG(deque me) {
|
||||
for (int i = 0; i < me->block_count; i++) {
|
||||
if (me->block[i].data == NULL) {
|
||||
printf("NULL\n");
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < BLOCK_SIZE; j++) {
|
||||
int *a = me->block[i].data + j * me->data_size;
|
||||
printf("%d, ", *a);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
deque deque_init(const size_t data_size) {
|
||||
struct _deque *const init = malloc(sizeof(struct _deque));
|
||||
if (init == NULL) {
|
||||
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 == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
init->block->data = malloc(BLOCK_SIZE * data_size);
|
||||
if (init->block->data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return init;
|
||||
}
|
||||
|
||||
int deque_size(deque me) {
|
||||
return me->end_index - me->start_index - 1;
|
||||
}
|
||||
|
||||
bool deque_is_empty(deque me) {
|
||||
return deque_size(me) == 0;
|
||||
}
|
||||
|
||||
int deque_trim(deque me) {
|
||||
deque_DEBUG(me);
|
||||
return -ENOSYS; // TODO
|
||||
}
|
||||
|
||||
void deque_to_array(void *const array, deque me) {
|
||||
void *const temp = malloc(me->data_size);
|
||||
if (temp == NULL) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < deque_size(me); i++) {
|
||||
deque_get_at(temp, me, i);
|
||||
memcpy(array + i * me->data_size, temp, me->data_size);
|
||||
}
|
||||
free(temp);
|
||||
}
|
||||
|
||||
int deque_push_front(deque me, void *const data) {
|
||||
int block_index = me->start_index / BLOCK_SIZE;
|
||||
int inner_index = me->start_index % BLOCK_SIZE;
|
||||
if (inner_index == -1) {
|
||||
block_index = -1;
|
||||
inner_index = BLOCK_SIZE - 1;
|
||||
}
|
||||
if (inner_index == BLOCK_SIZE - 1) {
|
||||
if (block_index == -1) {
|
||||
const int old_block_count = me->block_count;
|
||||
me->block_count = (int) ceil(1.5 * me->block_count);
|
||||
const int added_blocks = me->block_count - old_block_count;
|
||||
void *temp = realloc(me->block,
|
||||
me->block_count * sizeof(struct node));
|
||||
if (temp == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
me->block = temp;
|
||||
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 (int i = 0; i < added_blocks; i++) {
|
||||
me->block[i].data = NULL;
|
||||
}
|
||||
}
|
||||
if (me->block[block_index].data == NULL) {
|
||||
me->block[block_index].data = malloc(BLOCK_SIZE * me->data_size);
|
||||
if (me->block[block_index].data == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
memcpy(me->block[block_index].data + inner_index * me->data_size,
|
||||
data,
|
||||
me->data_size);
|
||||
me->start_index--;
|
||||
deque_DEBUG(me);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int deque_push_back(deque me, void *const data) {
|
||||
const int block_index = me->end_index / BLOCK_SIZE;
|
||||
const int inner_index = me->end_index % BLOCK_SIZE;
|
||||
if (inner_index == 0) {
|
||||
if (block_index == me->block_count) {
|
||||
me->block_count = (int) ceil(1.5 * me->block_count);
|
||||
void *temp = realloc(me->block,
|
||||
me->block_count * sizeof(struct node));
|
||||
if (temp == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
me->block = temp;
|
||||
for (int i = block_index; i < me->block_count; i++) {
|
||||
me->block[i].data = NULL;
|
||||
}
|
||||
}
|
||||
if (me->block[block_index].data == NULL) {
|
||||
me->block[block_index].data = malloc(BLOCK_SIZE * me->data_size);
|
||||
if (me->block[block_index].data == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
memcpy(me->block[block_index].data + inner_index * me->data_size,
|
||||
data,
|
||||
me->data_size);
|
||||
me->end_index++;
|
||||
deque_DEBUG(me);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int deque_pop_front(void *const data, deque me) {
|
||||
if (deque_is_empty(me)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
const int block_index = me->start_index / BLOCK_SIZE;
|
||||
const int inner_index = me->start_index % BLOCK_SIZE;
|
||||
memcpy(data,
|
||||
me->block[block_index].data + inner_index * me->data_size,
|
||||
me->data_size);
|
||||
me->start_index++;
|
||||
deque_DEBUG(me);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int deque_pop_back(void *const data, deque me) {
|
||||
if (deque_is_empty(me)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
const int block_index = me->end_index / BLOCK_SIZE;
|
||||
const int inner_index = me->end_index % BLOCK_SIZE;
|
||||
memcpy(data,
|
||||
me->block[block_index].data + inner_index * me->data_size,
|
||||
me->data_size);
|
||||
me->end_index--;
|
||||
deque_DEBUG(me);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int deque_set_first(deque me, void *const data) {
|
||||
return deque_set_at(me, 0, data);
|
||||
}
|
||||
|
||||
int deque_set_at(deque me, int index, void *const data) {
|
||||
if (index < 0 || index >= deque_size(me)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
index += me->start_index + 1;
|
||||
const int block_index = index / BLOCK_SIZE;
|
||||
const int inner_index = index % BLOCK_SIZE;
|
||||
memcpy(me->block[block_index].data + inner_index * me->data_size,
|
||||
data,
|
||||
me->data_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int deque_set_last(deque me, void *const data) {
|
||||
return deque_set_at(me, deque_size(me) - 1, data);
|
||||
}
|
||||
|
||||
int deque_get_first(void *const data, deque me) {
|
||||
return deque_get_at(data, me, 0);
|
||||
}
|
||||
|
||||
int deque_get_at(void *const data, deque me, int index) {
|
||||
if (index < 0 || index >= deque_size(me)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
index += me->start_index + 1;
|
||||
const int block_index = index / BLOCK_SIZE;
|
||||
const int inner_index = index % BLOCK_SIZE;
|
||||
memcpy(data,
|
||||
me->block[block_index].data + inner_index * me->data_size,
|
||||
me->data_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int deque_get_last(void *const data, deque me) {
|
||||
return deque_get_at(data, me, deque_size(me) - 1);
|
||||
}
|
||||
|
||||
int deque_clear(deque me) {
|
||||
deque_DEBUG(me);
|
||||
return -ENOSYS; // TODO
|
||||
}
|
||||
|
||||
deque deque_destroy(deque me) {
|
||||
return NULL; // TODO
|
||||
}
|
||||
55
src/deque.h
Normal file
55
src/deque.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2017 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
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef CONTAINERS_DEQUE_H
|
||||
#define CONTAINERS_DEQUE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct _deque *deque;
|
||||
|
||||
// Starting
|
||||
deque deque_init(size_t data_size);
|
||||
// Utility
|
||||
int deque_size(deque me);
|
||||
bool deque_is_empty(deque me);
|
||||
int deque_trim(deque me);
|
||||
void deque_to_array(void *array, deque me);
|
||||
// Adding
|
||||
int deque_push_front(deque me, void *data);
|
||||
int deque_push_back(deque me, void *data);
|
||||
// Removing
|
||||
int deque_pop_front(void *data, deque me);
|
||||
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_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_last(void *data, deque me);
|
||||
// Ending
|
||||
int deque_clear(deque me);
|
||||
deque deque_destroy(deque me);
|
||||
|
||||
#endif /* CONTAINERS_DEQUE_H */
|
||||
122
tst/test.c
122
tst/test.c
@@ -1,9 +1,11 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include "../src/vector.h"
|
||||
#include "../src/list.h"
|
||||
#include "../src/forward_list.h"
|
||||
#include "../src/deque.h"
|
||||
|
||||
static void test_vector(void) {
|
||||
int val[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
@@ -11,8 +13,6 @@ static void test_vector(void) {
|
||||
assert(me != NULL);
|
||||
assert(vector_size(me) == 0);
|
||||
assert(vector_is_empty(me));
|
||||
assert(vector_ensure_capacity(me, 8));
|
||||
assert(!vector_ensure_capacity(me, 9));
|
||||
for (int i = 0; i < 10; i++) {
|
||||
vector_add_first(me, &val[i]);
|
||||
int get = 0;
|
||||
@@ -21,8 +21,6 @@ static void test_vector(void) {
|
||||
}
|
||||
assert(vector_size(me) == 10);
|
||||
assert(!vector_is_empty(me));
|
||||
assert(vector_ensure_capacity(me, 12));
|
||||
assert(!vector_ensure_capacity(me, 13));
|
||||
int get_arr[10] = {0};
|
||||
vector_to_array(get_arr, me);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
@@ -32,8 +30,11 @@ static void test_vector(void) {
|
||||
assert(get_arr[i] == val[9 - i]);
|
||||
}
|
||||
int trimmed[5] = {0};
|
||||
vector_trim_to_size(me);
|
||||
vector_set_space(me, 3);
|
||||
vector_trim(me);
|
||||
vector_reserve(me, 3);
|
||||
for (int i = 0; i < 7; i++) {
|
||||
vector_remove_last(me);
|
||||
}
|
||||
vector_to_array(trimmed, me);
|
||||
assert(vector_size(me) == 3);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
@@ -343,9 +344,118 @@ static void test_forward_list(void) {
|
||||
assert(me == NULL);
|
||||
}
|
||||
|
||||
static void test_deque(void) {
|
||||
int val[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
deque me = deque_init(sizeof(int));
|
||||
assert(me != NULL);
|
||||
assert(deque_size(me) == 0);
|
||||
assert(deque_is_empty(me));
|
||||
for (int i = 0; i < 10; i++) {
|
||||
deque_push_front(me, &val[i]);
|
||||
int get = 0;
|
||||
deque_get_first(&get, me);
|
||||
assert(get == val[i]);
|
||||
}
|
||||
printf("ok\n");
|
||||
assert(deque_size(me) == 10);
|
||||
assert(!deque_is_empty(me));
|
||||
int get_arr[10] = {0};
|
||||
deque_to_array(get_arr, me);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
int get = 0;
|
||||
deque_get_at(&get, me, i);
|
||||
assert(get == val[9 - i]);
|
||||
assert(get_arr[i] == val[9 - i]);
|
||||
}
|
||||
int trimmed[5] = {0};
|
||||
int stuff = 5;
|
||||
deque_trim(me);
|
||||
for (int i = 0; i < 7; i++) {
|
||||
deque_pop_back(&stuff, me);
|
||||
}
|
||||
deque_to_array(trimmed, me);
|
||||
assert(deque_size(me) == 3);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
assert(10 - i == trimmed[i]);
|
||||
}
|
||||
int add = 3;
|
||||
deque_push_back(me, &add);
|
||||
add = -2;
|
||||
deque_push_back(me, &add);
|
||||
add = -1;
|
||||
deque_push_back(me, &add);
|
||||
assert(deque_size(me) == 6);
|
||||
int aa = 456;
|
||||
int a = 456;
|
||||
int b = 456;
|
||||
int c = 456;
|
||||
int d = 456;
|
||||
int e = 456;
|
||||
int f = 456;
|
||||
int ff = 456;
|
||||
deque_get_first(&aa, me);
|
||||
assert(aa == 10);
|
||||
deque_get_at(&a, me, 0);
|
||||
assert(a == 10);
|
||||
deque_get_at(&b, me, 1);
|
||||
assert(b == 9);
|
||||
deque_get_at(&c, me, 2);
|
||||
assert(c == 8);
|
||||
deque_get_at(&d, me, 3);
|
||||
assert(d == 3);
|
||||
deque_get_at(&e, me, 4);
|
||||
assert(e == -2);
|
||||
deque_get_at(&f, me, 5);
|
||||
assert(f == -1);
|
||||
deque_get_last(&ff, me);
|
||||
assert(ff == -1);
|
||||
deque_pop_front(&stuff, me);
|
||||
deque_pop_back(&stuff, me);
|
||||
deque_pop_back(&stuff, me);
|
||||
assert(deque_size(me) == 3);
|
||||
int get = 345;
|
||||
deque_get_first(&get, me);
|
||||
assert(get == 9);
|
||||
deque_get_at(&get, me, 1);
|
||||
assert(get == 8);
|
||||
deque_get_last(&get, me);
|
||||
assert(get == 3);
|
||||
int set = 12;
|
||||
deque_set_first(me, &set);
|
||||
set = 13;
|
||||
deque_set_at(me, 1, &set);
|
||||
set = 14;
|
||||
deque_set_last(me, &set);
|
||||
int arr[3] = {0};
|
||||
deque_to_array(arr, me);
|
||||
assert(arr[0] == 12);
|
||||
assert(arr[1] == 13);
|
||||
assert(arr[2] == 14);
|
||||
set = -5;
|
||||
deque_set_at(me, 0, &set);
|
||||
set = -6;
|
||||
deque_set_at(me, 1, &set);
|
||||
set = -7;
|
||||
deque_set_at(me, 2, &set);
|
||||
deque_to_array(arr, me);
|
||||
assert(arr[0] == -5);
|
||||
assert(arr[1] == -6);
|
||||
assert(arr[2] == -7);
|
||||
assert(deque_set_at(me, 4, &set) == -EINVAL);
|
||||
assert(deque_get_at(&set, me, 4) == -EINVAL);
|
||||
assert(deque_set_at(me, -1, &set) == -EINVAL);
|
||||
assert(deque_get_at(&set, me, -1) == -EINVAL);
|
||||
deque_clear(me);
|
||||
assert(deque_size(me) == 0);
|
||||
assert(deque_is_empty(me));
|
||||
me = deque_destroy(me);
|
||||
assert(me == NULL);
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_vector();
|
||||
test_list();
|
||||
test_forward_list();
|
||||
test_deque();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user