gmio_core/internal: make distinction between fast_strtof() and fast_atof()

This commit is contained in:
Hugues Delorme 2015-11-19 17:45:29 +01:00
parent efe3e64648
commit 3afcde257d
2 changed files with 67 additions and 183 deletions

View File

@ -57,24 +57,12 @@ static const float fast_atof_table[17] = {
*/ */
GMIO_INLINE uint32_t strtoul10(const char* in, const char** out) GMIO_INLINE uint32_t strtoul10(const char* in, const char** out)
{ {
gmio_bool_t overflow=GMIO_FALSE; unsigned int value = 0;
uint32_t unsignedValue = 0; for (; gmio_ascii_isdigit(*in); ++in)
value = (value * 10) + (*in - '0');
while ( gmio_ascii_isdigit(*in) )
{
const uint32_t tmp = ( unsignedValue * 10 ) + ( *in - '0' );
if (tmp<unsignedValue)
{
unsignedValue=(uint32_t)0xffffffff;
overflow=GMIO_TRUE;
}
if (!overflow)
unsignedValue = tmp;
++in;
}
if (out) if (out)
*out = in; *out = in;
return unsignedValue; return value;
} }
/*! Convert a simple string of base 10 digits into a signed 32 bit integer. /*! Convert a simple string of base 10 digits into a signed 32 bit integer.
@ -90,137 +78,15 @@ GMIO_INLINE uint32_t strtoul10(const char* in, const char** out)
*/ */
GMIO_INLINE int32_t strtol10(const char* in, const char** out) GMIO_INLINE int32_t strtol10(const char* in, const char** out)
{ {
const gmio_bool_t negative = ('-' == *in); const gmio_bool_t inv = (*in == '-');
uint32_t unsignedValue = 0; int value = 0;
if (inv || *in == '+')
if (negative || ('+' == *in))
++in; ++in;
unsignedValue = strtoul10(in,out);
if (unsignedValue > (uint32_t)INT_MAX)
{
if (negative)
return (int32_t)INT_MIN;
else
return (int32_t)INT_MAX;
}
else
{
if (negative)
return -((int32_t)unsignedValue);
else
return (int32_t)unsignedValue;
}
}
/*! Convert a hex-encoded character to an unsigned integer. value = strtoul10(in, out);
* if (inv)
* \param[in] in The digit to convert. Only digits 0 to 9 and chars A-F,a-f value = -value;
* will be considered. return value;
* \return The unsigned integer value of the digit. 0xffffffff if the input is
* not hex
*/
GMIO_INLINE uint32_t ctoul16(char in)
{
if (in >= '0' && in <= '9')
return in - '0';
else if (in >= 'a' && in <= 'f')
return 10u + in - 'a';
else if (in >= 'A' && in <= 'F')
return 10u + in - 'A';
else
return 0xffffffff;
}
/*! Convert a simple string of base 16 digits into an unsigned 32 bit integer.
*
* \param[in] in: The string of digits to convert. No leading chars are
* allowed, only digits 0 to 9 and chars A-F,a-f are allowed. Parsing stops
* at the first illegal char.
* \param[out] out: (optional) If provided, it will be set to point at the
* first character not used in the calculation.
* \return The unsigned integer value of the digits. If the string specifies
* too many digits to encode in an uint32_t then INT_MAX will be returned.
*/
GMIO_INLINE uint32_t strtoul16(const char* in, const char** out)
{
gmio_bool_t overflow=GMIO_FALSE;
uint32_t unsignedValue = 0;
for (;;)
{
uint32_t tmp = 0;
if (gmio_ascii_isdigit(*in))
tmp = (unsignedValue << 4u) + (*in - '0');
else if ((*in >= 'A') && (*in <= 'F'))
tmp = (unsignedValue << 4u) + (*in - 'A') + 10;
else if ((*in >= 'a') && (*in <= 'f'))
tmp = (unsignedValue << 4u) + (*in - 'a') + 10;
else
break;
if (tmp<unsignedValue)
{
unsignedValue=(uint32_t)INT_MAX;
overflow=GMIO_TRUE;
}
if (!overflow)
unsignedValue = tmp;
++in;
}
if (out)
*out = in;
return unsignedValue;
}
/*! Convert a simple string of base 8 digits into an unsigned 32 bit integer.
*
* \param[in] in The string of digits to convert. No leading chars are
* allowed, only digits 0 to 7 are allowed. Parsing stops at the first illegal
* char.
* \param[out] out (optional) If provided, it will be set to point at the
* first character not used in the calculation.
* \return The unsigned integer value of the digits. If the string specifies
* too many digits to encode in an uint32_t then INT_MAX will be returned.
*/
GMIO_INLINE uint32_t strtoul8(const char* in, const char** out)
{
gmio_bool_t overflow=GMIO_FALSE;
uint32_t unsignedValue = 0;
for (;;)
{
uint32_t tmp = 0;
if ((*in >= '0') && (*in <= '7'))
tmp = (unsignedValue << 3u) + (*in - '0');
else
break;
if (tmp<unsignedValue)
{
unsignedValue=(uint32_t)INT_MAX;
overflow=GMIO_TRUE;
}
if (!overflow)
unsignedValue = tmp;
++in;
}
if (out)
*out = in;
return unsignedValue;
}
/*! Convert a C-style prefixed string (hex, oct, integer) into an unsigned
* 32 bit integer.
*
* \param[in] in The string of digits to convert. If string starts with 0x the
* hex parser is used, if only leading 0 is used, oct parser is used. In all
* other cases, the usual unsigned parser is used.
* \param[out] out (optional) If provided, it will be set to point at the
* first character not used in the calculation.
* \return The unsigned integer value of the digits. If the string specifies
* too many digits to encode in an uint32_t then INT_MAX will be returned.
*/
GMIO_INLINE uint32_t strtoul_prefix(const char* in, const char** out)
{
if ('0'==in[0])
return ('x'==in[1] ? strtoul16(in+2,out) : strtoul8(in+1,out));
return strtoul10(in,out);
} }
/*! Converts a sequence of digits into a whole positive floating point value. /*! Converts a sequence of digits into a whole positive floating point value.
@ -233,24 +99,24 @@ GMIO_INLINE uint32_t strtoul_prefix(const char* in, const char** out)
* \return The whole positive floating point representation of the digit * \return The whole positive floating point representation of the digit
* sequence. * sequence.
*/ */
GMIO_INLINE gmio_float32_t strtof10(const char* in, const char** out) GMIO_INLINE float strtof10(const char* in, const char** out)
{ {
const uint32_t MAX_SAFE_U32_VALUE = UINT_MAX / 10 - 10; const uint32_t MAX_SAFE_U32_VALUE = UINT_MAX / 10 - 10;
uint32_t intValue = 0; uint32_t int_val = 0;
gmio_float32_t floatValue = 0.f; float float_val = 0.f;
/* Use integer arithmetic for as long as possible, for speed /* Use integer arithmetic for as long as possible, for speed and
* and precision. */ * precision */
for (; gmio_ascii_isdigit(*in) && intValue < MAX_SAFE_U32_VALUE; ++in) for (; gmio_ascii_isdigit(*in) && int_val < MAX_SAFE_U32_VALUE; ++in)
intValue = (intValue * 10) + (*in - '0'); int_val = (int_val * 10) + (*in - '0');
floatValue = (gmio_float32_t)intValue; float_val = (float)int_val;
/* If there are any digits left to parse, then we need to use /* If there are any digits left to parse, then we need to use floating point
* floating point arithmetic from here. */ * arithmetic from here */
for (; gmio_ascii_isdigit(*in) && floatValue <= FLT_MAX; ++in) for (; gmio_ascii_isdigit(*in) && float_val <= FLT_MAX; ++in)
floatValue = (floatValue * 10) + (*in - '0'); float_val = (float_val * 10) + (*in - '0');
if (out) if (out)
*out = in; *out = in;
return floatValue; return float_val;
} }
/*! Provides a fast function for converting a string into a float. /*! Provides a fast function for converting a string into a float.
@ -262,56 +128,60 @@ GMIO_INLINE gmio_float32_t strtof10(const char* in, const char** out)
* \return Pointer to the first character in the string that wasn't used * \return Pointer to the first character in the string that wasn't used
* to create the float value. * to create the float value.
*/ */
GMIO_INLINE const char* fast_atof_move( GMIO_INLINE const char* fast_atof_move(const char* in, float* result)
const char* in, gmio_float32_t* result)
{ {
const gmio_bool_t negative = ('-' == *in); const gmio_bool_t negative = ('-' == *in);
gmio_float32_t value = 0.f; float value = 0.f;
/* Please run the regression test when making any modifications to this /* Please run the regression test when making any modifications to this
* function. */ * function. */
*result = 0.f; *result = 0.f;
if (negative || ('+'==*in)) if (negative || ('+' == *in))
++in; ++in;
value = strtof10(in, &in); value = strtof10(in, &in);
if ( is_local_decimal_point(*in) ) if (is_local_decimal_point(*in)) {
{ const char* after_decimal = ++in;
const char* afterDecimal = ++in; const float decimal = strtof10(in, &after_decimal);
const gmio_float32_t decimal = strtof10(in, &afterDecimal); value += decimal * fast_atof_table[after_decimal - in];
value += decimal * fast_atof_table[afterDecimal - in]; in = after_decimal;
in = afterDecimal;
} }
if ('e' == *in || 'E' == *in) if ('e' == *in || 'E' == *in) {
{
++in; ++in;
/* Assume that the exponent is a whole number. /* Assume that the exponent is a whole number.
* strtol10() will deal with both + and - signs, * strtol10() will deal with both + and - signs,
* but calculate as gmio_float32_t to prevent overflow at FLT_MAX */ * but calculate as float to prevent overflow at FLT_MAX */
value *= value *=
#ifdef GMIO_HAVE_POWF_FUNC #ifdef GMIO_HAVE_POWF_FUNC
powf(10.f, (gmio_float32_t)strtol10(in, &in)); powf(10.f, (float)strtol10(in, &in));
#else #else
(gmio_float32_t)pow(10., (gmio_float64_t)strtol10(in, &in)); (float)pow(10., (double)strtol10(in, &in));
#endif #endif
} }
*result = negative?-value:value; *result = negative ? -value : value;
return in; return in;
} }
/*! Convert a string to a floating point number /*! Convert a string to a floating point number
* *
* \param floatAsString The string to convert. * \param str The string to convert.
* \param out Optional pointer to the first character in the string that * \param out Optional pointer to the first character in the string that
* wasn't used to create the float value. * wasn't used to create the float value.
* \result Float value parsed from the input string * \result Float value parsed from the input string
*/ */
GMIO_INLINE float fast_atof(const char* floatAsString, const char** out) GMIO_INLINE float fast_strtof(const char* str, const char** out)
{ {
float ret; float ret;
if (out) if (out)
*out=fast_atof_move(floatAsString, &ret); *out = fast_atof_move(str, &ret);
else else
fast_atof_move(floatAsString, &ret); fast_atof_move(str, &ret);
return ret;
}
GMIO_INLINE float fast_atof(const char* str)
{
float ret;
fast_atof_move(str, &ret);
return ret; return ret;
} }

View File

@ -50,7 +50,11 @@ GMIO_INLINE const char* gmio_current_char(
const gmio_string_stream_fwd_iterator_t* it); const gmio_string_stream_fwd_iterator_t* it);
/*! Moves on next char in stream */ /*! Moves on next char in stream */
GMIO_INLINE const char *gmio_next_char( GMIO_INLINE const char* gmio_next_char(
gmio_string_stream_fwd_iterator_t *it);
/*! Moves on next char in stream */
GMIO_INLINE gmio_string_stream_fwd_iterator_t* gmio_move_next_char(
gmio_string_stream_fwd_iterator_t *it); gmio_string_stream_fwd_iterator_t *it);
/*! Advances iterator until the first non-space char */ /*! Advances iterator until the first non-space char */
@ -85,16 +89,18 @@ gmio_bool_t gmio_checked_next_chars(
gmio_string_stream_fwd_iterator_t* it, const char* str); gmio_string_stream_fwd_iterator_t* it, const char* str);
#endif #endif
/*! Converts the string pointed to by \p str to gmio_float32_t representation /*! Converts C string \p str to float
* *
* \retval 0 On success * \retval 0 On success
* \retval -1 On error(check \c errno to see what happened) * \retval -1 On error(check \c errno to see what happened)
*/ */
GMIO_INLINE int gmio_get_float32(const char* str, gmio_float32_t* value_ptr); GMIO_INLINE int gmio_get_float32(const char* str, gmio_float32_t* value_ptr);
/*! Converts C string \p str to float */
GMIO_INLINE gmio_float32_t gmio_to_float32(const char* str); GMIO_INLINE gmio_float32_t gmio_to_float32(const char* str);
/* /*
* -- Implementation * -- Implementation
*/ */
@ -135,6 +141,14 @@ const char *gmio_next_char(gmio_string_stream_fwd_iterator_t *it)
return NULL; return NULL;
} }
gmio_string_stream_fwd_iterator_t* gmio_move_next_char(
gmio_string_stream_fwd_iterator_t *it)
{
gmio_next_char(it);
return it;
}
const char* gmio_skip_spaces( const char* gmio_skip_spaces(
gmio_string_stream_fwd_iterator_t* it) gmio_string_stream_fwd_iterator_t* it)
{ {
@ -162,7 +176,7 @@ int gmio_get_float32(const char* str, gmio_float32_t* value_ptr)
{ {
#if defined(GMIO_STRINGPARSE_USE_FAST_ATOF) #if defined(GMIO_STRINGPARSE_USE_FAST_ATOF)
const char* end_ptr = NULL; const char* end_ptr = NULL;
*value_ptr = fast_atof(str, &end_ptr); *value_ptr = fast_strtof(str, &end_ptr);
#elif defined(GMIO_HAVE_STRTOF_FUNC) /* Requires C99 */ #elif defined(GMIO_HAVE_STRTOF_FUNC) /* Requires C99 */
char* end_ptr = NULL; char* end_ptr = NULL;
*value_ptr = strtof(str, &end_ptr); *value_ptr = strtof(str, &end_ptr);
@ -173,10 +187,10 @@ int gmio_get_float32(const char* str, gmio_float32_t* value_ptr)
return (end_ptr == str || errno == ERANGE) ? -1 : 0; return (end_ptr == str || errno == ERANGE) ? -1 : 0;
} }
GMIO_INLINE gmio_float32_t gmio_to_float32(const char* str) gmio_float32_t gmio_to_float32(const char* str)
{ {
#if defined(GMIO_STRINGPARSE_USE_FAST_ATOF) #if defined(GMIO_STRINGPARSE_USE_FAST_ATOF)
return fast_atof(str, NULL); return fast_atof(str);
#elif defined(GMIO_HAVE_STRTOF_FUNC) /* Requires C99 */ #elif defined(GMIO_HAVE_STRTOF_FUNC) /* Requires C99 */
return strtof(str, NULL); return strtof(str, NULL);
#else #else