mirror of
https://github.com/bkthomps/Containers.git
synced 2025-11-16 12:34:47 +00:00
Add vector
This commit is contained in:
347
src/vector.c
Normal file
347
src/vector.c
Normal 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
59
src/vector.h
Normal 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
122
tst/test.c
Normal 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();
|
||||
}
|
||||
Reference in New Issue
Block a user