src/3rdparty: numeric conversion functions now return the number of characters added

This commit is contained in:
Vern Paxson 2022-09-16 09:44:32 -07:00 committed by Tim Wojtulewicz
parent 3e4512bc80
commit 790e920d66
2 changed files with 60 additions and 46 deletions

View file

@ -34,7 +34,8 @@ static void strreverse(char* begin, char* end)
} }
// Expects 'str' to have been made using "%e" scientific notation format string // Expects 'str' to have been made using "%e" scientific notation format string
static void sn_strip_trailing_zeros(char* str) // Returns the number of characters removed
static size_t sn_strip_trailing_zeros(char* str)
{ {
char* frac = 0; char* frac = 0;
@ -53,7 +54,7 @@ static void sn_strip_trailing_zeros(char* str)
} }
if ( ! frac ) if ( ! frac )
return; return 0;
char* start_dec = frac; char* start_dec = frac;
char* exp = 0; char* exp = 0;
@ -84,8 +85,11 @@ static void sn_strip_trailing_zeros(char* str)
if ( trailing_zeros == start_dec ) if ( trailing_zeros == start_dec )
--trailing_zeros; --trailing_zeros;
if ( trailing_zeros && exp ) if ( ! trailing_zeros || ! exp )
{ return 0;
char* start_exp = exp;
for ( ; ; ) for ( ; ; )
{ {
*trailing_zeros = *exp; *trailing_zeros = *exp;
@ -96,10 +100,11 @@ static void sn_strip_trailing_zeros(char* str)
++trailing_zeros; ++trailing_zeros;
++exp; ++exp;
} }
}
return exp - start_exp;
} }
void modp_itoa10(int32_t value, char* str) size_t modp_itoa10(int32_t value, char* str)
{ {
char* wstr=str; char* wstr=str;
// Take care of sign // Take care of sign
@ -111,9 +116,10 @@ void modp_itoa10(int32_t value, char* str)
// Reverse string // Reverse string
strreverse(str,wstr-1); strreverse(str,wstr-1);
return wstr - str - 1;
} }
void modp_uitoa10(uint32_t value, char* str) size_t modp_uitoa10(uint32_t value, char* str)
{ {
char* wstr=str; char* wstr=str;
// Conversion. Number is reversed. // Conversion. Number is reversed.
@ -121,9 +127,10 @@ void modp_uitoa10(uint32_t value, char* str)
*wstr='\0'; *wstr='\0';
// Reverse string // Reverse string
strreverse(str, wstr-1); strreverse(str, wstr-1);
return wstr - str - 1;
} }
void modp_litoa10(int64_t value, char* str) size_t modp_litoa10(int64_t value, char* str)
{ {
char* wstr=str; char* wstr=str;
uint64_t uvalue = (value < 0) ? (value == INT64_MIN ? (uint64_t)(INT64_MAX) + 1 : -value) : value; uint64_t uvalue = (value < 0) ? (value == INT64_MIN ? (uint64_t)(INT64_MAX) + 1 : -value) : value;
@ -135,9 +142,10 @@ void modp_litoa10(int64_t value, char* str)
// Reverse string // Reverse string
strreverse(str,wstr-1); strreverse(str,wstr-1);
return wstr - str - 1;
} }
void modp_ulitoa10(uint64_t value, char* str) size_t modp_ulitoa10(uint64_t value, char* str)
{ {
char* wstr=str; char* wstr=str;
// Conversion. Number is reversed. // Conversion. Number is reversed.
@ -145,9 +153,10 @@ void modp_ulitoa10(uint64_t value, char* str)
*wstr='\0'; *wstr='\0';
// Reverse string // Reverse string
strreverse(str, wstr-1); strreverse(str, wstr-1);
return wstr - str - 1;
} }
void modp_dtoa(double value, char* str, int prec) size_t modp_dtoa(double value, char* str, int prec)
{ {
/* Hacky test for NaN /* Hacky test for NaN
* under -fast-math this won't work, but then you also won't * under -fast-math this won't work, but then you also won't
@ -156,7 +165,7 @@ void modp_dtoa(double value, char* str, int prec)
*/ */
if (! (value == value)) { if (! (value == value)) {
str[0] = 'n'; str[1] = 'a'; str[2] = 'n'; str[3] = '\0'; str[0] = 'n'; str[1] = 'a'; str[2] = 'n'; str[3] = '\0';
return; return 3;
} }
/* we'll work in positive values and deal with the /* we'll work in positive values and deal with the
@ -177,9 +186,9 @@ void modp_dtoa(double value, char* str, int prec)
which can be 100s of characters overflowing your buffers == bad which can be 100s of characters overflowing your buffers == bad
*/ */
if (value >= thres_max) { if (value >= thres_max) {
sprintf(str, "%.*e", DBL_DECIMAL_DIG - 1, neg ? -value : value); int n = sprintf(str, "%.*e", DBL_DECIMAL_DIG - 1, neg ? -value : value);
sn_strip_trailing_zeros(str); n -= sn_strip_trailing_zeros(str);
return; return n;
} }
double diff = 0.0; double diff = 0.0;
@ -242,12 +251,13 @@ void modp_dtoa(double value, char* str, int prec)
} }
*wstr='\0'; *wstr='\0';
strreverse(str, wstr-1); strreverse(str, wstr-1);
return wstr - str - 1;
} }
// This is near identical to modp_dtoa above // This is near identical to modp_dtoa above
// The differnce is noted below // The differnce is noted below
void modp_dtoa2(double value, char* str, int prec) size_t modp_dtoa2(double value, char* str, int prec)
{ {
/* Hacky test for NaN /* Hacky test for NaN
* under -fast-math this won't work, but then you also won't * under -fast-math this won't work, but then you also won't
@ -256,7 +266,7 @@ void modp_dtoa2(double value, char* str, int prec)
*/ */
if (! (value == value)) { if (! (value == value)) {
str[0] = 'n'; str[1] = 'a'; str[2] = 'n'; str[3] = '\0'; str[0] = 'n'; str[1] = 'a'; str[2] = 'n'; str[3] = '\0';
return; return 3;
} }
/* we'll work in positive values and deal with the /* we'll work in positive values and deal with the
@ -277,9 +287,9 @@ void modp_dtoa2(double value, char* str, int prec)
which can be 100s of characters overflowing your buffers == bad which can be 100s of characters overflowing your buffers == bad
*/ */
if (value >= thres_max) { if (value >= thres_max) {
sprintf(str, "%.*e", DBL_DECIMAL_DIG - 1, neg ? -value : value); int n = sprintf(str, "%.*e", DBL_DECIMAL_DIG - 1, neg ? -value : value);
sn_strip_trailing_zeros(str); n -= sn_strip_trailing_zeros(str);
return; return n;
} }
int count; int count;
@ -296,9 +306,9 @@ void modp_dtoa2(double value, char* str, int prec)
double smallest = _pow10r[prec]; double smallest = _pow10r[prec];
if (value != 0.0 && value < smallest) { if (value != 0.0 && value < smallest) {
sprintf(str, "%.*e", DBL_DECIMAL_DIG - 1, neg ? -value : value); int n = sprintf(str, "%.*e", DBL_DECIMAL_DIG - 1, neg ? -value : value);
sn_strip_trailing_zeros(str); n -= sn_strip_trailing_zeros(str);
return; return n;
} }
int whole = (int) value; int whole = (int) value;
@ -362,11 +372,12 @@ void modp_dtoa2(double value, char* str, int prec)
} }
*wstr='\0'; *wstr='\0';
strreverse(str, wstr-1); strreverse(str, wstr-1);
return wstr - str - 1;
} }
// This is near identical to modp_dtoa2 above, excep that it never uses // This is near identical to modp_dtoa2 above, excep that it never uses
// exponential notation and requires a buffer length. // exponential notation and requires a buffer length.
void modp_dtoa3(double value, char* str, int n, int prec) size_t modp_dtoa3(double value, char* str, int n, int prec)
{ {
/* Hacky test for NaN /* Hacky test for NaN
* under -fast-math this won't work, but then you also won't * under -fast-math this won't work, but then you also won't
@ -375,7 +386,7 @@ void modp_dtoa3(double value, char* str, int n, int prec)
*/ */
if (! (value == value)) { if (! (value == value)) {
str[0] = 'n'; str[1] = 'a'; str[2] = 'n'; str[3] = '\0'; str[0] = 'n'; str[1] = 'a'; str[2] = 'n'; str[3] = '\0';
return; return 3;
} }
/* we'll work in positive values and deal with the /* we'll work in positive values and deal with the
@ -409,7 +420,7 @@ void modp_dtoa3(double value, char* str, int n, int prec)
if ( i < 0 || i >= n ) { if ( i < 0 || i >= n ) {
// Error or truncated output. // Error or truncated output.
snprintf(str, n, "NAN"); snprintf(str, n, "NAN");
return; return 3;
} }
/* Remove trailing zeros. */ /* Remove trailing zeros. */
@ -421,7 +432,7 @@ void modp_dtoa3(double value, char* str, int n, int prec)
--p; --p;
*++p = '\0'; *++p = '\0';
return; return p - str - 1;
/* ---- End of modified part.. */ /* ---- End of modified part.. */
} }
@ -491,4 +502,5 @@ void modp_dtoa3(double value, char* str, int n, int prec)
} }
*wstr='\0'; *wstr='\0';
strreverse(str, wstr-1); strreverse(str, wstr-1);
return wstr - str - 1;
} }

