FFstrbuf: adds number appending functions

This commit is contained in:
李通洲
2025-08-19 15:00:30 +08:00
parent 70b11d953c
commit dcbf76b233
3 changed files with 164 additions and 0 deletions
+68
View File
@@ -542,6 +542,74 @@ int64_t ffStrbufToSInt(const FFstrbuf* strbuf, int64_t defaultValue)
return str_end == strbuf->chars ? defaultValue : (int64_t)result;
}
void ffStrbufAppendSInt(FFstrbuf* strbuf, int64_t value)
{
ffStrbufEnsureFree(strbuf, 21); // Required by yyjson_write_number
char* start = strbuf->chars + strbuf->length;
yyjson_val val = {};
unsafe_yyjson_set_sint(&val, value);
char* end = yyjson_write_number(&val, start);
assert(end != NULL);
strbuf->length += (uint32_t)(end - start);
}
void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value)
{
ffStrbufEnsureFree(strbuf, 21); // Required by yyjson_write_number
char* start = strbuf->chars + strbuf->length;
yyjson_val val = {};
unsafe_yyjson_set_uint(&val, value);
char* end = yyjson_write_number(&val, start);
assert(end != NULL);
strbuf->length += (uint32_t)(end - start);
}
void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, uint8_t precision)
{
assert(precision <= 15); // yyjson_write_number supports up to 15 digits after the decimal point
ffStrbufEnsureFree(strbuf, 40); // Required by yyjson_write_number
char* start = strbuf->chars + strbuf->length;
yyjson_val val = {};
unsafe_yyjson_set_double(&val, value);
if (precision > 0) unsafe_yyjson_set_fp_to_fixed(&val, (int) precision);
// Write at most <precision> digits after the decimal point; doesn't append trailing zeros
char* end = yyjson_write_number(&val, start);
assert(end != NULL);
strbuf->length += (uint32_t)(end - start);
if (__builtin_expect(value > 1e21 || value < -1e21, false))
{
// If the value is too large, yyjson_write_number will write it in scientific notation
return;
}
if (precision > 1)
{
for (char* p = end - 1; *p != '.' && p > start; --p)
--precision;
if (precision > 0)
ffStrbufAppendNC(strbuf, precision, '0');
}
else if (precision == 0 && end[-1] == '0' && end[-2] == '.')
{
// yyjson always appends a decimal point if value is an integer
// Remove trailing zeros and the decimal point if precision is 0
strbuf->length -= 2;
strbuf->chars[strbuf->length] = '\0';
}
}
void ffStrbufUpperCase(FFstrbuf* strbuf)
{
for (uint32_t i = 0; i < strbuf->length; ++i)
+6
View File
@@ -103,6 +103,12 @@ bool ffStrbufMatchSeparatedNS(const FFstrbuf* strbuf, uint32_t compLength, const
int ffStrbufAppendUtf32CodePoint(FFstrbuf* strbuf, uint32_t codepoint);
void ffStrbufAppendSInt(FFstrbuf* strbuf, int64_t value);
void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value);
// Appends a double value to the string buffer with the specified precision.
// if `precision == 0`, let yyjson decide the precision
void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, uint8_t precision);
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateA(uint32_t allocate)
{
FFstrbuf strbuf;
+90
View File
@@ -720,6 +720,96 @@ int main(void)
ffStrbufDestroy(&strbuf);
}
{
ffStrbufAppendSInt(&strbuf, 1234567890);
VERIFY(ffStrbufEqualS(&strbuf, "1234567890"));
ffStrbufClear(&strbuf);
ffStrbufAppendSInt(&strbuf, -1234567890);
VERIFY(ffStrbufEqualS(&strbuf, "-1234567890"));
ffStrbufClear(&strbuf);
ffStrbufAppendSInt(&strbuf, 0);
VERIFY(ffStrbufEqualS(&strbuf, "0"));
ffStrbufClear(&strbuf);
ffStrbufAppendUInt(&strbuf, 1234567890);
VERIFY(ffStrbufEqualS(&strbuf, "1234567890"));
ffStrbufClear(&strbuf);
ffStrbufAppendUInt(&strbuf, 0);
VERIFY(ffStrbufEqualS(&strbuf, "0"));
ffStrbufDestroy(&strbuf);
}
{
ffStrbufAppendDouble(&strbuf, 120.0, 0);
VERIFY(ffStrbufEqualS(&strbuf, "120"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.0, 5);
VERIFY(ffStrbufEqualS(&strbuf, "120.00000"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.123456789, 5);
VERIFY(ffStrbufEqualS(&strbuf, "120.12346"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.123456789, 0);
VERIFY(ffStrbufEqualS(&strbuf, "120.123456789"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.123, 5);
VERIFY(ffStrbufEqualS(&strbuf, "120.12300"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.0, 0);
VERIFY(ffStrbufEqualS(&strbuf, "-120"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.0, 5);
VERIFY(ffStrbufEqualS(&strbuf, "-120.00000"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.123456789, 5);
VERIFY(ffStrbufEqualS(&strbuf, "-120.12346"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.123456789, 0);
VERIFY(ffStrbufEqualS(&strbuf, "-120.123456789"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.123, 5);
VERIFY(ffStrbufEqualS(&strbuf, "-120.12300"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 1.2345e50, 1);
VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -1.2345e50, 1);
VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 1.2345e20, 1);
VERIFY(ffStrbufEqualS(&strbuf, "123450000000000000000.0"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -1.2345e20, 1);
VERIFY(ffStrbufEqualS(&strbuf, "-123450000000000000000.0"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 0, 0);
VERIFY(ffStrbufEqualS(&strbuf, "0"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -0, 0);
VERIFY(ffStrbufEqualS(&strbuf, "0"));
ffStrbufDestroy(&strbuf);
}
//Success
puts("\e[32mAll tests passed!" FASTFETCH_TEXT_MODIFIER_RESET);
}