From ba467ac6b691b6cbc3a26cce01deb23e3e016862 Mon Sep 17 00:00:00 2001 From: herbglitch Date: Sun, 9 Mar 2025 06:20:07 -0600 Subject: [PATCH 01/10] working on unload and added getsize to hashtable --- include/arc/std/hashtable.h | 9 +++++++++ src/std/chemical.c | 26 +++++++++++++++++++++++++- src/std/hashtable.c | 19 +++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/include/arc/std/hashtable.h b/include/arc/std/hashtable.h index 16b3648..965762e 100644 --- a/include/arc/std/hashtable.h +++ b/include/arc/std/hashtable.h @@ -104,6 +104,15 @@ void ARC_Hashtable_Clear(ARC_Hashtable *hashtable); */ void *ARC_Hashtable_Get(ARC_Hashtable *hashtable, void *key); +/** + * @brief gets the number of elements stored in the hashtable + * + * @param[in] hashtable the hashtable to get number of elements from + * + * @return the size of the vector +*/ +uint32_t ARC_Hashtable_GetSize(ARC_Hashtable *hashtable); + /** * @brief iterates through a hashtable passing available key value pairs to a callback * diff --git a/src/std/chemical.c b/src/std/chemical.c index 03a0eef..4cb3578 100644 --- a/src/std/chemical.c +++ b/src/std/chemical.c @@ -16,6 +16,8 @@ struct ARC_Chemical { ARC_Hashtable *groups; ARC_Hashtable *currentGroup; + + ARC_Bool load; }; typedef struct ARC_ChemicalTypeData { @@ -313,6 +315,13 @@ void ARC_ChemicalData_RunVariableLineTag(ARC_ParserTagToken *tagToken, ARC_Chemi ARC_String_Create(&variableString, NULL, 0); ARC_ParserData_HelperRecurseStringAdd(&variableString, childTagToken); + //check if removing + if(chemical->load == ARC_False){ + ARC_Hashtable_Remove(chemical->currentGroup, (void *)variableString->data); + ARC_String_Destroy(variableString); + return; + } + //check to see if the current variable is already in the current group hashtable ARC_ChemicalTypeData *typeData = (ARC_ChemicalTypeData *)ARC_Hashtable_Get(chemical->currentGroup, variableString->data); if(typeData != NULL){ @@ -420,6 +429,13 @@ void ARC_ChemicalData_RunGroupTag(ARC_ParserTagToken *tagToken, ARC_Chemical *ch ARC_String_Create(&groupVariable, NULL, 0); ARC_ParserData_HelperRecurseStringAdd(&groupVariable, childTagToken); + //check if removing + if(chemical->load == ARC_False){ + //TODO: check if the group is empty and remove it if it is + ARC_String_Destroy(groupVariable); + return; + } + //get the needed hashtable or create it from the groups hashtable ARC_Hashtable *groupHashtable = ARC_Hashtable_Get(chemical->groups, (void *)groupVariable->data); if(groupHashtable == NULL){ @@ -577,6 +593,8 @@ void ARC_Chemical_Create(ARC_Chemical **chemical){ ARC_Hashtable_Create(&((*chemical)->currentGroup), NULL, &keyCompareFn, &groupDataDestroyKeyValueFn); ARC_Hashtable_Add((*chemical)->groups, (void *)emptyCStr, (*chemical)->currentGroup); + (*chemical)->load = ARC_True; + //cleanup ARC_String_Destroy(languageString); } @@ -691,16 +709,22 @@ void *ARC_Chemical_GetWithCStr(ARC_Chemical *chemical, const char *element){ } void ARC_Chemical_LoadFromString(ARC_Chemical *chemical, ARC_String **string){ + chemical->load = ARC_True; ARC_Parser_Parse(chemical->parser, string); } void ARC_Chemical_LoadFromFile(ARC_Chemical *chemical, ARC_String *path){ + chemical->load = ARC_True; ARC_Parser_ParseFile(chemical->parser, path); } void ARC_Chemical_UnloadFromString(ARC_Chemical *chemical, ARC_String **string){ + chemical->load = ARC_False; + ARC_Parser_Parse(chemical->parser, string); } -void ARC_Chemical_UnloadFromFile(ARC_Chemical *chemical, ARC_String *data){ +void ARC_Chemical_UnloadFromFile(ARC_Chemical *chemical, ARC_String *path){ + chemical->load = ARC_False; + ARC_Parser_ParseFile(chemical->parser, path); } diff --git a/src/std/hashtable.c b/src/std/hashtable.c index e22fa9f..8ccb06d 100644 --- a/src/std/hashtable.c +++ b/src/std/hashtable.c @@ -406,6 +406,25 @@ void *ARC_Hashtable_Get(ARC_Hashtable *hashtable, void *key){ return NULL; } +uint32_t ARC_Hashtable_GetSize(ARC_Hashtable *hashtable){ + uint32_t size = 0; + + //loop through the vector and add iterate the size when the value is not null + for(uint32_t index = 0; index < hashtable->currentCapacity; index++){ + //get the current node + ARC_HashtableNode node = hashtable->nodes[index]; + + //skip past NULL keys + if(node.key == NULL){ + continue; + } + + size++; + } + + return size; +} + void ARC_Hashtable_RunIteration(ARC_Hashtable *hashtable, ARC_Hashtable_IteratorFn iteratorFn, void *userData){ //pass each non NULL nodes into an iteratorFn callback for(uint32_t index = 0; index < hashtable->currentCapacity; index++){ From e698fb54a26973efc50e7c01a7027061941ac555 Mon Sep 17 00:00:00 2001 From: herbglitch Date: Sun, 9 Mar 2025 06:25:20 -0600 Subject: [PATCH 02/10] chemical (config) unload function basic working, still needs more testing --- src/std/chemical.c | 21 +++++++++++++++++++-- tests/std/chemical.c | 5 +++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/std/chemical.c b/src/std/chemical.c index 4cb3578..0b3a280 100644 --- a/src/std/chemical.c +++ b/src/std/chemical.c @@ -431,8 +431,25 @@ void ARC_ChemicalData_RunGroupTag(ARC_ParserTagToken *tagToken, ARC_Chemical *ch //check if removing if(chemical->load == ARC_False){ - //TODO: check if the group is empty and remove it if it is - ARC_String_Destroy(groupVariable); + /* ~ ~ */ + childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 6); + + // -> | LAMBDA + if(childTagToken->token == NULL && ARC_Vector_GetSize(childTagToken->tagTokens) == 2){ + ARC_ParserTagToken *variableLines = (ARC_ParserTagToken *)ARC_Vector_Get(childTagToken->tagTokens, 1); + ARC_ChemicalData_RunVariableLinesTag(variableLines, chemical); + + //log error if it happens + if(arc_errno != 0){ + ARC_DEBUG_LOG_ERROR("ARC_ChemicalData_RunGroupTag(tagToken, chemical), chemical errored when trying to used parsed data for variable lines"); + } + } + + //remove an empty hashtable if it is now empty + if(ARC_Hashtable_GetSize(chemical->groups)){ + ARC_String_Destroy(groupVariable); + } + return; } diff --git a/tests/std/chemical.c b/tests/std/chemical.c index 319b63e..32e5045 100644 --- a/tests/std/chemical.c +++ b/tests/std/chemical.c @@ -81,6 +81,11 @@ ARC_TEST(Chemical_BasicTest){ int32_t testVal = *(int32_t *)ARC_Chemical_GetWithCStr(chemical, "test::test"); ARC_CHECK(testVal == 5); + ARC_Chemical_UnloadFromFile(chemical, tempString); + + void *nullVal = ARC_Chemical_GetWithCStr(chemical, "test::test"); + ARC_CHECK(nullVal == NULL); + //cleanup ARC_String_Destroy(tempString); ARC_Chemical_Destroy(chemical); From 990c22d27d357f4a033a23b40d8a3484e7bcd4e8 Mon Sep 17 00:00:00 2001 From: herbglitch Date: Mon, 10 Mar 2025 03:11:55 -0600 Subject: [PATCH 03/10] added life (entity component system) type, and changed chemical param to try to match more to archeus (or at least what I've read from wikipedia) --- CMakeLists.txt | 2 +- include/arc/std/chemical.h | 11 ++++----- src/std/chemical.c | 32 +++++++++++++++------------ tests/res/std/chemical/first.chemical | 2 ++ tests/std/chemical.c | 16 ++++++++++++++ tests/std/hashtable.c | 1 - 6 files changed, 43 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index db60061..0b1f06b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,7 +128,7 @@ if(ARCHEUS_TESTS) add_executable(tests tests/test.c - tests/std/chemical.c + #tests/std/chemical.c #tests/std/hashtable.c #tests/std/lexer.c #tests/std/parser.c diff --git a/include/arc/std/chemical.h b/include/arc/std/chemical.h index 7ccab74..aafdcfb 100644 --- a/include/arc/std/chemical.h +++ b/include/arc/std/chemical.h @@ -89,11 +89,11 @@ void ARC_Chemical_SetGroupWithCStr(ARC_Chemical *chemical, const char *groupName * @note name may be prefaced with :: to specify group * * @param[in] chemical ARC_Chemical to get value from - * @param[in] element name of a variable that has been read in + * @param[in] energy name of a variable that has been read in * * @return the stored element on success, or NULL on failure */ -void *ARC_Chemical_Get(ARC_Chemical *chemical, ARC_String *element); +void *ARC_Chemical_Get(ARC_Chemical *chemical, ARC_String *energy); /** * @brief get a value from a given keyname @@ -102,11 +102,11 @@ void *ARC_Chemical_Get(ARC_Chemical *chemical, ARC_String *element); * @note this function uses ARC_Chemical_Get so it shares error messages with that function * * @param[in] chemical ARC_Chemical to get value from - * @param[in] element name of a variable that has been read in + * @param[in] energy name of a variable that has been read in * * @return the stored element on success, or NULL on failure */ -void *ARC_Chemical_GetWithCStr(ARC_Chemical *chemical, const char *element); +void *ARC_Chemical_GetWithCStr(ARC_Chemical *chemical, const char *energy); /** * @brief TODO: write this @@ -194,8 +194,9 @@ void ARC_Chemical_UnloadFromFile(ARC_Chemical *chemical, ARC_String *data); #define ARC_CHEMICAL_STRING_CHARS 0x36 #define ARC_CHEMICAL_STRING_CHAR 0x37 #define ARC_CHEMICAL_ESCAPE_CHAR 0x38 -#define ARC_CHEMICAL_WHITESPACE 0x39 +#define ARC_CHEMICAL_NUMBER_SIGN 0x39 #define ARC_CHEMICAL_NUMBER_TAG 0x3A +#define ARC_CHEMICAL_WHITESPACE 0x3B #ifdef __cplusplus } diff --git a/src/std/chemical.c b/src/std/chemical.c index 0b3a280..59f60c2 100644 --- a/src/std/chemical.c +++ b/src/std/chemical.c @@ -250,6 +250,9 @@ uint32_t ARC_Chemical_GetStringIdFn(ARC_String *string){ if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CHEMICAL_ESCAPE_CHAR; } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CHEMICAL_NUMBER_SIGN; + } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CHEMICAL_NUMBER_TAG; } @@ -561,7 +564,7 @@ void ARC_Chemical_Create(ARC_Chemical **chemical){ " -> SPACE | TAB | LAMBDA\n" " -> \n" - " -> | | | \n" + " -> | | | \n" " -> OPEN_CURLY_BRACE CLOSE_CURLY_BRACE\n" " -> COMMA | \n" @@ -574,6 +577,7 @@ void ARC_Chemical_Create(ARC_Chemical **chemical){ " -> TAB | SPACE | BANG | HASH | DOLLAR | PERCENT | AMPERSAND | SINGLE_QUOTE | OPEN_PAREN | CLOSE_PAREN | ASTERISK | PLUS | COMMA | MINUS | PERIOD | SLASH | NUMBER | COLON | SEMICOLON | LESS_THAN | GREATER_THAN | EQUAL | QUESTION_MARK | AT | ALPHA_UPPER_CHAR | OPEN_BRACKET | CLOSE_BRACKET | CARET | UNDERSCORE | GRAVE | ALPHA_LOWER_CHAR | OPEN_CURLY_BRACE | VERTICAL_LINE | CLOSE_CURLY_BRACE | TILDE\n" " -> BACKSLASH BACKSLASH | BACKSLASH QUOTE | BACKSLASH ALPHA_UPPER_CHAR | BACKSLASH ALPHA_LOWER_CHAR\n" + " -> MINUS | \n" " -> NUMBER | NUMBER\n" " -> SPACE | TAB | NEWLINE | LAMBDA\n"; @@ -669,15 +673,15 @@ void ARC_Chemical_SetGroupWithCStr(ARC_Chemical *chemical, const char *groupName chemical->currentGroup = currentGroup; } -void *ARC_Chemical_Get(ARC_Chemical *chemical, ARC_String *element){ +void *ARC_Chemical_Get(ARC_Chemical *chemical, ARC_String *energy){ //check if the group separator exists - uint64_t startSeparatorIndex = ARC_String_FindCStringWithStrlen(element, ARC_CHEMICAL_GROUP_SEPARATOR); + uint64_t startSeparatorIndex = ARC_String_FindCStringWithStrlen(energy, ARC_CHEMICAL_GROUP_SEPARATOR); if(startSeparatorIndex == ~(uint64_t)0){ //use empty group chemical->currentGroup = ARC_Hashtable_Get(chemical->groups, (void *)ARC_CHEMICAL_DEFAULT_GROUP); //get the typeData and pass back the data without the cleanup function - ARC_ChemicalTypeData *typeData = (ARC_ChemicalTypeData *)ARC_Hashtable_Get(chemical->currentGroup, (void *)element->data); + ARC_ChemicalTypeData *typeData = (ARC_ChemicalTypeData *)ARC_Hashtable_Get(chemical->currentGroup, (void *)energy->data); if(typeData == NULL){ return NULL; } @@ -688,7 +692,7 @@ void *ARC_Chemical_Get(ARC_Chemical *chemical, ARC_String *element){ //get the group startSeparatorIndex--; ARC_String *groupString; - ARC_String_CopySubstring(&groupString, element, 0, startSeparatorIndex); + ARC_String_CopySubstring(&groupString, energy, 0, startSeparatorIndex); //set the group chemical->currentGroup = ARC_Hashtable_Get(chemical->groups, (void *)groupString->data); @@ -697,13 +701,13 @@ void *ARC_Chemical_Get(ARC_Chemical *chemical, ARC_String *element){ ARC_String_Destroy(groupString); //get the element - ARC_String *elementString; + ARC_String *energyString; startSeparatorIndex += strlen(ARC_CHEMICAL_GROUP_SEPARATOR); - ARC_String_CopySubstring(&elementString, element, startSeparatorIndex, element->length - startSeparatorIndex); + ARC_String_CopySubstring(&energyString, energy, startSeparatorIndex, energy->length - startSeparatorIndex); //this will either return the value or NULL - ARC_ChemicalTypeData *typeData = (ARC_ChemicalTypeData *)ARC_Hashtable_Get(chemical->currentGroup, (void *)elementString->data); - ARC_String_Destroy(elementString); + ARC_ChemicalTypeData *typeData = (ARC_ChemicalTypeData *)ARC_Hashtable_Get(chemical->currentGroup, (void *)energyString->data); + ARC_String_Destroy(energyString); if(typeData == NULL){ return NULL; } @@ -711,16 +715,16 @@ void *ARC_Chemical_Get(ARC_Chemical *chemical, ARC_String *element){ return typeData->data; } -void *ARC_Chemical_GetWithCStr(ARC_Chemical *chemical, const char *element){ +void *ARC_Chemical_GetWithCStr(ARC_Chemical *chemical, const char *energy){ //create and copy into ARC_String - ARC_String *elementString; - ARC_String_CreateWithStrlen(&elementString, (char *)element); + ARC_String *energyString; + ARC_String_CreateWithStrlen(&energyString, (char *)energy); //get the return value - void *returnValue = ARC_Chemical_Get(chemical, elementString); + void *returnValue = ARC_Chemical_Get(chemical, energyString); //cleanup - ARC_String_Destroy(elementString); + ARC_String_Destroy(energyString); return returnValue; } diff --git a/tests/res/std/chemical/first.chemical b/tests/res/std/chemical/first.chemical index 93e9209..392097c 100644 --- a/tests/res/std/chemical/first.chemical +++ b/tests/res/std/chemical/first.chemical @@ -1,3 +1,5 @@ group test { int32 test = 5; + + int32 test1 = -7; } diff --git a/tests/std/chemical.c b/tests/std/chemical.c index 32e5045..bcdc12c 100644 --- a/tests/std/chemical.c +++ b/tests/std/chemical.c @@ -8,8 +8,22 @@ static const char *testType = "int32"; void TEST_ChemicalType_CopyInt32Fn(void **type, ARC_ParserTagToken *parsedData, ARC_Chemical *chemical){ + //go into the tag + ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(parsedData->tagTokens, 0); + if(childTagToken->id != ARC_CHEMICAL_NUMBER_SIGN){ + arc_errno = ARC_ERRNO_DATA; + ARC_DEBUG_LOG_ERROR("TEST_ChemicalType_CopyInt32Fn(type, parsedData, chemical), parsed data was not a "); + *type = NULL; + return; + } + + //check if the first tag is a minus sign and create a string starting with that if it is + childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(childTagToken->tagTokens, 0); ARC_String *int32String; ARC_String_Create(&int32String, NULL, 0); + if(childTagToken->id == ARC_CHEMICAL_MINUS){ + ARC_String_AppendCStringWithStrlen(&int32String, "-"); + } ARC_ParserData_HelperRecurseStringAdd(&int32String, parsedData); @@ -80,6 +94,8 @@ ARC_TEST(Chemical_BasicTest){ int32_t testVal = *(int32_t *)ARC_Chemical_GetWithCStr(chemical, "test::test"); ARC_CHECK(testVal == 5); + testVal = *(int32_t *)ARC_Chemical_GetWithCStr(chemical, "test::test1"); + ARC_CHECK(testVal == -7); ARC_Chemical_UnloadFromFile(chemical, tempString); diff --git a/tests/std/hashtable.c b/tests/std/hashtable.c index 8a24890..2d1956b 100644 --- a/tests/std/hashtable.c +++ b/tests/std/hashtable.c @@ -83,7 +83,6 @@ ARC_TEST(Hashtable_Add_Get_Remove){ ARC_CHECK(5 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key7")); ARC_CHECK(6 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key8")); - TEST_Hashtable_Print(hashtable); ARC_Hashtable_Remove(hashtable, (void *)"key2"); ARC_CHECK(2 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key0")); From 67c69dac8d4c8ae1ac8f97e09664ab3ef230645a Mon Sep 17 00:00:00 2001 From: herbglitch Date: Mon, 10 Mar 2025 03:12:07 -0600 Subject: [PATCH 04/10] added life --- include/arc/std/life.h | 122 +++++++++++++++++++++++++++++++++++++++++ src/std/life.c | 0 tests/std/life.c | 0 3 files changed, 122 insertions(+) create mode 100644 include/arc/std/life.h create mode 100644 src/std/life.c create mode 100644 tests/std/life.c diff --git a/include/arc/std/life.h b/include/arc/std/life.h new file mode 100644 index 0000000..dc496ce --- /dev/null +++ b/include/arc/std/life.h @@ -0,0 +1,122 @@ +#ifndef ARC_STD_LIFE_H_ +#define ARC_STD_LIFE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "arc/std/bool.h" +#include + +/** + * @brief an entity component system type +*/ +typedef struct ARC_Vector ARC_Vector; + +/** + * @brief a callback that allows the user to define a way to check the data stored in a vector for a match + * + * @param[in] dataA the first data to check + * @param[in] dataB the second data to check + * + * @return ARC_True when dataA == dataB, and ARC_False otherwise +*/ +typedef ARC_Bool (* ARC_Vector_CompareDataFn)(void *dataA, void *dataB); + +/** + * @brief a callback that cleans up memory when it is removed from the vector + * + * @param[in] data the item to destroy +*/ +typedef void (* ARC_Vector_DestroyDataFn)(void *data); + +/** + * @brief creates an ARC_Vector which is an "expandable" array + * + * @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] vector ARC_Vector to initialize + * @param[in] compareDataFn a callback that checks if data stored in the array matches, + * if set to NULL and ARC_Vector_Remove is called, the pointer addresses will be compared + * @param[in] destroyDataFn a callback that frees an item on remove or clear, can be set to NULL to do nothing +*/ +void ARC_Vector_Create(ARC_Vector **vector, ARC_Vector_CompareDataFn *compareDataFn, ARC_Vector_DestroyDataFn *destroyDataFn); + +/** + * @brief destroys an ARC_Vector + * + * @note this will only free the items if destroyDataFn is passed in on creation + * + * @param[in] vector ARC_Vector to free +*/ +void ARC_Vector_Destroy(ARC_Vector *vector); + +/** + * @brief adds an item to an ARC_Vector + * + * @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_Vector to add to + * @param[in] data data that is being added +*/ +void ARC_Vector_Add(ARC_Vector *vector, void *data); + +/** + * @brief removes an item from a matching item in an ARC_Vector + * + * @note this function uses the ARC_Vector_CompareDataFn that the ARC_Vector was created with + * @note this function will not throw an error if there is no match + * @note this function will call ARC_Vector_RemoveIndex, so it's notes are also applicable to this function + * + * @param[in] vector ARC_Vector to remove from + * @param[in] data matching data to remove +*/ +void ARC_Vector_Remove(ARC_Vector *vector, void *data); + +/** + * @brief removes an item from an ARC_Vector at an index + * + * @note this function will error if trying to remove an index that is outside the bounds of the ARC_Vector + * @note this function will use ARC_Vector_DeleteDataFn if it was set in the ARC_Vector_Create function + * + * @param[in] vector ARC_Vector to remove from + * @param[in] index position of data to remove +*/ +void ARC_Vector_RemoveIndex(ARC_Vector *vector, uint32_t index); + +/** + * @brief clears all items from a vector + * + * @note this function will call ARC_Vector_RemoveIndex, so it's notes are also applicable to this function + * + * @param[in] vector ARC_Vector to clear +*/ +void ARC_Vector_Clear(ARC_Vector *vector); + +/** + * @brief gets the current size of an ARC_Vector as an unsigned 32 bit integer + * + * @param[in] vector ARC_Vector to get current size from + * + * @return the current size as a unsigned 32 bit integer +*/ +uint32_t ARC_Vector_GetSize(ARC_Vector *vector); + +/** + * @brief gets an item from an ARC_Vector at a position index + * + * @note this function will error if trying to get an index that is outside the bounds of the ARC_Vector + * + * @param[in] vector ARC_Vector to get data from + * @param[in] index position of data to get + * + * @return a void * item, or NULL on error +*/ +void *ARC_Vector_Get(ARC_Vector *vector, uint32_t index); + +#ifdef __cplusplus +} +#endif + +#endif // !ARC_STD_VECTOR_H_ diff --git a/src/std/life.c b/src/std/life.c new file mode 100644 index 0000000..e69de29 diff --git a/tests/std/life.c b/tests/std/life.c new file mode 100644 index 0000000..e69de29 From 30e8d94805dfbc253f5bbacae6e2f1fe86ebc053 Mon Sep 17 00:00:00 2001 From: herbglitch Date: Mon, 10 Mar 2025 03:13:08 -0600 Subject: [PATCH 05/10] added life --- include/arc/std/life.h | 109 +---------------------------------------- 1 file changed, 2 insertions(+), 107 deletions(-) diff --git a/include/arc/std/life.h b/include/arc/std/life.h index dc496ce..d11aab1 100644 --- a/include/arc/std/life.h +++ b/include/arc/std/life.h @@ -5,118 +5,13 @@ extern "C" { #endif -#include "arc/std/bool.h" -#include - /** * @brief an entity component system type */ -typedef struct ARC_Vector ARC_Vector; - -/** - * @brief a callback that allows the user to define a way to check the data stored in a vector for a match - * - * @param[in] dataA the first data to check - * @param[in] dataB the second data to check - * - * @return ARC_True when dataA == dataB, and ARC_False otherwise -*/ -typedef ARC_Bool (* ARC_Vector_CompareDataFn)(void *dataA, void *dataB); - -/** - * @brief a callback that cleans up memory when it is removed from the vector - * - * @param[in] data the item to destroy -*/ -typedef void (* ARC_Vector_DestroyDataFn)(void *data); - -/** - * @brief creates an ARC_Vector which is an "expandable" array - * - * @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] vector ARC_Vector to initialize - * @param[in] compareDataFn a callback that checks if data stored in the array matches, - * if set to NULL and ARC_Vector_Remove is called, the pointer addresses will be compared - * @param[in] destroyDataFn a callback that frees an item on remove or clear, can be set to NULL to do nothing -*/ -void ARC_Vector_Create(ARC_Vector **vector, ARC_Vector_CompareDataFn *compareDataFn, ARC_Vector_DestroyDataFn *destroyDataFn); - -/** - * @brief destroys an ARC_Vector - * - * @note this will only free the items if destroyDataFn is passed in on creation - * - * @param[in] vector ARC_Vector to free -*/ -void ARC_Vector_Destroy(ARC_Vector *vector); - -/** - * @brief adds an item to an ARC_Vector - * - * @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_Vector to add to - * @param[in] data data that is being added -*/ -void ARC_Vector_Add(ARC_Vector *vector, void *data); - -/** - * @brief removes an item from a matching item in an ARC_Vector - * - * @note this function uses the ARC_Vector_CompareDataFn that the ARC_Vector was created with - * @note this function will not throw an error if there is no match - * @note this function will call ARC_Vector_RemoveIndex, so it's notes are also applicable to this function - * - * @param[in] vector ARC_Vector to remove from - * @param[in] data matching data to remove -*/ -void ARC_Vector_Remove(ARC_Vector *vector, void *data); - -/** - * @brief removes an item from an ARC_Vector at an index - * - * @note this function will error if trying to remove an index that is outside the bounds of the ARC_Vector - * @note this function will use ARC_Vector_DeleteDataFn if it was set in the ARC_Vector_Create function - * - * @param[in] vector ARC_Vector to remove from - * @param[in] index position of data to remove -*/ -void ARC_Vector_RemoveIndex(ARC_Vector *vector, uint32_t index); - -/** - * @brief clears all items from a vector - * - * @note this function will call ARC_Vector_RemoveIndex, so it's notes are also applicable to this function - * - * @param[in] vector ARC_Vector to clear -*/ -void ARC_Vector_Clear(ARC_Vector *vector); - -/** - * @brief gets the current size of an ARC_Vector as an unsigned 32 bit integer - * - * @param[in] vector ARC_Vector to get current size from - * - * @return the current size as a unsigned 32 bit integer -*/ -uint32_t ARC_Vector_GetSize(ARC_Vector *vector); - -/** - * @brief gets an item from an ARC_Vector at a position index - * - * @note this function will error if trying to get an index that is outside the bounds of the ARC_Vector - * - * @param[in] vector ARC_Vector to get data from - * @param[in] index position of data to get - * - * @return a void * item, or NULL on error -*/ -void *ARC_Vector_Get(ARC_Vector *vector, uint32_t index); +typedef struct ARC_Life ARC_Life; #ifdef __cplusplus } #endif -#endif // !ARC_STD_VECTOR_H_ +#endif // !ARC_STD_LIFE_H_ From 04c89e46fe52db631dde2164007e15ee76621b63 Mon Sep 17 00:00:00 2001 From: herbglitch Date: Tue, 11 Mar 2025 00:41:17 -0600 Subject: [PATCH 06/10] renamed chemical to config, and renamed life to entity --- CMakeLists.txt | 6 +- include/arc/std/chemical.h | 205 ---- include/arc/std/config.h | 241 +++-- include/arc/std/life.h | 17 - src/std/chemical.c | 751 --------------- src/std/config.c | 1254 ++++++++++++++----------- src/std/life.c | 0 tests/res/std/chemical/first.chemical | 5 - tests/std/chemical.c | 108 --- tests/std/life.c | 0 10 files changed, 862 insertions(+), 1725 deletions(-) delete mode 100644 include/arc/std/chemical.h delete mode 100644 include/arc/std/life.h delete mode 100644 src/std/chemical.c delete mode 100644 src/std/life.c delete mode 100644 tests/res/std/chemical/first.chemical delete mode 100644 tests/std/chemical.c delete mode 100644 tests/std/life.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b1f06b..a984c52 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,8 @@ set(ARCHEUS_LINK_LIBRARIES # ~ ARCHEUS_SOURCES ~ # set(ARCHEUS_SOURCES - src/std/chemical.c + src/std/config.c + src/std/entity.c src/std/errno.c src/std/handler.c src/std/hashtable.c @@ -128,7 +129,8 @@ if(ARCHEUS_TESTS) add_executable(tests tests/test.c - #tests/std/chemical.c + tests/std/config.c + #tests/std/entity.c #tests/std/hashtable.c #tests/std/lexer.c #tests/std/parser.c diff --git a/include/arc/std/chemical.h b/include/arc/std/chemical.h deleted file mode 100644 index aafdcfb..0000000 --- a/include/arc/std/chemical.h +++ /dev/null @@ -1,205 +0,0 @@ -#ifndef ARC_STD_PARSER_CHEMICAL_H_ -#define ARC_STD_PARSER_CHEMICAL_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include "arc/std/parser.h" - -/** - * @brief the config type for archeus, loads in a config file which syntax is specified in the documentation - * @TODO: add documentation link here -*/ -typedef struct ARC_Chemical ARC_Chemical; - -/** - * @brief a function callback to create a type stored within a config -*/ -typedef void (* ARC_ChemicalType_CopyFn)(void **type, ARC_ParserTagToken *parsedData, ARC_Chemical *chemical); - -/** - * @brief a function callback to destroy a type -*/ -typedef void (* ARC_ChemicalType_DestroyFn)(void *type); - -/** - * @brief the functions for used for loading and unloading a type, the name will be the key of a hashtable -*/ -typedef struct ARC_ChemicalType { - ARC_ChemicalType_CopyFn copyFn; - ARC_ChemicalType_DestroyFn destroyFn; -} ARC_ChemicalType; - -/** - * @brief creates the arc config type (a type that loads in chemical files and can have types added to it) -*/ -void ARC_Chemical_Create(ARC_Chemical **chemical); - -/** - * @brief destroys an ARC_Chemical type -*/ -void ARC_Chemical_Destroy(ARC_Chemical *chemical); - -/** - * @brief adds creation and destruction functions for a new user provided type will be used for chemical load and unload functions - * - * @note this function uses ARC_Chemical_RegisterTypeWithCStr so it shares error messages with that function - * - * @param[in] chemical the ARC_Chemical to set the new type into - * @param[in] typeName the name of the type like "uint32" or "ARC_Rect" that will be read in from a chemical file - * @param[in] type the copy and destroy functions for the type used on load and unload -*/ -void ARC_Chemical_RegisterType(ARC_Chemical *chemical, ARC_String *typeName, ARC_ChemicalType type); - -/** - * @brief adds creation and destruction functions for a new user provided type - * - * @param[in] chemical the ARC_Chemical to set the new type into - * @param[in] typeName the name of the type like "uint32" or "ARC_Rect" that will be read in from a chemical file - * @param[in] type the copy and destroy functions for the type used on load and unload -*/ -void ARC_Chemical_RegisterTypeWithCStr(ARC_Chemical *chemical, const char *typeNameCStr, ARC_ChemicalType type); - -/** - * @brief sets current group in config - * - * @note ARC_Chemical_Get will use this set group - * @note this function uses ARC_Chemical_SetGroupWithCStr so it shares error messages with that function - * - * @param[in] chemical ARC_Config we are setting current group in - * @param[in] groupname name of group that will be set - */ -void ARC_Chemical_SetGroup(ARC_Chemical *chemical, ARC_String *groupName); - -/** - * @brief sets current group in config - * - * @note ARC_Chemical_Get will use this set group - * - * @param[in] chemical ARC_Config we are setting current group in - * @param[in] groupname name of group that will be set - */ -void ARC_Chemical_SetGroupWithCStr(ARC_Chemical *chemical, const char *groupName); - -/** - * @brief get a value from a given keyname - * - * @note name may be prefaced with :: to specify group - * - * @param[in] chemical ARC_Chemical to get value from - * @param[in] energy name of a variable that has been read in - * - * @return the stored element on success, or NULL on failure - */ -void *ARC_Chemical_Get(ARC_Chemical *chemical, ARC_String *energy); - -/** - * @brief get a value from a given keyname - * - * @note name may be prefaced with :: to specify group - * @note this function uses ARC_Chemical_Get so it shares error messages with that function - * - * @param[in] chemical ARC_Chemical to get value from - * @param[in] energy name of a variable that has been read in - * - * @return the stored element on success, or NULL on failure - */ -void *ARC_Chemical_GetWithCStr(ARC_Chemical *chemical, const char *energy); - -/** - * @brief TODO: write this -*/ -void ARC_Chemical_LoadFromString(ARC_Chemical *chemical, ARC_String **string); - -/** - * @brief TODO: write this -*/ -void ARC_Chemical_LoadFromFile(ARC_Chemical *chemical, ARC_String *path); - -/** - * @brief TODO: write this -*/ -void ARC_Chemical_UnloadFromString(ARC_Chemical *chemical, ARC_String **string); - -/** - * @brief TODO: write this -*/ -void ARC_Chemical_UnloadFromFile(ARC_Chemical *chemical, ARC_String *data); - -#define ARC_CHEMICAL_DEFAULT_GROUP " " -#define ARC_CHEMICAL_GROUP_TAG_NAME "group" -#define ARC_CHEMICAL_GROUP_SEPARATOR "::" - -//the grouping is based on the ascii table, but the ids are sequential to make finding tokens quicker (look at the lexer continious for more explanation) -#define ARC_CHEMICAL_TAB 0x01 -#define ARC_CHEMICAL_NEWLINE 0x02 - -#define ARC_CHEMICAL_SPACE 0x03 -#define ARC_CHEMICAL_BANG 0x04 -#define ARC_CHEMICAL_QUOTE 0x05 -#define ARC_CHEMICAL_HASH 0x06 -#define ARC_CHEMICAL_DOLLAR 0x07 -#define ARC_CHEMICAL_PERCENT 0x08 -#define ARC_CHEMICAL_AMPERSAND 0x09 -#define ARC_CHEMICAL_SINGLE_QUOTE 0x0A -#define ARC_CHEMICAL_OPEN_PAREN 0x0B -#define ARC_CHEMICAL_CLOSE_PAREN 0x0C -#define ARC_CHEMICAL_ASTERISK 0x0D -#define ARC_CHEMICAL_PLUS 0x0E -#define ARC_CHEMICAL_COMMA 0x0F -#define ARC_CHEMICAL_MINUS 0x10 -#define ARC_CHEMICAL_PERIOD 0x11 -#define ARC_CHEMICAL_SLASH 0x12 -#define ARC_CHEMICAL_NUMBER 0x13 - -#define ARC_CHEMICAL_COLON 0x14 -#define ARC_CHEMICAL_SEMICOLON 0x15 -#define ARC_CHEMICAL_LESS_THAN 0x16 -#define ARC_CHEMICAL_GREATER_THAN 0x17 -#define ARC_CHEMICAL_EQUAL 0x18 -#define ARC_CHEMICAL_QUESTION_MARK 0x19 -#define ARC_CHEMICAL_AT 0x1A -#define ARC_CHEMICAL_ALPHA_UPPER_CHAR 0x1B - -#define ARC_CHEMICAL_OPEN_BRACKET 0x1C -#define ARC_CHEMICAL_BACKSLASH 0x1D -#define ARC_CHEMICAL_CLOSE_BRACKET 0x1E -#define ARC_CHEMICAL_CARET 0x1F -#define ARC_CHEMICAL_UNDERSCORE 0x20 -#define ARC_CHEMICAL_GRAVE 0x21 -#define ARC_CHEMICAL_ALPHA_LOWER_CHAR 0x22 - -#define ARC_CHEMICAL_OPEN_CURLY_BRACE 0x23 -#define ARC_CHEMICAL_VERTICAL_LINE 0x24 -#define ARC_CHEMICAL_CLOSE_CURLY_BRACE 0x25 -#define ARC_CHEMICAL_TILDE 0x26 - -#define ARC_CHEMICAL_LANGUAGE 0x27 -#define ARC_CHEMICAL_GROUP 0x28 -#define ARC_CHEMICAL_GROUP_NAME 0x29 -#define ARC_CHEMICAL_GROUP_ARGS 0x2A -#define ARC_CHEMICAL_VARIABLE_LINES 0x2B -#define ARC_CHEMICAL_VARIABLE_LINE 0x2C -#define ARC_CHEMICAL_ALLOW_SPACE 0x2D -#define ARC_CHEMICAL_TYPE 0x2E -#define ARC_CHEMICAL_VALUE 0x2F -#define ARC_CHEMICAL_NESTED_VALUE 0x30 -#define ARC_CHEMICAL_VALUE_ARGS 0x31 -#define ARC_CHEMICAL_VARIABLE 0x32 -#define ARC_CHEMICAL_VARIABLE_NAME 0x33 -#define ARC_CHEMICAL_VARIABLE_CHAR 0x34 -#define ARC_CHEMICAL_STRING 0x35 -#define ARC_CHEMICAL_STRING_CHARS 0x36 -#define ARC_CHEMICAL_STRING_CHAR 0x37 -#define ARC_CHEMICAL_ESCAPE_CHAR 0x38 -#define ARC_CHEMICAL_NUMBER_SIGN 0x39 -#define ARC_CHEMICAL_NUMBER_TAG 0x3A -#define ARC_CHEMICAL_WHITESPACE 0x3B - -#ifdef __cplusplus -} -#endif - -#endif //ARC_STD_PARSER_CHEMICAL_H_ diff --git a/include/arc/std/config.h b/include/arc/std/config.h index bd8bd60..956e93a 100644 --- a/include/arc/std/config.h +++ b/include/arc/std/config.h @@ -5,122 +5,201 @@ extern "C" { #endif -#include "arc/std/hashtable.h" -#include "arc/std/string.h" #include - -#define ARC_KEY_BUCKET_SIZE 0x20 -#define ARC_GROUP_BUCKET_SIZE 0x20 -#define ARC_GROUP_DATA_BUCKET_SIZE 0x20 +#include "arc/std/parser.h" /** - * @brief a type that keeps permanice of data for when loading and unloading config files - */ + * @brief the config type for archeus, loads in a config file which syntax is specified in the documentation + * @TODO: add documentation link here +*/ typedef struct ARC_Config ARC_Config; /** - * @brief a function to read a key from string to a ARC_ConfigTypeTemplate - * - * @param config ARC_Config to store data to - * @param string ARC_String of data that is being read in - * @param value value that is read in - * - * @note use ARC_Config_StoreValue(ARC_Config *config, ARC_String *name, void *value); to store a value to the config - * if there is an error, set arc_errno - * - * @return 0 if value not a reference, 1 if value is a reference - */ -typedef uint8_t (* ARC_ConfigKeyRead)(ARC_Config* config, ARC_String *string, void **value); - -/** - * @brief a function to delete a value from a key in ARC_Config - * - * @param config ARC_Config that can be used to check for references in data - * @param value pointer of data to be deleted - * - * @note this function can be NULL if memory does not need to be cleaned for this type - * if there is an error, set arc_errno - */ -typedef void (* ARC_ConfigKeyDelete)(ARC_Config* config, ARC_String *string, void *value); - -/** - * @brief adds a usable key to ARC_Config - * - * @param config ARC_Config to add keys to - * @param type string of key type - * @param keyRead function for reading/creating key from string - * @param keyDelete function for deleting stored key - */ -void ARC_Config_AddKey(ARC_Config *config, ARC_String *type, ARC_ConfigKeyRead keyRead, ARC_ConfigKeyDelete keyDelete); - -/** - * @brief adds a key from a cstring - * @param config ARC_Config to add keys to - * @param type cstring of key type - * @param length length of cstring - * @param keyRead function for reading/creating key from string - * @param keyDelete function for deleting stored key + * @brief a function callback to create a type stored within a config */ -//void ARC_Config_AddKeyCString(ARC_Config *config, const char *type, uint64_t length, ARC_ConfigKeyRead keyRead, ARC_ConfigKeyDelete keyDelete); +typedef void (* ARC_ConfigType_CopyFn)(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config); /** - * @brief external callback to add keys to config - */ -typedef void (* ARC_ConfigKey_AddFunc)(ARC_Config *config); + * @brief a function callback to destroy a type +*/ +typedef void (* ARC_ConfigType_DestroyFn)(void *type); /** - * @brief creates ARC_Config type - * - * @param config ARC_Config to initialize - */ + * @brief the functions for used for loading and unloading a type, the name will be the key of a hashtable +*/ +typedef struct ARC_ConfigType { + ARC_ConfigType_CopyFn copyFn; + ARC_ConfigType_DestroyFn destroyFn; +} ARC_ConfigType; + +/** + * @brief creates the arc config type (a type that loads in config files and can have types added to it) +*/ void ARC_Config_Create(ARC_Config **config); /** - * @brief destroys ARC_Config type - */ + * @brief destroys an ARC_Config type +*/ void ARC_Config_Destroy(ARC_Config *config); +/** + * @brief adds creation and destruction functions for a new user provided type will be used for config load and unload functions + * + * @note this function uses ARC_Config_RegisterTypeWithCStr so it shares error messages with that function + * + * @param[in] config the ARC_Config to set the new type into + * @param[in] typeName the name of the type like "uint32" or "ARC_Rect" that will be read in from a config file + * @param[in] type the copy and destroy functions for the type used on load and unload +*/ +void ARC_Config_RegisterType(ARC_Config *config, ARC_String *typeName, ARC_ConfigType type); + +/** + * @brief adds creation and destruction functions for a new user provided type + * + * @param[in] config the ARC_Config to set the new type into + * @param[in] typeName the name of the type like "uint32" or "ARC_Rect" that will be read in from a config file + * @param[in] type the copy and destroy functions for the type used on load and unload +*/ +void ARC_Config_RegisterTypeWithCStr(ARC_Config *config, const char *typeNameCStr, ARC_ConfigType type); + +/** + * @brief sets current group in config + * + * @note ARC_Config_Get will use this set group + * @note this function uses ARC_Config_SetGroupWithCStr so it shares error messages with that function + * + * @param[in] config ARC_Config we are setting current group in + * @param[in] groupname name of group that will be set + */ +void ARC_Config_SetGroup(ARC_Config *config, ARC_String *groupName); + /** * @brief sets current group in config * * @note ARC_Config_Get will use this set group * - * @param config ARC_Config we are setting current group in - * @param groupname name of group that will be set + * @param[in] config ARC_Config we are setting current group in + * @param[in] groupname name of group that will be set */ -void ARC_Config_SetGroup(ARC_Config *config, ARC_String *groupname); +void ARC_Config_SetGroupWithCStr(ARC_Config *config, const char *groupName); + +/** + * @brief get a value from a given name + * + * @note name should be prefaced with :: to specify group + * + * @param[in] config ARC_Config to get value from + * @param[in] name name of a variable that has been read in + * + * @return the stored element on success, or NULL on failure + */ +void *ARC_Config_Get(ARC_Config *config, ARC_String *name); /** * @brief get a value from a given keyname * - * @note name may be prefaced with :: to specify group + * @note name should be prefaced with :: to specify group + * @note this function uses ARC_Config_Get so it shares error messages with that function * - * @param config ARC_Config to get value from - * @param keyname name of key to get from config - * @param value data retrieved from config + * @param[in] config ARC_Config to get value from + * @param[in] name name of a variable that has been read in + * + * @return the stored element on success, or NULL on failure */ -//void ARC_Config_Get(ARC_Config *config, ARC_String *keyname, void **value); +void *ARC_Config_GetWithCStr(ARC_Config *config, const char *name); /** - * @brief commands that can be used in ARC_Config_FileIO - */ -#define ARC_CONFIG_FILE_IO_LOAD 0x00 -#define ARC_CONFIG_FILE_IO_UNLOAD 0x01 + * @brief TODO: write this +*/ +void ARC_Config_LoadFromString(ARC_Config *config, ARC_String **string); /** - * @brief handles file io for ARC_Config Type - * - * @param config ARC_Config where io operations will take place - * @param path file path for io - */ -void ARC_Config_FileIO(ARC_Config *config, ARC_String *path, uint8_t command); + * @brief TODO: write this +*/ +void ARC_Config_LoadFromFile(ARC_Config *config, ARC_String *path); + +/** + * @brief TODO: write this +*/ +void ARC_Config_UnloadFromString(ARC_Config *config, ARC_String **string); + +/** + * @brief TODO: write this +*/ +void ARC_Config_UnloadFromFile(ARC_Config *config, ARC_String *data); + +#define ARC_CONFIG_DEFAULT_GROUP " " +#define ARC_CONFIG_GROUP_TAG_NAME "group" +#define ARC_CONFIG_GROUP_SEPARATOR "::" + +//the grouping is based on the ascii table, but the ids are sequential to make finding tokens quicker (look at the lexer continious for more explanation) +#define ARC_CONFIG_TAB 0x01 +#define ARC_CONFIG_NEWLINE 0x02 + +#define ARC_CONFIG_SPACE 0x03 +#define ARC_CONFIG_BANG 0x04 +#define ARC_CONFIG_QUOTE 0x05 +#define ARC_CONFIG_HASH 0x06 +#define ARC_CONFIG_DOLLAR 0x07 +#define ARC_CONFIG_PERCENT 0x08 +#define ARC_CONFIG_AMPERSAND 0x09 +#define ARC_CONFIG_SINGLE_QUOTE 0x0A +#define ARC_CONFIG_OPEN_PAREN 0x0B +#define ARC_CONFIG_CLOSE_PAREN 0x0C +#define ARC_CONFIG_ASTERISK 0x0D +#define ARC_CONFIG_PLUS 0x0E +#define ARC_CONFIG_COMMA 0x0F +#define ARC_CONFIG_MINUS 0x10 +#define ARC_CONFIG_PERIOD 0x11 +#define ARC_CONFIG_SLASH 0x12 +#define ARC_CONFIG_NUMBER 0x13 + +#define ARC_CONFIG_COLON 0x14 +#define ARC_CONFIG_SEMICOLON 0x15 +#define ARC_CONFIG_LESS_THAN 0x16 +#define ARC_CONFIG_GREATER_THAN 0x17 +#define ARC_CONFIG_EQUAL 0x18 +#define ARC_CONFIG_QUESTION_MARK 0x19 +#define ARC_CONFIG_AT 0x1A +#define ARC_CONFIG_ALPHA_UPPER_CHAR 0x1B + +#define ARC_CONFIG_OPEN_BRACKET 0x1C +#define ARC_CONFIG_BACKSLASH 0x1D +#define ARC_CONFIG_CLOSE_BRACKET 0x1E +#define ARC_CONFIG_CARET 0x1F +#define ARC_CONFIG_UNDERSCORE 0x20 +#define ARC_CONFIG_GRAVE 0x21 +#define ARC_CONFIG_ALPHA_LOWER_CHAR 0x22 + +#define ARC_CONFIG_OPEN_CURLY_BRACE 0x23 +#define ARC_CONFIG_VERTICAL_LINE 0x24 +#define ARC_CONFIG_CLOSE_CURLY_BRACE 0x25 +#define ARC_CONFIG_TILDE 0x26 + +#define ARC_CONFIG_LANGUAGE 0x27 +#define ARC_CONFIG_GROUP 0x28 +#define ARC_CONFIG_GROUP_NAME 0x29 +#define ARC_CONFIG_GROUP_ARGS 0x2A +#define ARC_CONFIG_VARIABLE_LINES 0x2B +#define ARC_CONFIG_VARIABLE_LINE 0x2C +#define ARC_CONFIG_ALLOW_SPACE 0x2D +#define ARC_CONFIG_TYPE 0x2E +#define ARC_CONFIG_VALUE 0x2F +#define ARC_CONFIG_NESTED_VALUE 0x30 +#define ARC_CONFIG_VALUE_ARGS 0x31 +#define ARC_CONFIG_VARIABLE 0x32 +#define ARC_CONFIG_VARIABLE_NAME 0x33 +#define ARC_CONFIG_VARIABLE_CHAR 0x34 +#define ARC_CONFIG_STRING 0x35 +#define ARC_CONFIG_STRING_CHARS 0x36 +#define ARC_CONFIG_STRING_CHAR 0x37 +#define ARC_CONFIG_ESCAPE_CHAR 0x38 +#define ARC_CONFIG_NUMBER_SIGN 0x39 +#define ARC_CONFIG_NUMBER_TAG 0x3A +#define ARC_CONFIG_WHITESPACE 0x3B #ifdef __cplusplus } #endif #endif //ARC_STD_CONFIG_H_ - -#ifdef ARC_DEFAULT_CONFIG -#include "defaults/config.h" -#endif //ARC_DEFAULT_CONFIG diff --git a/include/arc/std/life.h b/include/arc/std/life.h deleted file mode 100644 index d11aab1..0000000 --- a/include/arc/std/life.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef ARC_STD_LIFE_H_ -#define ARC_STD_LIFE_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief an entity component system type -*/ -typedef struct ARC_Life ARC_Life; - -#ifdef __cplusplus -} -#endif - -#endif // !ARC_STD_LIFE_H_ diff --git a/src/std/chemical.c b/src/std/chemical.c deleted file mode 100644 index 59f60c2..0000000 --- a/src/std/chemical.c +++ /dev/null @@ -1,751 +0,0 @@ -#include "arc/std/chemical.h" -#include "arc/std/parser/helpers.h" -#include "arc/std/bool.h" -#include "arc/std/errno.h" -#include "arc/std/hashtable.h" -#include "arc/std/parser.h" -#include -#include -#include -#include - -struct ARC_Chemical { - ARC_Parser *parser; - - ARC_Hashtable *types; - - ARC_Hashtable *groups; - ARC_Hashtable *currentGroup; - - ARC_Bool load; -}; - -typedef struct ARC_ChemicalTypeData { - void *data; - ARC_ChemicalType_DestroyFn destroyFn; -} ARC_ChemicalTypeData; - -void ARC_Chemical_InitLexerRulesFn(ARC_Lexer *lexer){ - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_TAB , '\t')); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_NEWLINE, '\n')); - - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_SPACE , ' ' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_BANG , '!' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_QUOTE , '"' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_HASH , '#' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_DOLLAR , '$' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_PERCENT , '%' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_AMPERSAND , '&' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_SINGLE_QUOTE, '\'')); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_OPEN_PAREN , '(' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_CLOSE_PAREN , ')' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_ASTERISK , '*' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_PLUS , '+' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_COMMA , ',' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_MINUS , '-' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_PERIOD , '.' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_SLASH , '/' )); - - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharOrBetween(ARC_CHEMICAL_NUMBER , '0', '9')); - - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_COLON , ':')); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_SEMICOLON , ';')); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_LESS_THAN , '<')); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_GREATER_THAN , '>')); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_EQUAL , '=')); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_QUESTION_MARK, '?')); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_AT , '@')); - - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharOrBetween(ARC_CHEMICAL_ALPHA_UPPER_CHAR, 'A', 'Z')); - - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_OPEN_BRACKET , '[' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_BACKSLASH , '\\')); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_CLOSE_BRACKET, ']' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_CARET , '^' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_UNDERSCORE , '_' )); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_GRAVE , '`' )); - - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharOrBetween(ARC_CHEMICAL_ALPHA_LOWER_CHAR, 'a', 'z')); - - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_OPEN_CURLY_BRACE , '{')); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_VERTICAL_LINE , '|')); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_CLOSE_CURLY_BRACE, '}')); - ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_TILDE , '~')); -} - -uint32_t ARC_Chemical_GetStringIdFn(ARC_String *string){ - if(ARC_String_EqualsCStringWithStrlen(string, "LAMBDA")){ - return ARC_PARSER_TAG_LAMBDA; - } - if(ARC_String_EqualsCStringWithStrlen(string, "TAB")){ - return ARC_CHEMICAL_TAB; - } - if(ARC_String_EqualsCStringWithStrlen(string, "NEWLINE")){ - return ARC_CHEMICAL_NEWLINE; - } - - if(ARC_String_EqualsCStringWithStrlen(string, "SPACE")){ - return ARC_CHEMICAL_SPACE; - } - if(ARC_String_EqualsCStringWithStrlen(string, "BANG")){ - return ARC_CHEMICAL_BANG; - } - if(ARC_String_EqualsCStringWithStrlen(string, "QUOTE")){ - return ARC_CHEMICAL_QUOTE; - } - if(ARC_String_EqualsCStringWithStrlen(string, "HASH")){ - return ARC_CHEMICAL_HASH; - } - if(ARC_String_EqualsCStringWithStrlen(string, "DOLLAR")){ - return ARC_CHEMICAL_DOLLAR; - } - if(ARC_String_EqualsCStringWithStrlen(string, "PERCENT")){ - return ARC_CHEMICAL_PERCENT; - } - if(ARC_String_EqualsCStringWithStrlen(string, "AMPERSAND")){ - return ARC_CHEMICAL_AMPERSAND; - } - if(ARC_String_EqualsCStringWithStrlen(string, "SINGLE_QUOTE")){ - return ARC_CHEMICAL_SINGLE_QUOTE; - } - if(ARC_String_EqualsCStringWithStrlen(string, "OPEN_PAREN")){ - return ARC_CHEMICAL_OPEN_PAREN; - } - if(ARC_String_EqualsCStringWithStrlen(string, "CLOSE_PAREN")){ - return ARC_CHEMICAL_CLOSE_PAREN; - } - if(ARC_String_EqualsCStringWithStrlen(string, "ASTERISK")){ - return ARC_CHEMICAL_ASTERISK; - } - if(ARC_String_EqualsCStringWithStrlen(string, "PLUS")){ - return ARC_CHEMICAL_PLUS; - } - if(ARC_String_EqualsCStringWithStrlen(string, "COMMA")){ - return ARC_CHEMICAL_COMMA; - } - if(ARC_String_EqualsCStringWithStrlen(string, "MINUS")){ - return ARC_CHEMICAL_MINUS; - } - if(ARC_String_EqualsCStringWithStrlen(string, "PERIOD")){ - return ARC_CHEMICAL_PERIOD; - } - if(ARC_String_EqualsCStringWithStrlen(string, "SLASH")){ - return ARC_CHEMICAL_SLASH; - } - if(ARC_String_EqualsCStringWithStrlen(string, "NUMBER")){ - return ARC_CHEMICAL_NUMBER; - } - - if(ARC_String_EqualsCStringWithStrlen(string, "COLON")){ - return ARC_CHEMICAL_COLON; - } - if(ARC_String_EqualsCStringWithStrlen(string, "SEMICOLON")){ - return ARC_CHEMICAL_SEMICOLON; - } - if(ARC_String_EqualsCStringWithStrlen(string, "LESS_THAN")){ - return ARC_CHEMICAL_LESS_THAN; - } - if(ARC_String_EqualsCStringWithStrlen(string, "GREATER_THAN")){ - return ARC_CHEMICAL_GREATER_THAN; - } - if(ARC_String_EqualsCStringWithStrlen(string, "EQUAL")){ - return ARC_CHEMICAL_EQUAL; - } - if(ARC_String_EqualsCStringWithStrlen(string, "QUESTION_MARK")){ - return ARC_CHEMICAL_QUESTION_MARK; - } - if(ARC_String_EqualsCStringWithStrlen(string, "AT")){ - return ARC_CHEMICAL_AT; - } - if(ARC_String_EqualsCStringWithStrlen(string, "ALPHA_UPPER_CHAR")){ - return ARC_CHEMICAL_ALPHA_UPPER_CHAR; - } - - if(ARC_String_EqualsCStringWithStrlen(string, "OPEN_BRACKET")){ - return ARC_CHEMICAL_OPEN_BRACKET; - } - if(ARC_String_EqualsCStringWithStrlen(string, "BACKSLASH")){ - return ARC_CHEMICAL_BACKSLASH; - } - if(ARC_String_EqualsCStringWithStrlen(string, "CLOSE_BRACKET")){ - return ARC_CHEMICAL_CLOSE_BRACKET; - } - if(ARC_String_EqualsCStringWithStrlen(string, "CARET")){ - return ARC_CHEMICAL_CARET; - } - if(ARC_String_EqualsCStringWithStrlen(string, "UNDERSCORE")){ - return ARC_CHEMICAL_UNDERSCORE; - } - if(ARC_String_EqualsCStringWithStrlen(string, "GRAVE")){ - return ARC_CHEMICAL_GRAVE; - } - if(ARC_String_EqualsCStringWithStrlen(string, "ALPHA_LOWER_CHAR")){ - return ARC_CHEMICAL_ALPHA_LOWER_CHAR; - } - - if(ARC_String_EqualsCStringWithStrlen(string, "OPEN_CURLY_BRACE")){ - return ARC_CHEMICAL_OPEN_CURLY_BRACE; - } - if(ARC_String_EqualsCStringWithStrlen(string, "VERTICAL_LINE")){ - return ARC_CHEMICAL_VERTICAL_LINE; - } - if(ARC_String_EqualsCStringWithStrlen(string, "CLOSE_CURLY_BRACE")){ - return ARC_CHEMICAL_CLOSE_CURLY_BRACE; - } - if(ARC_String_EqualsCStringWithStrlen(string, "TILDE")){ - return ARC_CHEMICAL_TILDE; - } - - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_LANGUAGE; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_GROUP; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_GROUP_NAME; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_GROUP_ARGS; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_VARIABLE_LINES; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_VARIABLE_LINE; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_ALLOW_SPACE; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_TYPE; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_VALUE; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_NESTED_VALUE; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_VALUE_ARGS; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_VARIABLE; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_VARIABLE_NAME; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_VARIABLE_CHAR; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_STRING; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_STRING_CHARS; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_STRING_CHAR; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_ESCAPE_CHAR; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_NUMBER_SIGN; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_NUMBER_TAG; - } - if(ARC_String_EqualsCStringWithStrlen(string, "")){ - return ARC_CHEMICAL_WHITESPACE; - } - - return ~(uint32_t)0; -} - -//private function to check hashtable keys used by chemical -ARC_Bool ARC_Chemical_HashtableKeyCompareFn(void *key1, void *key2){ - return (ARC_Bool)strcmp((const char *)key1, (const char *)key2) == 0; -} - -//private function to clean up types -void ARC_Chemical_TypeHashtableDestroyKeyValueFn(void *key, void *value){ - free((char *)key); - free((ARC_ChemicalType *)value); -} - -//private function to clean up groups -void ARC_Chemical_GroupHashtableDestroyKeyValueFn(void *key, void *value){ - free((char *)key); - ARC_Hashtable_Destroy((ARC_Hashtable *)value); -} - -//private function to clean up goup data -void ARC_Chemical_GroupDataHashtableDestroyKeyValueFn(void *key, void *value){ - free((char *)key); - - ARC_ChemicalTypeData *typeData = (ARC_ChemicalTypeData *)value; - typeData->destroyFn(typeData->data); - free(typeData); -} - -// -> EQUAL SEMICOLON -void ARC_ChemicalData_RunVariableLineTag(ARC_ParserTagToken *tagToken, ARC_Chemical *chemical){ - //skip whitespace and check for group name - ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 1); - - //get the type - ARC_String *typeString; - ARC_String_Create(&typeString, NULL, 0); - ARC_ParserData_HelperRecurseStringAdd(&typeString, childTagToken); - - //check if type exists in the types hashtable - ARC_ChemicalType *type = (ARC_ChemicalType *)ARC_Hashtable_Get(chemical->types, typeString->data); - if(type == NULL){ - //throw an error and return - arc_errno = ARC_ERRNO_DATA; - ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ChemicalData_RunVariableLineTag(tagToken, chemical), type \"%s\" was not registered to chemical", typeString->data); - ARC_String_Destroy(typeString); - return; - } - - //cleanup - ARC_String_Destroy(typeString); - - //get the variable - childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 3); - ARC_String *variableString; - ARC_String_Create(&variableString, NULL, 0); - ARC_ParserData_HelperRecurseStringAdd(&variableString, childTagToken); - - //check if removing - if(chemical->load == ARC_False){ - ARC_Hashtable_Remove(chemical->currentGroup, (void *)variableString->data); - ARC_String_Destroy(variableString); - return; - } - - //check to see if the current variable is already in the current group hashtable - ARC_ChemicalTypeData *typeData = (ARC_ChemicalTypeData *)ARC_Hashtable_Get(chemical->currentGroup, variableString->data); - if(typeData != NULL){ - //there is already a value so throw an error and return - arc_errno = ARC_ERRNO_DATA; - ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ChemicalData_RunVariableLineTag(tagToken, chemical), variable \"%s\" already registered to the current group", variableString->data); - ARC_String_Destroy(variableString); - return; - } - - //copy the string into a cstring that will be stored in the hashtable - char *elementVariableCStr = malloc(sizeof(char) * (variableString->length + 1)); - strncpy(elementVariableCStr, variableString->data, variableString->length); - elementVariableCStr[variableString->length] = '\0'; - ARC_String_Destroy(variableString); - - //get - childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 7); - - //check if is a reference - ARC_String *valueString; - ARC_String_Create(&valueString, NULL, 0); - ARC_ParserData_HelperRecurseStringAdd(&valueString, childTagToken); - void *value = ARC_Hashtable_Get(chemical->currentGroup, valueString); - ARC_String_Destroy(valueString); - - //create where to store either the reference or type data - typeData = (ARC_ChemicalTypeData *)malloc(sizeof(ARC_ChemicalTypeData)); - if(value != NULL){ - //point to the already stored data - typeData->data = value; - typeData->destroyFn = NULL; - - //add to the current group hashtable - ARC_Hashtable_Add(chemical->currentGroup, (void *)elementVariableCStr, (void *)typeData); - return; - } - - //passed the parsed value into the copy type function and set the destroy function - type->copyFn(&(typeData->data), childTagToken, chemical); - typeData->destroyFn = type->destroyFn; - - //add to the current group hashtable - ARC_Hashtable_Add(chemical->currentGroup, (void *)elementVariableCStr, (void *)typeData); -} - -// -> | -void ARC_ChemicalData_RunVariableLinesTag(ARC_ParserTagToken *tagToken, ARC_Chemical *chemical){ -//loop through the tags either going to the next line or the next body - for(uint32_t index = 0; index < ARC_Vector_GetSize(tagToken->tagTokens); index++){ - ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, index); - - switch(childTagToken->id){ - //recuse to run the next line - case ARC_CHEMICAL_VARIABLE_LINES: - ARC_ChemicalData_RunVariableLinesTag(childTagToken, chemical); - if(arc_errno != 0){ - ARC_DEBUG_LOG_ERROR("ARC_ChemicalData_RunVariableLinesTag(tagToken, chemical), chemical errored when trying to used parsed data for variable lines"); - return; - } - continue; - - //recurse into a variable line tag - case ARC_CHEMICAL_VARIABLE_LINE: - ARC_ChemicalData_RunVariableLineTag(childTagToken, chemical); - if(arc_errno != 0){ - ARC_DEBUG_LOG_ERROR("ARC_ChemicalData_RunVariableLinesTag(tagToken, chemical), chemical errored when trying to used parsed data for variable line"); - return; - } - continue; - - //this is for whitespace and any oddities - default: - continue; - } - } -} - -// -> OPEN_CURLY_BRACE CLOSE_CURLY_BRACE -void ARC_ChemicalData_RunGroupTag(ARC_ParserTagToken *tagToken, ARC_Chemical *chemical){ - //skip whitespace and check for group name - ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 1); - - /* ~ ~ */ - //get the group name and check if it is named "group" - //NOTE: this check may be usedful in the future if there is different functionality for group like tag names - ARC_String *groupName; - ARC_String_Create(&groupName, NULL, 0); - ARC_ParserData_HelperRecurseStringAdd(&groupName, childTagToken); - if(ARC_String_EqualsCStringWithStrlen(groupName, ARC_CHEMICAL_GROUP_TAG_NAME) == ARC_False){ - //throw an error and return - arc_errno = ARC_ERRNO_DATA; - ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ChemicalData_RunGroupTag(tagToken, chemical), chemical contained keyword \"%s\" instead of using the correct keyword: \"%s\" ", groupName->data, ARC_CHEMICAL_GROUP_TAG_NAME); - ARC_String_Destroy(groupName); - return; - } - - //cleanup - ARC_String_Destroy(groupName); - - /* ~ ~ */ - //get the group's variable name - childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 3); - ARC_String *groupVariable; - ARC_String_Create(&groupVariable, NULL, 0); - ARC_ParserData_HelperRecurseStringAdd(&groupVariable, childTagToken); - - //check if removing - if(chemical->load == ARC_False){ - /* ~ ~ */ - childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 6); - - // -> | LAMBDA - if(childTagToken->token == NULL && ARC_Vector_GetSize(childTagToken->tagTokens) == 2){ - ARC_ParserTagToken *variableLines = (ARC_ParserTagToken *)ARC_Vector_Get(childTagToken->tagTokens, 1); - ARC_ChemicalData_RunVariableLinesTag(variableLines, chemical); - - //log error if it happens - if(arc_errno != 0){ - ARC_DEBUG_LOG_ERROR("ARC_ChemicalData_RunGroupTag(tagToken, chemical), chemical errored when trying to used parsed data for variable lines"); - } - } - - //remove an empty hashtable if it is now empty - if(ARC_Hashtable_GetSize(chemical->groups)){ - ARC_String_Destroy(groupVariable); - } - - return; - } - - //get the needed hashtable or create it from the groups hashtable - ARC_Hashtable *groupHashtable = ARC_Hashtable_Get(chemical->groups, (void *)groupVariable->data); - if(groupHashtable == NULL){ - //copy the string into a cstring that will be stored in the hashtable - char *groupVariableCStr = malloc(sizeof(char) * (groupVariable->length + 1)); - strncpy(groupVariableCStr, groupVariable->data, groupVariable->length); - groupVariableCStr[groupVariable->length] = '\0'; - - //create the hashtable with the given group name key - ARC_Hashtable_KeyCompareFn keyCompareFn = ARC_Chemical_HashtableKeyCompareFn; - ARC_Hashtable_DestroyKeyValueFn groupDataDestroyKeyValueFn = ARC_Chemical_GroupDataHashtableDestroyKeyValueFn; - ARC_Hashtable_Create(&groupHashtable, NULL, &keyCompareFn, &groupDataDestroyKeyValueFn); - ARC_Hashtable_Add(chemical->groups, (void *)groupVariableCStr, (void *)groupHashtable); - } - - //cleanup - ARC_String_Destroy(groupVariable); - - //set the current group to the group just created or found - chemical->currentGroup = groupHashtable; - - /* ~ ~ */ - childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 6); - - // -> | LAMBDA - if(childTagToken->token == NULL && ARC_Vector_GetSize(childTagToken->tagTokens) == 2){ - ARC_ParserTagToken *variableLines = (ARC_ParserTagToken *)ARC_Vector_Get(childTagToken->tagTokens, 1); - ARC_ChemicalData_RunVariableLinesTag(variableLines, chemical); - - //log error if it happens, but as setting the group back is the last thing we shouldn't return - if(arc_errno != 0){ - ARC_DEBUG_LOG_ERROR("ARC_ChemicalData_RunGroupTag(tagToken, chemical), chemical errored when trying to used parsed data for variable lines"); - } - } - - /* ~ reset current group ~ */ - chemical->currentGroup = ARC_Hashtable_Get(chemical->groups, (void *)ARC_CHEMICAL_DEFAULT_GROUP); -} - -// -> | | -void ARC_ChemicalData_RunLanguageTag(ARC_ParserTagToken *tagToken, ARC_Chemical *chemical){ - //loop through the tags either going to the next language, group, or variable lines - for(uint32_t index = 0; index < ARC_Vector_GetSize(tagToken->tagTokens); index++){ - ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, index); - - switch(childTagToken->id){ - //recuse to run the next line - case ARC_CHEMICAL_LANGUAGE: - ARC_ChemicalData_RunLanguageTag(childTagToken, chemical); - continue; - - //recurse into a group tag - case ARC_CHEMICAL_GROUP: - ARC_ChemicalData_RunGroupTag(childTagToken, chemical); - if(arc_errno != 0){ - ARC_DEBUG_LOG_ERROR("ARC_ChemicalData_RunLanguageTag(tagToken, chemical), chemical errored when trying to used parsed data for a group"); - return; - } - continue; - - //recurse through variable lines - case ARC_CHEMICAL_VARIABLE_LINES: - ARC_ChemicalData_RunVariableLinesTag(childTagToken, chemical); - ARC_ChemicalData_RunGroupTag(childTagToken, chemical); - if(arc_errno != 0){ - ARC_DEBUG_LOG_ERROR("ARC_ChemicalData_RunLanguageTag(tagToken, chemical), chemical errored when trying to used parsed data for variable lines"); - return; - } - continue; - - //this is for whitespace and any oddities - default: - continue; - } - } -} - -void ARC_ChemicalData_CreateFn(void **data, ARC_ParserTagToken *parsedData, void *userData){ - *data = NULL; - if(parsedData == NULL || userData == NULL){ - //TODO: error here? - *data = NULL; - return; - } - - ARC_ChemicalData_RunLanguageTag(parsedData, (ARC_Chemical *)userData); -} - -void ARC_ChemicalData_DestroyFn(void *data, ARC_Bool clear, void *userData){ - return; -} - -void ARC_Chemical_Create(ARC_Chemical **chemical){ - *chemical = (ARC_Chemical *)malloc(sizeof(ARC_Chemical)); - - /* ~ define the language as a string ~ */ - char *languageCString = - " -> | | \n" - - " -> OPEN_CURLY_BRACE CLOSE_CURLY_BRACE\n" - " -> \n" - " -> | LAMBDA\n" - - " -> | \n" - " -> EQUAL SEMICOLON\n" - " -> SPACE | TAB | LAMBDA\n" - - " -> \n" - " -> | | | \n" - " -> OPEN_CURLY_BRACE CLOSE_CURLY_BRACE\n" - " -> COMMA | \n" - - " -> ALPHA_UPPER_CHAR | ALPHA_LOWER_CHAR | UNDERSCORE \n" - " -> | LAMBDA\n" - " -> ALPHA_UPPER_CHAR | ALPHA_LOWER_CHAR | UNDERSCORE | NUMBER\n" - - " -> QUOTE QUOTE\n" - " -> | | LAMBDA\n" - " -> TAB | SPACE | BANG | HASH | DOLLAR | PERCENT | AMPERSAND | SINGLE_QUOTE | OPEN_PAREN | CLOSE_PAREN | ASTERISK | PLUS | COMMA | MINUS | PERIOD | SLASH | NUMBER | COLON | SEMICOLON | LESS_THAN | GREATER_THAN | EQUAL | QUESTION_MARK | AT | ALPHA_UPPER_CHAR | OPEN_BRACKET | CLOSE_BRACKET | CARET | UNDERSCORE | GRAVE | ALPHA_LOWER_CHAR | OPEN_CURLY_BRACE | VERTICAL_LINE | CLOSE_CURLY_BRACE | TILDE\n" - " -> BACKSLASH BACKSLASH | BACKSLASH QUOTE | BACKSLASH ALPHA_UPPER_CHAR | BACKSLASH ALPHA_LOWER_CHAR\n" - - " -> MINUS | \n" - " -> NUMBER | NUMBER\n" - - " -> SPACE | TAB | NEWLINE | LAMBDA\n"; - - /* ~ define the language as a string ~ */ - ARC_String *languageString; - ARC_String_CreateWithStrlen(&languageString, languageCString); - - /* ~ set chemical as userdata ~ */ - void *userdata = *chemical; - - /* ~ create the language ~ */ - ARC_ParserData_CreateFn createCharFn = ARC_ChemicalData_CreateFn; - ARC_ParserData_DestroyFn destroyCharFn = ARC_ChemicalData_DestroyFn; - ARC_Parser_CreateFromString(&((*chemical)->parser), languageString, ARC_Chemical_InitLexerRulesFn, ARC_Chemical_GetStringIdFn, &createCharFn, &destroyCharFn, userdata); - - /* ~ init types ~ */ - ARC_Hashtable_KeyCompareFn keyCompareFn = ARC_Chemical_HashtableKeyCompareFn; - ARC_Hashtable_DestroyKeyValueFn typeDestroyKeyValueFn = ARC_Chemical_TypeHashtableDestroyKeyValueFn; - ARC_Hashtable_Create(&((*chemical)->types), NULL, &keyCompareFn, &typeDestroyKeyValueFn); - - /* ~ init groups ~ */ - ARC_Hashtable_DestroyKeyValueFn groupDestroyKeyValueFn = ARC_Chemical_GroupHashtableDestroyKeyValueFn; - ARC_Hashtable_Create(&((*chemical)->groups), NULL, &keyCompareFn, &groupDestroyKeyValueFn); - - //add the default/empty group into the groups - ARC_Hashtable_DestroyKeyValueFn groupDataDestroyKeyValueFn = ARC_Chemical_GroupDataHashtableDestroyKeyValueFn; - - //copy empty group cstring (to be freed by hashtable on cleanup, passing directly would cause a segfault) - char *emptyCStr = (char *)malloc(sizeof(char) * (strlen(ARC_CHEMICAL_DEFAULT_GROUP) + 1)); - strcpy(emptyCStr, ARC_CHEMICAL_DEFAULT_GROUP); - - //set the current group as empty, then add that into the groups hashtable - ARC_Hashtable_Create(&((*chemical)->currentGroup), NULL, &keyCompareFn, &groupDataDestroyKeyValueFn); - ARC_Hashtable_Add((*chemical)->groups, (void *)emptyCStr, (*chemical)->currentGroup); - - (*chemical)->load = ARC_True; - - //cleanup - ARC_String_Destroy(languageString); -} - -void ARC_Chemical_Destroy(ARC_Chemical *chemical){ - ARC_Parser_Destroy(chemical->parser); - //NOTE: chemical->currentGroup does not need to be freed as it is stored in chemical->groups - ARC_Hashtable_Destroy(chemical->groups); - ARC_Hashtable_Destroy(chemical->types); - free(chemical); -} - -void ARC_Chemical_RegisterType(ARC_Chemical *chemical, ARC_String *typeName, ARC_ChemicalType type){ - ARC_Chemical_RegisterTypeWithCStr(chemical, typeName->data, type); -} - -void ARC_Chemical_RegisterTypeWithCStr(ARC_Chemical *chemical, const char *typeNameCStr, ARC_ChemicalType type){ - //check if the type key already exists and error if it does - if(ARC_Hashtable_Get(chemical->types, (void *)typeNameCStr) != NULL){ - arc_errno = ARC_ERRNO_EXISTS; - ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_Chemical_RegisterTypeWithCStr(chemical, typeName, type), type \"%s\" has already been registered", typeNameCStr); - return; - } - - //copy the string into a cstring for long term storage - uint64_t typeNameCopyLength = strlen(typeNameCStr) + 1; - char *typeNameCopy = (char *)malloc(sizeof(char) * typeNameCopyLength); - strncpy(typeNameCopy, typeNameCStr, typeNameCopyLength); - typeNameCopy[strlen(typeNameCStr)] = '\0'; - - //copy the type for long term storage - ARC_ChemicalType *typeCopy = (ARC_ChemicalType *)malloc(sizeof(ARC_ChemicalType)); - *typeCopy = type; - - //add the type to a hashtable containing all the types - ARC_Hashtable_Add(chemical->types, typeNameCopy, typeCopy); -} - -void ARC_Chemical_SetGroup(ARC_Chemical *chemical, ARC_String *groupName){ - ARC_Chemical_SetGroupWithCStr(chemical, groupName->data); -} - -void ARC_Chemical_SetGroupWithCStr(ARC_Chemical *chemical, const char *groupName){ - //try to get the current group - void *currentGroup = ARC_Hashtable_Get(chemical->groups, (void *)groupName); - - //error if the current group does not exist - if(currentGroup == NULL){ - arc_errno = ARC_ERRNO_NULL; - ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_Chemical_SetGroupWithCStr(chemical, groupName), no group with name \"%s\"", groupName); - return; - } - - //set the current group - chemical->currentGroup = currentGroup; -} - -void *ARC_Chemical_Get(ARC_Chemical *chemical, ARC_String *energy){ - //check if the group separator exists - uint64_t startSeparatorIndex = ARC_String_FindCStringWithStrlen(energy, ARC_CHEMICAL_GROUP_SEPARATOR); - if(startSeparatorIndex == ~(uint64_t)0){ - //use empty group - chemical->currentGroup = ARC_Hashtable_Get(chemical->groups, (void *)ARC_CHEMICAL_DEFAULT_GROUP); - - //get the typeData and pass back the data without the cleanup function - ARC_ChemicalTypeData *typeData = (ARC_ChemicalTypeData *)ARC_Hashtable_Get(chemical->currentGroup, (void *)energy->data); - if(typeData == NULL){ - return NULL; - } - - return typeData->data; - } - - //get the group - startSeparatorIndex--; - ARC_String *groupString; - ARC_String_CopySubstring(&groupString, energy, 0, startSeparatorIndex); - - //set the group - chemical->currentGroup = ARC_Hashtable_Get(chemical->groups, (void *)groupString->data); - - //cleanup - ARC_String_Destroy(groupString); - - //get the element - ARC_String *energyString; - startSeparatorIndex += strlen(ARC_CHEMICAL_GROUP_SEPARATOR); - ARC_String_CopySubstring(&energyString, energy, startSeparatorIndex, energy->length - startSeparatorIndex); - - //this will either return the value or NULL - ARC_ChemicalTypeData *typeData = (ARC_ChemicalTypeData *)ARC_Hashtable_Get(chemical->currentGroup, (void *)energyString->data); - ARC_String_Destroy(energyString); - if(typeData == NULL){ - return NULL; - } - - return typeData->data; -} - -void *ARC_Chemical_GetWithCStr(ARC_Chemical *chemical, const char *energy){ - //create and copy into ARC_String - ARC_String *energyString; - ARC_String_CreateWithStrlen(&energyString, (char *)energy); - - //get the return value - void *returnValue = ARC_Chemical_Get(chemical, energyString); - - //cleanup - ARC_String_Destroy(energyString); - - return returnValue; -} - -void ARC_Chemical_LoadFromString(ARC_Chemical *chemical, ARC_String **string){ - chemical->load = ARC_True; - ARC_Parser_Parse(chemical->parser, string); -} - -void ARC_Chemical_LoadFromFile(ARC_Chemical *chemical, ARC_String *path){ - chemical->load = ARC_True; - ARC_Parser_ParseFile(chemical->parser, path); -} - -void ARC_Chemical_UnloadFromString(ARC_Chemical *chemical, ARC_String **string){ - chemical->load = ARC_False; - ARC_Parser_Parse(chemical->parser, string); -} - -void ARC_Chemical_UnloadFromFile(ARC_Chemical *chemical, ARC_String *path){ - chemical->load = ARC_False; - ARC_Parser_ParseFile(chemical->parser, path); -} - diff --git a/src/std/config.c b/src/std/config.c index 5f0ed90..f27b340 100644 --- a/src/std/config.c +++ b/src/std/config.c @@ -1,609 +1,751 @@ #include "arc/std/config.h" - +#include "arc/std/parser/helpers.h" +#include "arc/std/bool.h" #include "arc/std/errno.h" #include "arc/std/hashtable.h" -#include "arc/std/io.h" -#include "arc/std/string.h" -#include +#include "arc/std/parser.h" +#include #include #include -#include #include struct ARC_Config { - ARC_Hashtable *currgroup; + ARC_Parser *parser; + + ARC_Hashtable *types; ARC_Hashtable *groups; - ARC_Hashtable *keys; + ARC_Hashtable *currentGroup; + + ARC_Bool load; }; -typedef struct ARC_ConfigKey { - ARC_ConfigKeyRead Read; - ARC_ConfigKeyDelete Delete; -} ARC_ConfigKey; - -typedef struct ARC_ConfigTypeTemplate { - ARC_ConfigKeyDelete Delete; - +typedef struct ARC_ConfigTypeData { void *data; -} ARC_ConfigTypeTemplate; + ARC_ConfigType_DestroyFn destroyFn; +} ARC_ConfigTypeData; -typedef struct ARC_ConfigDeleteKeyArgs { - ARC_Config *config; - ARC_String *string; -} ARC_ConfigDeleteKeyArgs; +void ARC_Config_InitLexerRulesFn(ARC_Lexer *lexer){ + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_TAB , '\t')); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_NEWLINE, '\n')); -int8_t ARC_Config_KeyComp(void *key1, size_t *key1size, void *key2, size_t *key2size); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_SPACE , ' ' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_BANG , '!' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_QUOTE , '"' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_HASH , '#' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_DOLLAR , '$' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_PERCENT , '%' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_AMPERSAND , '&' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_SINGLE_QUOTE, '\'')); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_OPEN_PAREN , '(' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_CLOSE_PAREN , ')' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_ASTERISK , '*' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_PLUS , '+' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_COMMA , ',' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_MINUS , '-' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_PERIOD , '.' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_SLASH , '/' )); -void ARC_Config_CreateGroup(ARC_Config *config, ARC_String *name); -void ARC_Config_DestroyGroup(ARC_HashtableNode *group, void *userdata); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharOrBetween(ARC_CONFIG_NUMBER , '0', '9')); -void ARC_Config_DestroyGroupNode(ARC_HashtableNode *node , void *userdata); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_COLON , ':')); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_SEMICOLON , ';')); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_LESS_THAN , '<')); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_GREATER_THAN , '>')); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_EQUAL , '=')); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_QUESTION_MARK, '?')); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_AT , '@')); -void ARC_Config_RemoveKey(ARC_HashtableNode *node, void *userdata); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharOrBetween(ARC_CONFIG_ALPHA_UPPER_CHAR, 'A', 'Z')); -void ARC_Config_AddKey(ARC_Config *config, ARC_String *type, ARC_ConfigKeyRead keyRead, ARC_ConfigKeyDelete keyDelete){ - ARC_ConfigKey *newKey = (ARC_ConfigKey *)malloc(sizeof(ARC_ConfigKey)); - newKey->Read = keyRead; - newKey->Delete = keyDelete; + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_OPEN_BRACKET , '[' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_BACKSLASH , '\\')); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_CLOSE_BRACKET, ']' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_CARET , '^' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_UNDERSCORE , '_' )); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_GRAVE , '`' )); - char *typeval = (char *)malloc(sizeof(char) * type->length); - strncpy(typeval, type->data, type->length); - ARC_Hashtable_Add(config->keys, (void *)typeval, type->length, newKey); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharOrBetween(ARC_CONFIG_ALPHA_LOWER_CHAR, 'a', 'z')); + + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_OPEN_CURLY_BRACE , '{')); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_VERTICAL_LINE , '|')); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_CLOSE_CURLY_BRACE, '}')); + ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_TILDE , '~')); } -void ARC_Config_AddKeyCString(ARC_Config *config, const char *type, uint64_t length, ARC_ConfigKeyRead keyRead, ARC_ConfigKeyDelete keyDelete){ - ARC_ConfigKey *newKey = (ARC_ConfigKey *)malloc(sizeof(ARC_ConfigKey)); - newKey->Read = keyRead; - newKey->Delete = keyDelete; +uint32_t ARC_Config_GetStringIdFn(ARC_String *string){ + if(ARC_String_EqualsCStringWithStrlen(string, "LAMBDA")){ + return ARC_PARSER_TAG_LAMBDA; + } + if(ARC_String_EqualsCStringWithStrlen(string, "TAB")){ + return ARC_CONFIG_TAB; + } + if(ARC_String_EqualsCStringWithStrlen(string, "NEWLINE")){ + return ARC_CONFIG_NEWLINE; + } - char *typeval = (char *)malloc(sizeof(char) * length); - strncpy(typeval, type, length); - ARC_Hashtable_Add(config->keys, (void *)typeval, length, newKey); + if(ARC_String_EqualsCStringWithStrlen(string, "SPACE")){ + return ARC_CONFIG_SPACE; + } + if(ARC_String_EqualsCStringWithStrlen(string, "BANG")){ + return ARC_CONFIG_BANG; + } + if(ARC_String_EqualsCStringWithStrlen(string, "QUOTE")){ + return ARC_CONFIG_QUOTE; + } + if(ARC_String_EqualsCStringWithStrlen(string, "HASH")){ + return ARC_CONFIG_HASH; + } + if(ARC_String_EqualsCStringWithStrlen(string, "DOLLAR")){ + return ARC_CONFIG_DOLLAR; + } + if(ARC_String_EqualsCStringWithStrlen(string, "PERCENT")){ + return ARC_CONFIG_PERCENT; + } + if(ARC_String_EqualsCStringWithStrlen(string, "AMPERSAND")){ + return ARC_CONFIG_AMPERSAND; + } + if(ARC_String_EqualsCStringWithStrlen(string, "SINGLE_QUOTE")){ + return ARC_CONFIG_SINGLE_QUOTE; + } + if(ARC_String_EqualsCStringWithStrlen(string, "OPEN_PAREN")){ + return ARC_CONFIG_OPEN_PAREN; + } + if(ARC_String_EqualsCStringWithStrlen(string, "CLOSE_PAREN")){ + return ARC_CONFIG_CLOSE_PAREN; + } + if(ARC_String_EqualsCStringWithStrlen(string, "ASTERISK")){ + return ARC_CONFIG_ASTERISK; + } + if(ARC_String_EqualsCStringWithStrlen(string, "PLUS")){ + return ARC_CONFIG_PLUS; + } + if(ARC_String_EqualsCStringWithStrlen(string, "COMMA")){ + return ARC_CONFIG_COMMA; + } + if(ARC_String_EqualsCStringWithStrlen(string, "MINUS")){ + return ARC_CONFIG_MINUS; + } + if(ARC_String_EqualsCStringWithStrlen(string, "PERIOD")){ + return ARC_CONFIG_PERIOD; + } + if(ARC_String_EqualsCStringWithStrlen(string, "SLASH")){ + return ARC_CONFIG_SLASH; + } + if(ARC_String_EqualsCStringWithStrlen(string, "NUMBER")){ + return ARC_CONFIG_NUMBER; + } + + if(ARC_String_EqualsCStringWithStrlen(string, "COLON")){ + return ARC_CONFIG_COLON; + } + if(ARC_String_EqualsCStringWithStrlen(string, "SEMICOLON")){ + return ARC_CONFIG_SEMICOLON; + } + if(ARC_String_EqualsCStringWithStrlen(string, "LESS_THAN")){ + return ARC_CONFIG_LESS_THAN; + } + if(ARC_String_EqualsCStringWithStrlen(string, "GREATER_THAN")){ + return ARC_CONFIG_GREATER_THAN; + } + if(ARC_String_EqualsCStringWithStrlen(string, "EQUAL")){ + return ARC_CONFIG_EQUAL; + } + if(ARC_String_EqualsCStringWithStrlen(string, "QUESTION_MARK")){ + return ARC_CONFIG_QUESTION_MARK; + } + if(ARC_String_EqualsCStringWithStrlen(string, "AT")){ + return ARC_CONFIG_AT; + } + if(ARC_String_EqualsCStringWithStrlen(string, "ALPHA_UPPER_CHAR")){ + return ARC_CONFIG_ALPHA_UPPER_CHAR; + } + + if(ARC_String_EqualsCStringWithStrlen(string, "OPEN_BRACKET")){ + return ARC_CONFIG_OPEN_BRACKET; + } + if(ARC_String_EqualsCStringWithStrlen(string, "BACKSLASH")){ + return ARC_CONFIG_BACKSLASH; + } + if(ARC_String_EqualsCStringWithStrlen(string, "CLOSE_BRACKET")){ + return ARC_CONFIG_CLOSE_BRACKET; + } + if(ARC_String_EqualsCStringWithStrlen(string, "CARET")){ + return ARC_CONFIG_CARET; + } + if(ARC_String_EqualsCStringWithStrlen(string, "UNDERSCORE")){ + return ARC_CONFIG_UNDERSCORE; + } + if(ARC_String_EqualsCStringWithStrlen(string, "GRAVE")){ + return ARC_CONFIG_GRAVE; + } + if(ARC_String_EqualsCStringWithStrlen(string, "ALPHA_LOWER_CHAR")){ + return ARC_CONFIG_ALPHA_LOWER_CHAR; + } + + if(ARC_String_EqualsCStringWithStrlen(string, "OPEN_CURLY_BRACE")){ + return ARC_CONFIG_OPEN_CURLY_BRACE; + } + if(ARC_String_EqualsCStringWithStrlen(string, "VERTICAL_LINE")){ + return ARC_CONFIG_VERTICAL_LINE; + } + if(ARC_String_EqualsCStringWithStrlen(string, "CLOSE_CURLY_BRACE")){ + return ARC_CONFIG_CLOSE_CURLY_BRACE; + } + if(ARC_String_EqualsCStringWithStrlen(string, "TILDE")){ + return ARC_CONFIG_TILDE; + } + + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_LANGUAGE; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_GROUP; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_GROUP_NAME; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_GROUP_ARGS; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_VARIABLE_LINES; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_VARIABLE_LINE; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_ALLOW_SPACE; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_TYPE; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_VALUE; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_NESTED_VALUE; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_VALUE_ARGS; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_VARIABLE; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_VARIABLE_NAME; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_VARIABLE_CHAR; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_STRING; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_STRING_CHARS; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_STRING_CHAR; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_ESCAPE_CHAR; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_NUMBER_SIGN; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_NUMBER_TAG; + } + if(ARC_String_EqualsCStringWithStrlen(string, "")){ + return ARC_CONFIG_WHITESPACE; + } + + return ~(uint32_t)0; +} + +//private function to check hashtable keys used by config +ARC_Bool ARC_Config_HashtableKeyCompareFn(void *key1, void *key2){ + return (ARC_Bool)strcmp((const char *)key1, (const char *)key2) == 0; +} + +//private function to clean up types +void ARC_Config_TypeHashtableDestroyKeyValueFn(void *key, void *value){ + free((char *)key); + free((ARC_ConfigType *)value); +} + +//private function to clean up groups +void ARC_Config_GroupHashtableDestroyKeyValueFn(void *key, void *value){ + free((char *)key); + ARC_Hashtable_Destroy((ARC_Hashtable *)value); +} + +//private function to clean up goup data +void ARC_Config_GroupDataHashtableDestroyKeyValueFn(void *key, void *value){ + free((char *)key); + + ARC_ConfigTypeData *typeData = (ARC_ConfigTypeData *)value; + typeData->destroyFn(typeData->data); + free(typeData); +} + +// -> EQUAL SEMICOLON +void ARC_ConfigData_RunVariableLineTag(ARC_ParserTagToken *tagToken, ARC_Config *config){ + //skip whitespace and check for group name + ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 1); + + //get the type + ARC_String *typeString; + ARC_String_Create(&typeString, NULL, 0); + ARC_ParserData_HelperRecurseStringAdd(&typeString, childTagToken); + + //check if type exists in the types hashtable + ARC_ConfigType *type = (ARC_ConfigType *)ARC_Hashtable_Get(config->types, typeString->data); + if(type == NULL){ + //throw an error and return + arc_errno = ARC_ERRNO_DATA; + ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ConfigData_RunVariableLineTag(tagToken, config), type \"%s\" was not registered to config", typeString->data); + ARC_String_Destroy(typeString); + return; + } + + //cleanup + ARC_String_Destroy(typeString); + + //get the variable + childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 3); + ARC_String *variableString; + ARC_String_Create(&variableString, NULL, 0); + ARC_ParserData_HelperRecurseStringAdd(&variableString, childTagToken); + + //check if removing + if(config->load == ARC_False){ + ARC_Hashtable_Remove(config->currentGroup, (void *)variableString->data); + ARC_String_Destroy(variableString); + return; + } + + //check to see if the current variable is already in the current group hashtable + ARC_ConfigTypeData *typeData = (ARC_ConfigTypeData *)ARC_Hashtable_Get(config->currentGroup, variableString->data); + if(typeData != NULL){ + //there is already a value so throw an error and return + arc_errno = ARC_ERRNO_DATA; + ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ConfigData_RunVariableLineTag(tagToken, config), variable \"%s\" already registered to the current group", variableString->data); + ARC_String_Destroy(variableString); + return; + } + + //copy the string into a cstring that will be stored in the hashtable + char *nameVariableCStr = malloc(sizeof(char) * (variableString->length + 1)); + strncpy(nameVariableCStr, variableString->data, variableString->length); + nameVariableCStr[variableString->length] = '\0'; + ARC_String_Destroy(variableString); + + //get + childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 7); + + //check if is a reference + ARC_String *valueString; + ARC_String_Create(&valueString, NULL, 0); + ARC_ParserData_HelperRecurseStringAdd(&valueString, childTagToken); + void *value = ARC_Hashtable_Get(config->currentGroup, valueString); + ARC_String_Destroy(valueString); + + //create where to store either the reference or type data + typeData = (ARC_ConfigTypeData *)malloc(sizeof(ARC_ConfigTypeData)); + if(value != NULL){ + //point to the already stored data + typeData->data = value; + typeData->destroyFn = NULL; + + //add to the current group hashtable + ARC_Hashtable_Add(config->currentGroup, (void *)nameVariableCStr, (void *)typeData); + return; + } + + //passed the parsed value into the copy type function and set the destroy function + type->copyFn(&(typeData->data), childTagToken, config); + typeData->destroyFn = type->destroyFn; + + //add to the current group hashtable + ARC_Hashtable_Add(config->currentGroup, (void *)nameVariableCStr, (void *)typeData); +} + +// -> | +void ARC_ConfigData_RunVariableLinesTag(ARC_ParserTagToken *tagToken, ARC_Config *config){ +//loop through the tags either going to the next line or the next body + for(uint32_t index = 0; index < ARC_Vector_GetSize(tagToken->tagTokens); index++){ + ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, index); + + switch(childTagToken->id){ + //recuse to run the next line + case ARC_CONFIG_VARIABLE_LINES: + ARC_ConfigData_RunVariableLinesTag(childTagToken, config); + if(arc_errno != 0){ + ARC_DEBUG_LOG_ERROR("ARC_ConfigData_RunVariableLinesTag(tagToken, config), config errored when trying to used parsed data for variable lines"); + return; + } + continue; + + //recurse into a variable line tag + case ARC_CONFIG_VARIABLE_LINE: + ARC_ConfigData_RunVariableLineTag(childTagToken, config); + if(arc_errno != 0){ + ARC_DEBUG_LOG_ERROR("ARC_ConfigData_RunVariableLinesTag(tagToken, config), config errored when trying to used parsed data for variable line"); + return; + } + continue; + + //this is for whitespace and any oddities + default: + continue; + } + } +} + +// -> OPEN_CURLY_BRACE CLOSE_CURLY_BRACE +void ARC_ConfigData_RunGroupTag(ARC_ParserTagToken *tagToken, ARC_Config *config){ + //skip whitespace and check for group name + ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 1); + + /* ~ ~ */ + //get the group name and check if it is named "group" + //NOTE: this check may be usedful in the future if there is different functionality for group like tag names + ARC_String *groupName; + ARC_String_Create(&groupName, NULL, 0); + ARC_ParserData_HelperRecurseStringAdd(&groupName, childTagToken); + if(ARC_String_EqualsCStringWithStrlen(groupName, ARC_CONFIG_GROUP_TAG_NAME) == ARC_False){ + //throw an error and return + arc_errno = ARC_ERRNO_DATA; + ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ConfigData_RunGroupTag(tagToken, config), config contained keyword \"%s\" instead of using the correct keyword: \"%s\" ", groupName->data, ARC_CONFIG_GROUP_TAG_NAME); + ARC_String_Destroy(groupName); + return; + } + + //cleanup + ARC_String_Destroy(groupName); + + /* ~ ~ */ + //get the group's variable name + childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 3); + ARC_String *groupVariable; + ARC_String_Create(&groupVariable, NULL, 0); + ARC_ParserData_HelperRecurseStringAdd(&groupVariable, childTagToken); + + //check if removing + if(config->load == ARC_False){ + /* ~ ~ */ + childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 6); + + // -> | LAMBDA + if(childTagToken->token == NULL && ARC_Vector_GetSize(childTagToken->tagTokens) == 2){ + ARC_ParserTagToken *variableLines = (ARC_ParserTagToken *)ARC_Vector_Get(childTagToken->tagTokens, 1); + ARC_ConfigData_RunVariableLinesTag(variableLines, config); + + //log error if it happens + if(arc_errno != 0){ + ARC_DEBUG_LOG_ERROR("ARC_ConfigData_RunGroupTag(tagToken, config), config errored when trying to used parsed data for variable lines"); + } + } + + //remove an empty hashtable if it is now empty + if(ARC_Hashtable_GetSize(config->groups)){ + ARC_String_Destroy(groupVariable); + } + + return; + } + + //get the needed hashtable or create it from the groups hashtable + ARC_Hashtable *groupHashtable = ARC_Hashtable_Get(config->groups, (void *)groupVariable->data); + if(groupHashtable == NULL){ + //copy the string into a cstring that will be stored in the hashtable + char *groupVariableCStr = malloc(sizeof(char) * (groupVariable->length + 1)); + strncpy(groupVariableCStr, groupVariable->data, groupVariable->length); + groupVariableCStr[groupVariable->length] = '\0'; + + //create the hashtable with the given group name key + ARC_Hashtable_KeyCompareFn keyCompareFn = ARC_Config_HashtableKeyCompareFn; + ARC_Hashtable_DestroyKeyValueFn groupDataDestroyKeyValueFn = ARC_Config_GroupDataHashtableDestroyKeyValueFn; + ARC_Hashtable_Create(&groupHashtable, NULL, &keyCompareFn, &groupDataDestroyKeyValueFn); + ARC_Hashtable_Add(config->groups, (void *)groupVariableCStr, (void *)groupHashtable); + } + + //cleanup + ARC_String_Destroy(groupVariable); + + //set the current group to the group just created or found + config->currentGroup = groupHashtable; + + /* ~ ~ */ + childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 6); + + // -> | LAMBDA + if(childTagToken->token == NULL && ARC_Vector_GetSize(childTagToken->tagTokens) == 2){ + ARC_ParserTagToken *variableLines = (ARC_ParserTagToken *)ARC_Vector_Get(childTagToken->tagTokens, 1); + ARC_ConfigData_RunVariableLinesTag(variableLines, config); + + //log error if it happens, but as setting the group back is the last thing we shouldn't return + if(arc_errno != 0){ + ARC_DEBUG_LOG_ERROR("ARC_ConfigData_RunGroupTag(tagToken, config), config errored when trying to used parsed data for variable lines"); + } + } + + /* ~ reset current group ~ */ + config->currentGroup = ARC_Hashtable_Get(config->groups, (void *)ARC_CONFIG_DEFAULT_GROUP); +} + +// -> | | +void ARC_ConfigData_RunLanguageTag(ARC_ParserTagToken *tagToken, ARC_Config *config){ + //loop through the tags either going to the next language, group, or variable lines + for(uint32_t index = 0; index < ARC_Vector_GetSize(tagToken->tagTokens); index++){ + ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, index); + + switch(childTagToken->id){ + //recuse to run the next line + case ARC_CONFIG_LANGUAGE: + ARC_ConfigData_RunLanguageTag(childTagToken, config); + continue; + + //recurse into a group tag + case ARC_CONFIG_GROUP: + ARC_ConfigData_RunGroupTag(childTagToken, config); + if(arc_errno != 0){ + ARC_DEBUG_LOG_ERROR("ARC_ConfigData_RunLanguageTag(tagToken, config), config errored when trying to used parsed data for a group"); + return; + } + continue; + + //recurse through variable lines + case ARC_CONFIG_VARIABLE_LINES: + ARC_ConfigData_RunVariableLinesTag(childTagToken, config); + ARC_ConfigData_RunGroupTag(childTagToken, config); + if(arc_errno != 0){ + ARC_DEBUG_LOG_ERROR("ARC_ConfigData_RunLanguageTag(tagToken, config), config errored when trying to used parsed data for variable lines"); + return; + } + continue; + + //this is for whitespace and any oddities + default: + continue; + } + } +} + +void ARC_ConfigData_CreateFn(void **data, ARC_ParserTagToken *parsedData, void *userData){ + *data = NULL; + if(parsedData == NULL || userData == NULL){ + //TODO: error here? + *data = NULL; + return; + } + + ARC_ConfigData_RunLanguageTag(parsedData, (ARC_Config *)userData); +} + +void ARC_ConfigData_DestroyFn(void *data, ARC_Bool clear, void *userData){ + return; } void ARC_Config_Create(ARC_Config **config){ *config = (ARC_Config *)malloc(sizeof(ARC_Config)); - (*config)->currgroup = NULL; - ARC_Hashtable *groups; - ARC_Hashtable_Create(&groups, ARC_GROUP_BUCKET_SIZE, NULL, ARC_Config_KeyComp); - (*config)->groups = groups; - ARC_Config_CreateGroup(*config, NULL); + /* ~ define the language as a string ~ */ + char *languageCString = + " -> | | \n" - ARC_Hashtable *keys; - ARC_Hashtable_Create(&keys, ARC_KEY_BUCKET_SIZE, NULL, ARC_Config_KeyComp); - (*config)->keys = keys; + " -> OPEN_CURLY_BRACE CLOSE_CURLY_BRACE\n" + " -> \n" + " -> | LAMBDA\n" -#ifdef ARC_DEFAULT_CONFIG - ARC_Defaults_ConfigKey_Create(*config); -#endif + " -> | \n" + " -> EQUAL SEMICOLON\n" + " -> SPACE | TAB | LAMBDA\n" + + " -> \n" + " -> | | | \n" + " -> OPEN_CURLY_BRACE CLOSE_CURLY_BRACE\n" + " -> COMMA | \n" + + " -> ALPHA_UPPER_CHAR | ALPHA_LOWER_CHAR | UNDERSCORE \n" + " -> | LAMBDA\n" + " -> ALPHA_UPPER_CHAR | ALPHA_LOWER_CHAR | UNDERSCORE | NUMBER\n" + + " -> QUOTE QUOTE\n" + " -> | | LAMBDA\n" + " -> TAB | SPACE | BANG | HASH | DOLLAR | PERCENT | AMPERSAND | SINGLE_QUOTE | OPEN_PAREN | CLOSE_PAREN | ASTERISK | PLUS | COMMA | MINUS | PERIOD | SLASH | NUMBER | COLON | SEMICOLON | LESS_THAN | GREATER_THAN | EQUAL | QUESTION_MARK | AT | ALPHA_UPPER_CHAR | OPEN_BRACKET | CLOSE_BRACKET | CARET | UNDERSCORE | GRAVE | ALPHA_LOWER_CHAR | OPEN_CURLY_BRACE | VERTICAL_LINE | CLOSE_CURLY_BRACE | TILDE\n" + " -> BACKSLASH BACKSLASH | BACKSLASH QUOTE | BACKSLASH ALPHA_UPPER_CHAR | BACKSLASH ALPHA_LOWER_CHAR\n" + + " -> MINUS | \n" + " -> NUMBER | NUMBER\n" + + " -> SPACE | TAB | NEWLINE | LAMBDA\n"; + + /* ~ define the language as a string ~ */ + ARC_String *languageString; + ARC_String_CreateWithStrlen(&languageString, languageCString); + + /* ~ set config as userdata ~ */ + void *userdata = *config; + + /* ~ create the language ~ */ + ARC_ParserData_CreateFn createCharFn = ARC_ConfigData_CreateFn; + ARC_ParserData_DestroyFn destroyCharFn = ARC_ConfigData_DestroyFn; + ARC_Parser_CreateFromString(&((*config)->parser), languageString, ARC_Config_InitLexerRulesFn, ARC_Config_GetStringIdFn, &createCharFn, &destroyCharFn, userdata); + + /* ~ init types ~ */ + ARC_Hashtable_KeyCompareFn keyCompareFn = ARC_Config_HashtableKeyCompareFn; + ARC_Hashtable_DestroyKeyValueFn typeDestroyKeyValueFn = ARC_Config_TypeHashtableDestroyKeyValueFn; + ARC_Hashtable_Create(&((*config)->types), NULL, &keyCompareFn, &typeDestroyKeyValueFn); + + /* ~ init groups ~ */ + ARC_Hashtable_DestroyKeyValueFn groupDestroyKeyValueFn = ARC_Config_GroupHashtableDestroyKeyValueFn; + ARC_Hashtable_Create(&((*config)->groups), NULL, &keyCompareFn, &groupDestroyKeyValueFn); + + //add the default/empty group into the groups + ARC_Hashtable_DestroyKeyValueFn groupDataDestroyKeyValueFn = ARC_Config_GroupDataHashtableDestroyKeyValueFn; + + //copy empty group cstring (to be freed by hashtable on cleanup, passing directly would cause a segfault) + char *emptyCStr = (char *)malloc(sizeof(char) * (strlen(ARC_CONFIG_DEFAULT_GROUP) + 1)); + strcpy(emptyCStr, ARC_CONFIG_DEFAULT_GROUP); + + //set the current group as empty, then add that into the groups hashtable + ARC_Hashtable_Create(&((*config)->currentGroup), NULL, &keyCompareFn, &groupDataDestroyKeyValueFn); + ARC_Hashtable_Add((*config)->groups, (void *)emptyCStr, (*config)->currentGroup); + + (*config)->load = ARC_True; + + //cleanup + ARC_String_Destroy(languageString); } void ARC_Config_Destroy(ARC_Config *config){ - ARC_ConfigDeleteKeyArgs keyArgs = { - .config = config, - .string = NULL, - }; - - ARC_Hashtable_Destroy(config->groups, ARC_Config_DestroyGroup, (void *)&keyArgs); - ARC_Hashtable_Destroy(config->keys , ARC_Config_RemoveKey , NULL ); + ARC_Parser_Destroy(config->parser); + //NOTE: config->currentGroup does not need to be freed as it is stored in config->groups + ARC_Hashtable_Destroy(config->groups); + ARC_Hashtable_Destroy(config->types); free(config); } -//TODO: fix NULL group -void ARC_Config_SetGroup(ARC_Config *config, ARC_String *groupname){ - if(!config){ - return; - } - - if(groupname == NULL){ - ARC_Hashtable_Get(config->groups, (void *)" ", 1, (void **)&(config->currgroup)); - return; - } - - ARC_Hashtable_Get(config->groups, (void *)groupname->data, groupname->length, (void **)&(config->currgroup)); - arc_errno = 0; - -// if(arc_errno && arc_errno != ARC_ERRNO_NULL){ -// return; -// } - - if(config->currgroup){ - return; - } - - ARC_Config_CreateGroup(config, groupname); - if(arc_errno){ - return; - } - - ARC_Hashtable_Get(config->groups, (void *)groupname->data, groupname->length, (void **)&(config->currgroup)); +void ARC_Config_RegisterType(ARC_Config *config, ARC_String *typeName, ARC_ConfigType type){ + ARC_Config_RegisterTypeWithCStr(config, typeName->data, type); } -void ARC_Config_Get(ARC_Config *config, ARC_String *keyname, void **value){ - ARC_ConfigTypeTemplate *temp = NULL; - - uint64_t length = ARC_String_FindCString(keyname, "::", 2); - if(arc_errno){ - //TODO: Debug info here - ARC_DEBUG_LOG_ERROR("in ARC_Config_Get(config, keyname, value); length threw error"); - *value = NULL; +void ARC_Config_RegisterTypeWithCStr(ARC_Config *config, const char *typeNameCStr, ARC_ConfigType type){ + //check if the type key already exists and error if it does + if(ARC_Hashtable_Get(config->types, (void *)typeNameCStr) != NULL){ + arc_errno = ARC_ERRNO_EXISTS; + ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_Config_RegisterTypeWithCStr(config, typeName, type), type \"%s\" has already been registered", typeNameCStr); return; } - if(length != ~((uint64_t)0)){ - length--; - ARC_String *group = NULL; + //copy the string into a cstring for long term storage + uint64_t typeNameCopyLength = strlen(typeNameCStr) + 1; + char *typeNameCopy = (char *)malloc(sizeof(char) * typeNameCopyLength); + strncpy(typeNameCopy, typeNameCStr, typeNameCopyLength); + typeNameCopy[strlen(typeNameCStr)] = '\0'; - if(length != 0){ - ARC_String_CopySubstring(&group, keyname, 0, length); - } + //copy the type for long term storage + ARC_ConfigType *typeCopy = (ARC_ConfigType *)malloc(sizeof(ARC_ConfigType)); + *typeCopy = type; - ARC_Hashtable *currgroup = config->currgroup; - ARC_Config_SetGroup(config, group); - if(arc_errno){ - ARC_DEBUG_LOG_ERROR("in ARC_Config_Get(config, keyname, value); setting group threw error"); - ARC_String_Destroy(group); - *value = NULL; - return; - } - - ARC_String *name; - ARC_String_CopySubstring(&name, keyname, length + 2, keyname->length - (length + 2)); - ARC_Hashtable_Get(config->currgroup, (void *)name->data, name->length, (void **)&temp); - ARC_String_Destroy(name); - - config->currgroup = currgroup; - if(group){ - ARC_String_Destroy(group); - } - - if(temp == NULL){ - *value = NULL; - return; - } - - *value = temp->data; - return; - } - - if(!keyname){ - *value = NULL; - return; - } - - ARC_Hashtable_Get(config->currgroup, (void *)keyname->data, keyname->length, (void **)&temp); - if(arc_errno || temp == NULL){ - *value = NULL; - return; - } - - *value = temp->data; + //add the type to a hashtable containing all the types + ARC_Hashtable_Add(config->types, typeNameCopy, typeCopy); } -void ARC_Config_Recurse(ARC_Config *config, ARC_String **data, ARC_String *groupstr, uint8_t *command); - -void ARC_Config_SetKeyGroup(ARC_Config *config, ARC_String **data, uint8_t *command){ - uint64_t index = ARC_String_FindCString(*data, " ", 1); - uint64_t nextIndex = ARC_String_FindCString(*data, "{", 1); - if(index == ~(uint64_t)0 || nextIndex == ~(uint64_t)0){ - arc_errno = ARC_ERRNO_DATA; - } - - if(arc_errno){ - return; - } - - ARC_String *name, *temp; - ARC_String_CopySubstring(&temp, *data, index, nextIndex - index - 1); - ARC_String_StripEndsWhitespace(&name, temp); - ARC_String_Destroy(temp); - - temp = *data; - ARC_String_CopySubstring(data, temp, nextIndex + 1, (*data)->length - (nextIndex + 1)); - ARC_String_Destroy(temp); - - ARC_Config_Recurse(config, data, name, command); - ARC_String_Destroy(name); +void ARC_Config_SetGroup(ARC_Config *config, ARC_String *groupName){ + ARC_Config_SetGroupWithCStr(config, groupName->data); } -void ARC_Config_LoadFromKey(ARC_Config *config, ARC_String *keyType, ARC_String *name, ARC_String *value){ - ARC_ConfigKey *key; - ARC_Hashtable_Get(config->keys, keyType->data, keyType->length, (void **)&key); - if(key == NULL){ - arc_errno = ARC_ERRNO_DATA; - ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("in ARC_Config_LoadFromKey(config, string, value); no matching key: %s", keyType->data); - } +void ARC_Config_SetGroupWithCStr(ARC_Config *config, const char *groupName){ + //try to get the current group + void *currentGroup = ARC_Hashtable_Get(config->groups, (void *)groupName); - if(arc_errno){ - return; - } - - ARC_ConfigTypeTemplate *templateVal = (ARC_ConfigTypeTemplate *) malloc(sizeof(ARC_ConfigTypeTemplate)); - templateVal->Delete = NULL; - templateVal->data = NULL; - - uint8_t reference = key->Read(config, value, &(templateVal->data)); - if(!reference){ - templateVal->Delete = key->Delete; - } - - if(arc_errno){ - return; - } - - char *nameval = (char *)malloc(sizeof(char) * name->length + 1); - strncpy(nameval, name->data, name->length); - nameval[name->length] = '\0'; - ARC_Hashtable_Add(config->currgroup, nameval, name->length, (void *)templateVal); -} - -void ARC_Config_UnloadFromKey(ARC_Config *config, ARC_String *keyType, ARC_String *name, ARC_String *value){ - ARC_ConfigDeleteKeyArgs keyArgs = { - .config = config, - .string = value, - }; - - ARC_Hashtable_Remove(config->currgroup, name->data, name->length, ARC_Config_DestroyGroupNode, &keyArgs); -} - -void ARC_Config_GetNameAndValue(ARC_String *data, ARC_String **name, ARC_String **value){ - uint64_t index = ARC_String_FindCString(data, "=", 1); - if(arc_errno || index == ~(uint64_t)0){ - *name = NULL; - *value = NULL; - return; - } - - ARC_String_CopySubstring(name, data, 0, index - 1); - index++; - - ARC_String *dataTemp = *name; - ARC_String_StripEndsWhitespace(name, dataTemp); - ARC_String_Destroy(dataTemp); - - ARC_String_CopySubstring(&dataTemp, data, index, data->length - index); - ARC_String_StripEndsWhitespace(value, dataTemp); - ARC_String_Destroy(dataTemp); -} - -void ARC_Config_Recurse(ARC_Config *config, ARC_String **data, ARC_String *groupstr, uint8_t *command){ - ARC_Config_SetGroup(config, groupstr); - if(arc_errno){ - return; - } - - ARC_Hashtable *group = config->currgroup; - - while(*data && (*data)->length){ - ARC_String *dataTemp = *data; - ARC_String_StripEndsWhitespace(data, dataTemp); - ARC_String_Destroy(dataTemp); - - // break out of current group - if((*data)->data[0] == '}'){ - config->currgroup = NULL; - - dataTemp = *data; - ARC_String_CopySubstring(data, dataTemp, 1, dataTemp->length - 1); - ARC_String_Destroy(dataTemp); - return; - } - - // set group - if(!(config->currgroup)){ - config->currgroup = group; - } - - // get keys type - uint64_t index = ARC_String_FindCString(*data, " ", 1); - if(arc_errno || index == ~(uint64_t)0){ - return; - } - - ARC_String *keyType, *keyTypeTemp; - ARC_String_CopySubstring(&keyTypeTemp, *data, 0, index); - ARC_String_StripEndsWhitespace(&keyType, keyTypeTemp); - ARC_String_Destroy(keyTypeTemp); - - if(ARC_String_EqualsCString(keyType, "group", 5)){ - ARC_Config_SetKeyGroup(config, data, command); - ARC_String_Destroy(keyType); - config->currgroup = group; - if(arc_errno){ - return; - } - - continue; - } - - // get and copy up to the ; - ARC_String *nameAndValue; - uint64_t nextIndex = ARC_String_FindCString(*data, ";", 1); - if(nextIndex == ~(uint64_t)0){ - arc_errno = ARC_ERRNO_DATA; - } - - if(arc_errno){ - ARC_String_Destroy(keyType); - return; - } - - ARC_String_CopySubstring(&nameAndValue, *data, index, nextIndex - (index + 1)); - if(arc_errno){ - ARC_String_Destroy(keyType); - return; - } - - // remove up to the ; from data string - dataTemp = *data; - ARC_String_CopySubstring(data, dataTemp, nextIndex, (*data)->length - nextIndex); - ARC_String_Destroy(dataTemp); - if(arc_errno){ - ARC_String_Destroy(keyType); - ARC_String_Destroy(nameAndValue); - return; - } - - // get name and value of string - ARC_String *name, *value; - ARC_Config_GetNameAndValue(nameAndValue, &name, &value); - ARC_String_Destroy(nameAndValue); - if(arc_errno){ - ARC_String_Destroy(keyType); - return; - } - - // load from key - if(*command == ARC_CONFIG_FILE_IO_LOAD){ - ARC_Config_LoadFromKey(config, keyType, name, value); - - ARC_String_Destroy(keyType); - ARC_String_Destroy(name ); - ARC_String_Destroy(value ); - - if(arc_errno){ - return; - } - - continue; - } - - // unload from key - if(*command == ARC_CONFIG_FILE_IO_UNLOAD){ - ARC_Config_UnloadFromKey(config, keyType, name, value); - - ARC_String_Destroy(keyType); - ARC_String_Destroy(name ); - ARC_String_Destroy(value ); - - if(arc_errno){ - return; - } - - continue; - } - - // config file wasn't loaded correctly - ARC_String_Destroy(keyType); - ARC_String_Destroy(name ); - ARC_String_Destroy(value ); - arc_errno = ARC_ERRNO_DATA; - return; - } - - config->currgroup = group; -} - -void ARC_Config_StripComment(ARC_String *original, ARC_String **stripped, ARC_String *lineStart, ARC_String *lineEnd){ - ARC_String *current = NULL; - ARC_String_Copy(¤t, original); - - uint64_t index = ARC_String_Find(original, lineStart); - while(index != ~(uint64_t)0){ - ARC_String *commentString; - ARC_String_CopySubstring(&commentString, current, index + lineStart->length, current->length - (index + lineStart->length)); - - uint64_t endIndex = ARC_String_Find(commentString, lineEnd); - ARC_String_Destroy(commentString); - if(endIndex == ~(uint64_t)0){ - ARC_DEBUG_LOG_ERROR("ARC_Config_RemoveComments(original, commentRemoved); No newline found when stripping single line comment"); - arc_errno = ARC_ERRNO_DATA; - ARC_String_Destroy(current); - *stripped = NULL; - break; - } - - ARC_String *currentTemp = current; - ARC_String_RemoveSection(¤t, currentTemp, index, endIndex + lineStart->length + lineEnd->length); - ARC_String_Destroy(currentTemp); - - index = ARC_String_Find(current, lineStart); - } - - *stripped = current; -} - -void ARC_Config_RemoveComments(ARC_String *original, ARC_String **commentRemoved){ - ARC_String *lineStart, *lineEnd; - - //Single Line Comment - ARC_String_Create(&lineStart, "//", 2); - ARC_String_Create(&lineEnd , "\n", 1); - - ARC_String *singleLineStripped; - ARC_Config_StripComment(original, &singleLineStripped, lineStart, lineEnd); - - ARC_String_Destroy(lineStart); - ARC_String_Destroy(lineEnd ); - - if(arc_errno){ - commentRemoved = NULL; - return; - } - - //Multi Line Comment - ARC_String_Create(&lineStart, "/*", 2); - ARC_String_Create(&lineEnd , "*/", 2); - - ARC_Config_StripComment(singleLineStripped, commentRemoved, lineStart, lineEnd); - ARC_String_Destroy(singleLineStripped); - - ARC_String_Destroy(lineStart); - ARC_String_Destroy(lineEnd ); -} - -void ARC_Config_RunCommand(ARC_Config *config, ARC_String *command){ - ARC_String *space; - ARC_String_Create(&space, " " , 1); - - uint64_t index = ARC_String_Find(command, space); - if(index == ~(uint64_t)0){ - arc_errno = ARC_ERRNO_DATA; - ARC_String_Destroy(space); - return; - } - - ARC_String *commandOpt; - ARC_String_CopySubstring(&commandOpt, command, 0, index); - - ARC_String *commandArgTemp, *commandArg; - ARC_String_CopySubstring(&commandArgTemp, command, index + space->length, command->length - (index + space->length)); - ARC_String_StripWhitespace(&commandArg, commandArgTemp); - ARC_String_Destroy(commandArgTemp); - - if(ARC_String_EqualsCString(command, "load", 4)){ - ARC_Config_FileIO(config, commandArg, ARC_CONFIG_FILE_IO_LOAD); - } - else if(ARC_String_EqualsCString(command, "unload", 6)){ - ARC_Config_FileIO(config, commandArg, ARC_CONFIG_FILE_IO_UNLOAD); - } - else { - arc_errno = ARC_ERRNO_DATA; - } - - ARC_String_Destroy(commandOpt); - ARC_String_Destroy(commandArg); - ARC_String_Destroy(space ); -} - -void ARC_Config_RemoveAndRunCommands(ARC_Config *config, ARC_String *original, ARC_String **commandRemoved){ - ARC_String *current; - ARC_String_Copy(¤t, original); - - ARC_String *lineStart, *lineEnd; - ARC_String_Create(&lineStart, "#" , 1); - ARC_String_Create(&lineEnd , "\n", 1); - - uint64_t index = ARC_String_Find(current, lineStart); - - while(index != ~(uint64_t)0){ - uint64_t endIndex = ARC_String_Find(current, lineEnd); - if(endIndex == ~(uint64_t)0){ - arc_errno = ARC_ERRNO_DATA; - ARC_String_Destroy(current ); - ARC_String_Destroy(lineStart); - ARC_String_Destroy(lineEnd ); - *commandRemoved = NULL; - return; - } - - ARC_String *command; - ARC_String_CopySubstring(&command, current, index + lineStart->length, endIndex - (index + lineStart->length)); - ARC_Config_RunCommand(config, command); - - ARC_String *currentTemp = current; - ARC_String_RemoveSubstring(¤t, currentTemp, command); - ARC_String_Destroy(command); - ARC_String_Destroy(currentTemp); - } - - ARC_String_Destroy(lineStart); - ARC_String_Destroy(lineEnd ); - - *commandRemoved = current; -} - -void ARC_Config_FileIO(ARC_Config *config, ARC_String *path, uint8_t command){ - arc_errno = 0; //TODO: Remove this, just testing - ARC_String *data; - ARC_IO_FileToStr(path, &data); - if(arc_errno){ - ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_IO_FileToStr(%s, &data, &size);\n", path->data); - return; - } - - ARC_String_AppendCStringWithStrlen(&data, "\n"); - - ARC_String *temp = data; - ARC_Config_RemoveComments(temp, &data); - ARC_String_Destroy(temp); - - temp = data; - ARC_Config_RemoveAndRunCommands(config, temp, &data); - ARC_String_Destroy(temp); - - temp = data; - ARC_String_StripEndsWhitespace(&data, temp); - ARC_String_Destroy(temp); - - ARC_Config_Recurse(config, &data, NULL, &command); - if(data){ - ARC_String_Destroy(data); - } -} - -int8_t ARC_Config_KeyComp(void *key1, size_t *key1size, void *key2, size_t *key2size){ - if(*key1size - *key2size){ - return -1; - } - - return strncmp((const char *)key1, (const char *)key2, *key1size); -} - -void ARC_Config_CreateGroup(ARC_Config *config, ARC_String *name){ - ARC_Hashtable *data; - ARC_Hashtable_Create(&data, ARC_GROUP_DATA_BUCKET_SIZE, NULL, ARC_Config_KeyComp); - - if(name){ - char *nameval = (char *)malloc(sizeof(char) * name->length); - strncpy(nameval, name->data, name->length); - ARC_Hashtable_Add(config->groups, nameval, name->length, (void *)data); - return; - } - - char *emptyGroup = (char *)malloc(sizeof(char)); - emptyGroup[0] = ' '; - ARC_Hashtable_Add(config->groups, emptyGroup, 1, (void *)data); -} - -void ARC_Config_DestroyGroup(ARC_HashtableNode *group, void *userdata){ - free((char *)group->key); - ARC_Hashtable_Destroy((ARC_Hashtable *)group->data, ARC_Config_DestroyGroupNode, userdata); -} - -void ARC_Config_DestroyGroupNode(ARC_HashtableNode *node, void *userdata){ - free((char *)node->key); - - ARC_ConfigTypeTemplate *temp = (ARC_ConfigTypeTemplate *)node->data; - if(temp->Delete && temp->data && userdata){ - ARC_ConfigDeleteKeyArgs *args = (ARC_ConfigDeleteKeyArgs *)userdata; - - temp->Delete(args->config, args->string, temp->data); - } - - free(temp); - node->data = NULL; -} - -void ARC_Config_RemoveKey(ARC_HashtableNode *node, void *userdata){ - free((char *)node->key); - - if(!node->data){ + //error if the current group does not exist + if(currentGroup == NULL){ arc_errno = ARC_ERRNO_NULL; + ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_Config_SetGroupWithCStr(config, groupName), no group with name \"%s\"", groupName); return; } - free((ARC_ConfigKey *)node->data); + //set the current group + config->currentGroup = currentGroup; } + +void *ARC_Config_Get(ARC_Config *config, ARC_String *name){ + //check if the group separator exists + uint64_t startSeparatorIndex = ARC_String_FindCStringWithStrlen(name, ARC_CONFIG_GROUP_SEPARATOR); + if(startSeparatorIndex == ~(uint64_t)0){ + //use empty group + config->currentGroup = ARC_Hashtable_Get(config->groups, (void *)ARC_CONFIG_DEFAULT_GROUP); + + //get the typeData and pass back the data without the cleanup function + ARC_ConfigTypeData *typeData = (ARC_ConfigTypeData *)ARC_Hashtable_Get(config->currentGroup, (void *)name->data); + if(typeData == NULL){ + return NULL; + } + + return typeData->data; + } + + //get the group + startSeparatorIndex--; + ARC_String *groupString; + ARC_String_CopySubstring(&groupString, name, 0, startSeparatorIndex); + + //set the group + config->currentGroup = ARC_Hashtable_Get(config->groups, (void *)groupString->data); + + //cleanup + ARC_String_Destroy(groupString); + + //get the name + ARC_String *nameString; + startSeparatorIndex += strlen(ARC_CONFIG_GROUP_SEPARATOR); + ARC_String_CopySubstring(&nameString, name, startSeparatorIndex, name->length - startSeparatorIndex); + + //this will either return the value or NULL + ARC_ConfigTypeData *typeData = (ARC_ConfigTypeData *)ARC_Hashtable_Get(config->currentGroup, (void *)nameString->data); + ARC_String_Destroy(nameString); + if(typeData == NULL){ + return NULL; + } + + return typeData->data; +} + +void *ARC_Config_GetWithCStr(ARC_Config *config, const char *name){ + //create and copy into ARC_String + ARC_String *nameString; + ARC_String_CreateWithStrlen(&nameString, (char *)name); + + //get the return value + void *returnValue = ARC_Config_Get(config, nameString); + + //cleanup + ARC_String_Destroy(nameString); + + return returnValue; +} + +void ARC_Config_LoadFromString(ARC_Config *config, ARC_String **string){ + config->load = ARC_True; + ARC_Parser_Parse(config->parser, string); +} + +void ARC_Config_LoadFromFile(ARC_Config *config, ARC_String *path){ + config->load = ARC_True; + ARC_Parser_ParseFile(config->parser, path); +} + +void ARC_Config_UnloadFromString(ARC_Config *config, ARC_String **string){ + config->load = ARC_False; + ARC_Parser_Parse(config->parser, string); +} + +void ARC_Config_UnloadFromFile(ARC_Config *config, ARC_String *path){ + config->load = ARC_False; + ARC_Parser_ParseFile(config->parser, path); +} + diff --git a/src/std/life.c b/src/std/life.c deleted file mode 100644 index e69de29..0000000 diff --git a/tests/res/std/chemical/first.chemical b/tests/res/std/chemical/first.chemical deleted file mode 100644 index 392097c..0000000 --- a/tests/res/std/chemical/first.chemical +++ /dev/null @@ -1,5 +0,0 @@ -group test { - int32 test = 5; - - int32 test1 = -7; -} diff --git a/tests/std/chemical.c b/tests/std/chemical.c deleted file mode 100644 index bcdc12c..0000000 --- a/tests/std/chemical.c +++ /dev/null @@ -1,108 +0,0 @@ -#include "../test.h" -#include "arc/std/errno.h" -#include "arc/std/chemical.h" -#include "arc/std/parser.h" -#include "arc/std/parser/helpers.h" -#include - -static const char *testType = "int32"; - -void TEST_ChemicalType_CopyInt32Fn(void **type, ARC_ParserTagToken *parsedData, ARC_Chemical *chemical){ - //go into the tag - ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(parsedData->tagTokens, 0); - if(childTagToken->id != ARC_CHEMICAL_NUMBER_SIGN){ - arc_errno = ARC_ERRNO_DATA; - ARC_DEBUG_LOG_ERROR("TEST_ChemicalType_CopyInt32Fn(type, parsedData, chemical), parsed data was not a "); - *type = NULL; - return; - } - - //check if the first tag is a minus sign and create a string starting with that if it is - childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(childTagToken->tagTokens, 0); - ARC_String *int32String; - ARC_String_Create(&int32String, NULL, 0); - if(childTagToken->id == ARC_CHEMICAL_MINUS){ - ARC_String_AppendCStringWithStrlen(&int32String, "-"); - } - - ARC_ParserData_HelperRecurseStringAdd(&int32String, parsedData); - - //set the max character size 2,147,483,647 (10 characters) or -2,147,483,648 (11 characters) - uint32_t maxInt32Size = 10; - if(int32String->data[0] == '-'){ - maxInt32Size++; - } - - //if the string is bigger than the possible size return NULL and error - if(int32String->length > maxInt32Size){ - arc_errno = ARC_ERRNO_DATA; - ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("TEST_ChemicalType_CopyInt32Fn(type, parsedData, chemical), size \"%s\" was bigger or smaller than the max 2,147,483,647 or min -2,147,483,648", int32String->data); - *type = NULL; - ARC_String_Destroy(int32String); - return; - } - - if(int32String->length == maxInt32Size){ - char maxint32CStr[10] = "2147483647"; - - //offset starting index and last number if there is a negative - uint8_t stringIndex = 0; - if(int32String->data[0] == '-'){ - stringIndex++; - maxint32CStr[9]++; - } - - for(uint8_t index = 0; index < 10; index++, stringIndex++){ - if(int32String->data[stringIndex] > maxint32CStr[index]){ - arc_errno = ARC_ERRNO_DATA; - ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("TEST_ChemicalType_CopyInt32Fn(type, parsedData, chemical), size \"%s\" was bigger or smaller than the max 2,147,483,647 or min -2,147,483,648", int32String->data); - *type = NULL; - ARC_String_Destroy(int32String); - return; - } - } - } - - //copy the int32_t - *type = malloc(sizeof(int32_t)); - *(int32_t *)(*type) = (int32_t)ARC_String_ToInt64_t(int32String); - - //cleanup - ARC_String_Destroy(int32String); -} - -void TEST_ChemicalType_DestroyInt32Fn(void *type){ - free((int32_t *)type); -} - -ARC_TEST(Chemical_BasicTest){ - ARC_Chemical *chemical; - ARC_Chemical_Create(&chemical); - - ARC_CHECK(arc_errno == 0); - - ARC_ChemicalType int32Type = { - TEST_ChemicalType_CopyInt32Fn, - TEST_ChemicalType_DestroyInt32Fn - }; - ARC_Chemical_RegisterTypeWithCStr(chemical, testType, int32Type); - - char *tempCString = "tests/res/std/chemical/first.chemical"; - ARC_String *tempString; - ARC_String_CreateWithStrlen(&tempString, tempCString); - ARC_Chemical_LoadFromFile(chemical, tempString); - - int32_t testVal = *(int32_t *)ARC_Chemical_GetWithCStr(chemical, "test::test"); - ARC_CHECK(testVal == 5); - testVal = *(int32_t *)ARC_Chemical_GetWithCStr(chemical, "test::test1"); - ARC_CHECK(testVal == -7); - - ARC_Chemical_UnloadFromFile(chemical, tempString); - - void *nullVal = ARC_Chemical_GetWithCStr(chemical, "test::test"); - ARC_CHECK(nullVal == NULL); - - //cleanup - ARC_String_Destroy(tempString); - ARC_Chemical_Destroy(chemical); -} diff --git a/tests/std/life.c b/tests/std/life.c deleted file mode 100644 index e69de29..0000000 From ccf13ba4704dcc02dfaa6ad2de87a0de5d85f1de Mon Sep 17 00:00:00 2001 From: herbglitch Date: Tue, 11 Mar 2025 00:41:24 -0600 Subject: [PATCH 07/10] renamed chemical to config, and renamed life to entity --- include/arc/std/entity.h | 36 ++++++++++ src/std/entity.c | 3 + tests/res/std/config/first.chemical | 5 ++ tests/std/config.c | 108 ++++++++++++++++++++++++++++ tests/std/entity.c | 5 ++ 5 files changed, 157 insertions(+) create mode 100644 include/arc/std/entity.h create mode 100644 src/std/entity.c create mode 100644 tests/res/std/config/first.chemical create mode 100644 tests/std/config.c create mode 100644 tests/std/entity.c diff --git a/include/arc/std/entity.h b/include/arc/std/entity.h new file mode 100644 index 0000000..a6dd54e --- /dev/null +++ b/include/arc/std/entity.h @@ -0,0 +1,36 @@ +#ifndef ARC_STD_ENTITY_H_ +#define ARC_STD_ENTITY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * @brief an entity component system type +*/ +typedef struct ARC_EntitySystem ARC_EntitySystem; + +/** + * @brief an entity component system type +*/ +typedef uint32_t ARC_Entity; + +/** + * @brief +*/ +void ARC_EntitySystem_Create(ARC_EntitySystem **entitySystem); + +/** + * @brief destroys an ARC_EntitySystem + * + * @param[in] vector ARC_EntitySystem to free +*/ +void ARC_EntitySystem_Destroy(ARC_EntitySystem *entitySystem); + +#ifdef __cplusplus +} +#endif + +#endif // !ARC_STD_ENTITY_H_ diff --git a/src/std/entity.c b/src/std/entity.c new file mode 100644 index 0000000..c5bbcfb --- /dev/null +++ b/src/std/entity.c @@ -0,0 +1,3 @@ +#include "arc/std/entity.h" + + diff --git a/tests/res/std/config/first.chemical b/tests/res/std/config/first.chemical new file mode 100644 index 0000000..392097c --- /dev/null +++ b/tests/res/std/config/first.chemical @@ -0,0 +1,5 @@ +group test { + int32 test = 5; + + int32 test1 = -7; +} diff --git a/tests/std/config.c b/tests/std/config.c new file mode 100644 index 0000000..aa711e1 --- /dev/null +++ b/tests/std/config.c @@ -0,0 +1,108 @@ +#include "../test.h" +#include "arc/std/errno.h" +#include "arc/std/config.h" +#include "arc/std/parser.h" +#include "arc/std/parser/helpers.h" +#include + +static const char *testType = "int32"; + +void TEST_configType_CopyInt32Fn(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config){ + //go into the tag + ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(parsedData->tagTokens, 0); + if(childTagToken->id != ARC_CONFIG_NUMBER_SIGN){ + arc_errno = ARC_ERRNO_DATA; + ARC_DEBUG_LOG_ERROR("TEST_configType_CopyInt32Fn(type, parsedData, config), parsed data was not a "); + *type = NULL; + return; + } + + //check if the first tag is a minus sign and create a string starting with that if it is + childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(childTagToken->tagTokens, 0); + ARC_String *int32String; + ARC_String_Create(&int32String, NULL, 0); + if(childTagToken->id == ARC_CONFIG_MINUS){ + ARC_String_AppendCStringWithStrlen(&int32String, "-"); + } + + ARC_ParserData_HelperRecurseStringAdd(&int32String, parsedData); + + //set the max character size 2,147,483,647 (10 characters) or -2,147,483,648 (11 characters) + uint32_t maxInt32Size = 10; + if(int32String->data[0] == '-'){ + maxInt32Size++; + } + + //if the string is bigger than the possible size return NULL and error + if(int32String->length > maxInt32Size){ + arc_errno = ARC_ERRNO_DATA; + ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("TEST_configType_CopyInt32Fn(type, parsedData, config), size \"%s\" was bigger or smaller than the max 2,147,483,647 or min -2,147,483,648", int32String->data); + *type = NULL; + ARC_String_Destroy(int32String); + return; + } + + if(int32String->length == maxInt32Size){ + char maxint32CStr[10] = "2147483647"; + + //offset starting index and last number if there is a negative + uint8_t stringIndex = 0; + if(int32String->data[0] == '-'){ + stringIndex++; + maxint32CStr[9]++; + } + + for(uint8_t index = 0; index < 10; index++, stringIndex++){ + if(int32String->data[stringIndex] > maxint32CStr[index]){ + arc_errno = ARC_ERRNO_DATA; + ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("TEST_configType_CopyInt32Fn(type, parsedData, config), size \"%s\" was bigger or smaller than the max 2,147,483,647 or min -2,147,483,648", int32String->data); + *type = NULL; + ARC_String_Destroy(int32String); + return; + } + } + } + + //copy the int32_t + *type = malloc(sizeof(int32_t)); + *(int32_t *)(*type) = (int32_t)ARC_String_ToInt64_t(int32String); + + //cleanup + ARC_String_Destroy(int32String); +} + +void TEST_configType_DestroyInt32Fn(void *type){ + free((int32_t *)type); +} + +ARC_TEST(config_BasicTest){ + ARC_Config *config; + ARC_Config_Create(&config); + + ARC_CHECK(arc_errno == 0); + + ARC_ConfigType int32Type = { + TEST_configType_CopyInt32Fn, + TEST_configType_DestroyInt32Fn + }; + ARC_Config_RegisterTypeWithCStr(config, testType, int32Type); + + char *tempCString = "tests/res/std/config/first.chemical"; + ARC_String *tempString; + ARC_String_CreateWithStrlen(&tempString, tempCString); + ARC_Config_LoadFromFile(config, tempString); + + int32_t testVal = *(int32_t *)ARC_Config_GetWithCStr(config, "test::test"); + ARC_CHECK(testVal == 5); + testVal = *(int32_t *)ARC_Config_GetWithCStr(config, "test::test1"); + ARC_CHECK(testVal == -7); + + ARC_Config_UnloadFromFile(config, tempString); + + void *nullVal = ARC_Config_GetWithCStr(config, "test::test"); + ARC_CHECK(nullVal == NULL); + + //cleanup + ARC_String_Destroy(tempString); + ARC_Config_Destroy(config); +} diff --git a/tests/std/entity.c b/tests/std/entity.c new file mode 100644 index 0000000..cf524e9 --- /dev/null +++ b/tests/std/entity.c @@ -0,0 +1,5 @@ +#include "../test.h" +#include "arc/std/entity.h" + +ARC_TEST(Entity_Init){ +} From ba09aff914ddd42f10f10d1e956309a512afaca9 Mon Sep 17 00:00:00 2001 From: herbglitch Date: Thu, 13 Mar 2025 19:22:27 -0600 Subject: [PATCH 08/10] 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); +} From c078ce907f164587e389ff904968e6f62de51840 Mon Sep 17 00:00:00 2001 From: herbglitch Date: Fri, 14 Mar 2025 01:02:00 -0600 Subject: [PATCH 09/10] basics of ecs written, working on query, needs testing --- include/arc/std/entity.h | 54 ++++++++++++- src/std/entity.c | 167 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 205 insertions(+), 16 deletions(-) diff --git a/include/arc/std/entity.h b/include/arc/std/entity.h index 02ca6a1..011b49b 100644 --- a/include/arc/std/entity.h +++ b/include/arc/std/entity.h @@ -5,6 +5,8 @@ extern "C" { #endif +#include "arc/std/array.h" +#include "arc/std/bool.h" #include /** @@ -17,6 +19,14 @@ typedef struct ARC_EntitySystem ARC_EntitySystem; */ typedef uint32_t ARC_Entity; +/** + * @brief an entity component system type +*/ +typedef enum ARC_EntityFlags { + ARC_ENTITY_DEAD = 0, + ARC_ENTITY_ALIVE = 1 +} ARC_EntityFlags; + /** * @brief an entity component system type */ @@ -35,15 +45,51 @@ void ARC_EntitySystem_Create(ARC_EntitySystem **entitySystem); /** * @brief destroys an ARC_EntitySystem * - * @param[in] vector ARC_EntitySystem to free + * @param[in] entitySystem ARC_EntitySystem to free */ void ARC_EntitySystem_Destroy(ARC_EntitySystem *entitySystem); -void ARC_EntitySystem_RegisterComponent(ARC_EntitySystem *entitySystem, uint32_t componentSize); +/** + * @brief registers space for a component and an id for the compenent within the entity system + * + * @note this function will set arc_errno if the components run out of space + * + * @param[in] entitySystem the entity system to register the component to + * @param[in] componentSize the size of the component to register + * + * @return an id for for the component +*/ +uint32_t ARC_EntitySystem_RegisterComponent(ARC_EntitySystem *entitySystem, uint32_t componentSize); -//void ARC_EntitySystem_RunSystem(ARC_EntitySystem *entitySystem, ARC_Component component); +/** + * @brief +*/ +ARC_Entity ARC_EntitySystem_InitEntity(ARC_EntitySystem *entitySystem); -void ARC_EntitySystem_Run(ARC_EntitySystem *entitySystem); +/** + * @brief +*/ +void ARC_EntitySystem_ReleaseEntity(ARC_EntitySystem *entitySystem, ARC_Entity entity); + +/** + * @brief +*/ +void ARC_EntitySystem_AddComponent(ARC_EntitySystem *entitySystem, ARC_Entity entity, ARC_EntityComponent component, void *data); + +/** + * @brief +*/ +ARC_Bool ARC_EntitySystem_HasComponent(ARC_EntitySystem *entitySystem, ARC_Entity entity, ARC_EntityComponent component); + +/** + * @brief +*/ +void *ARC_EntitySystem_GetComponentData(ARC_EntitySystem *entitySystem, ARC_Entity entity, ARC_EntityComponent component); + +/** + * @brief +*/ +ARC_Array ARC_EntitySystem_QueryComponentsData(ARC_EntitySystem *entitySystem, uint32_t components); #ifdef __cplusplus } diff --git a/src/std/entity.c b/src/std/entity.c index c65c308..ebe1414 100644 --- a/src/std/entity.c +++ b/src/std/entity.c @@ -1,31 +1,174 @@ #include "arc/std/entity.h" +#include "arc/std/array.h" +#include "arc/std/errno.h" #include "arc/std/bool.h" -#include "arc/std/vector.h" +#include "arc/std/vector/inline.h" #include +#include //TODO: might want to change how vector holds data for speed struct ARC_EntitySystem { - ARC_Vector *flagVector; - ARC_Vector *maskVector; + //entity data + ARC_VectorInline *flagVector; + ARC_VectorInline *maskVector; - void *data; + //component data + ARC_VectorInline *offsetVector; + ARC_VectorInline *sizeVector; + + //stored component data + ARC_VectorInline *data; + + //TODO: this would probs be better to use a queue + ARC_VectorInline *freeEntities; }; 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_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); + ARC_VectorInline_Create(&((*entitySystem)->flagVector) , sizeof(uint8_t) , NULL, NULL); + ARC_VectorInline_Create(&((*entitySystem)->maskVector) , sizeof(uint32_t), NULL, NULL); + ARC_VectorInline_Create(&((*entitySystem)->offsetVector), sizeof(uint32_t), NULL, NULL); + ARC_VectorInline_Create(&((*entitySystem)->sizeVector) , sizeof(uint32_t), NULL, NULL); + //can't create the data vector because no components have been registered + (*entitySystem)->data = NULL; + + //TODO: this would probs be better to use a queue + ARC_VectorInline_Create(&((*entitySystem)->freeEntities), sizeof(ARC_Entity), NULL, NULL); +} + +void ARC_EntitySystem_Destroy(ARC_EntitySystem *entitySystem){ + if(entitySystem->data != NULL){ + ARC_VectorInline_Destroy(entitySystem->data); + } + + ARC_VectorInline_Destroy(entitySystem->sizeVector); + ARC_VectorInline_Destroy(entitySystem->offsetVector); + ARC_VectorInline_Destroy(entitySystem->maskVector); + ARC_VectorInline_Destroy(entitySystem->flagVector); + + free(entitySystem); +} + +uint32_t ARC_EntitySystem_RegisterComponent(ARC_EntitySystem *entitySystem, uint32_t componentSize){ + //error if componentSize is zero, it must have been an error because a component is a type, and types have size + if(componentSize == 0){ + arc_errno = ARC_ERRNO_NULL; + ARC_DEBUG_LOG_ERROR("ARC_EntitySystem_RegisterComponent(entitySystem, componentSize), cannot add a component that does not have a size"); + return ~(uint32_t)0; + } + + //if data exists, free it to recreate it with the new size + if(entitySystem->data != NULL){ + ARC_VectorInline_Destroy(entitySystem->data); + } + + //get the total component size + uint32_t offsetEndIndex = ARC_VectorInline_GetSize(entitySystem->offsetVector); + uint32_t totalSize = *(uint32_t *)ARC_VectorInline_Get(entitySystem->offsetVector, offsetEndIndex); + + //if the new component size would overflow, throw an error + if(totalSize > (~(uint32_t)0) - componentSize){ + arc_errno = ARC_ERRNO_NULL; + ARC_DEBUG_LOG_ERROR("ARC_EntitySystem_RegisterComponent(entitySystem, componentSize), cannot add a component because combined size with all the other components is bigger than a uint32_t max val"); + return ~(uint32_t)0; + } + + //add the component size to the total size and the offset vector array + ARC_VectorInline_Add(entitySystem->offsetVector, &totalSize); + ARC_VectorInline_Add(entitySystem->sizeVector , &componentSize); + totalSize += componentSize; + + //create the resized data vector that can now house the registered component + ARC_VectorInline_Create(&(entitySystem->data), totalSize, NULL, NULL); + + //get the id (last index) in the offset vector + return ARC_VectorInline_GetSize(entitySystem->offsetVector) - 1; +} + +ARC_Entity ARC_EntitySystem_InitEntity(ARC_EntitySystem *entitySystem){ + //check if there is a free id to use + if(ARC_VectorInline_GetSize(entitySystem->freeEntities) != 0){ + //get the next free entity and remove the used id from the free entities + ARC_Entity entity = *(ARC_Entity *)ARC_VectorInline_Get(entitySystem->freeEntities, 0); + ARC_VectorInline_RemoveIndex(entitySystem->freeEntities, 0); + + //set the flag to make the current entity alive + uint8_t *flagData = (uint8_t *)ARC_VectorInline_Get(entitySystem->flagVector, (uint32_t)entity); + *flagData = (uint8_t)ARC_ENTITY_ALIVE; + + //reset the mask data to clear all the components + uint8_t *maskData = (uint8_t *)ARC_VectorInline_Get(entitySystem->maskVector, (uint32_t)entity); + *maskData = 0; + + //return the entity + return entity; + } + + //get the next free entity + ARC_Entity entity = (ARC_Entity)ARC_VectorInline_GetSize(entitySystem->data); + //TODO: check if this works + ARC_VectorInline_Add(entitySystem->data, NULL); + + //set the flag to make the current entity alive + uint8_t *flagData = (uint8_t *)ARC_VectorInline_Get(entitySystem->flagVector, (uint32_t)entity); + *flagData = (uint8_t)ARC_ENTITY_ALIVE; + + //reset the mask data to clear all the components + uint8_t *maskData = (uint8_t *)ARC_VectorInline_Get(entitySystem->maskVector, (uint32_t)entity); + *maskData = 0; + + //return the entity + return entity; +} + +void ARC_EntitySystem_ReleaseEntity(ARC_EntitySystem *entitySystem, ARC_Entity entity){ + //set the flag to make the current entity dead + uint8_t *flagData = (uint8_t *)ARC_VectorInline_Get(entitySystem->flagVector, (uint32_t)entity); + *flagData = (uint8_t)ARC_ENTITY_DEAD; + + //add the entity to the free entities vector + ARC_VectorInline_Add(entitySystem->freeEntities, &entity); +} + +void ARC_EntitySystem_AddComponent(ARC_EntitySystem *entitySystem, ARC_Entity entity, ARC_EntityComponent component, void *data){ + //get the component data to set + uint32_t componentSize = *(uint32_t *)ARC_VectorInline_Get(entitySystem->sizeVector, (uint32_t)component); + void *componentData = ARC_EntitySystem_GetComponentData(entitySystem, entity, component); + + //set the component in the entity mask + uint32_t *maskData = (uint32_t *)ARC_VectorInline_Get(entitySystem->maskVector, (uint32_t)entity); + *maskData |= 1 << (uint32_t)component; + + //copy the data into the component + memcpy(componentData, data, componentSize); +} + +ARC_Bool ARC_EntitySystem_HasComponent(ARC_EntitySystem *entitySystem, ARC_Entity entity, ARC_EntityComponent component){ + //get the mask, then check if it holds a component + uint32_t *maskData = (uint32_t *)ARC_VectorInline_Get(entitySystem->maskVector, (uint32_t)entity); + return (ARC_Bool)((*maskData & (1 << (uint32_t)component)) != 0); +} + +void *ARC_EntitySystem_GetComponentData(ARC_EntitySystem *entitySystem, ARC_Entity entity, ARC_EntityComponent component){ + //get the entity row, then offset that for the component to get the component data + void *data = ARC_VectorInline_Get(entitySystem->data, (uint32_t)entity); + return data + *(int32_t *)ARC_VectorInline_Get(entitySystem->offsetVector, (uint32_t)component); +} + + +ARC_Array ARC_EntitySystem_QueryComponentsData(ARC_EntitySystem *entitySystem, uint32_t components){ + ARC_Array componentsData = { 0, NULL }; + + componentsData.size = ARC_VectorInline_GetSize(entitySystem->data) - ARC_VectorInline_GetSize(entitySystem->freeEntities); + + return componentsData; } From 6085d22df4f63d6a7bdd2fb959fb445b2e9dccd1 Mon Sep 17 00:00:00 2001 From: herbglitch Date: Sun, 16 Mar 2025 01:35:09 -0600 Subject: [PATCH 10/10] added get data function to inline and finished basic entity (still needs testing though --- include/arc/std/entity.h | 2 +- include/arc/std/vector/inline.h | 12 +++++++ src/std/entity.c | 59 +++++++++++++++++++++++++++------ src/std/vector/inline.c | 9 +++++ 4 files changed, 71 insertions(+), 11 deletions(-) diff --git a/include/arc/std/entity.h b/include/arc/std/entity.h index 011b49b..10d9112 100644 --- a/include/arc/std/entity.h +++ b/include/arc/std/entity.h @@ -89,7 +89,7 @@ void *ARC_EntitySystem_GetComponentData(ARC_EntitySystem *entitySystem, ARC_Enti /** * @brief */ -ARC_Array ARC_EntitySystem_QueryComponentsData(ARC_EntitySystem *entitySystem, uint32_t components); +ARC_Array ARC_EntitySystem_QueryComponentsData(ARC_EntitySystem *entitySystem, ARC_Array components); #ifdef __cplusplus } diff --git a/include/arc/std/vector/inline.h b/include/arc/std/vector/inline.h index cb5a466..3c6a409 100644 --- a/include/arc/std/vector/inline.h +++ b/include/arc/std/vector/inline.h @@ -5,6 +5,7 @@ extern "C" { #endif +#include "arc/std/array.h" #include "arc/std/vector.h" #include @@ -102,6 +103,17 @@ uint32_t ARC_VectorInline_GetSize(ARC_VectorInline *vectorInline); */ void *ARC_VectorInline_Get(ARC_VectorInline *vectorInline, uint32_t index); +/** + * @brief gets the data from the vector as an ARC_Array + * + * @note this function will does not copy the data it returns, so changes will affect the contents of the vector inline + * + * @param[in] vectorInline ARC_VectorInline to get data from + * + * @return an ARC_Array that holds the current contents of the vector inline +*/ +ARC_Array ARC_VectorInline_GetData(ARC_VectorInline *vectorInline); + #ifdef __cplusplus } #endif diff --git a/src/std/entity.c b/src/std/entity.c index ebe1414..2673f9b 100644 --- a/src/std/entity.c +++ b/src/std/entity.c @@ -21,18 +21,14 @@ struct ARC_EntitySystem { //TODO: this would probs be better to use a queue ARC_VectorInline *freeEntities; -}; -ARC_Bool ARC_EntitySystem_VectorCompareDataFn(void *dataA, void *dataB){ - return (ARC_Bool)(*(uint32_t *)dataA == *(uint32_t *)dataB); -} + //temporary array for the query function + ARC_Entity *query; +}; 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_VectorInline_Create(&((*entitySystem)->flagVector) , sizeof(uint8_t) , NULL, NULL); ARC_VectorInline_Create(&((*entitySystem)->maskVector) , sizeof(uint32_t), NULL, NULL); ARC_VectorInline_Create(&((*entitySystem)->offsetVector), sizeof(uint32_t), NULL, NULL); @@ -43,9 +39,16 @@ void ARC_EntitySystem_Create(ARC_EntitySystem **entitySystem){ //TODO: this would probs be better to use a queue ARC_VectorInline_Create(&((*entitySystem)->freeEntities), sizeof(ARC_Entity), NULL, NULL); + + //init an empty query + (*entitySystem)->query = NULL; } void ARC_EntitySystem_Destroy(ARC_EntitySystem *entitySystem){ + if(entitySystem->query != NULL){ + free(entitySystem->query); + } + if(entitySystem->data != NULL){ ARC_VectorInline_Destroy(entitySystem->data); } @@ -164,11 +167,47 @@ void *ARC_EntitySystem_GetComponentData(ARC_EntitySystem *entitySystem, ARC_Enti return data + *(int32_t *)ARC_VectorInline_Get(entitySystem->offsetVector, (uint32_t)component); } +ARC_Array ARC_EntitySystem_QueryComponentsData(ARC_EntitySystem *entitySystem, ARC_Array components){ + //get the mask for all the components + ARC_EntityComponent componentsMask = 0; + for(uint32_t index = 0; index < components.size; index++){ + componentsMask |= (1 << ((ARC_EntityComponent *)components.data)[index]); + } -ARC_Array ARC_EntitySystem_QueryComponentsData(ARC_EntitySystem *entitySystem, uint32_t components){ - ARC_Array componentsData = { 0, NULL }; + //setup teh components data and get a return size + uint32_t maxEntitySize = ARC_VectorInline_GetSize(entitySystem->data) - ARC_VectorInline_GetSize(entitySystem->freeEntities); - componentsData.size = ARC_VectorInline_GetSize(entitySystem->data) - ARC_VectorInline_GetSize(entitySystem->freeEntities); + //clear the query if it already exists + if(entitySystem->query != NULL){ + free(entitySystem->query); + } + //reserve space for the query + entitySystem->query = (ARC_Entity *)malloc(sizeof(ARC_Entity) * maxEntitySize); + + //get all the alive entities that match the components + uint32_t queryIndex = 0; + for(uint32_t index = 0; index < ARC_VectorInline_GetSize(entitySystem->data); index++){ + uint8_t entityFlag = *(uint8_t *)ARC_VectorInline_Get(entitySystem->flagVector, index); + if((entityFlag & ARC_ENTITY_DEAD) != 0){ + continue; + } + + //if the entity's component mask matches the components passed in + uint32_t entityComponentMask = *(uint32_t *)ARC_VectorInline_Get(entitySystem->maskVector, index); + if((entityComponentMask & componentsMask) == componentsMask){ + //set the value at the queryIndex + entitySystem->query[queryIndex] = index; + queryIndex++; + } + } + + //set components data to the query array + ARC_Array componentsData = { + queryIndex, + entitySystem->query + }; + + //return the ids that hold all the components return componentsData; } diff --git a/src/std/vector/inline.c b/src/std/vector/inline.c index add84e5..fb7129e 100644 --- a/src/std/vector/inline.c +++ b/src/std/vector/inline.c @@ -1,7 +1,9 @@ #include "arc/std/vector/inline.h" +#include "arc/std/array.h" #include "arc/std/bool.h" #include "arc/std/errno.h" +#include "arc/std/vector.h" #include #include #include @@ -165,3 +167,10 @@ void *ARC_VectorInline_Get(ARC_VectorInline *vectorInline, uint32_t index){ return (vectorInline->data + (vectorInline->typeSize * index)); } + +ARC_Array ARC_VectorInline_GetData(ARC_VectorInline *vectorInline){ + return (ARC_Array){ + vectorInline->currentSize, + vectorInline->data + }; +}