From ba09aff914ddd42f10f10d1e956309a512afaca9 Mon Sep 17 00:00:00 2001 From: herbglitch Date: Thu, 13 Mar 2025 19:22:27 -0600 Subject: [PATCH] added vector inline to hopefully make caching work for the entity component system --- CMakeLists.txt | 4 +- include/arc/std/entity.h | 16 +++ include/arc/std/vector/inline.h | 109 +++++++++++++++++++++ src/std/entity.c | 28 ++++++ src/std/vector.c | 1 - src/std/vector/inline.c | 167 ++++++++++++++++++++++++++++++++ tests/std/vector/inline.c | 159 ++++++++++++++++++++++++++++++ 7 files changed, 482 insertions(+), 2 deletions(-) create mode 100644 include/arc/std/vector/inline.h create mode 100644 src/std/vector/inline.c create mode 100644 tests/std/vector/inline.c diff --git a/CMakeLists.txt b/CMakeLists.txt index a984c52..e076dc6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,7 @@ set(ARCHEUS_SOURCES src/std/string.c src/std/time.c src/std/vector.c + src/std/vector/inline.c src/math/circle.c src/math/obround.c @@ -129,7 +130,7 @@ if(ARCHEUS_TESTS) add_executable(tests tests/test.c - tests/std/config.c + #tests/std/config.c #tests/std/entity.c #tests/std/hashtable.c #tests/std/lexer.c @@ -137,6 +138,7 @@ if(ARCHEUS_TESTS) #tests/std/parser/csv.c #tests/std/parser/parserlang.c #tests/std/vector.c + tests/std/vector/inline.c ${ARCHEUS_SOURCES} ) diff --git a/include/arc/std/entity.h b/include/arc/std/entity.h index a6dd54e..02ca6a1 100644 --- a/include/arc/std/entity.h +++ b/include/arc/std/entity.h @@ -17,6 +17,16 @@ typedef struct ARC_EntitySystem ARC_EntitySystem; */ typedef uint32_t ARC_Entity; +/** + * @brief an entity component system type +*/ +typedef uint32_t ARC_EntityComponent; + +/** + * @brief +*/ +typedef void (* ARC_EntityCoponent_CreateEmptyFn)(void **type); + /** * @brief */ @@ -29,6 +39,12 @@ void ARC_EntitySystem_Create(ARC_EntitySystem **entitySystem); */ void ARC_EntitySystem_Destroy(ARC_EntitySystem *entitySystem); +void ARC_EntitySystem_RegisterComponent(ARC_EntitySystem *entitySystem, uint32_t componentSize); + +//void ARC_EntitySystem_RunSystem(ARC_EntitySystem *entitySystem, ARC_Component component); + +void ARC_EntitySystem_Run(ARC_EntitySystem *entitySystem); + #ifdef __cplusplus } #endif diff --git a/include/arc/std/vector/inline.h b/include/arc/std/vector/inline.h new file mode 100644 index 0000000..cb5a466 --- /dev/null +++ b/include/arc/std/vector/inline.h @@ -0,0 +1,109 @@ +#ifndef ARC_STD_VECTOR_INLINE_H_ +#define ARC_STD_VECTOR_INLINE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "arc/std/vector.h" +#include + +/** + * @brief a dynamic array type that stores elements next to eachother +*/ +typedef struct ARC_VectorInline ARC_VectorInline; + +/** + * @brief creates an ARC_VectorInline which is an "expandable" array, this version allocates an array with set length for segments instead of void pointers for the data + * + * @note this vector relies on correct casting to not have errors, and is a lot less safe than "arc/std/vector.h", + * it is recommended that you use "arc/std/vector.h" if you don't have a specific reason to use this type + * @note to avoid writing a ton of callback types, this will use callback types defined in "arc/std/vector.h" + * @note for this basic implementation, the array will double in size every time the capacity is hit + * @note the array will also half in size when the array is only half filled + * + * @param[out] vectorInline ARC_VectorInline to initialize + * @param[in] typeSize the size of the type to store within the inline vector + * @param[in] compareDataFn a callback that checks if data stored in the array matches, + * if set to NULL and ARC_VectorIndex_Remove is called, an error will be thrown + * @param[in] destroyDataFn a callback that frees an item on remove or clear, can be set to NULL to do nothing +*/ +void ARC_VectorInline_Create(ARC_VectorInline **vectorInline, uint32_t typeSize, ARC_Vector_CompareDataFn *compareDataFn, ARC_Vector_DestroyDataFn *destroyDataFn); + +/** + * @brief destroys an ARC_VectorInline + * + * @note this will only free the items if destroyDataFn is passed in on creation + * + * @param[in] vector ARC_VectorInline to free +*/ +void ARC_VectorInline_Destroy(ARC_VectorInline *vectorInline); + +/** + * @brief adds an item to an ARC_VectorInline + * + * @note this will error if you add more than 4,294,967,295 items (the max value of an unsigned int 32) + * + * @param[in] vector ARC_VectorInline to add to + * @param[in] data data that is being added +*/ +void ARC_VectorInline_Add(ARC_VectorInline *vectorInline, void *data); + +/** + * @brief removes an item from a matching item in an ARC_VectorInline + * + * @note this function uses the ARC_Vector_CompareDataFn that the ARC_VectorInline was created with + * @note this function will not throw an error if there is no match + * @note this function will call ARC_VectorInline_RemoveIndex, so it's notes are also applicable to this function + * + * @param[in] vectorInline ARC_VectorInline to remove from + * @param[in] data matching data to remove +*/ +void ARC_VectorInline_Remove(ARC_VectorInline *vectorInline, void *data); + +/** + * @brief removes an item from an ARC_VectorInline at an index + * + * @note this function will error if trying to remove an index that is outside the bounds of the ARC_VectorInline + * @note this function will use ARC_Vector_DeleteDataFn if it was set in the ARC_VectorInline_Create function + * + * @param[in] vectorInline ARC_VectorInline to remove from + * @param[in] index position of data to remove +*/ +void ARC_VectorInline_RemoveIndex(ARC_VectorInline *vectorInline, uint32_t index); + +/** + * @brief clears all items from a vector + * + * @note this function will call ARC_VectorInline_RemoveIndex, so it's notes are also applicable to this function + * + * @param[in] vector ARC_VectorInline to clear +*/ +void ARC_VectorInline_Clear(ARC_VectorInline *vectorInline); + +/** + * @brief gets the current size of an ARC_VectorInline as an unsigned 32 bit integer + * + * @param[in] vector ARC_VectorInline to get current size from + * + * @return the current size as a unsigned 32 bit integer +*/ +uint32_t ARC_VectorInline_GetSize(ARC_VectorInline *vectorInline); + +/** + * @brief gets an item from an ARC_VectorInline at a position index + * + * @note this function will error if trying to get an index that is outside the bounds of the ARC_VectorInline + * + * @param[in] vectorInline ARC_VectorInline to get data from + * @param[in] index position of data to get + * + * @return a void * item, or NULL on error +*/ +void *ARC_VectorInline_Get(ARC_VectorInline *vectorInline, uint32_t index); + +#ifdef __cplusplus +} +#endif + +#endif // !ARC_STD_VECTOR_INLINE_H_ diff --git a/src/std/entity.c b/src/std/entity.c index c5bbcfb..c65c308 100644 --- a/src/std/entity.c +++ b/src/std/entity.c @@ -1,3 +1,31 @@ #include "arc/std/entity.h" +#include "arc/std/bool.h" +#include "arc/std/vector.h" +#include +//TODO: might want to change how vector holds data for speed +struct ARC_EntitySystem { + ARC_Vector *flagVector; + ARC_Vector *maskVector; + void *data; +}; + +ARC_Bool ARC_EntitySystem_VectorCompareDataFn(void *dataA, void *dataB){ + return (ARC_Bool)(*(uint32_t *)dataA == *(uint32_t *)dataB); +} + +void ARC_EntitySystem_VectorDestroyDataFn(void *data){ + free((uint32_t *)data); +} + +void ARC_EntitySystem_Create(ARC_EntitySystem **entitySystem){ + *entitySystem = (ARC_EntitySystem *)malloc(sizeof(ARC_EntitySystem)); + + ARC_Vector_CompareDataFn compareDataFn = ARC_EntitySystem_VectorCompareDataFn; + ARC_Vector_DestroyDataFn destroyDataFn = ARC_EntitySystem_VectorDestroyDataFn; + + ARC_Vector_Create(&((*entitySystem)->flagVector), &compareDataFn, &destroyDataFn); + ARC_Vector_Create(&((*entitySystem)->maskVector), &compareDataFn, &destroyDataFn); + +} diff --git a/src/std/vector.c b/src/std/vector.c index ee80205..1bef01d 100644 --- a/src/std/vector.c +++ b/src/std/vector.c @@ -1,4 +1,3 @@ - #include "arc/std/vector.h" #include "arc/std/bool.h" diff --git a/src/std/vector/inline.c b/src/std/vector/inline.c new file mode 100644 index 0000000..add84e5 --- /dev/null +++ b/src/std/vector/inline.c @@ -0,0 +1,167 @@ +#include "arc/std/vector/inline.h" + +#include "arc/std/bool.h" +#include "arc/std/errno.h" +#include +#include +#include + +struct ARC_VectorInline { + uint32_t currentCapacity; + uint32_t currentSize; + uint32_t typeSize; + + void *data; + + ARC_Vector_CompareDataFn compareDataFn; + ARC_Vector_DestroyDataFn *destroyDataFn; +}; + +void ARC_VectorInline_Create(ARC_VectorInline **vectorInline, uint32_t typeSize, ARC_Vector_CompareDataFn *compareDataFn, ARC_Vector_DestroyDataFn *destroyDataFn){ + //error if no type size was provided + if(typeSize == 0){ + arc_errno = ARC_ERRNO_NULL; + ARC_DEBUG_LOG_ERROR("ARC_VectorInline_Create(vectorInline, typeSize, compareDataFn, destroyDataFn), vector inline could not be created with typeSize 0"); + *vectorInline = NULL; + return; + } + + //create the vector + *vectorInline = (ARC_VectorInline *)malloc(sizeof(ARC_VectorInline)); + + //initialize all the values stored in the vector + (*vectorInline)->data = (void *)malloc(typeSize); + (*vectorInline)->currentCapacity = 1; + (*vectorInline)->currentSize = 0; + (*vectorInline)->typeSize = typeSize; + + //set a default for compareDataFn, then override it if it is passed in through parameters + (*vectorInline)->compareDataFn = NULL; + if(compareDataFn != NULL){ + (*vectorInline)->compareDataFn = *compareDataFn; + } + + //set NULL as a default for deleteDataFn, then copy the delete data function callback if it exists + (*vectorInline)->destroyDataFn = NULL; + if(destroyDataFn != NULL){ + (*vectorInline)->destroyDataFn = (ARC_Vector_DestroyDataFn *)malloc(sizeof(ARC_Vector_DestroyDataFn)); + *((*vectorInline)->destroyDataFn) = *destroyDataFn; + } +} + +void ARC_VectorInline_Destroy(ARC_VectorInline *vectorInline){ + //remove all the contents before destroying the vector + ARC_VectorInline_Clear(vectorInline); + + //free the delete data function if it exists + if(vectorInline->destroyDataFn != NULL){ + free(vectorInline->destroyDataFn); + } + + //free everything stored in the vector + free(vectorInline->data); + + //free the vector + free(vectorInline); +} + +void ARC_VectorInline_Add(ARC_VectorInline *vectorInline, 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(vectorInline->currentSize == ~((uint32_t)0)){ + arc_errno = ARC_ERRNO_OVERFLOW; + ARC_DEBUG_LOG_ERROR("ARC_VectorInline_Add(vectorInline, data), vector inline at max capacity tried adding another value"); + return; + } + + //check if we are at the max of the current capacity + if(vectorInline->currentSize == vectorInline->currentCapacity){ + //increase the current capacity by double + vectorInline->currentCapacity <<= 1; + + //if for some reason the capacity is 0, we should set it to one so we do not error on realloc + if(vectorInline->currentCapacity != 0){ + vectorInline->currentCapacity++; + } + + //resize the vectors array and copy the contents at the same time + vectorInline->data = (void *)realloc(vectorInline->data, vectorInline->typeSize * vectorInline->currentCapacity); + } + + //add to the vectors array and increase its current size + memcpy(vectorInline->data + (vectorInline->currentSize * vectorInline->typeSize), data, vectorInline->typeSize); + vectorInline->currentSize++; +} + +void ARC_VectorInline_Remove(ARC_VectorInline *vectorInline, void *data){ + //error if return function was never set + if(vectorInline->compareDataFn == NULL){ + arc_errno = ARC_ERRNO_NULL; + ARC_DEBUG_LOG_ERROR("ARC_VectorInline_Remove(vectorInline, data), vector inline did not have a compare data function set on creation"); + return; + } + + //iterate through every item to check to see if it exists + for(uint32_t index = 0; index < vectorInline->currentSize; index++){ + //keep the code cleaner by pulling the current index data into a temp variable + void *dataB = vectorInline->data + (vectorInline->typeSize * index); + + //check if the data matches, and if so remove by index + if(vectorInline->compareDataFn(data, dataB) == ARC_True){ + ARC_VectorInline_RemoveIndex(vectorInline, index); + } + } +} + +void ARC_VectorInline_RemoveIndex(ARC_VectorInline *vectorInline, uint32_t index){ + //check to make sure the given index is in bounds of the vector + if(index >= vectorInline->currentSize){ + arc_errno = ARC_ERRNO_DATA; + ARC_DEBUG_LOG_ERROR("ARC_VectorInline_Add(vectorInline, data), vector at max capacity tried adding another value"); + return; + } + + //call delete data to clean up item if delete data function exists + if(vectorInline->destroyDataFn != NULL){ + (*(vectorInline->destroyDataFn))(vectorInline->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 < vectorInline->currentSize; index++){ + //override the data from index to the end by shifting it back one + memcpy(vectorInline->data + (index * vectorInline->typeSize), vectorInline->data + ((index + 1) * vectorInline->typeSize), vectorInline->typeSize); + } + + //we have removed the item so we can decrease the current size + vectorInline->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(vectorInline->currentSize != vectorInline->currentCapacity >> 1 || vectorInline->currentCapacity == 1){ + return; + } + + //half the capacity and copy it into a smaller array + vectorInline->currentCapacity >>= 1; + vectorInline->data = (void *)realloc(vectorInline->data, vectorInline->typeSize * vectorInline->currentCapacity); +} + +void ARC_VectorInline_Clear(ARC_VectorInline *vectorInline){ + //remove each item in the vector untill the vector is empty + while(ARC_VectorInline_GetSize(vectorInline) != 0){ + ARC_VectorInline_RemoveIndex(vectorInline, 0); + } +} + +uint32_t ARC_VectorInline_GetSize(ARC_VectorInline *vectorInline){ + return vectorInline->currentSize; +} + +void *ARC_VectorInline_Get(ARC_VectorInline *vectorInline, uint32_t index){ + //check to make sure the given index is in bounds of the vector + if(index >= vectorInline->currentSize){ + arc_errno = ARC_ERRNO_DATA; + ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_VectorInline_Get(vectorInline, %u), index %u bounds", index, index); + return NULL; + } + + return (vectorInline->data + (vectorInline->typeSize * index)); +} diff --git a/tests/std/vector/inline.c b/tests/std/vector/inline.c new file mode 100644 index 0000000..de72e28 --- /dev/null +++ b/tests/std/vector/inline.c @@ -0,0 +1,159 @@ +#include "../../test.h" +#include "arc/std/bool.h" +#include "arc/std/errno.h" +#include "arc/std/vector/inline.h" +#include +#include + +ARC_Bool TEST_VectorInline_CompareDataFn(void *dataA, void *dataB){ + if(*(int32_t *)dataA == *(int32_t *)dataB){ + return ARC_True; + } + + return ARC_False; +} + +//TODO: more tests with destroy data fn added +void TEST_VectorInline_DestroyDataFn(void *data){ + free((int32_t *)data); +} + +ARC_TEST(VectorInline_Add_RemoveIndex_Get){ + ARC_VectorInline *vectorInline; + ARC_VectorInline_Create(&vectorInline, sizeof(int32_t), NULL, NULL); + + int32_t val0 = 0; + int32_t val1 = 1; + int32_t val2 = 2; + int32_t val3 = 3; + int32_t val4 = 4; + + ARC_VectorInline_Add(vectorInline, &val0); + ARC_VectorInline_Add(vectorInline, &val1); + ARC_VectorInline_Add(vectorInline, &val2); + ARC_VectorInline_Add(vectorInline, &val3); + ARC_VectorInline_Add(vectorInline, &val4); + + ARC_CHECK(0 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 0)); + ARC_CHECK(1 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 1)); + ARC_CHECK(2 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 2)); + ARC_CHECK(3 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 3)); + ARC_CHECK(4 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 4)); + ARC_VectorInline_RemoveIndex(vectorInline, 0); + + ARC_CHECK(1 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 0)); + ARC_CHECK(2 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 1)); + ARC_CHECK(3 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 2)); + ARC_CHECK(4 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 3)); + ARC_VectorInline_RemoveIndex(vectorInline, 3); + + ARC_CHECK(1 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 0)); + ARC_CHECK(2 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 1)); + ARC_CHECK(3 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 2)); + ARC_VectorInline_RemoveIndex(vectorInline, 1); + + ARC_CHECK(1 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 0)); + ARC_CHECK(3 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 1)); + ARC_VectorInline_RemoveIndex(vectorInline, 1); + + ARC_CHECK(1 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 0)); + ARC_VectorInline_RemoveIndex(vectorInline, 0); + + ARC_VectorInline_Destroy(vectorInline); +} + +ARC_TEST(VectorInline_Add_Remove_Get){ + ARC_VectorInline *vectorInline; + ARC_Vector_CompareDataFn testCompareDataFn = TEST_VectorInline_CompareDataFn; + ARC_VectorInline_Create(&vectorInline, sizeof(int32_t), &testCompareDataFn, NULL); + + int32_t val0 = 0; + int32_t val1 = 1; + int32_t val2 = 2; + int32_t val3 = 3; + int32_t val4 = 4; + + ARC_VectorInline_Add(vectorInline, &val0); + ARC_VectorInline_Add(vectorInline, &val1); + ARC_VectorInline_Add(vectorInline, &val2); + ARC_VectorInline_Add(vectorInline, &val3); + ARC_VectorInline_Add(vectorInline, &val4); + + ARC_CHECK(0 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 0)); + ARC_CHECK(1 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 1)); + ARC_CHECK(2 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 2)); + ARC_CHECK(3 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 3)); + ARC_CHECK(4 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 4)); + ARC_VectorInline_Remove(vectorInline, &val0); + + ARC_CHECK(1 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 0)); + ARC_CHECK(2 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 1)); + ARC_CHECK(3 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 2)); + ARC_CHECK(4 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 3)); + ARC_VectorInline_Remove(vectorInline, &val4); + + ARC_CHECK(1 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 0)); + ARC_CHECK(2 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 1)); + ARC_CHECK(3 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 2)); + ARC_VectorInline_Remove(vectorInline, &val2); + + ARC_CHECK(1 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 0)); + ARC_CHECK(3 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 1)); + ARC_VectorInline_Remove(vectorInline, &val1); + + ARC_CHECK(3 == *(int32_t *)ARC_VectorInline_Get(vectorInline, 0)); + ARC_VectorInline_Remove(vectorInline, &val3); + + ARC_VectorInline_Destroy(vectorInline); +} + +ARC_TEST(VectorInline_Add_RemoveIndex_GetSize){ + ARC_VectorInline *vectorInline; + ARC_VectorInline_Create(&vectorInline, sizeof(int32_t), NULL, NULL); + + int32_t val0 = 0; + int32_t val1 = 1; + int32_t val2 = 2; + int32_t val3 = 3; + int32_t val4 = 4; + + ARC_VectorInline_Add(vectorInline, &val0); + ARC_VectorInline_Add(vectorInline, &val1); + ARC_VectorInline_Add(vectorInline, &val2); + ARC_VectorInline_Add(vectorInline, &val3); + ARC_VectorInline_Add(vectorInline, &val4); + + ARC_CHECK(5 == ARC_VectorInline_GetSize(vectorInline)); + ARC_VectorInline_RemoveIndex(vectorInline, 0); + + ARC_CHECK(4 == ARC_VectorInline_GetSize(vectorInline)); + ARC_VectorInline_RemoveIndex(vectorInline, 0); + + ARC_CHECK(3 == ARC_VectorInline_GetSize(vectorInline)); + ARC_VectorInline_RemoveIndex(vectorInline, 0); + + ARC_CHECK(2 == ARC_VectorInline_GetSize(vectorInline)); + ARC_VectorInline_RemoveIndex(vectorInline, 0); + + ARC_CHECK(1 == ARC_VectorInline_GetSize(vectorInline)); + ARC_VectorInline_RemoveIndex(vectorInline, 0); + + ARC_CHECK(0 == ARC_VectorInline_GetSize(vectorInline)); + + ARC_VectorInline_Destroy(vectorInline); +} + +ARC_TEST(VectorInline_Add_RemoveIndex_Get_Try_Out_Of_Bounds){ + ARC_Vector *vector; + ARC_Vector_Create(&vector, NULL, NULL); + + int32_t val0 = 0; + + ARC_Vector_Add(vector, &val0); + ARC_CHECK(NULL == ARC_Vector_Get(vector, 1)); + arc_errno = 0; + + ARC_Vector_RemoveIndex(vector, 0); + + ARC_Vector_Destroy(vector); +}