Skip to content

Commit dcbf76b

Browse files
committed
FFstrbuf: adds number appending functions
1 parent 70b11d9 commit dcbf76b

File tree

3 files changed

+164
-0
lines changed

3 files changed

+164
-0
lines changed

src/util/FFstrbuf.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,74 @@ int64_t ffStrbufToSInt(const FFstrbuf* strbuf, int64_t defaultValue)
542542
return str_end == strbuf->chars ? defaultValue : (int64_t)result;
543543
}
544544

545+
void ffStrbufAppendSInt(FFstrbuf* strbuf, int64_t value)
546+
{
547+
ffStrbufEnsureFree(strbuf, 21); // Required by yyjson_write_number
548+
char* start = strbuf->chars + strbuf->length;
549+
550+
yyjson_val val = {};
551+
unsafe_yyjson_set_sint(&val, value);
552+
char* end = yyjson_write_number(&val, start);
553+
554+
assert(end != NULL);
555+
556+
strbuf->length += (uint32_t)(end - start);
557+
}
558+
559+
void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value)
560+
{
561+
ffStrbufEnsureFree(strbuf, 21); // Required by yyjson_write_number
562+
char* start = strbuf->chars + strbuf->length;
563+
564+
yyjson_val val = {};
565+
unsafe_yyjson_set_uint(&val, value);
566+
char* end = yyjson_write_number(&val, start);
567+
568+
assert(end != NULL);
569+
570+
strbuf->length += (uint32_t)(end - start);
571+
}
572+
573+
void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, uint8_t precision)
574+
{
575+
assert(precision <= 15); // yyjson_write_number supports up to 15 digits after the decimal point
576+
577+
ffStrbufEnsureFree(strbuf, 40); // Required by yyjson_write_number
578+
char* start = strbuf->chars + strbuf->length;
579+
580+
yyjson_val val = {};
581+
unsafe_yyjson_set_double(&val, value);
582+
if (precision > 0) unsafe_yyjson_set_fp_to_fixed(&val, (int) precision);
583+
584+
// Write at most <precision> digits after the decimal point; doesn't append trailing zeros
585+
char* end = yyjson_write_number(&val, start);
586+
587+
assert(end != NULL);
588+
589+
strbuf->length += (uint32_t)(end - start);
590+
591+
if (__builtin_expect(value > 1e21 || value < -1e21, false))
592+
{
593+
// If the value is too large, yyjson_write_number will write it in scientific notation
594+
return;
595+
}
596+
597+
if (precision > 1)
598+
{
599+
for (char* p = end - 1; *p != '.' && p > start; --p)
600+
--precision;
601+
if (precision > 0)
602+
ffStrbufAppendNC(strbuf, precision, '0');
603+
}
604+
else if (precision == 0 && end[-1] == '0' && end[-2] == '.')
605+
{
606+
// yyjson always appends a decimal point if value is an integer
607+
// Remove trailing zeros and the decimal point if precision is 0
608+
strbuf->length -= 2;
609+
strbuf->chars[strbuf->length] = '\0';
610+
}
611+
}
612+
545613
void ffStrbufUpperCase(FFstrbuf* strbuf)
546614
{
547615
for (uint32_t i = 0; i < strbuf->length; ++i)

src/util/FFstrbuf.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,12 @@ bool ffStrbufMatchSeparatedNS(const FFstrbuf* strbuf, uint32_t compLength, const
103103

104104
int ffStrbufAppendUtf32CodePoint(FFstrbuf* strbuf, uint32_t codepoint);
105105

106+
void ffStrbufAppendSInt(FFstrbuf* strbuf, int64_t value);
107+
void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value);
108+
// Appends a double value to the string buffer with the specified precision.
109+
// if `precision == 0`, let yyjson decide the precision
110+
void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, uint8_t precision);
111+
106112
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateA(uint32_t allocate)
107113
{
108114
FFstrbuf strbuf;

tests/strbuf.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,96 @@ int main(void)
720720
ffStrbufDestroy(&strbuf);
721721
}
722722

