mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-13 02:14:37 +02:00
FFstrbuf: updates ffStrbufSet* that they won't reserve extra space
This commit is contained in:
+40
-51
@@ -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);
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user