1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-12 10:04:14 +02:00

Refactor String, Buffer, and Variant types with inline getters.

Extend the pattern introduced in 79a2d02c to the String, Buffer, and Variant types.
This commit is contained in:
David Steele 2021-04-27 15:25:10 -04:00
parent 1edcfde93e
commit 066fbcf268
9 changed files with 440 additions and 461 deletions

View File

@ -28,8 +28,7 @@ Contains information about the buffer
***********************************************************************************************************************************/
struct Buffer
{
BUFFER_COMMON // Variables that are common to static and dynamic buffers
unsigned char *buffer; // Internal buffer
BufferPub pub; // Publicly accessible variables
};
/**********************************************************************************************************************************/
@ -49,14 +48,17 @@ bufNew(size_t size)
*this = (Buffer)
{
.memContext = MEM_CONTEXT_NEW(),
.sizeAlloc = size,
.size = size,
.pub =
{
.memContext = MEM_CONTEXT_NEW(),
.sizeAlloc = size,
.size = size,
},
};
// Allocate buffer
if (size > 0)
this->buffer = memNew(this->sizeAlloc);
this->pub.buffer = memNew(this->pub.sizeAlloc);
}
MEM_CONTEXT_NEW_END();
@ -76,8 +78,8 @@ bufNewC(const void *buffer, size_t size)
// Create object and copy data
Buffer *this = bufNew(size);
memcpy(this->buffer, buffer, this->size);
this->used = this->size;
memcpy(this->pub.buffer, buffer, bufSize(this));
this->pub.used = bufSize(this);
FUNCTION_TEST_RETURN(this);
}
@ -110,9 +112,9 @@ bufDup(const Buffer *buffer)
ASSERT(buffer != NULL);
// Create object and copy data
Buffer *this = bufNew(buffer->used);
memcpy(this->buffer, buffer->buffer, this->size);
this->used = this->size;
Buffer *this = bufNew(buffer->pub.used);
memcpy(this->pub.buffer, buffer->pub.buffer, bufSize(this));
this->pub.used = bufSize(this);
FUNCTION_TEST_RETURN(this);
}
@ -129,7 +131,7 @@ bufCat(Buffer *this, const Buffer *cat)
ASSERT(this != NULL);
if (cat != NULL)
bufCatC(this, cat->buffer, 0, cat->used);
bufCatC(this, cat->pub.buffer, 0, cat->pub.used);
FUNCTION_TEST_RETURN(this);
}
@ -150,14 +152,14 @@ bufCatC(Buffer *this, const unsigned char *cat, size_t catOffset, size_t catSize
if (catSize > 0)
{
if (this->used + catSize > bufSize(this))
bufResize(this, this->used + catSize);
if (bufUsed(this) + catSize > bufSize(this))
bufResize(this, bufUsed(this) + catSize);
// Just here to silence nonnull warnings from clang static analyzer
ASSERT(this->buffer != NULL);
ASSERT(bufPtr(this) != NULL);
memcpy(this->buffer + this->used, cat + catOffset, catSize);
this->used += catSize;
memcpy(bufPtr(this) + bufUsed(this), cat + catOffset, catSize);
this->pub.used += catSize;
}
FUNCTION_TEST_RETURN(this);
@ -178,10 +180,10 @@ bufCatSub(Buffer *this, const Buffer *cat, size_t catOffset, size_t catSize)
if (cat != NULL)
{
ASSERT(catOffset <= cat->used);
ASSERT(catSize <= cat->used - catOffset);
ASSERT(catOffset <= cat->pub.used);
ASSERT(catSize <= cat->pub.used - catOffset);
bufCatC(this, cat->buffer, catOffset, catSize);
bufCatC(this, cat->pub.buffer, catOffset, catSize);
}
FUNCTION_TEST_RETURN(this);
@ -199,12 +201,10 @@ bufEq(const Buffer *this, const Buffer *compare)
ASSERT(this != NULL);
ASSERT(compare != NULL);
bool result = false;
if (bufUsed(this) == bufUsed(compare))
FUNCTION_TEST_RETURN(memcmp(bufPtrConst(this), bufPtrConst(compare), bufUsed(compare)) == 0);
if (this->used == compare->used)
result = memcmp(this->buffer, compare->buffer, compare->used) == 0;
FUNCTION_TEST_RETURN(result);
FUNCTION_TEST_RETURN(false);
}
/**********************************************************************************************************************************/
@ -220,7 +220,7 @@ bufHex(const Buffer *this)
String *result = strNew("");
for (unsigned int bufferIdx = 0; bufferIdx < bufUsed(this); bufferIdx++)
strCatFmt(result, "%02x", this->buffer[bufferIdx]);
strCatFmt(result, "%02x", bufPtrConst(this)[bufferIdx]);
FUNCTION_TEST_RETURN(result);
}
@ -237,45 +237,45 @@ bufResize(Buffer *this, size_t size)
ASSERT(this != NULL);
// Only resize if it the new size is different
if (this->sizeAlloc != size)
if (bufSizeAlloc(this) != size)
{
// If new size is zero then free memory if allocated
if (size == 0)
{
// When setting size down to 0 the buffer should always be allocated
ASSERT(this->buffer != NULL);
ASSERT(bufPtrConst(this) != NULL);
MEM_CONTEXT_BEGIN(this->memContext)
MEM_CONTEXT_BEGIN(this->pub.memContext)
{
memFree(this->buffer);
memFree(bufPtr(this));
}
MEM_CONTEXT_END();
this->buffer = NULL;
this->sizeAlloc = 0;
this->pub.buffer = NULL;
this->pub.sizeAlloc = 0;
}
// Else allocate or resize
else
{
MEM_CONTEXT_BEGIN(this->memContext)
MEM_CONTEXT_BEGIN(this->pub.memContext)
{
if (this->buffer == NULL)
this->buffer = memNew(size);
if (bufPtrConst(this) == NULL)
this->pub.buffer = memNew(size);
else
this->buffer = memResize(this->buffer, size);
this->pub.buffer = memResize(bufPtr(this), size);
}
MEM_CONTEXT_END();
this->sizeAlloc = size;
this->pub.sizeAlloc = size;
}
if (this->used > this->sizeAlloc)
this->used = this->sizeAlloc;
if (bufUsed(this) > bufSizeAlloc(this))
this->pub.used = bufSizeAlloc(this);
if (!this->sizeLimit)
this->size = this->sizeAlloc;
else if (this->size > this->sizeAlloc)
this->size = this->sizeAlloc;
if (!bufSizeLimit(this))
this->pub.size = bufSizeAlloc(this);
else if (bufSize(this) > bufSizeAlloc(this))
this->pub.size = bufSizeAlloc(this);
}
FUNCTION_TEST_RETURN(this);
@ -291,8 +291,8 @@ bufLimitClear(Buffer *this)
ASSERT(this != NULL);
this->sizeLimit = false;
this->size = this->sizeAlloc;
this->pub.sizeLimit = false;
this->pub.size = bufSizeAlloc(this);
FUNCTION_TEST_RETURN_VOID();
}
@ -306,11 +306,11 @@ bufLimitSet(Buffer *this, size_t limit)
FUNCTION_TEST_END();
ASSERT(this != NULL);
ASSERT(limit <= this->sizeAlloc);
ASSERT(limit >= this->used);
ASSERT(limit <= bufSizeAlloc(this));
ASSERT(limit >= bufUsed(this));
this->size = limit;
this->sizeLimit = true;
this->pub.size = limit;
this->pub.sizeLimit = true;
FUNCTION_TEST_RETURN_VOID();
}
@ -325,9 +325,9 @@ bufUsedInc(Buffer *this, size_t inc)
FUNCTION_TEST_END();
ASSERT(this != NULL);
ASSERT(this->used + inc <= bufSize(this));
ASSERT(bufUsed(this) + inc <= bufSize(this));
this->used += inc;
this->pub.used += inc;
FUNCTION_TEST_RETURN_VOID();
}
@ -343,7 +343,7 @@ bufUsedSet(Buffer *this, size_t used)
ASSERT(this != NULL);
ASSERT(used <= bufSize(this));
this->used = used;
this->pub.used = used;
FUNCTION_TEST_RETURN_VOID();
}
@ -357,7 +357,7 @@ bufUsedZero(Buffer *this)
ASSERT(this != NULL);
this->used = 0;
this->pub.used = 0;
FUNCTION_TEST_RETURN_VOID();
}
@ -367,8 +367,8 @@ String *
bufToLog(const Buffer *this)
{
String *result = strNewFmt(
"{used: %zu, size: %zu%s", this->used, this->size,
this->sizeLimit ? strZ(strNewFmt(", sizeAlloc: %zu}", this->sizeAlloc)) : "}");
"{used: %zu, size: %zu%s", bufUsed(this), bufSize(this),
bufSizeLimit(this) ? strZ(strNewFmt(", sizeAlloc: %zu}", bufSizeAlloc(this))) : "}");
return result;
}

