archeus/src/std/vector.c

158 lines
5.4 KiB
C

#include "arc/std/vector.h"
#include "arc/std/bool.h"
#include "arc/std/errno.h"
#include <stdint.h>
#include <stdlib.h>
struct ARC_Vector {
uint32_t currentCapacity;
uint32_t currentSize;
void **data;
ARC_Vector_CompareDataFn compareDataFn;
ARC_Vector_DestroyDataFn *destroyDataFn;
};
//this is a private function used as the default check for removing data from a given pointer
ARC_Bool ARC_Vector_CompareDataDefaultFn(void *dataA, void *dataB){
if(dataA == dataB){
return ARC_True;
}
return ARC_False;
}
void ARC_Vector_Create(ARC_Vector **vector, ARC_Vector_CompareDataFn *compareDataFn, ARC_Vector_DestroyDataFn *destroyDataFn){
//create the vector
*vector = (ARC_Vector *)malloc(sizeof(ARC_Vector));
//initialize all the values stored in the vector
(*vector)->data = (void **)malloc(sizeof(void *));
(*vector)->currentCapacity = 1;
(*vector)->currentSize = 0;
//set a default for compareDataFn, then override it if it is passed in through parameters
(*vector)->compareDataFn = ARC_Vector_CompareDataDefaultFn;
if(compareDataFn != NULL){
(*vector)->compareDataFn = *compareDataFn;
}
//set NULL as a default for deleteDataFn, then copy the delete data function callback if it exists
(*vector)->destroyDataFn = NULL;
if(destroyDataFn != NULL){
(*vector)->destroyDataFn = (ARC_Vector_DestroyDataFn *)malloc(sizeof(ARC_Vector_DestroyDataFn));
*((*vector)->destroyDataFn) = *destroyDataFn;
}
}
void ARC_Vector_Destroy(ARC_Vector *vector){
//remove all the contents before destroying the vector
ARC_Vector_Clear(vector);
//free the delete data function if it exists
if(vector->destroyDataFn != NULL){
free(vector->destroyDataFn);
}
//free everything stored in the vector
free(vector->data);
//free the vector
free(vector);
}
void ARC_Vector_Add(ARC_Vector *vector, void *data){
//check to see if the current size is the same as a max uint32_t and if so it will overflow so throw an error
if(vector->currentSize == ~((uint32_t)0)){
arc_errno = ARC_ERRNO_OVERFLOW;
ARC_DEBUG_LOG_ERROR("ARC_Vector_Add(vector, data), vector at max capacity tried adding another value");
return;
}
//check if we are at the max of the current capacity
if(vector->currentSize == vector->currentCapacity){
//increase the current capacity by double
vector->currentCapacity <<= 1;
//if for some reason the capacity is 0, we should set it to one so we do not error on realloc
if(vector->currentCapacity != 0){
vector->currentCapacity++;
}
//resize the vectors array and copy the contents at the same time
vector->data = (void **)realloc(vector->data, sizeof(void *) * vector->currentCapacity);
}
//add to the vectors array and increase its current size
vector->data[vector->currentSize] = data;
vector->currentSize++;
}
void ARC_Vector_Remove(ARC_Vector *vector, void *data){
//iterate through every item to check to see if it exists
for(uint32_t index = 0; index < vector->currentSize; index++){
//keep the code cleaner by pulling the current index data into a temp variable
void *dataB = vector->data[index];
//check if the data matches, and if so remove by index
if(vector->compareDataFn(data, dataB) == ARC_True){
ARC_Vector_RemoveIndex(vector, index);
}
}
}
void ARC_Vector_RemoveIndex(ARC_Vector *vector, uint32_t index){
//check to make sure the given index is in bounds of the vector
if(index >= vector->currentSize){
arc_errno = ARC_ERRNO_DATA;
ARC_DEBUG_LOG_ERROR("ARC_Vector_Add(vector, data), vector at max capacity tried adding another value");
return;
}
//call delete data to clean up item if delete data function exists
if(vector->destroyDataFn != NULL){
(*(vector->destroyDataFn))(vector->data[index]);
}
//we will be using index to iterate as we will not use it again, so we can skip the first part of the for loop
for(; index + 1 < vector->currentSize; index++){
//override the data from index to the end by shifting it back one
vector->data[index] = vector->data[index + 1];
}
//we have removed the item so we can decrease the current size
vector->currentSize--;
//if the current size is half the current capacity or the current capacity is at the smallest limit, we do not need to do anything else
if(vector->currentSize != vector->currentCapacity >> 1 || vector->currentCapacity == 1){
return;
}
//half the capacity and copy it into a smaller array
vector->currentCapacity >>= 1;
vector->data = (void **)realloc(vector->data, sizeof(void *) * vector->currentCapacity);
}
void ARC_Vector_Clear(ARC_Vector *vector){
//remove each item in the vector untill the vector is empty
while(ARC_Vector_GetSize(vector) != 0){
ARC_Vector_RemoveIndex(vector, 0);
}
}
uint32_t ARC_Vector_GetSize(ARC_Vector *vector){
return vector->currentSize;
}
void *ARC_Vector_Get(ARC_Vector *vector, uint32_t index){
//check to make sure the given index is in bounds of the vector
if(index >= vector->currentSize){
arc_errno = ARC_ERRNO_DATA;
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_Vector_Get(vector, %u), null value as the index was out of bounds", index);
return NULL;
}
return vector->data[index];
}