723+
{
724+
ffStrbufAppendSInt(&strbuf, 1234567890);
725+
VERIFY(ffStrbufEqualS(&strbuf, "1234567890"));
726+
727+
ffStrbufClear(&strbuf);
728+
ffStrbufAppendSInt(&strbuf, -1234567890);
729+
VERIFY(ffStrbufEqualS(&strbuf, "-1234567890"));
730+
731+
ffStrbufClear(&strbuf);
732+
ffStrbufAppendSInt(&strbuf, 0);
733+
VERIFY(ffStrbufEqualS(&strbuf, "0"));
734+
735+
ffStrbufClear(&strbuf);
736+
ffStrbufAppendUInt(&strbuf, 1234567890);
737+
VERIFY(ffStrbufEqualS(&strbuf, "1234567890"));
738+
739+
ffStrbufClear(&strbuf);
740+
ffStrbufAppendUInt(&strbuf, 0);
741+
VERIFY(ffStrbufEqualS(&strbuf, "0"));
742+
743+
ffStrbufDestroy(&strbuf);
744+
}
745+
746+
{
747+
ffStrbufAppendDouble(&strbuf, 120.0, 0);
748+
VERIFY(ffStrbufEqualS(&strbuf, "120"));
749+
750+
ffStrbufClear(&strbuf);
751+
ffStrbufAppendDouble(&strbuf, 120.0, 5);
752+
VERIFY(ffStrbufEqualS(&strbuf, "120.00000"));
753+
754+
ffStrbufClear(&strbuf);
755+
ffStrbufAppendDouble(&strbuf, 120.123456789, 5);
756+
VERIFY(ffStrbufEqualS(&strbuf, "120.12346"));
757+
758+
ffStrbufClear(&strbuf);
759+
ffStrbufAppendDouble(&strbuf, 120.123456789, 0);
760+
VERIFY(ffStrbufEqualS(&strbuf, "120.123456789"));
761+
762+
ffStrbufClear(&strbuf);
763+
ffStrbufAppendDouble(&strbuf, 120.123, 5);
764+
VERIFY(ffStrbufEqualS(&strbuf, "120.12300"));
765+
766+
ffStrbufClear(&strbuf);
767+
ffStrbufAppendDouble(&strbuf, -120.0, 0);
768+
VERIFY(ffStrbufEqualS(&strbuf, "-120"));
769+
770+
ffStrbufClear(&strbuf);
771+
ffStrbufAppendDouble(&strbuf, -120.0, 5);
772+
VERIFY(ffStrbufEqualS(&strbuf, "-120.00000"));
773+
774+
ffStrbufClear(&strbuf);
775+
ffStrbufAppendDouble(&strbuf, -120.123456789, 5);
776+
VERIFY(ffStrbufEqualS(&strbuf, "-120.12346"));
777+
778+
ffStrbufClear(&strbuf);
779+
ffStrbufAppendDouble(&strbuf, -120.123456789, 0);
780+
VERIFY(ffStrbufEqualS(&strbuf, "-120.123456789"));
781+
782+
ffStrbufClear(&strbuf);
783+
ffStrbufAppendDouble(&strbuf, -120.123, 5);
784+
VERIFY(ffStrbufEqualS(&strbuf, "-120.12300"));
785+
786+
ffStrbufClear(&strbuf);
787+
ffStrbufAppendDouble(&strbuf, 1.2345e50, 1);
788+
VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50"));
789+
790+
ffStrbufClear(&strbuf);
791+
ffStrbufAppendDouble(&strbuf, -1.2345e50, 1);
792+
VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50"));
793+
794+
ffStrbufClear(&strbuf);
795+
ffStrbufAppendDouble(&strbuf, 1.2345e20, 1);
796+
VERIFY(ffStrbufEqualS(&strbuf, "123450000000000000000.0"));
797+
798+
ffStrbufClear(&strbuf);
799+
ffStrbufAppendDouble(&strbuf, -1.2345e20, 1);
800+
VERIFY(ffStrbufEqualS(&strbuf, "-123450000000000000000.0"));
801+
802+
ffStrbufClear(&strbuf);
803+
ffStrbufAppendDouble(&strbuf, 0, 0);
804+
VERIFY(ffStrbufEqualS(&strbuf, "0"));
805+
806+
ffStrbufClear(&strbuf);
807+
ffStrbufAppendDouble(&strbuf, -0, 0);
808+
VERIFY(ffStrbufEqualS(&strbuf, "0"));
809+
810+
ffStrbufDestroy(&strbuf);
811+
}
812+
723813
//Success
724814
puts("\e[32mAll tests passed!" FASTFETCH_TEXT_MODIFIER_RESET);
725815
}

0 commit comments

Comments
 (0)