From a7eecf6fc7b68473b70f3166b4ebb0b8bf56ce33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 19 Aug 2025 16:03:04 +0800 Subject: [PATCH] FFstrbuf: improves double formatting precision handling --- src/util/FFstrbuf.c | 13 ++++++------- src/util/FFstrbuf.h | 6 +++--- tests/strbuf.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/util/FFstrbuf.c b/src/util/FFstrbuf.c index db2e6e737..7fc5fa87e 100644 --- a/src/util/FFstrbuf.c +++ b/src/util/FFstrbuf.c @@ -570,7 +570,7 @@ void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value) strbuf->length += (uint32_t)(end - start); } -void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, uint8_t precision) +void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision) { assert(precision <= 15); // yyjson_write_number supports up to 15 digits after the decimal point @@ -579,12 +579,12 @@ void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, uint8_t precision) yyjson_val val = {}; unsafe_yyjson_set_double(&val, value); - if (precision > 0) unsafe_yyjson_set_fp_to_fixed(&val, (int) precision); + if (precision >= 0) unsafe_yyjson_set_fp_to_fixed(&val, precision == 0 ? 1 : precision); // yyjson ignores precision == 0 // Write at most digits after the decimal point; doesn't append trailing zeros char* end = yyjson_write_number(&val, start); - assert(end != NULL); + assert(end > start); strbuf->length += (uint32_t)(end - start); @@ -599,12 +599,11 @@ void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, uint8_t precision) for (char* p = end - 1; *p != '.' && p > start; --p) --precision; if (precision > 0) - ffStrbufAppendNC(strbuf, precision, '0'); + ffStrbufAppendNC(strbuf, (uint32_t) precision, '0'); } - else if (precision == 0 && end[-1] == '0' && end[-2] == '.') + else if (precision == 0 || (precision < 0 && end[-1] == '0')) { - // yyjson always appends a decimal point if value is an integer - // Remove trailing zeros and the decimal point if precision is 0 + // yyjson always appends ".0", so we need to remove it strbuf->length -= 2; strbuf->chars[strbuf->length] = '\0'; } diff --git a/src/util/FFstrbuf.h b/src/util/FFstrbuf.h index 3d9c6efe6..704f2a332 100644 --- a/src/util/FFstrbuf.h +++ b/src/util/FFstrbuf.h @@ -105,9 +105,9 @@ 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); +// Appends a double value to the string buffer with the specified precision (0~15). +// if `precision < 0`, let yyjson decide the precision +void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision); FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateA(uint32_t allocate) { diff --git a/tests/strbuf.c b/tests/strbuf.c index 931b8629f..c7ac50fe5 100644 --- a/tests/strbuf.c +++ b/tests/strbuf.c @@ -747,6 +747,10 @@ int main(void) ffStrbufAppendDouble(&strbuf, 120.0, 0); VERIFY(ffStrbufEqualS(&strbuf, "120")); + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.0, 1); + VERIFY(ffStrbufEqualS(&strbuf, "120.0")); + ffStrbufClear(&strbuf); ffStrbufAppendDouble(&strbuf, 120.0, 5); VERIFY(ffStrbufEqualS(&strbuf, "120.00000")); @@ -757,6 +761,10 @@ int main(void) ffStrbufClear(&strbuf); ffStrbufAppendDouble(&strbuf, 120.123456789, 0); + VERIFY(ffStrbufEqualS(&strbuf, "120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.123456789, -1); VERIFY(ffStrbufEqualS(&strbuf, "120.123456789")); ffStrbufClear(&strbuf); @@ -767,6 +775,10 @@ int main(void) ffStrbufAppendDouble(&strbuf, -120.0, 0); VERIFY(ffStrbufEqualS(&strbuf, "-120")); + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.0, 1); + VERIFY(ffStrbufEqualS(&strbuf, "-120.0")); + ffStrbufClear(&strbuf); ffStrbufAppendDouble(&strbuf, -120.0, 5); VERIFY(ffStrbufEqualS(&strbuf, "-120.00000")); @@ -777,6 +789,10 @@ int main(void) ffStrbufClear(&strbuf); ffStrbufAppendDouble(&strbuf, -120.123456789, 0); + VERIFY(ffStrbufEqualS(&strbuf, "-120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.123456789, -1); VERIFY(ffStrbufEqualS(&strbuf, "-120.123456789")); ffStrbufClear(&strbuf); @@ -791,6 +807,22 @@ int main(void) ffStrbufAppendDouble(&strbuf, -1.2345e50, 1); VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 1.2345e50, 0); + VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -1.2345e50, 0); + VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); + + 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"));