From d62ee2a9a37ba16d64ebeb743ea38cadbd61c571 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Mon, 7 Oct 2024 14:13:39 +1100 Subject: [PATCH] Added 'name' to string types --- source/toy_string.c | 53 +++++++++++++++++++++++---- source/toy_string.h | 9 +++++ tests/cases/test_string.c | 76 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 6 deletions(-) diff --git a/source/toy_string.c b/source/toy_string.c index d64ad1e..bf50984 100644 --- a/source/toy_string.c +++ b/source/toy_string.c @@ -53,6 +53,20 @@ Toy_String* Toy_createStringLength(Toy_Bucket** bucketHandle, const char* cstrin return ret; } +TOY_API Toy_String* Toy_createNameString(Toy_Bucket** bucketHandle, const char* cname) { + int length = strlen(cname); + + Toy_String* ret = (Toy_String*)Toy_partitionBucket(bucketHandle, sizeof(Toy_String) + length + 1); //TODO: compensate for partitioning more space than bucket capacity + + ret->type = TOY_STRING_NAME; + ret->length = length; + ret->refCount = 1; + memcpy(ret->as.name.data, cname, length); + ret->as.name.data[length] = '\0'; + + return ret; +} + Toy_String* Toy_copyString(Toy_Bucket** bucketHandle, Toy_String* str) { if (str->refCount == 0) { fprintf(stderr, TOY_CC_ERROR "ERROR: Can't copy a string with refcount of zero\n" TOY_CC_RESET); @@ -69,17 +83,30 @@ Toy_String* Toy_deepCopyString(Toy_Bucket** bucketHandle, Toy_String* str) { } Toy_String* ret = (Toy_String*)Toy_partitionBucket(bucketHandle, sizeof(Toy_String) + str->length + 1); //TODO: compensate for partitioning more space than bucket capacity - // - ret->type = TOY_STRING_LEAF; - ret->length = str->length; - ret->refCount = 1; - deepCopyUtil(ret->as.leaf.data, str); //copy each leaf into the buffer - ret->as.leaf.data[ret->length] = '\0'; + if (str->type == TOY_STRING_NODE || str->type == TOY_STRING_LEAF) { + ret->type = TOY_STRING_LEAF; + ret->length = str->length; + ret->refCount = 1; + deepCopyUtil(ret->as.leaf.data, str); //copy each leaf into the buffer + ret->as.leaf.data[ret->length] = '\0'; + } + else { + ret->type = TOY_STRING_NAME; + ret->length = str->length; + ret->refCount = 1; + memcpy(ret->as.name.data, str->as.name.data, str->length); + ret->as.name.data[ret->length] = '\0'; + } return ret; } Toy_String* Toy_concatStrings(Toy_Bucket** bucketHandle, Toy_String* left, Toy_String* right) { + if (left->type == TOY_STRING_NAME || right->type == TOY_STRING_NAME) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Can't concatenate a name string\n" TOY_CC_RESET); + exit(-1); + } + if (left->refCount == 0 || right->refCount == 0) { fprintf(stderr, TOY_CC_ERROR "ERROR: Can't concatenate a string with refcount of zero\n" TOY_CC_RESET); exit(-1); @@ -112,6 +139,11 @@ int Toy_getStringRefCount(Toy_String* str) { } char* Toy_getStringRawBuffer(Toy_String* str) { + if (str->type == TOY_STRING_NAME) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Can't get raw string buffer of a name string\n" TOY_CC_RESET); + exit(-1); + } + if (str->refCount == 0) { fprintf(stderr, TOY_CC_ERROR "ERROR: Can't get raw string buffer of a string with refcount of zero\n" TOY_CC_RESET); exit(-1); @@ -204,6 +236,15 @@ int Toy_compareStrings(Toy_String* left, Toy_String* right) { return left->length - right->length; } + if (left->type == TOY_STRING_NAME || right->type == TOY_STRING_NAME) { + if (left->type != right->type) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Can't compare a name string to a non-name string\n" TOY_CC_RESET); + exit(-1); + } + + return strcmp(left->as.name.data, right->as.name.data); + } + //util pointers const char* leftHead = NULL; const char* rightHead = NULL; diff --git a/source/toy_string.h b/source/toy_string.h index ef1d83a..1e69b43 100644 --- a/source/toy_string.h +++ b/source/toy_string.h @@ -1,12 +1,14 @@ #include "toy_common.h" #include "toy_bucket.h" +#include "toy_value.h" //rope pattern typedef struct Toy_String { //32 | 64 BITNESS enum Toy_StringType { TOY_STRING_NODE, TOY_STRING_LEAF, + TOY_STRING_NAME, } type; //4 | 4 unsigned int length; //4 | 4 @@ -24,12 +26,19 @@ typedef struct Toy_String { //32 | 64 BITNESS int _dummy; //4 | 4 char data[]; //- | - } leaf; //4 | 4 + + struct { + Toy_ValueType type; //4 | 4 + char data[]; //- | - + } name; //4 | 4 } as; //8 | 16 } Toy_String; //24 | 32 TOY_API Toy_String* Toy_createString(Toy_Bucket** bucketHandle, const char* cstring); TOY_API Toy_String* Toy_createStringLength(Toy_Bucket** bucketHandle, const char* cstring, int length); +TOY_API Toy_String* Toy_createNameString(Toy_Bucket** bucketHandle, const char* cname); //for variable names + TOY_API Toy_String* Toy_copyString(Toy_Bucket** bucketHandle, Toy_String* str); TOY_API Toy_String* Toy_deepCopyString(Toy_Bucket** bucketHandle, Toy_String* str); diff --git a/tests/cases/test_string.c b/tests/cases/test_string.c index cea11e5..e4bb7c6 100644 --- a/tests/cases/test_string.c +++ b/tests/cases/test_string.c @@ -100,6 +100,32 @@ int test_string_allocation() { Toy_freeBucket(&bucket); } + //copy and deep copy a name string + { + //setup + Toy_Bucket* bucket = Toy_allocateBucket(1024); + + const char* cstring = "Hello world"; + Toy_String* str = Toy_createNameString(&bucket, cstring); + + //shallow and deep + Toy_String* shallow = Toy_copyString(&bucket, str); + Toy_String* deep = Toy_deepCopyString(&bucket, str); + + if (str != shallow || + str == deep || + shallow->refCount != 2 || + deep->refCount != 1 || + strcmp(shallow->as.name.data, deep->as.name.data) != 0) + { + fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to copy a name string correctly\n" TOY_CC_RESET); + Toy_freeBucket(&bucket); + return -1; + } + + Toy_freeBucket(&bucket); + } + //allocate a zero-length string { //setup @@ -623,6 +649,56 @@ int test_string_equality() { Toy_freeBucket(&bucket); } + //simple name equality + { + //setup + Toy_Bucket* bucket = Toy_allocateBucket(1024); + Toy_String* helloWorldOne = Toy_createNameString(&bucket, "Hello world"); + Toy_String* helloWorldTwo = Toy_createNameString(&bucket, "Hello world"); + Toy_String* helloEveryone = Toy_createNameString(&bucket, "Hello everyone"); + + int result = 0; //for print the errors + + //check match + if ((result = Toy_compareStrings(helloWorldOne, helloWorldTwo)) != 0) + { + char* leftBuffer = Toy_getStringRawBuffer(helloWorldOne); + char* rightBuffer = Toy_getStringRawBuffer(helloWorldTwo); + fprintf(stderr, TOY_CC_ERROR "ERROR: Name string equality '%s' == '%s' is incorrect, found %s\n" TOY_CC_RESET, leftBuffer, rightBuffer, result < 0 ? "<" : result == 0 ? "==" : ">"); + free(leftBuffer); + free(rightBuffer); + Toy_freeBucket(&bucket); + return -1; + } + + //check mismatch + if ((result = Toy_compareStrings(helloWorldOne, helloEveryone)) == 0) + { + char* leftBuffer = Toy_getStringRawBuffer(helloWorldOne); + char* rightBuffer = Toy_getStringRawBuffer(helloEveryone); + fprintf(stderr, TOY_CC_ERROR "ERROR: Name string equality '%s' != '%s' is incorrect, found %s\n" TOY_CC_RESET, leftBuffer, rightBuffer, result < 0 ? "<" : result == 0 ? "==" : ">"); + free(leftBuffer); + free(rightBuffer); + Toy_freeBucket(&bucket); + return -1; + } + + //check match (same object) + if ((result = Toy_compareStrings(helloWorldOne, helloWorldOne)) != 0) + { + char* leftBuffer = Toy_getStringRawBuffer(helloWorldOne); + char* rightBuffer = Toy_getStringRawBuffer(helloWorldOne); + fprintf(stderr, TOY_CC_ERROR "ERROR: Name string equality '%s' == '%s' is incorrect, found %s (these are the same object)\n" TOY_CC_RESET, leftBuffer, rightBuffer, result < 0 ? "<" : result == 0 ? "==" : ">"); + free(leftBuffer); + free(rightBuffer); + Toy_freeBucket(&bucket); + return -1; + } + + //cleanup + Toy_freeBucket(&bucket); + } + return 0; }