gmio_core/internal: make distinction between fast_strtof() and fast_atof()
This commit is contained in:
parent
efe3e64648
commit
3afcde257d
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user