Created
May 6, 2020 16:57
-
-
Save Xunnamius/2fad5f85ae5012681347dae5659e1167 to your computer and use it in GitHub Desktop.
C void* vectors
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// vector.h | |
#ifndef VECTOR_H_ | |
#define VECTOR_H_ | |
#include <stdint.h> | |
#include "cexception_configured.h" | |
#define VECTOR_GROWTH_FACTOR 2 | |
/** | |
* Dynamically allocated "growth on demand" array. | |
* | |
* @data The data elements stored in the vector | |
* @size The bytesize of the vector (as void * pouint32_ters) | |
* @count Number of elements in the vector | |
*/ | |
typedef struct vector_t | |
{ | |
const void ** data; | |
uint32_t size; | |
uint32_t count; | |
} vector_t; | |
/** | |
* Create a new vector yielded to the vector pointer parameter. | |
* | |
* XXX: It is advisable that you do NOT mix different types in the same vector! | |
* | |
* This function is O(1). | |
* | |
* @param vector | |
*/ | |
vector_t * vector_init(); | |
/** | |
* Destroy a vector (free all components). Note that the elements of the vector | |
* will not themselves be freed. This must be done manually. | |
* | |
* This function is O(1). | |
* | |
* @param vector | |
*/ | |
void vector_fini(vector_t * vector); | |
/** | |
* Add element to the end of vector. | |
* | |
* This function is O(1). | |
* | |
* @param vector | |
* @param element | |
*/ | |
void vector_add(vector_t * vector, const void * element); | |
/** | |
* Delete the element in vector at index. | |
* | |
* Note that while the element at the specified index will be removed, the | |
* element itself will not be free()'d. You'll have to do that manually. | |
* | |
* This function is O(n). | |
* | |
* @param vector | |
* @param index | |
*/ | |
void vector_delete(vector_t * vector, uint32_t index); | |
/** | |
* Get the element in vector at index. | |
* | |
* This function is O(1). | |
* | |
* @param vector | |
* @param index | |
* | |
* @return Void pointer to the requested element | |
*/ | |
const void * vector_get(vector_t * vector, uint32_t index); | |
/** | |
* Set an index in vector to element. | |
* | |
* This function is O(1). | |
* | |
* @param vector | |
* @param index | |
* @param element | |
*/ | |
void vector_set(vector_t * vector, uint32_t index, const void * element); | |
#endif | |
// vector.c | |
/* | |
* Dynamically allocated "boundless" array-type so-called vector implementation. | |
* | |
* @author Bernard Dickens | |
*/ | |
#include <stdlib.h> | |
#include <string.h> | |
#include "vector.h" | |
vector_t * vector_init() | |
{ | |
vector_t * vector = malloc(sizeof(vector_t)); | |
if(vector == NULL) | |
Throw(EXCEPTION_ALLOC_FAILURE); | |
vector->data = NULL; | |
vector->size = 0; | |
vector->count = 0; | |
return vector; | |
} | |
void vector_fini(vector_t * vector) | |
{ | |
free(vector->data); | |
free(vector); | |
} | |
void vector_add(vector_t * vector, const void * element) | |
{ | |
if(vector->size == 0) | |
{ | |
vector->size = 10; | |
vector->data = calloc(vector->size, sizeof(void *)); | |
if(vector->data == NULL) | |
Throw(EXCEPTION_ALLOC_FAILURE); | |
} | |
if(vector->size == vector->count) | |
{ | |
vector->size *= VECTOR_GROWTH_FACTOR; | |
vector->data = realloc(vector->data, sizeof(void *) * vector->size); | |
if(vector->data == NULL) | |
Throw(EXCEPTION_ALLOC_FAILURE); | |
} | |
vector->data[vector->count] = element; | |
vector->count++; | |
} | |
void vector_delete(vector_t * vector, uint32_t index) | |
{ | |
if(index >= vector->count) | |
Throw(EXCEPTION_OUT_OF_BOUNDS); | |
for(uint32_t i = index, j = i + 1; j < vector->count; j++, i++) | |
vector->data[i] = vector->data[j]; | |
vector->count--; | |
} | |
const void * vector_get(vector_t * vector, uint32_t index) | |
{ | |
if(index >= vector->count) | |
Throw(EXCEPTION_OUT_OF_BOUNDS); | |
return vector->data[index]; | |
} | |
void vector_set(vector_t * vector, uint32_t index, const void * element) | |
{ | |
if(index >= vector->count) | |
Throw(EXCEPTION_OUT_OF_BOUNDS); | |
vector->data[index] = element; | |
} | |
// test_vector.c | |
/* | |
* @author Bernard Dickens | |
*/ | |
#include <string.h> | |
#include "unity.h" | |
#include "vector.h" | |
#define TRY_FN_CATCH_EXCEPTION(fn_call) \ | |
e_actual = EXCEPTION_NO_EXCEPTION; \ | |
Try \ | |
{ \ | |
fn_call; \ | |
TEST_FAIL(); \ | |
} \ | |
Catch(e_actual) \ | |
TEST_ASSERT_EQUAL_INT(e_expected, e_actual); | |
static vector_t * vector; | |
void setUp(void) | |
{ | |
vector = vector_init(); | |
} | |
void tearDown(void) | |
{ | |
vector_fini(vector); | |
} | |
void test_vector_functions_throw_exceptions_as_expected(void) | |
{ | |
CEXCEPTION_T e_expected = EXCEPTION_OUT_OF_BOUNDS; | |
CEXCEPTION_T e_actual = EXCEPTION_NO_EXCEPTION; | |
TRY_FN_CATCH_EXCEPTION(vector_delete(vector, 0)); | |
TRY_FN_CATCH_EXCEPTION(vector_get(vector, 0)); | |
TRY_FN_CATCH_EXCEPTION(vector_set(vector, 0, 0)); | |
TRY_FN_CATCH_EXCEPTION(vector_delete(vector, 1)); | |
TRY_FN_CATCH_EXCEPTION(vector_get(vector, 1)); | |
TRY_FN_CATCH_EXCEPTION(vector_set(vector, 1, (int *) 1)); | |
TEST_ASSERT_EQUAL_INT(0, vector->count); | |
} | |
void test_vector_add_and_get_perform_as_expected(void) | |
{ | |
CEXCEPTION_T e_expected = EXCEPTION_OUT_OF_BOUNDS; | |
CEXCEPTION_T e_actual = EXCEPTION_NO_EXCEPTION; | |
int i_expected = 5; | |
int j_expected = 15; | |
vector_add(vector, &i_expected); | |
TEST_ASSERT_EQUAL_INT(i_expected, *(int *) vector_get(vector, 0)); | |
TEST_ASSERT_EQUAL_INT(i_expected, *(int *) vector_get(vector, 0)); | |
TRY_FN_CATCH_EXCEPTION(vector_get(vector, 1)); | |
vector_add(vector, &i_expected); | |
TEST_ASSERT_EQUAL_INT(i_expected, *(int *) vector_get(vector, 1)); | |
TEST_ASSERT_EQUAL_INT(i_expected, *(int *) vector_get(vector, 1)); | |
TRY_FN_CATCH_EXCEPTION(vector_get(vector, 2)); | |
vector_add(vector, &j_expected); | |
TEST_ASSERT_EQUAL_INT(i_expected, *(int *) vector_get(vector, 0)); | |
TEST_ASSERT_EQUAL_INT(i_expected, *(int *) vector_get(vector, 1)); | |
TEST_ASSERT_EQUAL_INT(j_expected, *(int *) vector_get(vector, 2)); | |
TEST_ASSERT_EQUAL_INT(3, vector->count); | |
} | |
void test_vector_delete_removes_element_as_expected(void) | |
{ | |
CEXCEPTION_T e_expected = EXCEPTION_OUT_OF_BOUNDS; | |
CEXCEPTION_T e_actual = EXCEPTION_NO_EXCEPTION; | |
int i_expected = 5; | |
int j_expected = -55; | |
int k_expected = 555; | |
vector_add(vector, &i_expected); | |
vector_delete(vector, 0); | |
TRY_FN_CATCH_EXCEPTION(vector_get(vector, 0)); | |
TRY_FN_CATCH_EXCEPTION(vector_get(vector, 1)); | |
TEST_ASSERT_EQUAL_INT(0, vector->count); | |
vector_add(vector, &i_expected); | |
vector_add(vector, &j_expected); | |
vector_add(vector, &k_expected); | |
vector_delete(vector, 0); | |
TRY_FN_CATCH_EXCEPTION(vector_get(vector, 2)); | |
TEST_ASSERT_EQUAL_INT(j_expected, *(int *) vector_get(vector, 0)); | |
TEST_ASSERT_EQUAL_INT(k_expected, *(int *) vector_get(vector, 1)); | |
} | |
void test_vector_set_sets_element_as_expected(void) | |
{ | |
int i_expected = 5; | |
int set_expected = -5; | |
vector_add(vector, &i_expected); | |
vector_add(vector, &i_expected); | |
vector_add(vector, &i_expected); | |
TEST_ASSERT_EQUAL_INT(i_expected, *(int *) vector_get(vector, 1)); | |
TEST_ASSERT_EQUAL_INT(i_expected, *(int *) vector_get(vector, 2)); | |
vector_set(vector, 1, &set_expected); | |
TEST_ASSERT_EQUAL_INT(set_expected, *(int *) vector_get(vector, 1)); | |
TEST_ASSERT_EQUAL_INT(i_expected, *(int *) vector_get(vector, 0)); | |
TEST_ASSERT_EQUAL_INT(i_expected, *(int *) vector_get(vector, 2)); | |
} | |
void test_vector_add_grows_array_size_as_expected(void) | |
{ | |
int i_expected = 5; | |
int j_expected = -55; | |
int k_expected = 555; | |
for(size_t i = 0; i < 50; ++i) | |
{ | |
vector_add(vector, &i_expected); | |
vector_add(vector, &j_expected); | |
vector_add(vector, &k_expected); | |
} | |
TEST_ASSERT_EQUAL_INT(150, vector->count); | |
TEST_ASSERT_EQUAL_INT(160, vector->size); // XXX: Assuming 2x growth factor | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment