diff --git a/vector/vector.c b/vector/vector.c index 9925a54..a8790b7 100644 --- a/vector/vector.c +++ b/vector/vector.c @@ -58,6 +58,9 @@ static inline vector_t* initialize_vector() { /* Returns SUCCESS_CODE_VECTOR_C on success and FAILURE_CODE_VECTOR_C on failure. */ /* Undefined behavior for NULL vectors. */ static inline int append_to_vector(vector_t* vector, void* const data) { + /* Sanity check. */ + assert(vector); + /* Check if the vector has enough space. */ if (check_vector_grow(vector, THRESHOLD_GROW_VECTOR_C)) { /* Grow the vector. */ @@ -85,6 +88,9 @@ static inline int append_to_vector(vector_t* vector, void* const data) { /* Returns SUCCESS_CODE_VECTOR_C on success and FAILURE_CODE_VECTOR_C on failure. */ /* Undefined behavior for NULL vectors. */ static inline int prepend_to_vector(vector_t* const vector, void* const data) { + /* Sanity check. */ + assert(vector); + /* Check if the vector has enough space. */ if (check_vector_grow(vector, THRESHOLD_GROW_VECTOR_C)) { /* Grow the vector. */ @@ -109,16 +115,12 @@ static inline int prepend_to_vector(vector_t* const vector, void* const data) { } /* This function reads from the vector at the given index. */ -/* Returns NULL on error and sets error to the error code. */ +/* Returns NULL on error. */ /* NULL can also be a perfectly fine value to store and retrieve. */ /* Undefined behavior for NULL vectors. */ -static inline void* read_from_vector(const vector_t* const vector, const size_t index, int* const error) { - /* Check if read index is within bounds. */ - if (vector->last_element < index || vector->empty) { - /* Index out of bounds. */ - *error = INDEX_NOT_FOUND_CODE_VECTOR_C; - return NULL; - } +static inline void* read_from_vector(const vector_t* const vector, const size_t index) { + /* Sanity check. */ + assert(vector && vector->last_element >= index && !(vector->empty)); /* Read and return the pointer. */ return *(vector->array + (index * vector->element_size)); @@ -130,9 +132,8 @@ static inline void* read_from_vector(const vector_t* const vector, const size_t /* Undefined behavior for NULL vectors. */ /* Disallows writes beyond last_index + 1. */ static inline int write_to_vector(vector_t* const vector, const size_t index, void* const data) { - /* Check if write index is within bounds. */ - if ((vector->length <= index) || ((vector->last_element + 1L) < index)) - return INDEX_NOT_FOUND_CODE_VECTOR_C; + /* Sanity check. */ + assert(vector && vector->length > index && (vector->last_element + 1L) > index); /* Check if the vector is empty. */ if (vector->empty) @@ -155,24 +156,27 @@ static inline int write_to_vector(vector_t* const vector, const size_t index, vo } /* This function deletes from the vector at the given index. */ -/* Returns error code on error. */ /* Undefined behavior for NULL vectors. */ /* Disallows deletes out of bounds. */ /* free_function mustn't be NULL. */ -static inline int delete_from_vector(vector_t* const vector, const size_t index, void (*free_function)(const void*)) { +/* Silently fails when index is out of bounds. */ +static inline void delete_from_vector(vector_t* const vector, const size_t index, void (*free_function)(const void*)) { + /* Sanity checks. */ + assert(vector && (vector->array) && !((vector->length <= index) || ((vector->last_element + 1L) < index))); + + /* Check if the vector is empty. */ + if (vector->empty) + return; + /* Local variables. */ void_ptr pointer = vector->array; size_t i, j; - /* Check if the free function is NULL or not. */ - if (free_function == NULL) - return INVALID_FREE_FUNCTION_POINTER; - /* Check if delete index is within bounds. */ - if (vector->empty || (vector->length <= index) || ((vector->last_element + 1L) < index)) - return INDEX_NOT_FOUND_CODE_VECTOR_C; - /* Free the internal data. */ - free_function((vector->array + (index * vector->element_size))); + if (free_function) + free_function((vector->array + (index * vector->element_size))); + else + free((vector->array + (index * vector->element_size))); *(vector->array + (index * vector->element_size)) = NULL; /* Compact the vector manually and return the result accordingly. */ @@ -187,10 +191,7 @@ static inline int delete_from_vector(vector_t* const vector, const size_t index, /* Check if the vector should be shrunk. */ if (check_vector_shrink(vector, THRESHOLD_SHRINK_VECTOR_C)) - return (shrink_vector(vector)) ? SUCCESS_CODE_VECTOR_C : DELETE_SUCCESS_VECTOR_SHRINK_FAIL_VECTOR_C; - - /* Done. */ - return SUCCESS_CODE_VECTOR_C; + shrink_vector(vector); } /* This function serializes a vector into a copy array. */ @@ -199,6 +200,9 @@ static inline int delete_from_vector(vector_t* const vector, const size_t index, /* Caller should free the allocated buffer! */ /* Note that calling this function on an empty vector might result in Undefined Behavior. */ static inline void_ptr* serialize_vector(const vector_t* const vector) { + /* Sanity check. */ + assert(vector); + /* Attempt to allocate the new buffer. */ void_ptr *buffer = (void_ptr*) malloc(vector->length * vector->element_size); @@ -215,6 +219,9 @@ static inline void_ptr* serialize_vector(const vector_t* const vector) { /* Will exhibit undefined behavior if the vector is NULL or is internally undefined. */ /* Caller should free the allocated data! */ static inline int copy_vector(vector_t *restrict source, vector_t **restrict destination) { + /* Sanity check. */ + assert(source && source->array && destination); + /* Attempt to intialize an empty vector struct. */ *destination = initialize_vector(); if (*destination == NULL) @@ -247,6 +254,9 @@ static inline void free_vector(vector_t *vector, void (*free_function)(const voi /* Local variables. */ size_t index; + /* Sanity check. */ + assert(vector); + /* Check if to free the data. */ if (free_function != NULL) for (index = 0L; index <= vector->last_element; index++) @@ -261,6 +271,9 @@ static inline void free_vector(vector_t *vector, void (*free_function)(const voi /* Internal functions. */ /* This function checks if the vector needs to be grown or kept as is. */ static inline int check_vector_grow(const vector_t* const vector, const double threshold) { + /* Sanity check. */ + assert(vector); + /* Calculate the threshold and length. */ size_t current_size = vector->last_element; size_t current_threshold = (size_t)((vector->length) * threshold); @@ -270,6 +283,9 @@ static inline int check_vector_grow(const vector_t* const vector, const double t /* This function checks if the vector needs to be shrunk or kept as is. */ static inline int check_vector_shrink(const vector_t* const vector, const double threshold) { + /* Sanity check. */ + assert(vector); + /* Calculate the threshold and length. */ size_t current_size = vector->last_element; size_t current_threshold = (size_t)((vector->length) * (THRESHOLD_WHOLE_VECTOR_C - threshold)); @@ -280,6 +296,9 @@ static inline int check_vector_shrink(const vector_t* const vector, const double /* This function grows a vector, doesn't change it on failure. */ /* Returns SUCCESS_CODE_VECTOR_C on success and FAILURE_CODE_VECTOR_C on failure. */ static inline int grow_vector(vector_t* const vector) { + /* Sanity check. */ + assert(vector && (vector->array)); + /* Local variables. */ size_t size; void* array; @@ -308,6 +327,9 @@ static inline int grow_vector(vector_t* const vector) { /* Note that if the vector cannot be shrunk according to the growth factor, data loss may occure. */ /* Returns SUCCESS_CODE_VECTOR_C on success and FAILURE_CODE_VECTOR_C on failure. */ static inline int shrink_vector(vector_t* const vector) { + /* Sanity check. */ + assert(vector); + /* Local variables. */ size_t size; void* array; @@ -335,6 +357,9 @@ static inline int shrink_vector(vector_t* const vector) { /* This function compacts a vector by pushing all the NULLs to the end. */ /* Try to avoid calling it unless needed as it has an O(n^2) runtime complexity. */ static inline void compact_vector(vector_t* const vector) { + /* Sanity check. */ + assert(vector && (vector->array)); + /* Loop and push. */ void_ptr *pointer = vector->array; size_t i, j; @@ -350,6 +375,9 @@ static inline void compact_vector(vector_t* const vector) { /* This function creates a "gap" (of NULL) at the start of the vector, doesn't do any sanity checking! */ static inline void push_vector(const vector_t* const vector, const size_t gap_length) { + /* Sanity check. */ + assert(vector && (vector->array)); + /* Local variables. */ size_t i; diff --git a/vector/vector.h b/vector/vector.h index 5012f1e..def3c09 100644 --- a/vector/vector.h +++ b/vector/vector.h @@ -19,8 +19,18 @@ #include /* Used in allocations and deallocations. */ #include #include +/* Include assert.h to allow code generation, but only run with debug flag. */ +#ifdef DEBUG +#ifndef NDEBUG +#define NDEBUG +#endif /* NDEBUG. */ +#endif /* DEBUG. */ +#include +/* Include the void swapping. */ #include "../utils/swap_void.c" + + #ifndef VECTOR_H #define VECTOR_H /* Constants. */ @@ -92,11 +102,11 @@ static inline int append_to_vector(vector_t* vector, void* const data); /* This function prepends to the vector. */ static inline int prepend_to_vector(vector_t* const vector, void* const data); /* This function reads from the vector at the given index. */ -static inline void* read_from_vector(const vector_t* const vector, const size_t index, int* const error); +static inline void* read_from_vector(const vector_t* const vector, const size_t index); /* This function overwrites the value at the given index. */ static inline int write_to_vector(vector_t* const vector, const size_t index, void* const data); /* This function frees the data at the given index (using the given free function, if NULL doesn't change it!) and marks the cell there as NULL. */ -static inline int delete_from_vector(vector_t* const vector, const size_t index, void (*free_function)(const void*)); +static inline void delete_from_vector(vector_t* const vector, const size_t index, void (*free_function)(const void*)); /* This function serializes the vector into an array! */ static inline void_ptr* serialize_vector(const vector_t* const vector); /* This function copies a vector. */