FFstrbuf: updates ffStrbufSet* that they won't reserve extra space

This commit is contained in:
李通洲
2026-01-09 15:19:46 +08:00
parent 5d901da81b
commit 420d1cf804
3 changed files with 204 additions and 57 deletions
+40 -51
View File
@@ -24,6 +24,8 @@
#define FASTFETCH_STRBUF_DEFAULT_ALLOC 32
// static string (allocated == 0), chars points to a string literal
// dynamic string (allocated > 0), chars points to a heap allocated buffer
typedef struct FFstrbuf
{
uint32_t allocated;
@@ -55,6 +57,10 @@ void ffStrbufPrependC(FFstrbuf* strbuf, char c);
void ffStrbufInsertNC(FFstrbuf* strbuf, uint32_t index, uint32_t num, char c);
// Clear the content of strbuf and set new value
// NOTE: Unlike ffStrbufAppend*, ffStrbufSet* functions may NOT reserve extra space
void ffStrbufSet(FFstrbuf* strbuf, const FFstrbuf* value);
void ffStrbufSetNS(FFstrbuf* strbuf, uint32_t length, const char* value);
FF_C_PRINTF(2, 3) void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...);
void ffStrbufTrimLeft(FFstrbuf* strbuf, char c);
@@ -148,7 +154,7 @@ FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateA(uint32_t allocate)
static inline void ffStrbufInitCopy(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict src)
{
if (src->allocated == 0) // static string
memcpy(strbuf, src, sizeof(FFstrbuf));
*strbuf = *src;
else
{
ffStrbufInitA(strbuf, src->allocated);
@@ -168,9 +174,7 @@ static inline void ffStrbufInitMove(FFstrbuf* strbuf, FFstrbuf* src)
{
if (src)
{
strbuf->allocated = src->allocated;
strbuf->chars = src->chars;
strbuf->length = src->length;
*strbuf = *src;
ffStrbufInit(src);
}
else
@@ -220,19 +224,10 @@ static inline void ffStrbufInitMoveS(FFstrbuf* strbuf, char* heapStr)
static inline void ffStrbufDestroy(FFstrbuf* strbuf)
{
extern char* CHAR_NULL_PTR;
if(strbuf->allocated > 0)
free(strbuf->chars);
if(strbuf->allocated == 0)
{
strbuf->length = 0;
strbuf->chars = CHAR_NULL_PTR;
return;
}
//Avoid free-after-use. These 3 assignments are cheap so don't remove them
strbuf->allocated = strbuf->length = 0;
free(strbuf->chars);
strbuf->chars = CHAR_NULL_PTR;
ffStrbufInit(strbuf);
}
FF_C_NODISCARD static inline uint32_t ffStrbufGetFree(const FFstrbuf* strbuf)
@@ -249,6 +244,30 @@ static inline void ffStrbufRecalculateLength(FFstrbuf* strbuf)
strbuf->length = (uint32_t) strlen(strbuf->chars);
}
static inline void ffStrbufSetS(FFstrbuf* strbuf, const char* value)
{
assert(strbuf != NULL);
if (value == NULL)
ffStrbufClear(strbuf);
else
ffStrbufSetNS(strbuf, (uint32_t) strlen(value), value);
}
static inline bool ffStrbufSetJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal)
{
assert(strbuf != NULL);
if (yyjson_is_str(jsonVal))
{
ffStrbufSetNS(strbuf, (uint32_t) unsafe_yyjson_get_len(jsonVal), unsafe_yyjson_get_str(jsonVal));
return true;
}
ffStrbufClear(strbuf);
return false;
}
static inline void ffStrbufAppendS(FFstrbuf* strbuf, const char* value)
{
if(value == NULL)
@@ -266,42 +285,10 @@ static inline bool ffStrbufAppendJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal)
return false;
}
static inline void ffStrbufSetS(FFstrbuf* strbuf, const char* value)
{
ffStrbufClear(strbuf);
if(value != NULL)
ffStrbufAppendNS(strbuf, (uint32_t) strlen(value), value);
}
static inline void ffStrbufSetNS(FFstrbuf* strbuf, uint32_t length, const char* value)
{
ffStrbufClear(strbuf);
ffStrbufAppendNS(strbuf, length, value);
}
static inline void ffStrbufSet(FFstrbuf* strbuf, const FFstrbuf* value)
{
assert(value && value != strbuf);
if (strbuf->allocated == 0 && value->allocated == 0)
{
memcpy(strbuf, value, sizeof(FFstrbuf));
return;
}
ffStrbufSetNS(strbuf, value->length, value->chars);
}
static inline bool ffStrbufSetJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal)
{
ffStrbufClear(strbuf);
return ffStrbufAppendJsonVal(strbuf, jsonVal);
}
static inline void ffStrbufInit(FFstrbuf* strbuf)
{
extern char* CHAR_NULL_PTR;
strbuf->allocated = 0;
strbuf->length = 0;
strbuf->allocated = strbuf->length = 0;
strbuf->chars = CHAR_NULL_PTR;
}
@@ -332,10 +319,12 @@ FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateStatic(const char* str)
static inline void ffStrbufSetStatic(FFstrbuf* strbuf, const char* value)
{
if(strbuf->allocated > 0)
ffStrbufDestroy(strbuf);
free(strbuf->chars);
if(value != NULL)
ffStrbufInitStatic(strbuf, value);
else
ffStrbufInit(strbuf);
}
static inline void ffStrbufInitNS(FFstrbuf* strbuf, uint32_t length, const char* str)
@@ -392,7 +381,7 @@ static inline void ffStrbufPrependS(FFstrbuf* strbuf, const char* value)
ffStrbufPrependNS(strbuf, (uint32_t) strlen(value), value);
}
static inline int ffStrbufComp(const FFstrbuf* strbuf, const FFstrbuf* comp)
static inline FF_C_NODISCARD int ffStrbufComp(const FFstrbuf* strbuf, const FFstrbuf* comp)
{
uint32_t length = strbuf->length > comp->length ? comp->length : strbuf->length;
return memcmp(strbuf->chars, comp->chars, length + 1);
+60 -2
View File
@@ -72,6 +72,7 @@ void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free)
strbuf->allocated = allocate;
}
// Ensure that at least `free` bytes are available in the buffer besides the current length
// for an empty buffer, free + 1 length memory will be allocated(+1 for the NUL)
void ffStrbufEnsureFixedLengthFree(FFstrbuf* strbuf, uint32_t free)
{
@@ -165,7 +166,7 @@ void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments)
uint32_t free = ffStrbufGetFree(strbuf);
int written = vsnprintf(strbuf->chars + strbuf->length, strbuf->allocated > 0 ? free + 1 : 0, format, arguments);
if(written > 0 && strbuf->length + (uint32_t) written > free)
if(written > 0 && (uint32_t) written > free)
{
ffStrbufEnsureFree(strbuf, (uint32_t) written);
written = vsnprintf(strbuf->chars + strbuf->length, (uint32_t) written + 1, format, copy);
@@ -237,6 +238,55 @@ void ffStrbufPrependC(FFstrbuf* strbuf, char c)
strbuf->length += 1;
}
void ffStrbufSetNS(FFstrbuf* strbuf, uint32_t length, const char* value)
{
assert(strbuf != NULL);
if (length == 0)
{
ffStrbufClear(strbuf);
return;
}
assert(value != NULL);
if (strbuf->allocated < length + 1)
{
if (strbuf->allocated > 0)
free(strbuf->chars);
strbuf->allocated = length + 1;
strbuf->chars = malloc(sizeof(char) * strbuf->allocated);
}
memcpy(strbuf->chars, value, length);
strbuf->length = length;
strbuf->chars[length] = '\0';
}
void ffStrbufSet(FFstrbuf* strbuf, const FFstrbuf* value)
{
assert(value && value != strbuf);
if (value->length == 0)
{
ffStrbufClear(strbuf);
return;
}
if (value->allocated == 0) // static string
{
if (strbuf->allocated != 0)
{
free(strbuf->chars);
strbuf->allocated = 0;
}
strbuf->chars = value->chars;
strbuf->length = value->length;
return;
}
ffStrbufSetNS(strbuf, value->length, value->chars);
}
void ffStrbufTrimLeft(FFstrbuf* strbuf, char c)
{
if(strbuf->length == 0)
@@ -398,7 +448,15 @@ void ffStrbufReplaceAllC(FFstrbuf* strbuf, char find, char replace)
return;
ffStrbufEnsureFree(strbuf, 0);
for (char *current_pos = strchr(strbuf->chars, find); current_pos; current_pos = strchr(current_pos + 1, find))
for (
char *current_pos = memchr(strbuf->chars, find, strbuf->length);
current_pos;
current_pos = memchr(
current_pos + 1,
find,
strbuf->length - (uint32_t)(current_pos + 1 - strbuf->chars)
)
)
*current_pos = replace;
}
+104 -4
View File
@@ -629,17 +629,28 @@ int main(void)
ffStrbufSetStatic(&strbuf, "abcdef");
FF_STRBUF_AUTO_DESTROY newStr = ffStrbufCreateS("123456");
ffStrbufSet(&newStr, &strbuf);
VERIFY(newStr.allocated > 0);
VERIFY(newStr.chars != strbuf.chars);
VERIFY(newStr.allocated == 0);
VERIFY(newStr.chars == strbuf.chars);
VERIFY(ffStrbufEqualS(&newStr, "abcdef"));
}
{
ffStrbufClear(&strbuf);
FF_STRBUF_AUTO_DESTROY newStr = ffStrbufCreateS("123456");
uint32_t oldAlloc = newStr.allocated;
VERIFY(oldAlloc > newStr.length);
ffStrbufSet(&newStr, &strbuf);
VERIFY(newStr.allocated == oldAlloc);
VERIFY(newStr.chars != strbuf.chars);
VERIFY(ffStrbufEqualS(&newStr, ""));
}
{
ffStrbufSetStatic(&strbuf, "abcdefghijkl");
FF_STRBUF_AUTO_DESTROY newStr = ffStrbufCreateS("123456");
ffStrbufSet(&newStr, &strbuf);
VERIFY(newStr.allocated > 0);
VERIFY(newStr.chars != strbuf.chars);
VERIFY(newStr.allocated == 0);
VERIFY(newStr.chars == strbuf.chars);
VERIFY(ffStrbufEqualS(&newStr, "abcdefghijkl"));
}
@@ -1024,6 +1035,95 @@ int main(void)
ffStrbufDestroy(&strbuf);
}
//setS
ffStrbufInitStatic(&strbuf, "STATIC");
ffStrbufSetS(&strbuf, "DYNAMIC");
VERIFY(ffStrbufEqualS(&strbuf, "DYNAMIC"));
VERIFY(strbuf.allocated > 0);
ffStrbufDestroy(&strbuf);
ffStrbufInit(&strbuf);
ffStrbufSetS(&strbuf, "");
VERIFY(ffStrbufEqualS(&strbuf, ""));
VERIFY(strbuf.allocated == 0);
ffStrbufDestroy(&strbuf);
ffStrbufInitStatic(&strbuf, "STATIC");
ffStrbufSetS(&strbuf, "");
VERIFY(ffStrbufEqualS(&strbuf, ""));
VERIFY(strbuf.allocated == 0);
ffStrbufDestroy(&strbuf);
ffStrbufInitStatic(&strbuf, "STATIC");
ffStrbufSetStatic(&strbuf, "");
VERIFY(ffStrbufEqualS(&strbuf, ""));
VERIFY(strbuf.allocated == 0);
ffStrbufDestroy(&strbuf);
ffStrbufInitS(&strbuf, "DYNAMIC");
ffStrbufSetStatic(&strbuf, "");
VERIFY(ffStrbufEqualS(&strbuf, ""));
VERIFY(strbuf.allocated == 0);
ffStrbufDestroy(&strbuf);
ffStrbufInitS(&strbuf, "DYNAMIC");
ffStrbufSetS(&strbuf, "ANOTHER DYNAMIC");
VERIFY(ffStrbufEqualS(&strbuf, "ANOTHER DYNAMIC"));
VERIFY(strbuf.allocated > 0);
ffStrbufDestroy(&strbuf);
ffStrbufInit(&strbuf);
ffStrbufSetStatic(&strbuf, "");
VERIFY(ffStrbufEqualS(&strbuf, ""));
VERIFY(strbuf.allocated == 0);
ffStrbufDestroy(&strbuf);
//set
ffStrbufInitStatic(&strbuf, "STATIC");
{
FF_STRBUF_AUTO_DESTROY other = ffStrbufCreateS("DYNAMIC");
ffStrbufSet(&strbuf, &other);
}
VERIFY(ffStrbufEqualS(&strbuf, "DYNAMIC"));
VERIFY(strbuf.allocated > 0);
ffStrbufDestroy(&strbuf);
ffStrbufInit(&strbuf);
{
FF_STRBUF_AUTO_DESTROY other = ffStrbufCreateS("");
ffStrbufSet(&strbuf, &other);
}
VERIFY(ffStrbufEqualS(&strbuf, ""));
VERIFY(strbuf.allocated == 0);
ffStrbufDestroy(&strbuf);
ffStrbufInitStatic(&strbuf, "STATIC");
{
FF_STRBUF_AUTO_DESTROY other = ffStrbufCreateS("");
ffStrbufSet(&strbuf, &other);
}
VERIFY(ffStrbufEqualS(&strbuf, ""));
VERIFY(strbuf.allocated == 0);
ffStrbufDestroy(&strbuf);
ffStrbufInitS(&strbuf, "DYNAMIC");
{
FF_STRBUF_AUTO_DESTROY other = ffStrbufCreateS("");
ffStrbufSet(&strbuf, &other);
}
VERIFY(ffStrbufEqualS(&strbuf, ""));
VERIFY(strbuf.allocated > 0);
ffStrbufDestroy(&strbuf);
ffStrbufInitS(&strbuf, "DYNAMIC");
{
FF_STRBUF_AUTO_DESTROY other = ffStrbufCreateStatic("STATIC");
ffStrbufSet(&strbuf, &other);
}
VERIFY(ffStrbufEqualS(&strbuf, "STATIC"));
VERIFY(strbuf.allocated == 0);
ffStrbufDestroy(&strbuf);
//Success
puts("\e[32mAll tests passed!" FASTFETCH_TEXT_MODIFIER_RESET);
}