View File

@ -13,27 +13,6 @@ typedef struct Buffer Buffer;
#include "common/type/object.h"
#include "common/type/string.h"
/***********************************************************************************************************************************
Fields that are common between dynamically allocated and constant buffers
There is nothing user-accessible here but this construct allows constant buffers to be created and then handled by the same
functions that process dynamically allocated buffers.
***********************************************************************************************************************************/
#define BUFFER_COMMON \
MemContext *memContext; /* Mem context */ \
size_t sizeAlloc; /* Allocated size of the buffer */ \
size_t size; /* Reported size of the buffer */ \
bool sizeLimit; /* Is the size limited to make the buffer appear smaller? */ \
size_t used; /* Amount of buffer used */
typedef struct BufferConst
{
BUFFER_COMMON
// This version of buffer is for const macro assignments because casting can be dangerous
const void *buffer;
} BufferConst;
/***********************************************************************************************************************************
Constructors
***********************************************************************************************************************************/
@ -48,6 +27,90 @@ Buffer *bufNewDecode(EncodeType type, const String *string);
// Duplicate a buffer
Buffer *bufDup(const Buffer *buffer);
/***********************************************************************************************************************************
Getters/Setters
***********************************************************************************************************************************/
typedef struct BufferPub
{
MemContext *memContext; // Mem context
size_t sizeAlloc; // Allocated size of the buffer
size_t size; // Reported size of the buffer
bool sizeLimit; // Is the size limited to make the buffer appear smaller?
size_t used; // Amount of buffer used
unsigned char *buffer; // Buffer
} BufferPub;
// Amount of the buffer actually used. This will be updated automatically when possible but if the buffer is modified by using
// bufPtr() then the user is responsible for updating used.
__attribute__((always_inline)) static inline size_t
bufUsed(const Buffer *const this)
{
return THIS_PUB(Buffer)->used;
}
// Is the buffer empty?
__attribute__((always_inline)) static inline bool
bufEmpty(const Buffer *const this)
{
return bufUsed(this) == 0;
}
// Buffer size
__attribute__((always_inline)) static inline size_t
bufSize(const Buffer *const this)
{
return THIS_PUB(Buffer)->size;
}
// Is the buffer full?
__attribute__((always_inline)) static inline bool
bufFull(const Buffer *const this)
{
return bufUsed(this) == bufSize(this);
}
// Buffer pointer
__attribute__((always_inline)) static inline unsigned char *
bufPtr(Buffer *const this)
{
return THIS_PUB(Buffer)->buffer;
}
// Const buffer pointer
__attribute__((always_inline)) static inline const unsigned char *
bufPtrConst(const Buffer *const this)
{
return THIS_PUB(Buffer)->buffer;
}
// Remaining space in the buffer
__attribute__((always_inline)) static inline size_t
bufRemains(const Buffer *const this)
{
return bufSize(this) - bufUsed(this);
}
// Pointer to remaining buffer space (after used space)
__attribute__((always_inline)) static inline unsigned char *
bufRemainsPtr(Buffer *const this)
{
return bufPtr(this) + bufUsed(this);
}
// Allocated buffer size. This may be different from bufSize() if a limit has been set.
__attribute__((always_inline)) static inline size_t
bufSizeAlloc(const Buffer *const this)
{
return THIS_PUB(Buffer)->sizeAlloc;
}
// Is the size limited to make the buffer appear smaller?
__attribute__((always_inline)) static inline bool
bufSizeLimit(const Buffer *const this)
{
return THIS_PUB(Buffer)->sizeLimit;
}
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
@ -80,82 +143,10 @@ Buffer *bufResize(Buffer *this, size_t size);
void bufLimitClear(Buffer *this);
void bufLimitSet(Buffer *this, size_t limit);
// Buffer size
__attribute__((always_inline)) static inline size_t
bufSize(const Buffer *const this)
{
ASSERT_INLINE(this != NULL);
return ((const BufferConst *)this)->size;
}
// Allocated buffer size. This may be different from bufSize() if a limit has been set.
__attribute__((always_inline)) static inline size_t
bufSizeAlloc(const Buffer *const this)
{
ASSERT_INLINE(this != NULL);
return ((const BufferConst *)this)->sizeAlloc;
}
// Amount of the buffer actually used. This will be updated automatically when possible but if the buffer is modified by using
// bufPtr() then the user is responsible for updating used.
__attribute__((always_inline)) static inline size_t
bufUsed(const Buffer *const this)
{
ASSERT_INLINE(this != NULL);
return ((const BufferConst *)this)->used;
}
void bufUsedInc(Buffer *this, size_t inc);
void bufUsedSet(Buffer *this, size_t used);
void bufUsedZero(Buffer *this);
// Is the buffer empty?
__attribute__((always_inline)) static inline bool
bufEmpty(const Buffer *const this)
{
return bufUsed(this) == 0;
}
// Remaining space in the buffer
__attribute__((always_inline)) static inline size_t
bufRemains(const Buffer *const this)
{
return bufSize(this) - bufUsed(this);
}
// Is the buffer full?
__attribute__((always_inline)) static inline bool
bufFull(const Buffer *const this)
{
return bufUsed(this) == bufSize(this);
}
/***********************************************************************************************************************************
Getters/Setters
***********************************************************************************************************************************/
// Buffer pointer
__attribute__((always_inline)) static inline unsigned char *
bufPtr(Buffer *const this)
{
ASSERT_INLINE(this != NULL);
return (void *)((BufferConst *)this)->buffer;
}
// Const buffer pointer
__attribute__((always_inline)) static inline const unsigned char *
bufPtrConst(const Buffer *const this)
{
ASSERT_INLINE(this != NULL);
return ((const BufferConst *)this)->buffer;
}
// Pointer to remaining buffer space (after used space)
__attribute__((always_inline)) static inline unsigned char *
bufRemainsPtr(Buffer *const this)
{
return bufPtr(this) + bufUsed(this);
}
/***********************************************************************************************************************************
Destructor
***********************************************************************************************************************************/
@ -177,7 +168,7 @@ By convention all buffer constant identifiers are appended with _BUF.
***********************************************************************************************************************************/
// Create a buffer constant inline from an unsigned char[]
#define BUF(bufferParam, sizeParam) \
((const Buffer *)&(const BufferConst){.size = sizeParam, .used = sizeParam, .buffer = bufferParam})
((const Buffer *)&(const BufferPub){.size = sizeParam, .used = sizeParam, .buffer = (unsigned char *)bufferParam})
// Create a buffer constant inline from a non-constant zero-terminated string
#define BUFSTRZ(stringz) \

View File

