Add vector

This commit is contained in:
Bailey Thompson
2017-10-14 22:45:53 -04:00
committed by GitHub
parent cf50c39887
commit f6ea19b357
3 changed files with 528 additions and 0 deletions

347
src/vector.c Normal file
View File

@@ -0,0 +1,347 @@
/*
* 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 <memory.h>
#include <errno.h>
#include "vector.h"
const int START_SPACE = 8;
struct _vector {
size_t data_size;
int offset;
int space;
void *storage;
};
/**
* Initialize a vector.
*
* @param data_size The size of each element in the vector.
*
* @return The newly-initialized vector, or NULL if memory allocation error.
*/
vector vector_init(const size_t data_size) {
struct _vector *const init = malloc(sizeof(struct _vector));
if (init == NULL) {
return NULL;
}
init->data_size = data_size;
init->offset = 0;
init->space = START_SPACE;
init->storage = malloc(init->space * init->data_size);
if (init->storage == NULL) {
free(init);
return NULL;
}
return init;
}
/**
* Get the size being used by the vector.
*
* @param me The vector to check.
*
* @return The size being used by the vector.
*/
int vector_size(vector me) {
return me->offset;
}
/**
* Whether or not the vector is empty.
*
* @param me The vector to check.
*
* @return True if the vector is empty, else false.
*/
bool vector_is_empty(vector me) {
return vector_size(me) == 0;
}
/**
* Checks if the vector is big enough for the capacity specified.
*
* @param me The vector to check.
* @param capacity The capacity to check the vector for.
*
* @return True if big enough, else false.
*/
bool vector_ensure_capacity(vector me, const int capacity) {
return capacity <= me->space;
}
/**
* Sets the size to use for the vector buffer. The size is in units and not in
* bytes. Each unit is of size specified from init. If the size to set is
* smaller than the current size, the data is lost.
*
* @param me The vector to set size.
* @param size The size to set the vector to.
*
* @return 0 No error.
* -ENOMEM Out of memory.
*/
int vector_set_space(vector me, const int size) {
me->space = size;
if (me->space < me->offset) {
me->offset = me->space;
}
void *const temp = realloc(me->storage, me->space * me->data_size);
if (temp == NULL) {
return -ENOMEM;
}
me->storage = temp;
return 0;
}
/**
* Sets the size of the vector buffer to the current size being used.
*
* @param me The vector to trim.
*
* @return 0 No error.
* -ENOMEM Out of memory.
*/
int vector_trim_to_size(vector me) {
return vector_set_space(me, me->offset);
}
/**
* Copies the storage element of vector to an array.
*
* @param me The vector to copy from.
* @param array The array to copy to.
*/
void vector_to_array(void *array, vector me) {
memcpy(array, me->storage, me->offset * me->data_size);
}
/**
* Adds an element to the start of the vector.
*
* @param me The vector to add to.
* @param data The data to add to the vector.
*
* @return 0 No error.
* -ENOMEM Out of memory.
*/
int vector_add_first(vector me, void *const data) {
return vector_add_at(me, 0, data);
}
/**
* Adds an element to the location specified.
*
* @param me The vector to add to.
* @param index The location in the vector to add the data to.
* @param data The data to add to the vector.
*
* @return 0 No error.
* -ENOMEM Out of memory.
* -EINVAL Invalid parameter.
*/
int vector_add_at(vector me, const int index, void *const data) {
if (index < 0 || index > me->offset) {
return -EINVAL;
}
const int full_space = me->space;
if (me->offset + 1 >= me->space) {
me->space *= 1.5;
void *const temp = realloc(me->storage, me->space * me->data_size);
if (temp == NULL) {
return -ENOMEM;
}
me->storage = temp;
}
if (index != me->offset) {
memmove(me->storage + (index + 1) * me->data_size,
me->storage + index * me->data_size,
(full_space - index) * me->data_size);
}
memcpy(me->storage + index * me->data_size, data, me->data_size);
me->offset++;
return 0;
}
/**
* Adds an element to the end of the vector.
*
* @param me The vector to add to.
* @param data The data to add to the vector.
*
* @return 0 No error.
* -ENOMEM Out of memory.
*/
int vector_add_last(vector me, void *const data) {
return vector_add_at(me, me->offset, data);
}
/**
* Removes the first element from the vector.
*
* @param me The vector to remove from.
*
* @return 0 No error.
* -EINVAL Invalid parameter.
*/
int vector_remove_first(vector me) {
return vector_remove_at(me, 0);
}
/**
* Removes element based on its index.
*
* @param me The vector to remove from.
* @param index The location in the vector to remove the data from.
*
* @return 0 No error.
* -EINVAL Invalid parameter.
*/
int vector_remove_at(vector me, const int index) {
if (index < 0 || index >= me->offset || me->offset == 0) {
return -EINVAL;
}
memmove(me->storage + index * me->data_size,
me->storage + (index + 1) * me->data_size,
(me->space - index) * me->data_size);
me->offset--;
return 0;
}
/**
* Removes the last element from the vector.
*
* @param me The vector to remove from.
*
* @return 0 No error.
* -EINVAL Invalid parameter.
*/
int vector_remove_last(vector me) {
if (me->offset == 0) {
return -EINVAL;
}
me->offset--;
return 0;
}
/**
* Sets the data for the first element in the vector.
*
* @param me The vector to set data for.
*/
void vector_set_first(vector me, void *const data) {
vector_set_at(me, 0, data);
}
/**
*
* @param me The vector to set data for.
* @param index The location to set data at in the vector.
* @param data The data to set at the location in the vector.
*
* @return 0 No error.
* -EINVAL Invalid parameter.
*/
int vector_set_at(vector me, const int index, void *const data) {
if (index < 0 || index >= me->offset) {
return -EINVAL;
}
memcpy(me->storage + index * me->data_size, data, me->data_size);
return 0;
}
/**
* Sets the data for the last element in the vector.
*
* @param me The vector to set data for.
*/
void vector_set_last(vector me, void *const data) {
vector_set_at(me, me->offset - 1, data);
}
/**
* Copies the first element of the vector to data.
*
* @param data The data to copy to.
* @param me The vector to copy from.
*/
void vector_get_first(void *const data, vector me) {
vector_get_at(data, me, 0);
}
/**
* Copies the element at index of the vector to data.
*
* @param data The data to copy to.
* @param me The vector to copy from.
* @param index The index to copy from in the vector.
*
* @return 0 No error.
* -EINVAL Invalid parameter.
*/
int vector_get_at(void *const data, vector me, const int index) {
if (index < 0 || index >= me->offset) {
return -EINVAL;
}
memcpy(data, me->storage + index * me->data_size, me->data_size);
return 0;
}
/**
* Copies the last element of the vector to data.
*
* @param data The data to copy to.
* @param me The vector to copy from.
*/
void vector_get_last(void *const data, vector me) {
vector_get_at(data, me, me->offset - 1);
}
/**
* Clears the elements from the vector.
*
* @param me The vector to clear.
*
* @return 0 No error.
* -ENOMEM Out of memory.
*/
int vector_clear(vector me) {
const int ret = vector_set_space(me, START_SPACE);
me->offset = 0;
return ret;
}
/**
* Frees the vector memory.
*
* @param me The vector to free from memory.
*
* @return NULL
*/
vector vector_destroy(vector me) {
free(me->storage);
me->storage = NULL;
free(me);
return NULL;
}