View file

@ -34,37 +34,38 @@
BEGIN_C BEGIN_C
#include <stdint.h> #include <stdint.h>
#include <stddef.h>
/** \brief convert an signed integer to char buffer /** \brief convert an signed integer to char buffer, return # characters added
* *
* \param[in] value * \param[in] value
* \param[out] buf the output buffer. Should be 16 chars or more. * \param[out] buf the output buffer. Should be 16 chars or more.
*/ */
void modp_itoa10(int32_t value, char* buf); size_t modp_itoa10(int32_t value, char* buf);
/** \brief convert an unsigned integer to char buffer /** \brief convert an unsigned integer to char buffer, return # characters added
* *
* \param[in] value * \param[in] value
* \param[out] buf The output buffer, should be 16 chars or more. * \param[out] buf The output buffer, should be 16 chars or more.
*/ */
void modp_uitoa10(uint32_t value, char* buf); size_t modp_uitoa10(uint32_t value, char* buf);
/** \brief convert an signed long integer to char buffer /** \brief convert an signed long integer to char buffer, return # characters added
* *
* \param[in] value * \param[in] value
* \param[out] buf the output buffer. Should be 24 chars or more. * \param[out] buf the output buffer. Should be 24 chars or more.
*/ */
void modp_litoa10(int64_t value, char* buf); size_t modp_litoa10(int64_t value, char* buf);
/** \brief convert an unsigned long integer to char buffer /** \brief convert an unsigned long integer to char buffer, return # characters added
* *
* \param[in] value * \param[in] value
* \param[out] buf The output buffer, should be 24 chars or more. * \param[out] buf The output buffer, should be 24 chars or more.
*/ */
void modp_ulitoa10(uint64_t value, char* buf); size_t modp_ulitoa10(uint64_t value, char* buf);
/** \brief convert a floating point number to char buffer with /** \brief convert a floating point number to char buffer with
* fixed-precision format * fixed-precision format, return # characters added
* *
* This is similar to "%.[0-9]f" in the printf style. It will include * This is similar to "%.[0-9]f" in the printf style. It will include
* trailing zeros * trailing zeros
@ -78,10 +79,11 @@ void modp_ulitoa10(uint64_t value, char* buf);
* \param[in] precision Number of digits to the right of the decimal point. * \param[in] precision Number of digits to the right of the decimal point.
* Can only be 0-9. * Can only be 0-9.
*/ */
void modp_dtoa(double value, char* buf, int precision); size_t modp_dtoa(double value, char* buf, int precision);
/** \brief convert a floating point number to char buffer with a /** \brief convert a floating point number to char buffer with a
* variable-precision format, and no trailing zeros * variable-precision format, and no trailing zero, return
* number of characters added
* *
* This is similar to "%.[0-9]f" in the printf style, except it will * This is similar to "%.[0-9]f" in the printf style, except it will
* NOT include trailing zeros after the decimal point. This type * NOT include trailing zeros after the decimal point. This type
@ -100,15 +102,15 @@ void modp_dtoa(double value, char* buf, int precision);
* \param[in] precision Number of digits to the right of the decimal point. * \param[in] precision Number of digits to the right of the decimal point.
* Can only be 0-9. * Can only be 0-9.
*/ */
void modp_dtoa2(double value, char* buf, int precision); size_t modp_dtoa2(double value, char* buf, int precision);
/** \brief convert a floating point number to char buffer with a /** \brief convert a floating point number to char buffer with a
* variable-precision format, no trailing zeros, and no * variable-precision format, no trailing zeros, and no
* scientific notation. * scientific notation, return number of characters added
* *
* Other than avoiding scientific notation, this is the same as mop_dtoa2. It does however * Other than avoiding scientific notation, this is the same as mop_dtoa2. It does however
* require the max buffer length. The buffer will always be null-terminated. * require the max buffer length. The buffer will always be null-terminated.
*/ */
void modp_dtoa3(double value, char* buf, int n, int precision); size_t modp_dtoa3(double value, char* buf, int n, int precision);
END_C END_C