@ -57,7 +57,7 @@ Object type
***********************************************************************************************************************************/
struct String
{
STRING_COMMON // Shared in common with constant strings
StringPub pub; // Publicly accessible variables
MemContext *memContext; // Required for dynamically allocated strings
};
@ -80,16 +80,19 @@ strNew(const char *string)
*this = (String)
{
.memContext = memContextCurrent(),
.size = (unsigned int)stringSize,
.pub =
{
.size = (unsigned int)stringSize,
// A zero-length string is not very useful so assume this string is being created for appending and allocate extra space
.extra = stringSize == 0 ? STRING_EXTRA_MIN : 0,
// A zero-length string is not very useful so assume this string is being created for appending and allocate extra space
.extra = stringSize == 0 ? STRING_EXTRA_MIN : 0,
},
.memContext = memContextCurrent(),
};
// Allocate and assign string
this->buffer = memNew(this->size + this->extra + 1);
strcpy(this->buffer, string);
this->pub.buffer = memNew(strSize(this) + this->pub.extra + 1);
strcpy(this->pub.buffer, string);
FUNCTION_TEST_RETURN(this);
}
@ -126,14 +129,17 @@ strNewBuf(const Buffer *buffer)
*this = (String)
{
.pub =
{
.size = (unsigned int)bufUsed(buffer),
},
.memContext = memContextCurrent(),
.size = (unsigned int)bufUsed(buffer),
};
// Allocate and assign string
this->buffer = memNew(this->size + 1);
memcpy(this->buffer, bufPtrConst(buffer), this->size);
this->buffer[this->size] = 0;
this->pub.buffer = memNew(strSize(this) + 1);
memcpy(this->pub.buffer, bufPtrConst(buffer), strSize(this));
this->pub.buffer[strSize(this)] = 0;
FUNCTION_TEST_RETURN(this);
}
@ -158,13 +164,16 @@ strNewEncode(EncodeType type, const Buffer *buffer)
*this = (String)
{
.pub =
{
.size = (unsigned int)size,
},
.memContext = memContextCurrent(),
.size = (unsigned int)size,
};
// Allocate and encode buffer
this->buffer = memNew(this->size + 1);
encodeToStr(type, bufPtrConst(buffer), bufUsed(buffer), this->buffer);
this->pub.buffer = memNew(strSize(this) + 1);
encodeToStr(type, bufPtrConst(buffer), bufUsed(buffer), this->pub.buffer);
FUNCTION_TEST_RETURN(this);
}
@ -197,10 +206,10 @@ strNewFmt(const char *format, ...)
CHECK_SIZE(formatSize);
// Allocate and assign string
this->size = (unsigned int)formatSize;
this->buffer = memNew(this->size + 1);
this->pub.size = (unsigned int)formatSize;
this->pub.buffer = memNew(strSize(this) + 1);
va_start(argumentList, format);
vsnprintf(this->buffer, this->size + 1, format, argumentList);
vsnprintf(this->pub.buffer, strSize(this) + 1, format, argumentList);
va_end(argumentList);
FUNCTION_TEST_RETURN(this);
@ -225,14 +234,17 @@ strNewN(const char *string, size_t size)
*this = (String)
{
.pub =
{
.size = (unsigned int)size,
},
.memContext = memContextCurrent(),
.size = (unsigned int)size,
};
// Allocate and assign string
this->buffer = memNew(this->size + 1);
strncpy(this->buffer, string, this->size);
this->buffer[this->size] = 0;
this->pub.buffer = memNew(strSize(this) + 1);
strncpy(this->pub.buffer, string, strSize(this));
this->pub.buffer[strSize(this)] = 0;
// Return buffer
FUNCTION_TEST_RETURN(this);
@ -260,9 +272,9 @@ strBaseZ(const String *this)
ASSERT(this != NULL);
const char *end = this->buffer + this->size;
const char *end = this->pub.buffer + strSize(this);
while (end > this->buffer && *(end - 1) != '/')
while (end > this->pub.buffer && *(end - 1) != '/')
end--;
FUNCTION_TEST_RETURN(end);
@ -297,7 +309,7 @@ strBeginsWithZ(const String *this, const char *beginsWith)
bool result = false;
unsigned int beginsWithSize = (unsigned int)strlen(beginsWith);
if (this->size >= beginsWithSize)
if (strSize(this) >= beginsWithSize)
result = strncmp(strZ(this), beginsWith, beginsWithSize) == 0;
FUNCTION_TEST_RETURN(result);
@ -314,21 +326,21 @@ strResize(String *this, size_t requested)
FUNCTION_TEST_PARAM(SIZE, requested);
FUNCTION_TEST_END();
if (requested > this->extra)
if (requested > this->pub.extra)
{
// Check size
CHECK_SIZE((size_t)this->size + requested);
CHECK_SIZE(strSize(this) + requested);
// Calculate new extra needs to satisfy request and leave extra space for new growth
this->extra = (unsigned int)requested + ((this->size + (unsigned int)requested) / 2);
this->pub.extra = (unsigned int)(requested + ((strSize(this) + requested) / 2));
// Adding too little extra space usually leads to immediate resizing so enforce a minimum
if (this->extra < STRING_EXTRA_MIN)
this->extra = STRING_EXTRA_MIN;
if (this->pub.extra < STRING_EXTRA_MIN)
this->pub.extra = STRING_EXTRA_MIN;
MEM_CONTEXT_BEGIN(this->memContext)
{
this->buffer = memResize(this->buffer, this->size + this->extra + 1);
this->pub.buffer = memResize(this->pub.buffer, strSize(this) + this->pub.extra + 1);
}
MEM_CONTEXT_END();
}
@ -369,9 +381,9 @@ strCatZ(String *this, const char *cat)
strResize(this, sizeGrow);
// Append the string
strcpy(this->buffer + this->size, cat);
this->size += (unsigned int)sizeGrow;
this->extra -= (unsigned int)sizeGrow;
strcpy(this->pub.buffer + strSize(this), cat);
this->pub.size += (unsigned int)sizeGrow;
this->pub.extra -= (unsigned int)sizeGrow;
FUNCTION_TEST_RETURN(this);
}
@ -392,12 +404,12 @@ strCatZN(String *this, const char *cat, size_t size)
strResize(this, size);
// Append the string
strncpy(this->buffer + this->size, cat, size);
this->buffer[this->size + size] = '\0';
strncpy(this->pub.buffer + strSize(this), cat, size);
this->pub.buffer[strSize(this) + size] = '\0';
// Update size/extra
this->size += (unsigned int)size;
this->extra -= (unsigned int)size;
this->pub.size += (unsigned int)size;
this->pub.extra -= (unsigned int)size;
FUNCTION_TEST_RETURN(this);
}
@ -418,9 +430,9 @@ strCatChr(String *this, char cat)
strResize(this, 1);
// Append the character
this->buffer[this->size++] = cat;
this->buffer[this->size] = 0;
this->extra--;
this->pub.buffer[this->pub.size++] = cat;
this->pub.buffer[this->pub.size] = 0;
this->pub.extra--;
FUNCTION_TEST_RETURN(this);
}
@ -443,11 +455,11 @@ strCatEncode(String *this, EncodeType type, const Buffer *buffer)
strResize(this, encodeSize);
// Append the encoded string
encodeToStr(type, bufPtrConst(buffer), bufUsed(buffer), this->buffer + this->size);
encodeToStr(type, bufPtrConst(buffer), bufUsed(buffer), this->pub.buffer + strSize(this));
// Update size/extra
this->size += (unsigned int)encodeSize;
this->extra -= (unsigned int)encodeSize;
this->pub.size += (unsigned int)encodeSize;
this->pub.extra -= (unsigned int)encodeSize;
FUNCTION_TEST_RETURN(this);
}
@ -475,11 +487,11 @@ strCatFmt(String *this, const char *format, ...)
// Append the formatted string
va_start(argumentList, format);
vsnprintf(this->buffer + this->size, sizeGrow + 1, format, argumentList);
vsnprintf(this->pub.buffer + strSize(this), sizeGrow + 1, format, argumentList);
va_end(argumentList);
this->size += (unsigned int)sizeGrow;
this->extra -= (unsigned int)sizeGrow;
this->pub.size += (unsigned int)sizeGrow;
this->pub.extra -= (unsigned int)sizeGrow;
FUNCTION_TEST_RETURN(this);
}
@ -573,8 +585,8 @@ strEndsWithZ(const String *this, const char *endsWith)
bool result = false;
unsigned int endsWithSize = (unsigned int)strlen(endsWith);
if (this->size >= endsWithSize)
result = strcmp(strZ(this) + (this->size - endsWithSize), endsWith) == 0;
if (strSize(this) >= endsWithSize)
result = strcmp(strZ(this) + (strSize(this) - endsWithSize), endsWith) == 0;
FUNCTION_TEST_RETURN(result);
}
@ -595,7 +607,7 @@ strEq(const String *this, const String *compare)
if (this != NULL && compare != NULL)
{
if (this->size == compare->size)
if (strSize(this) == strSize(compare))
result = strcmp(strZ(this), strZ(compare)) == 0;
}
else
@ -628,8 +640,8 @@ strFirstUpper(String *this)
ASSERT(this != NULL);
if (this->size > 0)
this->buffer[0] = (char)toupper(this->buffer[0]);
if (strSize(this) > 0)
this->pub.buffer[0] = (char)toupper(this->pub.buffer[0]);
FUNCTION_TEST_RETURN(this);
}
@ -644,8 +656,8 @@ strFirstLower(String *this)
ASSERT(this != NULL);
if (this->size > 0)
this->buffer[0] = (char)tolower(this->buffer[0]);
if (strSize(this) > 0)
this->pub.buffer[0] = (char)tolower(this->pub.buffer[0]);
FUNCTION_TEST_RETURN(this);
}
@ -660,9 +672,9 @@ strUpper(String *this)
ASSERT(this != NULL);
if (this->size > 0)
for (unsigned int idx = 0; idx <= this->size; idx++)
this->buffer[idx] = (char)toupper(this->buffer[idx]);
if (strSize(this) > 0)
for (size_t idx = 0; idx <= strSize(this); idx++)
this->pub.buffer[idx] = (char)toupper(this->pub.buffer[idx]);
FUNCTION_TEST_RETURN(this);
}
@ -677,9 +689,9 @@ strLower(String *this)
ASSERT(this != NULL);
if (this->size > 0)
for (unsigned int idx = 0; idx <= this->size; idx++)
this->buffer[idx] = (char)tolower(this->buffer[idx]);
if (strSize(this) > 0)
for (size_t idx = 0; idx <= strSize(this); idx++)
this->pub.buffer[idx] = (char)tolower(this->pub.buffer[idx]);
FUNCTION_TEST_RETURN(this);
}
@ -694,15 +706,15 @@ strPath(const String *this)
ASSERT(this != NULL);
const char *end = this->buffer + this->size;
const char *end = this->pub.buffer + strSize(this);
while (end > this->buffer && *(end - 1) != '/')
while (end > this->pub.buffer && *(end - 1) != '/')
end--;
FUNCTION_TEST_RETURN(
strNewN(
this->buffer,
end - this->buffer <= 1 ? (size_t)(end - this->buffer) : (size_t)(end - this->buffer - 1)));
this->pub.buffer,
end - this->pub.buffer <= 1 ? (size_t)(end - this->pub.buffer) : (size_t)(end - this->pub.buffer - 1)));
}
/**********************************************************************************************************************************/
@ -797,7 +809,7 @@ strZNull(const String *this)
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_END();
FUNCTION_TEST_RETURN(this == NULL ? NULL : this->buffer);
FUNCTION_TEST_RETURN(this == NULL ? NULL : strZ(this));
}
/**********************************************************************************************************************************/
@ -841,10 +853,10 @@ strReplaceChr(String *this, char find, char replace)
ASSERT(this != NULL);
for (unsigned int stringIdx = 0; stringIdx < this->size; stringIdx++)
for (size_t stringIdx = 0; stringIdx < strSize(this); stringIdx++)
{
if (this->buffer[stringIdx] == find)
this->buffer[stringIdx] = replace;
if (this->pub.buffer[stringIdx] == find)
this->pub.buffer[stringIdx] = replace;
}
FUNCTION_TEST_RETURN(this);
@ -860,9 +872,9 @@ strSub(const String *this, size_t start)
FUNCTION_TEST_END();
ASSERT(this != NULL);
ASSERT(start <= this->size);
ASSERT(start <= this->pub.size);
FUNCTION_TEST_RETURN(strSubN(this, start, this->size - start));
FUNCTION_TEST_RETURN(strSubN(this, start, strSize(this) - start));
}
/**********************************************************************************************************************************/
@ -876,10 +888,10 @@ strSubN(const String *this, size_t start, size_t size)
FUNCTION_TEST_END();
ASSERT(this != NULL);
ASSERT(start <= this->size);
ASSERT(start + size <= this->size);
ASSERT(start <= strSize(this));
ASSERT(start + size <= strSize(this));
FUNCTION_TEST_RETURN(strNewN(this->buffer + start, size));
FUNCTION_TEST_RETURN(strNewN(strZ(this) + start, size));
}
/**********************************************************************************************************************************/
@ -893,16 +905,16 @@ strTrim(String *this)
ASSERT(this != NULL);
// Nothing to trim if size is zero
if (this->size > 0)
if (strSize(this) > 0)
{
// Find the beginning of the string skipping all whitespace
char *begin = this->buffer;
char *begin = this->pub.buffer;
while (*begin != 0 && (*begin == ' ' || *begin == '\t' || *begin == '\r' || *begin == '\n'))
begin++;
// Find the end of the string skipping all whitespace
char *end = this->buffer + (this->size - 1);
char *end = this->pub.buffer + (strSize(this) - 1);
while (end > begin && (*end == ' ' || *end == '\t' || *end == '\r' || *end == '\n'))
end--;
@ -910,20 +922,20 @@ strTrim(String *this)
// Is there anything to trim?
size_t newSize = (size_t)(end - begin + 1);
if (begin != this->buffer || newSize < strSize(this))
if (begin != this->pub.buffer || newSize < strSize(this))
{
// Calculate new size
this->size = (unsigned int)newSize;
this->pub.size = (unsigned int)newSize;
// Move the substr to the beginning of the buffer
memmove(this->buffer, begin, this->size);
this->buffer[this->size] = 0;
this->extra = 0;
memmove(this->pub.buffer, begin, strSize(this));
this->pub.buffer[strSize(this)] = 0;
this->pub.extra = 0;
MEM_CONTEXT_BEGIN(this->memContext)
{
// Resize the buffer
this->buffer = memResize(this->buffer, this->size + 1);
this->pub.buffer = memResize(this->pub.buffer, strSize(this) + 1);
}
MEM_CONTEXT_END();
}
@ -945,12 +957,12 @@ strChr(const String *this, char chr)
int result = -1;
if (this->size > 0)
if (strSize(this) > 0)
{
const char *ptr = strchr(this->buffer, chr);
const char *ptr = strchr(this->pub.buffer, chr);
if (ptr != NULL)
result = (int)(ptr - this->buffer);
result = (int)(ptr - this->pub.buffer);
}
FUNCTION_TEST_RETURN(result);
@ -965,19 +977,19 @@ strTrunc(String *this, int idx)
FUNCTION_TEST_END();
ASSERT(this != NULL);
ASSERT(idx >= 0 && (size_t)idx <= this->size);
ASSERT(idx >= 0 && (size_t)idx <= strSize(this));
if (this->size > 0)
if (strSize(this) > 0)
{
// Reset the size to end at the index
this->size = (unsigned int)(idx);
this->buffer[this->size] = 0;
this->extra = 0;
this->pub.size = (unsigned int)(idx);
this->pub.buffer[strSize(this)] = 0;
this->pub.extra = 0;
MEM_CONTEXT_BEGIN(this->memContext)
{
// Resize the buffer
this->buffer = memResize(this->buffer, this->size + 1);
this->pub.buffer = memResize(this->pub.buffer, strSize(this) + 1);
}
MEM_CONTEXT_END();
}
@ -1060,7 +1072,7 @@ strFree(String *this)
{
MEM_CONTEXT_BEGIN(this->memContext)
{
memFree(this->buffer);
memFree(this->pub.buffer);
memFree(this);
}
MEM_CONTEXT_END();

View File

@ -39,22 +39,6 @@ typedef struct String String;
#include "common/encode.h"
#include "common/type/buffer.h"
/***********************************************************************************************************************************
Fields that are common between dynamically allocated and constant strings
There is nothing user-accessible here but this construct allows constant strings to be created and then handled by the same
functions that process dynamically allocated strings.
***********************************************************************************************************************************/
#define STRING_COMMON \
uint64_t size:32; /* Actual size of the string */ \
uint64_t extra:32; /* Extra space allocated for expansion */ \
char *buffer; /* String buffer */
typedef struct StringConst
{
STRING_COMMON
} StringConst;
/***********************************************************************************************************************************
Constructors
***********************************************************************************************************************************/
@ -81,6 +65,32 @@ String *strNewN(const char *string, size_t size);
// Duplicate a string
String *strDup(const String *this);
/***********************************************************************************************************************************
Getters/setters
***********************************************************************************************************************************/
typedef struct StringPub
{
uint64_t size:32; // Actual size of the string
uint64_t extra:32; // Extra space allocated for expansion
char *buffer; // String buffer
} StringPub;
// String size minus null-terminator, i.e. the same value that strlen() would return
__attribute__((always_inline)) static inline size_t
strSize(const String *this)
{
return THIS_PUB(String)->size;
}
// Pointer to zero-terminated string. strZNull() returns NULL when the String is NULL.
__attribute__((always_inline)) static inline const char *
strZ(const String *this)
{
return THIS_PUB(String)->buffer;
}
const char *strZNull(const String *this);
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
@ -146,16 +156,6 @@ String *strPath(const String *this);
// Combine with a base path to get an absolute path
String *strPathAbsolute(const String *this, const String *base);
// Pointer to zero-terminated string. strZNull() returns NULL when the String is NULL.
__attribute__((always_inline)) static inline const char *
strZ(const String *const this)
{
ASSERT_INLINE(this != NULL);
return ((const StringConst *)this)->buffer;
}
const char *strZNull(const String *this);
// Quote a string
String *strQuote(const String *this, const String *quote);
String *strQuoteZ(const String *this, const char *quote);
@ -163,14 +163,6 @@ String *strQuoteZ(const String *this, const char *quote);
// Replace a character with another character
String *strReplaceChr(String *this, char find, char replace);
// String size minus null-terminator, i.e. the same value that strlen() would return
__attribute__((always_inline)) static inline size_t
strSize(const String *const this)
{
ASSERT_INLINE(this != NULL);
return ((const StringConst *)this)->size;
}
// Format sizes (file, buffer, etc.) in human-readable form
String *strSizeFormat(const uint64_t fileSize);
@ -203,11 +195,11 @@ By convention all string constant identifiers are appended with _STR.
***********************************************************************************************************************************/
// Create a String constant inline from any zero-terminated string
#define STR(bufferParam) \
((const String *)&(const StringConst){.buffer = (char *)(bufferParam), .size = (unsigned int)strlen(bufferParam)})
((const String *)&(const StringPub){.buffer = (char *)(bufferParam), .size = (unsigned int)strlen(bufferParam)})
// Create a String constant inline from a #define or inline string constant
#define STRDEF(bufferParam) \
((const String *)&(const StringConst){.buffer = (char *)(bufferParam), .size = (unsigned int)sizeof(bufferParam) - 1})
((const String *)&(const StringPub){.buffer = (char *)(bufferParam), .size = (unsigned int)sizeof(bufferParam) - 1})
// Used to declare String constants that will be externed using STRING_DECLARE(). Must be used in a .c file.
#define STRING_EXTERN(name, buffer) \

View File

@ -21,7 +21,7 @@ Constant variants that are generally useful
***********************************************************************************************************************************/
// Used to declare Bool Variant constants that will be externed using VARIANT_DECLARE(). Must be used in a .c file.
#define VARIANT_BOOL_EXTERN(name, dataParam) \
const Variant *const name = ((const Variant *)&(const VariantBoolConst){.type = varTypeBool, .data = dataParam})
const Variant *const name = ((const Variant *)&(const VariantBoolPub){.type = varTypeBool, .data = dataParam})
VARIANT_BOOL_EXTERN(BOOL_FALSE_VAR, false);
VARIANT_BOOL_EXTERN(BOOL_TRUE_VAR, true);
@ -31,62 +31,56 @@ Information about the variant
***********************************************************************************************************************************/
struct Variant
{
VARIANT_COMMON
VariantPub pub; // Publicly accessible variables
};
typedef struct VariantBool
{
VARIANT_COMMON
VARIANT_BOOL_COMMON
VariantBoolPub pub; // Publicly accessible variables
MemContext *memContext;
} VariantBool;
typedef struct VariantInt
{
VARIANT_COMMON
VARIANT_INT_COMMON
VariantIntPub pub; // Publicly accessible variables
MemContext *memContext;
} VariantInt;
typedef struct VariantInt64
{
VARIANT_COMMON
VARIANT_INT64_COMMON
VariantInt64Pub pub; // Publicly accessible variables
MemContext *memContext;
} VariantInt64;
typedef struct VariantKeyValue
{
VARIANT_COMMON
KeyValue *data; /* KeyValue data */
KeyValue *data; // KeyValue data
MemContext *memContext;
} VariantKeyValue;
typedef struct VariantString
{
VARIANT_COMMON
VARIANT_STRING_COMMON
VariantStringPub pub; // Publicly accessible variables
MemContext *memContext;
} VariantString;
typedef struct VariantUInt
{
VARIANT_COMMON
VARIANT_UINT_COMMON
VariantUIntPub pub; // Publicly accessible variables
MemContext *memContext;
} VariantUInt;
typedef struct VariantUInt64
{
VARIANT_COMMON
VARIANT_UINT64_COMMON
VariantUInt64Pub pub; // Publicly accessible variables
MemContext *memContext;
} VariantUInt64;
typedef struct VariantVariantList
{
VARIANT_COMMON
VariantList *data; /* VariantList data */
VariantList *data; // VariantList data
MemContext *memContext;
} VariantVariantList;
@ -117,7 +111,7 @@ varDup(const Variant *this)
if (this != NULL)
{
switch (this->type)
switch (varType(this))
{
case varTypeBool:
result = varNewBool(varBool(this));
@ -211,7 +205,7 @@ varEq(const Variant *this1, const Variant *this2)
break;
default:
THROW_FMT(AssertError, "unable to test equality for %s", variantTypeName[this1->type]);
THROW_FMT(AssertError, "unable to test equality for %s", variantTypeName[varType(this1)]);
}
}
}
@ -222,19 +216,6 @@ varEq(const Variant *this1, const Variant *this2)
FUNCTION_TEST_RETURN(result);
}
/**********************************************************************************************************************************/
VariantType
varType(const Variant *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(VARIANT, this);
FUNCTION_TEST_END();
ASSERT(this != NULL);
FUNCTION_TEST_RETURN(this->type);
}
/**********************************************************************************************************************************/
Variant *
varNewBool(bool data)
@ -248,9 +229,12 @@ varNewBool(bool data)
*this = (VariantBool)
{
.pub =
{
.type = varTypeBool,
.data = data,
},
.memContext = memContextCurrent(),
.type = varTypeBool,
.data = data,
};
FUNCTION_TEST_RETURN((Variant *)this);
@ -265,9 +249,9 @@ varBool(const Variant *this)
FUNCTION_TEST_END();
ASSERT(this != NULL);
ASSERT(this->type == varTypeBool);
ASSERT(varType(this) == varTypeBool);
FUNCTION_TEST_RETURN(((VariantBool *)this)->data);
FUNCTION_TEST_RETURN(((VariantBool *)this)->pub.data);
}
bool
@ -281,7 +265,7 @@ varBoolForce(const Variant *this)
bool result = false;
switch (this->type)
switch (varType(this))
{
case varTypeBool:
result = varBool(this);
@ -331,7 +315,7 @@ varBoolForce(const Variant *this)
break;
default:
THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeBool]);
THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeBool]);
}
FUNCTION_TEST_RETURN(result);
@ -350,9 +334,12 @@ varNewInt(int data)
*this = (VariantInt)
{
.pub =
{
.type = varTypeInt,
.data = data,
},
.memContext = memContextCurrent(),
.type = varTypeInt,
.data = data,
};
FUNCTION_TEST_RETURN((Variant *)this);
@ -367,9 +354,9 @@ varInt(const Variant *this)
FUNCTION_TEST_END();
ASSERT(this != NULL);
ASSERT(this->type == varTypeInt);
ASSERT(varType(this) == varTypeInt);
FUNCTION_TEST_RETURN(((VariantInt *)this)->data);
FUNCTION_TEST_RETURN(((VariantInt *)this)->pub.data);
}
int
@ -383,7 +370,7 @@ varIntForce(const Variant *this)
int result = 0;
switch (this->type)
switch (varType(this))
{
case varTypeBool:
result = varBool(this);
@ -400,7 +387,7 @@ varIntForce(const Variant *this)
// Make sure the value fits into a normal 32-bit int range since 32-bit platforms are supported
if (resultTest > INT32_MAX || resultTest < INT32_MIN)
THROW_FMT(
FormatError, "unable to convert %s %" PRId64 " to %s", variantTypeName[this->type], resultTest,
FormatError, "unable to convert %s %" PRId64 " to %s", variantTypeName[varType(this)], resultTest,
variantTypeName[varTypeInt]);
result = (int)resultTest;
@ -418,7 +405,7 @@ varIntForce(const Variant *this)
// Make sure the value fits into a normal 32-bit int range
if (resultTest > INT32_MAX)
THROW_FMT(
FormatError, "unable to convert %s %u to %s", variantTypeName[this->type], resultTest,
FormatError, "unable to convert %s %u to %s", variantTypeName[varType(this)], resultTest,
variantTypeName[varTypeInt]);
result = (int)resultTest;
@ -432,7 +419,7 @@ varIntForce(const Variant *this)
// Make sure the value fits into a normal 32-bit int range
if (resultTest > INT32_MAX)
THROW_FMT(
FormatError, "unable to convert %s %" PRIu64 " to %s", variantTypeName[this->type], resultTest,
FormatError, "unable to convert %s %" PRIu64 " to %s", variantTypeName[varType(this)], resultTest,
variantTypeName[varTypeInt]);
result = (int)resultTest;
@ -440,7 +427,7 @@ varIntForce(const Variant *this)
}
default:
THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeInt]);
THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeInt]);
}
FUNCTION_TEST_RETURN(result);
@ -459,9 +446,12 @@ varNewInt64(int64_t data)
*this = (VariantInt64)
{
.pub =
{
.type = varTypeInt64,
.data = data,
},
.memContext = memContextCurrent(),
.type = varTypeInt64,
.data = data,
};
FUNCTION_TEST_RETURN((Variant *)this);
@ -476,9 +466,9 @@ varInt64(const Variant *this)
FUNCTION_TEST_END();
ASSERT(this != NULL);
ASSERT(this->type == varTypeInt64);
ASSERT(varType(this) == varTypeInt64);
FUNCTION_TEST_RETURN(((VariantInt64 *)this)->data);
FUNCTION_TEST_RETURN(((VariantInt64 *)this)->pub.data);
}
int64_t
@ -492,7 +482,7 @@ varInt64Force(const Variant *this)
int64_t result = 0;
switch (this->type)
switch (varType(this))
{
case varTypeBool:
result = varBool(this);
@ -525,7 +515,7 @@ varInt64Force(const Variant *this)
else
{
THROW_FMT(
FormatError, "unable to convert %s %" PRIu64 " to %s", variantTypeName[this->type], resultTest,
FormatError, "unable to convert %s %" PRIu64 " to %s", variantTypeName[varType(this)], resultTest,
variantTypeName[varTypeInt64]);
}
@ -533,7 +523,7 @@ varInt64Force(const Variant *this)
}
default:
THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeInt64]);
THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeInt64]);
}
FUNCTION_TEST_RETURN(result);
@ -552,9 +542,12 @@ varNewUInt(unsigned int data)
*this = (VariantUInt)
{
.pub =
{
.type = varTypeUInt,
.data = data,
},
.memContext = memContextCurrent(),
.type = varTypeUInt,
.data = data,
};
FUNCTION_TEST_RETURN((Variant *)this);
@ -569,9 +562,9 @@ varUInt(const Variant *this)
FUNCTION_TEST_END();
ASSERT(this != NULL);
ASSERT(this->type == varTypeUInt);
ASSERT(varType(this) == varTypeUInt);
FUNCTION_TEST_RETURN(((VariantUInt *)this)->data);
FUNCTION_TEST_RETURN(((VariantUInt *)this)->pub.data);
}
unsigned int
@ -585,7 +578,7 @@ varUIntForce(const Variant *this)
unsigned int result = 0;
switch (this->type)
switch (varType(this))
{
case varTypeBool:
result = varBool(this);
@ -601,7 +594,7 @@ varUIntForce(const Variant *this)
else
{
THROW_FMT(
FormatError, "unable to convert %s %d to %s", variantTypeName[this->type], resultTest,
FormatError, "unable to convert %s %d to %s", variantTypeName[varType(this)], resultTest,
variantTypeName[varTypeUInt]);
}
@ -618,7 +611,7 @@ varUIntForce(const Variant *this)
else
{
THROW_FMT(
FormatError, "unable to convert %s %" PRId64 " to %s", variantTypeName[this->type], resultTest,
FormatError, "unable to convert %s %" PRId64 " to %s", variantTypeName[varType(this)], resultTest,
variantTypeName[varTypeUInt]);
}
@ -639,7 +632,7 @@ varUIntForce(const Variant *this)
else
{
THROW_FMT(
FormatError, "unable to convert %s %" PRIu64 " to %s", variantTypeName[this->type], resultTest,
FormatError, "unable to convert %s %" PRIu64 " to %s", variantTypeName[varType(this)], resultTest,
variantTypeName[varTypeUInt]);
}
@ -651,7 +644,7 @@ varUIntForce(const Variant *this)
break;
default:
THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeUInt]);
THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeUInt]);
}
FUNCTION_TEST_RETURN(result);
@ -670,9 +663,12 @@ varNewUInt64(uint64_t data)
*this = (VariantUInt64)
{
.pub =
{
.type = varTypeUInt64,
.data = data,
},
.memContext = memContextCurrent(),
.type = varTypeUInt64,
.data = data,
};
FUNCTION_TEST_RETURN((Variant *)this);
@ -687,9 +683,9 @@ varUInt64(const Variant *this)
FUNCTION_TEST_END();
ASSERT(this != NULL);
ASSERT(this->type == varTypeUInt64);
ASSERT(varType(this) == varTypeUInt64);
FUNCTION_TEST_RETURN(((VariantUInt64 *)this)->data);
FUNCTION_TEST_RETURN(((VariantUInt64 *)this)->pub.data);
}
uint64_t
@ -703,7 +699,7 @@ varUInt64Force(const Variant *this)
uint64_t result = 0;
switch (this->type)
switch (varType(this))
{
case varTypeBool:
result = varBool(this);
@ -719,7 +715,7 @@ varUInt64Force(const Variant *this)
else
{
THROW_FMT(
FormatError, "unable to convert %s %d to %s", variantTypeName[this->type], resultTest,
FormatError, "unable to convert %s %d to %s", variantTypeName[varType(this)], resultTest,
variantTypeName[varTypeUInt64]);
}
@ -736,7 +732,7 @@ varUInt64Force(const Variant *this)
else
{
THROW_FMT(
FormatError, "unable to convert %s %" PRId64 " to %s", variantTypeName[this->type], resultTest,
FormatError, "unable to convert %s %" PRId64 " to %s", variantTypeName[varType(this)], resultTest,
variantTypeName[varTypeUInt64]);
}
@ -756,7 +752,7 @@ varUInt64Force(const Variant *this)
break;
default:
THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeUInt64]);
THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeUInt64]);
}
FUNCTION_TEST_RETURN(result);
@ -797,7 +793,7 @@ varKv(const Variant *this)
if (this != NULL)
{
ASSERT(this->type == varTypeKeyValue);
ASSERT(varType(this) == varTypeKeyValue);
result = ((VariantKeyValue *)this)->data;
}
@ -817,9 +813,12 @@ varNewStr(const String *data)
*this = (VariantString)
{
.pub =
{
.type = varTypeString,
.data = strDup(data),
},
.memContext = memContextCurrent(),
.type = varTypeString,
.data = strDup(data),
};
FUNCTION_TEST_RETURN((Variant *)this);
@ -847,8 +846,8 @@ varStr(const Variant *this)
if (this != NULL)
{
ASSERT(this->type == varTypeString);
result = ((VariantString *)this)->data;
ASSERT(varType(this) == varTypeString);
result = ((VariantString *)this)->pub.data;
}
FUNCTION_TEST_RETURN(result);
@ -912,7 +911,7 @@ varStrForce(const Variant *this)
}
default:
THROW_FMT(FormatError, "unable to force %s to %s", variantTypeName[this->type], variantTypeName[varTypeString]);
THROW_FMT(FormatError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeString]);
}
FUNCTION_TEST_RETURN(result);
@ -953,7 +952,7 @@ varVarLst(const Variant *this)
if (this != NULL)
{
ASSERT(this->type == varTypeVariantList);
ASSERT(varType(this) == varTypeVariantList);
result = ((VariantVariantList *)this)->data;
}
@ -1011,7 +1010,7 @@ varFree(Variant *this)
{
MemContext *memContext = NULL;
switch (this->type)
switch (varType(this))
{
case varTypeBool:
memContext = ((VariantBool *)this)->memContext;
@ -1032,7 +1031,7 @@ varFree(Variant *this)
case varTypeString:
memContext = ((VariantString *)this)->memContext;
strFree(((VariantString *)this)->data);
strFree(((VariantString *)this)->pub.data);
break;
case varTypeUInt:

View File

@ -66,18 +66,53 @@ Variant *varNewVarLst(const VariantList *data);
Variant *varDup(const Variant *this);
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
// Test if Variants are equal
bool varEq(const Variant *this1, const Variant *this2);
// Variant type
VariantType varType(const Variant *this);
/***********************************************************************************************************************************
Getters/Setters
***********************************************************************************************************************************/
#define VARIANT_COMMON \
VariantType type; /* Variant type */
typedef struct VariantPub
{
VARIANT_COMMON
} VariantPub;
typedef struct VariantBoolPub
{
VARIANT_COMMON
bool data; // Boolean data
} VariantBoolPub;
typedef struct VariantIntPub
{
VARIANT_COMMON
int data; // Signed integer data
} VariantIntPub;
typedef struct VariantInt64Pub
{
VARIANT_COMMON
int64_t data; // 64-bit signed integer data
} VariantInt64Pub;
typedef struct VariantStringPub
{
VARIANT_COMMON
String *data; // String data
} VariantStringPub;
typedef struct VariantUIntPub
{
VARIANT_COMMON
unsigned int data; // Unsigned integer data
} VariantUIntPub;
typedef struct VariantUInt64Pub
{
VARIANT_COMMON
uint64_t data; // 64-bit unsigned integer data
} VariantUInt64Pub;
bool varBool(const Variant *this);
bool varBoolForce(const Variant *this);
@ -100,74 +135,24 @@ uint64_t varUInt64Force(const Variant *this);
VariantList *varVarLst(const Variant *this);
// Variant type
__attribute__((always_inline)) static inline VariantType
varType(const Variant *const this)
{
return THIS_PUB(Variant)->type;
}
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
// Test if Variants are equal
bool varEq(const Variant *this1, const Variant *this2);
/***********************************************************************************************************************************
Destructor
***********************************************************************************************************************************/
void varFree(Variant *this);
/***********************************************************************************************************************************
Fields that are common between dynamically allocated and constant variants
There is nothing user-accessible here but this construct allows constant variants to be created and then handled by the same
functions that process dynamically allocated variants.
***********************************************************************************************************************************/
#define VARIANT_COMMON \
VariantType type; /* Variant type */
#define VARIANT_BOOL_COMMON \
bool data; /* Boolean data */
typedef struct VariantBoolConst
{
VARIANT_COMMON
const VARIANT_BOOL_COMMON
} VariantBoolConst;
#define VARIANT_INT_COMMON \
int data; /* Signed integer data */
typedef struct VariantIntConst
{
VARIANT_COMMON
const VARIANT_INT_COMMON
} VariantIntConst;
#define VARIANT_INT64_COMMON \
int64_t data; /* 64-bit signed integer data */
typedef struct VariantInt64Const
{
VARIANT_COMMON
const VARIANT_INT64_COMMON
} VariantInt64Const;
#define VARIANT_STRING_COMMON \
String *data; /* String data */
typedef struct VariantStringConst
{
VARIANT_COMMON
const VARIANT_STRING_COMMON
} VariantStringConst;
#define VARIANT_UINT_COMMON \
unsigned int data; /* unsigned integer data */
typedef struct VariantUIntConst
{
VARIANT_COMMON
const VARIANT_UINT_COMMON
} VariantUIntConst;
#define VARIANT_UINT64_COMMON \
uint64_t data; /* 64-bit unsigned integer data */
typedef struct VariantUInt64Const
{
VARIANT_COMMON
const VARIANT_UINT64_COMMON
} VariantUInt64Const;
/***********************************************************************************************************************************
Macros for constant variants
@ -180,27 +165,27 @@ By convention all variant constant identifiers are appended with _VAR.
***********************************************************************************************************************************/
// Create a Bool Variant constant inline from a bool
#define VARBOOL(dataParam) \
((const Variant *)&(const VariantBoolConst){.type = varTypeBool, .data = dataParam})
((const Variant *)&(const VariantBoolPub){.type = varTypeBool, .data = dataParam})
// Create an Int Variant constant inline from an int
#define VARINT(dataParam) \
((const Variant *)&(const VariantIntConst){.type = varTypeInt, .data = dataParam})
((const Variant *)&(const VariantIntPub){.type = varTypeInt, .data = dataParam})
// Create an Int64 Variant constant inline from an int64_t
#define VARINT64(dataParam) \
((const Variant *)&(const VariantInt64Const){.type = varTypeInt64, .data = dataParam})
((const Variant *)&(const VariantInt64Pub){.type = varTypeInt64, .data = dataParam})
// Create a String Variant constant inline from any zero-terminated string
#define VARSTRZ(dataParam) \
((const Variant *)&(const VariantStringConst){.type = varTypeString, .data = STR(dataParam)})
((const Variant *)&(const VariantStringPub){.type = varTypeString, .data = (String *)STR(dataParam)})
// Create a String Variant constant inline from a #define or inline string constant
#define VARSTRDEF(dataParam) \
((const Variant *)&(const VariantStringConst){.type = varTypeString, .data = STRDEF(dataParam)})
((const Variant *)&(const VariantStringPub){.type = varTypeString, .data = (String *)STRDEF(dataParam)})
// Create a String Variant constant inline from a String constant
#define VARSTR(dataParam) \
((const Variant *)&(const VariantStringConst){.type = varTypeString, .data = dataParam})
((const Variant *)&(const VariantStringPub){.type = varTypeString, .data = (String *)(dataParam)})
// Used to declare String Variant constants that will be externed using VARIANT_DECLARE(). Must be used in a .c file.
#define VARIANT_STRDEF_EXTERN(name, dataParam) \
@ -212,11 +197,11 @@ By convention all variant constant identifiers are appended with _VAR.
// Create a UInt Variant constant inline from an unsigned int
#define VARUINT(dataParam) \
((const Variant *)&(const VariantUIntConst){.type = varTypeUInt, .data = dataParam})
((const Variant *)&(const VariantUIntPub){.type = varTypeUInt, .data = dataParam})
// Create a UInt64 Variant constant inline from a uint64_t
#define VARUINT64(dataParam) \
((const Variant *)&(const VariantUInt64Const){.type = varTypeUInt64, .data = dataParam})
((const Variant *)&(const VariantUInt64Pub){.type = varTypeUInt64, .data = dataParam})
// Used to extern String Variant constants declared with VARIANT_STRDEF_EXTERN/STATIC(). Must be used in a .h file.
#define VARIANT_DECLARE(name) \

View File

@ -22,7 +22,7 @@ testRun(void)
}
MEM_CONTEXT_TEMP_END();
TEST_RESULT_PTR(bufPtr(buffer), buffer->buffer, "buffer pointer");
TEST_RESULT_PTR(bufPtr(buffer), buffer->pub.buffer, "buffer pointer");
TEST_RESULT_UINT(bufSize(buffer), 256, "buffer size");
TEST_RESULT_UINT(bufSizeAlloc(buffer), 256, "buffer allocation size");
@ -99,7 +99,7 @@ testRun(void)
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("error when used > new limit");
TEST_ERROR(bufLimitSet(buffer, 64), AssertError, "assertion 'limit >= this->used' failed");
TEST_ERROR(bufLimitSet(buffer, 64), AssertError, "assertion 'limit >= bufUsed(this)' failed");
TEST_RESULT_VOID(bufUsedSet(buffer, 64), "set used");
// Use limits to change size reporting

View File

@ -35,7 +35,7 @@ testRun(void)
{
// We don't want this struct to grow since there are generally a lot of strings, so make sure it doesn't grow without us
// knowing about it
TEST_RESULT_UINT(sizeof(StringConst), TEST_64BIT() ? 16 : 12, "check StringConst struct size");
TEST_RESULT_UINT(sizeof(StringPub), TEST_64BIT() ? 16 : 12, "check StringConst struct size");
// Test the size macro
TEST_RESULT_VOID(CHECK_SIZE(555), "valid size");
@ -77,8 +77,8 @@ testRun(void)
TEST_TITLE("empty string is allocated extra space");
TEST_ASSIGN(string, strNew(""), "new empty string");
TEST_RESULT_UINT(string->size, 0, " check size");
TEST_RESULT_UINT(string->extra, 64, " check extra");
TEST_RESULT_UINT(string->pub.size, 0, " check size");
TEST_RESULT_UINT(string->pub.extra, 64, " check extra");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("strNewEncode()");
@ -126,19 +126,19 @@ testRun(void)
String *string2 = strNew("ZZZZ");
TEST_RESULT_STR_Z(strCat(string, STRDEF("YYYY")), "XXXXYYYY", "cat string");
TEST_RESULT_UINT(string->extra, 60, "check extra");
TEST_RESULT_UINT(string->pub.extra, 60, "check extra");
TEST_RESULT_STR_Z(strCatFmt(string, "%05d", 777), "XXXXYYYY00777", "cat formatted string");
TEST_RESULT_UINT(string->extra, 55, "check extra");
TEST_RESULT_UINT(string->pub.extra, 55, "check extra");
TEST_RESULT_STR_Z(strCatChr(string, '!'), "XXXXYYYY00777!", "cat chr");
TEST_RESULT_UINT(string->extra, 54, "check extra");
TEST_RESULT_UINT(string->pub.extra, 54, "check extra");
TEST_RESULT_STR_Z(
strCatZN(string, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$*", 55),
"XXXXYYYY00777!$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "cat chr");
TEST_RESULT_UINT(string->extra, 34, "check extra");
TEST_RESULT_UINT(string->pub.extra, 34, "check extra");
TEST_RESULT_STR_Z(
strCatEncode(string, encodeBase64, BUFSTRDEF("zzzzz")),
"XXXXYYYY00777!$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$enp6eno=", "cat encode");
TEST_RESULT_UINT(string->extra, 26, "check extra");
TEST_RESULT_UINT(string->pub.extra, 26, "check extra");
TEST_RESULT_STR_Z(string2, "ZZZZ", "check unaltered string");
}
@ -265,8 +265,8 @@ testRun(void)
String *val = strNew("abcdef");
TEST_ERROR(
strTrunc(val, (int)(strSize(val) + 1)), AssertError,
"assertion 'idx >= 0 && (size_t)idx <= this->size' failed");
TEST_ERROR(strTrunc(val, -1), AssertError, "assertion 'idx >= 0 && (size_t)idx <= this->size' failed");
"assertion 'idx >= 0 && (size_t)idx <= strSize(this)' failed");
TEST_ERROR(strTrunc(val, -1), AssertError, "assertion 'idx >= 0 && (size_t)idx <= strSize(this)' failed");
TEST_RESULT_STR_Z(strTrunc(val, strChr(val, 'd')), "abc", "simple string truncated");
strCatZ(val, "\r\n to end");

View File

@ -15,7 +15,7 @@ testRun(void)
if (testBegin("bool"))
{
// Ensure type sizes are as expected
TEST_RESULT_UINT(sizeof(VariantBoolConst), 8, "check VariantBoolConst size");
TEST_RESULT_UINT(sizeof(VariantBoolPub), 8, "check VariantBoolConst size");
TEST_RESULT_UINT(sizeof(VariantBool), TEST_64BIT() ? 16 : 12, "check VariantBool size");
// -------------------------------------------------------------------------------------------------------------------------
@ -24,7 +24,7 @@ testRun(void)
varFree(boolean);
// -------------------------------------------------------------------------------------------------------------------------
TEST_ERROR(varBool(varNewStrZ("string")), AssertError, "assertion 'this->type == varTypeBool' failed");
TEST_ERROR(varBool(varNewStrZ("string")), AssertError, "assertion 'varType(this) == varTypeBool' failed");
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_BOOL(varBool(BOOL_TRUE_VAR), true, "true bool variant");
@ -56,7 +56,7 @@ testRun(void)
if (testBegin("int"))
{
// Ensure type sizes are as expected
TEST_RESULT_UINT(sizeof(VariantIntConst), 8, "check VariantIntConst size");
TEST_RESULT_UINT(sizeof(VariantIntPub), 8, "check VariantIntConst size");
TEST_RESULT_UINT(sizeof(VariantInt), TEST_64BIT() ? 16 : 12, "check VariantInt size");
// -------------------------------------------------------------------------------------------------------------------------
@ -77,7 +77,7 @@ testRun(void)
TEST_ERROR(varIntForce(VARUINT64(2147483648)), FormatError, "unable to convert uint64 2147483648 to int");
// -------------------------------------------------------------------------------------------------------------------------
TEST_ERROR(varInt(varNewStrZ("string")), AssertError, "assertion 'this->type == varTypeInt' failed");
TEST_ERROR(varInt(varNewStrZ("string")), AssertError, "assertion 'varType(this) == varTypeInt' failed");
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_INT(varInt(varDup(VARINT(88976))), 88976, "dup int");
@ -95,7 +95,7 @@ testRun(void)
if (testBegin("int64"))
{
// Ensure type sizes are as expected
TEST_RESULT_UINT(sizeof(VariantInt64Const), TEST_64BIT() ? 16 : 12, "check VariantInt64Const size");
TEST_RESULT_UINT(sizeof(VariantInt64Pub), TEST_64BIT() ? 16 : 12, "check VariantInt64Const size");
TEST_RESULT_UINT(sizeof(VariantInt64), TEST_64BIT() ? 24 : 16, "check VariantInt64 size");
// -------------------------------------------------------------------------------------------------------------------------
@ -119,7 +119,7 @@ testRun(void)
"unable to convert uint64 9223372036854775808 to int64");
// -------------------------------------------------------------------------------------------------------------------------
TEST_ERROR(varInt64(varNewStrZ("string")), AssertError, "assertion 'this->type == varTypeInt64' failed");
TEST_ERROR(varInt64(varNewStrZ("string")), AssertError, "assertion 'varType(this) == varTypeInt64' failed");
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_INT(varInt64(varDup(VARINT64(88976))), 88976, "dup int64");
@ -136,7 +136,7 @@ testRun(void)
if (testBegin("unsigned int"))
{
// Ensure type sizes are as expected
TEST_RESULT_UINT(sizeof(VariantUIntConst), 8, "check VariantUIntConst size");
TEST_RESULT_UINT(sizeof(VariantUIntPub), 8, "check VariantUIntConst size");
TEST_RESULT_UINT(sizeof(VariantUInt), TEST_64BIT() ? 16 : 12, "check VariantUInt size");
// -------------------------------------------------------------------------------------------------------------------------
@ -163,7 +163,7 @@ testRun(void)
TEST_ERROR(varUIntForce(VARINT(-1)), FormatError, "unable to convert int -1 to unsigned int");
// -------------------------------------------------------------------------------------------------------------------------
TEST_ERROR(varUInt(varNewStrZ("string")), AssertError, "assertion 'this->type == varTypeUInt' failed");
TEST_ERROR(varUInt(varNewStrZ("string")), AssertError, "assertion 'varType(this) == varTypeUInt' failed");
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_UINT(varUInt(varDup(VARUINT(88976))), 88976, "dup uint");
@ -177,7 +177,7 @@ testRun(void)
if (testBegin("uint64"))
{
// Ensure type sizes are as expected
TEST_RESULT_UINT(sizeof(VariantUInt64Const), TEST_64BIT() ? 16 : 12, "check VariantUInt64Const size");
TEST_RESULT_UINT(sizeof(VariantUInt64Pub), TEST_64BIT() ? 16 : 12, "check VariantUInt64Const size");
TEST_RESULT_UINT(sizeof(VariantUInt64), TEST_64BIT() ? 24 : 16, "check VariantUInt64 size");
// -------------------------------------------------------------------------------------------------------------------------
@ -203,7 +203,7 @@ testRun(void)
TEST_ERROR(varUInt64Force(VARINT(-1)), FormatError, "unable to convert int -1 to uint64");
// -------------------------------------------------------------------------------------------------------------------------
TEST_ERROR(varUInt64(varNewStrZ("string")), AssertError, "assertion 'this->type == varTypeUInt64' failed");
TEST_ERROR(varUInt64(varNewStrZ("string")), AssertError, "assertion 'varType(this) == varTypeUInt64' failed");
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_UINT(varUInt64(varDup(VARUINT64(88976))), 88976, "dup uint64");
@ -223,7 +223,7 @@ testRun(void)
TEST_RESULT_UINT(sizeof(VariantKeyValue), TEST_64BIT() ? 24 : 12, "check VariantKeyValue size");
// -------------------------------------------------------------------------------------------------------------------------
TEST_ERROR(varKv(VARINT(66)), AssertError, "assertion 'this->type == varTypeKeyValue' failed");
TEST_ERROR(varKv(VARINT(66)), AssertError, "assertion 'varType(this) == varTypeKeyValue' failed");
// -------------------------------------------------------------------------------------------------------------------------
Variant *keyValue = NULL;
@ -253,7 +253,7 @@ testRun(void)
if (testBegin("String"))
{
// Ensure type sizes are as expected
TEST_RESULT_UINT(sizeof(VariantStringConst), TEST_64BIT() ? 16 : 8, "check VariantStringConst size");
TEST_RESULT_UINT(sizeof(VariantStringPub), TEST_64BIT() ? 16 : 8, "check VariantStringConst size");
TEST_RESULT_UINT(sizeof(VariantString), TEST_64BIT() ? 24 : 12, "check VariantString size");
// -------------------------------------------------------------------------------------------------------------------------
@ -267,7 +267,7 @@ testRun(void)
TEST_RESULT_STR(varStr(NULL), NULL, "get null string variant");
// -------------------------------------------------------------------------------------------------------------------------
TEST_ERROR(varStr(varNewBool(true)), AssertError, "assertion 'this->type == varTypeString' failed");
TEST_ERROR(varStr(varNewBool(true)), AssertError, "assertion 'varType(this) == varTypeString' failed");
// -------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_INT(varIntForce(VARSTR(STRDEF("777"))), 777, "int from string");
@ -319,7 +319,7 @@ testRun(void)
TEST_RESULT_UINT(sizeof(VariantVariantList), TEST_64BIT() ? 24 : 12, "check VariantVariantList size");
// -------------------------------------------------------------------------------------------------------------------------
TEST_ERROR(varVarLst(VARINT(66)), AssertError, "assertion 'this->type == varTypeVariantList' failed");
TEST_ERROR(varVarLst(VARINT(66)), AssertError, "assertion 'varType(this) == varTypeVariantList' failed");
// -------------------------------------------------------------------------------------------------------------------------
Variant *listVar = NULL;