59
src/vector.h Normal file
View File

@@ -0,0 +1,59 @@
/*
* 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_VECTOR_H
#define CONTAINERS_VECTOR_H
#include <stdbool.h>
typedef struct _vector *vector;
// Starting
vector vector_init(size_t data_size);
// Utility
int vector_size(vector me);
bool vector_is_empty(vector me);
bool vector_ensure_capacity(vector me, int capacity);
int vector_set_space(vector me, int size);
int vector_trim_to_size(vector me);
void vector_to_array(void *array, vector me);
// Adding
int vector_add_first(vector me, void *data);
int vector_add_at(vector me, int index, void *data);
int vector_add_last(vector me, void *data);
// Removing
int vector_remove_first(vector me);
int vector_remove_at(vector me, int index);
int vector_remove_last(vector me);
// Setting
void vector_set_first(vector me, void *data);
int vector_set_at(vector me, int index, void *data);
void vector_set_last(vector me, void *data);
// Getting
void vector_get_first(void *data, vector me);
int vector_get_at(void *data, vector me, int index);
void vector_get_last(void *data, vector me);
// Ending
int vector_clear(vector me);
vector vector_destroy(vector me);
#endif /* CONTAINERS_VECTOR_H */

122
tst/test.c Normal file
View File

@@ -0,0 +1,122 @@
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include "../src/vector.h"
static void test_vector(void) {
int val[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
vector me = vector_init(sizeof(int));
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;
vector_get_first(&get, me);
assert(get == val[i]);
}
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++) {
int get = 0;
vector_get_at(&get, me, i);
assert(get == val[9 - i]);
assert(get_arr[i] == val[9 - i]);
}
int trimmed[5] = {0};
vector_trim_to_size(me);
vector_set_space(me, 3);
vector_to_array(trimmed, me);
assert(vector_size(me) == 3);
for (int i = 0; i < 3; i++) {
assert(10 - i == trimmed[i]);
}
int add = 3;
vector_add_last(me, &add);
add = -1;
vector_add_at(me, 1, &add);
add = -2;
vector_add_last(me, &add);
assert(vector_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;
vector_get_first(&aa, me);
assert(aa == 10);
vector_get_at(&a, me, 0);
assert(a == 10);
vector_get_at(&b, me, 1);
assert(b == -1);
vector_get_at(&c, me, 2);
assert(c == 9);
vector_get_at(&d, me, 3);
assert(d == 8);
vector_get_at(&e, me, 4);
assert(e == 3);
vector_get_at(&f, me, 5);
assert(f == -2);
vector_get_last(&ff, me);
assert(ff == -2);
vector_remove_first(me);
vector_remove_at(me, 2);
vector_remove_last(me);
assert(vector_size(me) == 3);
int get = 345;
vector_get_first(&get, me);
assert(get == -1);
vector_get_at(&get, me, 1);
assert(get == 9);
vector_get_last(&get, me);
assert(get == 3);
int set = 12;
vector_set_first(me, &set);
set = 13;
vector_set_at(me, 1, &set);
set = 14;
vector_set_last(me, &set);
int arr[3] = {0};
vector_to_array(arr, me);
assert(arr[0] == 12);
assert(arr[1] == 13);
assert(arr[2] == 14);
set = -5;
vector_set_at(me, 0, &set);
set = -6;
vector_set_at(me, 1, &set);
set = -7;
vector_set_at(me, 2, &set);
vector_to_array(arr, me);
assert(arr[0] == -5);
assert(arr[1] == -6);
assert(arr[2] == -7);
assert(vector_set_at(me, 4, &set) == -EINVAL);
assert(vector_get_at(&set, me, 4) == -EINVAL);
assert(vector_remove_at(me, 4) == -EINVAL);
assert(vector_add_at(me, 5, &set) == -EINVAL);
assert(vector_set_at(me, -1, &set) == -EINVAL);
assert(vector_get_at(&set, me, -1) == -EINVAL);
assert(vector_remove_at(me, -1) == -EINVAL);
assert(vector_add_at(me, -1, &set) == -EINVAL);
vector_clear(me);
assert(vector_size(me) == 0);
assert(vector_is_empty(me));
assert(vector_remove_first(me) == -EINVAL);
assert(vector_remove_last(me) == -EINVAL);
me = vector_destroy(me);
assert(me == NULL);
}
int main() {
test_vector();
}