|
#include <stdlib.h> |
|
#include <stdio.h> |
|
#include "vector.h" |
|
|
|
/* |
|
* Initializes vector field. |
|
* Starts with INIT_CAPACITY (8). I do this because I wanted the initial |
|
* capacity to be a power of 2 as the growth polcy grows/shrinks by 2. 16 was |
|
* too many, whereas 8 was better. |
|
* Can crash program if Out of Memory. |
|
*/ |
|
void vector_init(vector *vec) |
|
{ |
|
vec->size = 0; |
|
vec->capacity = INIT_CAPACITY; |
|
vec->elems = malloc((vec->capacity)*sizeof(void *)); |
|
if (!vec->elems) |
|
{ |
|
vector_die(0); |
|
} |
|
} |
|
|
|
/* |
|
* Frees underlying array structure |
|
* Note if the vector struct was intialized onto the heap, that must be freed |
|
* too. |
|
*/ |
|
void vector_free(vector *vec) |
|
{ |
|
free(vec->elems); |
|
vec->capacity = 0; |
|
vec->size = 0; |
|
} |
|
|
|
/* |
|
* Growth Policy handling |
|
* If the current size is equal to the capacity, grow capacity by a factor of |
|
* 2. |
|
* If the current size is 4 times less than or equal to the capacity, shrink |
|
* capacity by a factor of 2. |
|
* Can crash program with Out of Memory error. |
|
*/ |
|
static void growth_policy(vector *vec) |
|
{ |
|
if (vec->capacity == vec->size) |
|
{ |
|
vector_grow(vec, 2*(vec->capacity)); |
|
} |
|
if (vec->size > 0 && vec->size*4 <= vec->capacity) |
|
{ |
|
vector_grow(vec, (vec->capacity)/2); |
|
} |
|
} |
|
|
|
/* |
|
* Called by growth_policy() |
|
* Can crash program with Out of Memory error |
|
*/ |
|
static void vector_grow(vector *vec, int new_size) |
|
{ |
|
void **elems = realloc(vec->elems, new_size * sizeof(void *)); |
|
if (elems) |
|
{ |
|
vec->capacity = new_size; |
|
vec->elems = elems; |
|
} |
|
else |
|
{ |
|
vector_die(0); |
|
} |
|
} |
|
|
|
/* |
|
* Appends an element to the end of the array. |
|
* Complexity: Amortized O(1) | O(n) |
|
* May grow array size. |
|
*/ |
|
void vector_add(vector *vec, void *new_elem) |
|
{ |
|
growth_policy(vec); |
|
vec->elems[vec->size++] = new_elem; |
|
} |
|
|
|
/* |
|
* Sets element within the vector at given index to the value of new_elem. |
|
* Complexity: O(1) |
|
* Program may crash if index is out of bounds. |
|
*/ |
|
void vector_set(vector *vec, int ind, void *new_elem) |
|
{ |
|
if (ind >= vec->size || ind < 0) |
|
{ |
|
vector_die(1); |
|
} |
|
vec->elems[ind] = new_elem; |
|
} |
|
|
|
/* |
|
* Returns element within vector at given index. |
|
* Complexity: O(1) |
|
* Program may crash if index is out of bounds. |
|
*/ |
|
void *vector_get(vector *vec, int ind) |
|
{ |
|
if (ind >= vec->size || ind < 0) |
|
{ |
|
vector_die(1); |
|
} |
|
return vec->elems[ind]; |
|
} |
|
|
|
/* |
|
* Removes and returns last element within vector. |
|
* Complexity: Amortized O(1) | O(n) |
|
* Can throw both Out of memory and index out of bounds errors. |
|
*/ |
|
void *vector_pop(vector *vec) |
|
{ |
|
return vector_delete(vec, vec->size-1); |
|
} |
|
|
|
/* |
|
* Removes and returns element at given index within vector. |
|
* Complexity: Amortized O(1) | O(n) |
|
* Can throw both Out of memory and index out of bounds errors. |
|
*/ |
|
void *vector_delete(vector *vec, int ind) |
|
{ |
|
if (ind < 0 || ind >= vec->size) |
|
{ |
|
vector_die(1); |
|
} |
|
void *ret = vec->elems[ind]; |
|
vec->elems[ind] = NULL; |
|
|
|
int i; |
|
for (i = ind; i< vec->size; i++) |
|
{ |
|
vec->elems[i] = vec->elems[i+1]; |
|
vec->elems[i+1] = NULL; |
|
} |
|
vec->size--; |
|
growth_policy(vec); |
|
return ret; |
|
} |
|
|
|
/* |
|
* HERE BE DRAGONS!! |
|
* Sorts the vector using stdlib qsort. Works only for numeric types. |
|
* Complexity: O(nlog(n)) |
|
* See C reference for qsort implementation. |
|
*/ |
|
void vector_sort(vector *vec) |
|
{ |
|
qsort(vec->elems, vector_size(vec), sizeof(vec->elems[0]), cmpfunc); |
|
} |
|
|
|
static int cmpfunc (const void *a, const void *b) |
|
{ |
|
if (*(const double*)a < *(const double*)b) |
|
return -1; |
|
if (*(const double*)a > *(const double*)b) |
|
return 1; |
|
return 0; |
|
} |
|
|
|
/* |
|
* Returns first element within vector. |
|
* Complexity: O(1) |
|
* Can throw out of index error if size is 0. |
|
*/ |
|
void *vector_front(vector *vec) |
|
{ |
|
if (vec->size == 0) |
|
{ |
|
vector_die(1); |
|
} |
|
return vec->elems[0]; |
|
} |
|
|
|
/* |
|
* Returns last element within vector |
|
* Complexity: O(1) |
|
* Can throw out of index error if size is 0. |
|
*/ |
|
void *vector_back(vector *vec) |
|
{ |
|
if (vec->size == 0) |
|
{ |
|
vector_die(1); |
|
} |
|
return vec->elems[vec->size-1]; |
|
} |
|
|
|
/* |
|
* Returns underlying void array containing elements. |
|
* Complexity: O(n) |
|
* The array is allocated on the heap, so it must be freed after usage is done. |
|
*/ |
|
void **vector_data(vector *vec) |
|
{ |
|
void **arr = malloc(vec->size * sizeof(void *)); |
|
int i; |
|
for (i = 0; i < vec->size; i++) |
|
{ |
|
arr[i] = vec->elems[i]; |
|
} |
|
return arr; |
|
} |
|
|
|
/* |
|
* Returns capacity of array |
|
* Complexity: O(1) |
|
*/ |
|
int vector_capacity(vector *vec) |
|
{ |
|
return vec->capacity; |
|
} |
|
|
|
/* |
|
* Returns size of array |
|
* Complexity: O(1) |
|
*/ |
|
int vector_size(vector *vec) |
|
{ |
|
return vec->size; |
|
} |
|
|
|
/* |
|
* Returns 1 if size is zero, otherwise zero. |
|
* Complexity: O(1) |
|
*/ |
|
int vector_empty(vector *vec) |
|
{ |
|
return (vec->size == 0); |
|
} |
|
|
|
/* |
|
* Oh shit. |
|
* Exits the process after printing information regarding the crash. |
|
* Case 0: Out of memory |
|
* Case 1: Indexing error |
|
* ... |
|
* TODO: |
|
* Does this not end properly with concurrency? |
|
*/ |
|
void vector_die(int error) |
|
{ |
|
switch(error) |
|
{ |
|
case 0: |
|
printf("vector_die:\nOut of memory. Aborting.\n"); |
|
break; |
|
case 1: |
|
printf("vector_die:\nIndexing error. Aborting.\n"); |
|
break; |
|
} |
|
exit(1); |
|
} |