Update vector to have less runtime checks and make them into debug-only checks instead.
This commit is contained in:
parent
ac078dc1f4
commit
5c54cb8e0a
|
@ -58,6 +58,9 @@ static inline vector_t* initialize_vector() {
|
||||||
/* Returns SUCCESS_CODE_VECTOR_C on success and FAILURE_CODE_VECTOR_C on failure. */
|
/* Returns SUCCESS_CODE_VECTOR_C on success and FAILURE_CODE_VECTOR_C on failure. */
|
||||||
/* Undefined behavior for NULL vectors. */
|
/* Undefined behavior for NULL vectors. */
|
||||||
static inline int append_to_vector(vector_t* vector, void* const data) {
|
static inline int append_to_vector(vector_t* vector, void* const data) {
|
||||||
|
/* Sanity check. */
|
||||||
|
assert(vector);
|
||||||
|
|
||||||
/* Check if the vector has enough space. */
|
/* Check if the vector has enough space. */
|
||||||
if (check_vector_grow(vector, THRESHOLD_GROW_VECTOR_C)) {
|
if (check_vector_grow(vector, THRESHOLD_GROW_VECTOR_C)) {
|
||||||
/* Grow the vector. */
|
/* 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. */
|
/* Returns SUCCESS_CODE_VECTOR_C on success and FAILURE_CODE_VECTOR_C on failure. */
|
||||||
/* Undefined behavior for NULL vectors. */
|
/* Undefined behavior for NULL vectors. */
|
||||||
static inline int prepend_to_vector(vector_t* const vector, void* const data) {
|
static inline int prepend_to_vector(vector_t* const vector, void* const data) {
|
||||||
|
/* Sanity check. */
|
||||||
|
assert(vector);
|
||||||
|
|
||||||
/* Check if the vector has enough space. */
|
/* Check if the vector has enough space. */
|
||||||
if (check_vector_grow(vector, THRESHOLD_GROW_VECTOR_C)) {
|
if (check_vector_grow(vector, THRESHOLD_GROW_VECTOR_C)) {
|
||||||
/* Grow the vector. */
|
/* 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. */
|
/* 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. */
|
/* NULL can also be a perfectly fine value to store and retrieve. */
|
||||||
/* Undefined behavior for NULL vectors. */
|
/* Undefined behavior for NULL vectors. */
|
||||||
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) {
|
||||||
/* Check if read index is within bounds. */
|
/* Sanity check. */
|
||||||
if (vector->last_element < index || vector->empty) {
|
assert(vector && vector->last_element >= index && !(vector->empty));
|
||||||
/* Index out of bounds. */
|
|
||||||
*error = INDEX_NOT_FOUND_CODE_VECTOR_C;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read and return the pointer. */
|
/* Read and return the pointer. */
|
||||||
return *(vector->array + (index * vector->element_size));
|
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. */
|
/* Undefined behavior for NULL vectors. */
|
||||||
/* Disallows writes beyond last_index + 1. */
|
/* Disallows writes beyond last_index + 1. */
|
||||||
static inline int write_to_vector(vector_t* const vector, const size_t index, void* const data) {
|
static inline int write_to_vector(vector_t* const vector, const size_t index, void* const data) {
|
||||||
/* Check if write index is within bounds. */
|
/* Sanity check. */
|
||||||
if ((vector->length <= index) || ((vector->last_element + 1L) < index))
|
assert(vector && vector->length > index && (vector->last_element + 1L) > index);
|
||||||
return INDEX_NOT_FOUND_CODE_VECTOR_C;
|
|
||||||
|
|
||||||
/* Check if the vector is empty. */
|
/* Check if the vector is empty. */
|
||||||
if (vector->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. */
|
/* This function deletes from the vector at the given index. */
|
||||||
/* Returns error code on error. */
|
|
||||||
/* Undefined behavior for NULL vectors. */
|
/* Undefined behavior for NULL vectors. */
|
||||||
/* Disallows deletes out of bounds. */
|
/* Disallows deletes out of bounds. */
|
||||||
/* free_function mustn't be NULL. */
|
/* 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. */
|
/* Local variables. */
|
||||||
void_ptr pointer = vector->array;
|
void_ptr pointer = vector->array;
|
||||||
size_t i, j;
|
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 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;
|
*(vector->array + (index * vector->element_size)) = NULL;
|
||||||
|
|
||||||
/* Compact the vector manually and return the result accordingly. */
|
/* 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. */
|
/* Check if the vector should be shrunk. */
|
||||||
if (check_vector_shrink(vector, THRESHOLD_SHRINK_VECTOR_C))
|
if (check_vector_shrink(vector, THRESHOLD_SHRINK_VECTOR_C))
|
||||||
return (shrink_vector(vector)) ? SUCCESS_CODE_VECTOR_C : DELETE_SUCCESS_VECTOR_SHRINK_FAIL_VECTOR_C;
|
shrink_vector(vector);
|
||||||
|
|
||||||
/* Done. */
|
|
||||||
return SUCCESS_CODE_VECTOR_C;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function serializes a vector into a copy array. */
|
/* 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! */
|
/* Caller should free the allocated buffer! */
|
||||||
/* Note that calling this function on an empty vector might result in Undefined Behavior. */
|
/* 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) {
|
static inline void_ptr* serialize_vector(const vector_t* const vector) {
|
||||||
|
/* Sanity check. */
|
||||||
|
assert(vector);
|
||||||
|
|
||||||
/* Attempt to allocate the new buffer. */
|
/* Attempt to allocate the new buffer. */
|
||||||
void_ptr *buffer = (void_ptr*) malloc(vector->length * vector->element_size);
|
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. */
|
/* Will exhibit undefined behavior if the vector is NULL or is internally undefined. */
|
||||||
/* Caller should free the allocated data! */
|
/* Caller should free the allocated data! */
|
||||||
static inline int copy_vector(vector_t *restrict source, vector_t **restrict destination) {
|
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. */
|
/* Attempt to intialize an empty vector struct. */
|
||||||
*destination = initialize_vector();
|
*destination = initialize_vector();
|
||||||
if (*destination == NULL)
|
if (*destination == NULL)
|
||||||
|
@ -247,6 +254,9 @@ static inline void free_vector(vector_t *vector, void (*free_function)(const voi
|
||||||
/* Local variables. */
|
/* Local variables. */
|
||||||
size_t index;
|
size_t index;
|
||||||
|
|
||||||
|
/* Sanity check. */
|
||||||
|
assert(vector);
|
||||||
|
|
||||||
/* Check if to free the data. */
|
/* Check if to free the data. */
|
||||||
if (free_function != NULL)
|
if (free_function != NULL)
|
||||||
for (index = 0L; index <= vector->last_element; index++)
|
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. */
|
/* Internal functions. */
|
||||||
/* This function checks if the vector needs to be grown or kept as is. */
|
/* 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) {
|
static inline int check_vector_grow(const vector_t* const vector, const double threshold) {
|
||||||
|
/* Sanity check. */
|
||||||
|
assert(vector);
|
||||||
|
|
||||||
/* Calculate the threshold and length. */
|
/* Calculate the threshold and length. */
|
||||||
size_t current_size = vector->last_element;
|
size_t current_size = vector->last_element;
|
||||||
size_t current_threshold = (size_t)((vector->length) * threshold);
|
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. */
|
/* 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) {
|
static inline int check_vector_shrink(const vector_t* const vector, const double threshold) {
|
||||||
|
/* Sanity check. */
|
||||||
|
assert(vector);
|
||||||
|
|
||||||
/* Calculate the threshold and length. */
|
/* Calculate the threshold and length. */
|
||||||
size_t current_size = vector->last_element;
|
size_t current_size = vector->last_element;
|
||||||
size_t current_threshold = (size_t)((vector->length) * (THRESHOLD_WHOLE_VECTOR_C - threshold));
|
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. */
|
/* 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. */
|
/* Returns SUCCESS_CODE_VECTOR_C on success and FAILURE_CODE_VECTOR_C on failure. */
|
||||||
static inline int grow_vector(vector_t* const vector) {
|
static inline int grow_vector(vector_t* const vector) {
|
||||||
|
/* Sanity check. */
|
||||||
|
assert(vector && (vector->array));
|
||||||
|
|
||||||
/* Local variables. */
|
/* Local variables. */
|
||||||
size_t size;
|
size_t size;
|
||||||
void* array;
|
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. */
|
/* 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. */
|
/* Returns SUCCESS_CODE_VECTOR_C on success and FAILURE_CODE_VECTOR_C on failure. */
|
||||||
static inline int shrink_vector(vector_t* const vector) {
|
static inline int shrink_vector(vector_t* const vector) {
|
||||||
|
/* Sanity check. */
|
||||||
|
assert(vector);
|
||||||
|
|
||||||
/* Local variables. */
|
/* Local variables. */
|
||||||
size_t size;
|
size_t size;
|
||||||
void* array;
|
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. */
|
/* 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. */
|
/* 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) {
|
static inline void compact_vector(vector_t* const vector) {
|
||||||
|
/* Sanity check. */
|
||||||
|
assert(vector && (vector->array));
|
||||||
|
|
||||||
/* Loop and push. */
|
/* Loop and push. */
|
||||||
void_ptr *pointer = vector->array;
|
void_ptr *pointer = vector->array;
|
||||||
size_t i, j;
|
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! */
|
/* 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) {
|
static inline void push_vector(const vector_t* const vector, const size_t gap_length) {
|
||||||
|
/* Sanity check. */
|
||||||
|
assert(vector && (vector->array));
|
||||||
|
|
||||||
/* Local variables. */
|
/* Local variables. */
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,18 @@
|
||||||
#include <stdlib.h> /* Used in allocations and deallocations. */
|
#include <stdlib.h> /* Used in allocations and deallocations. */
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
/* Include assert.h to allow code generation, but only run with debug flag. */
|
||||||
|
#ifdef DEBUG
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#define NDEBUG
|
||||||
|
#endif /* NDEBUG. */
|
||||||
|
#endif /* DEBUG. */
|
||||||
|
#include <assert.h>
|
||||||
|
/* Include the void swapping. */
|
||||||
#include "../utils/swap_void.c"
|
#include "../utils/swap_void.c"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef VECTOR_H
|
#ifndef VECTOR_H
|
||||||
#define VECTOR_H
|
#define VECTOR_H
|
||||||
/* Constants. */
|
/* Constants. */
|
||||||
|
@ -92,11 +102,11 @@ static inline int append_to_vector(vector_t* vector, void* const data);
|
||||||
/* This function prepends to the vector. */
|
/* This function prepends to the vector. */
|
||||||
static inline int prepend_to_vector(vector_t* const vector, void* const data);
|
static inline int prepend_to_vector(vector_t* const vector, void* const data);
|
||||||
/* This function reads from the vector at the given index. */
|
/* 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. */
|
/* 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);
|
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. */
|
/* 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! */
|
/* This function serializes the vector into an array! */
|
||||||
static inline void_ptr* serialize_vector(const vector_t* const vector);
|
static inline void_ptr* serialize_vector(const vector_t* const vector);
|
||||||
/* This function copies a vector. */
|
/* This function copies a vector. */
|
||||||
|
|
Loading…
Reference in New Issue