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_bool_t overflow=GMIO_FALSE;
uint32_t unsignedValue = 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;
}
unsigned int value = 0;
for (; gmio_ascii_isdigit(*in); ++in)
value = (value * 10) + (*in - '0');
if (out)
*out = in;
return unsignedValue;
return value;
}
/*! 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)
{
const gmio_bool_t negative = ('-' == *in);
uint32_t unsignedValue = 0;
if (negative || ('+' == *in))
const gmio_bool_t inv = (*in == '-');
int value = 0;
if (inv || *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.
*
* \param[in] in The digit to convert. Only digits 0 to 9 and chars A-F,a-f
* will be considered.
* \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);
value = strtoul10(in, out);
if (inv)
value = -value;
return 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
* 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;
uint32_t intValue = 0;
gmio_float32_t floatValue = 0.f;
uint32_t int_val = 0;
float float_val = 0.f;
/* Use integer arithmetic for as long as possible, for speed
* and precision. */
for (; gmio_ascii_isdigit(*in) && intValue < MAX_SAFE_U32_VALUE; ++in)
intValue = (intValue * 10) + (*in - '0');
floatValue = (gmio_float32_t)intValue;
/* If there are any digits left to parse, then we need to use
* floating point arithmetic from here. */
for (; gmio_ascii_isdigit(*in) && floatValue <= FLT_MAX; ++in)
floatValue = (floatValue * 10) + (*in - '0');
/* Use integer arithmetic for as long as possible, for speed and
* precision */
for (; gmio_ascii_isdigit(*in) && int_val < MAX_SAFE_U32_VALUE; ++in)
int_val = (int_val * 10) + (*in - '0');
float_val = (float)int_val;
/* If there are any digits left to parse, then we need to use floating point
* arithmetic from here */
for (; gmio_ascii_isdigit(*in) && float_val <= FLT_MAX; ++in)
float_val = (float_val * 10) + (*in - '0');
if (out)
*out = in;
return floatValue;
return float_val;
}
/*! 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
* to create the float value.
*/
GMIO_INLINE const char* fast_atof_move(
const char* in, gmio_float32_t* result)
GMIO_INLINE const char* fast_atof_move(const char* in, float* result)
{
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
* function. */
*result = 0.f;
if (negative || ('+'==*in))
if (negative || ('+' == *in))
++in;
value = strtof10(in, &in);
if ( is_local_decimal_point(*in) )
{
const char* afterDecimal = ++in;
const gmio_float32_t decimal = strtof10(in, &afterDecimal);
value += decimal * fast_atof_table[afterDecimal - in];
in = afterDecimal;
if (is_local_decimal_point(*in)) {
const char* after_decimal = ++in;
const float decimal = strtof10(in, &after_decimal);
value += decimal * fast_atof_table[after_decimal - in];
in = after_decimal;
}
if ('e' == *in || 'E' == *in)
{
if ('e' == *in || 'E' == *in) {
++in;
/* Assume that the exponent is a whole number.
* 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 *=
#ifdef GMIO_HAVE_POWF_FUNC
powf(10.f, (gmio_float32_t)strtol10(in, &in));
powf(10.f, (float)strtol10(in, &in));
#else
(gmio_float32_t)pow(10., (gmio_float64_t)strtol10(in, &in));
(float)pow(10., (double)strtol10(in, &in));
#endif
}
*result = negative?-value:value;
*result = negative ? -value : value;
return in;
}
/*! 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
* wasn't used to create the float value.
* \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;
if (out)
*out=fast_atof_move(floatAsString, &ret);
*out = fast_atof_move(str, &ret);
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;
}

View File

@ -50,7 +50,11 @@ GMIO_INLINE const char* gmio_current_char(
const gmio_string_stream_fwd_iterator_t* it);
/*! 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);
/*! 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);
#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 -1 On error(check \c errno to see what happened)
*/
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);
/*
* -- Implementation
*/
@ -135,6 +141,14 @@ const char *gmio_next_char(gmio_string_stream_fwd_iterator_t *it)
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(
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)
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 */
char* end_ptr = NULL;
*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;
}
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)
return fast_atof(str, NULL);
return fast_atof(str);
#elif defined(GMIO_HAVE_STRTOF_FUNC) /* Requires C99 */
return strtof(str, NULL);
#else