gmio_core/internal: add gmio_parse_float32()
This commit is contained in:
parent
3afcde257d
commit
be5c1cd65d
@ -25,6 +25,8 @@
|
|||||||
* To be used with API below.
|
* To be used with API below.
|
||||||
* It allows to iterate over a stream (until end is reached) as if it was a
|
* It allows to iterate over a stream (until end is reached) as if it was a
|
||||||
* string.
|
* string.
|
||||||
|
*
|
||||||
|
* TODO: rename to gmio_string_stream
|
||||||
*/
|
*/
|
||||||
struct gmio_string_stream_fwd_iterator
|
struct gmio_string_stream_fwd_iterator
|
||||||
{
|
{
|
||||||
@ -34,8 +36,7 @@ struct gmio_string_stream_fwd_iterator
|
|||||||
const char* strbuff_ptr_at; /*!< Position indicator in buffer */
|
const char* strbuff_ptr_at; /*!< Position indicator in buffer */
|
||||||
|
|
||||||
void* cookie;
|
void* cookie;
|
||||||
void (*func_stream_read_hook)(
|
void (*func_stream_read_hook)(void* cookie, const gmio_string_t* strbuff);
|
||||||
void* cookie, const gmio_string_t* str_buffer);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct gmio_string_stream_fwd_iterator
|
typedef struct gmio_string_stream_fwd_iterator
|
||||||
@ -89,6 +90,10 @@ 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
|
||||||
|
|
||||||
|
/*! Parses float from string iterator \p it */
|
||||||
|
GMIO_INLINE gmio_float32_t gmio_parse_float32(
|
||||||
|
gmio_string_stream_fwd_iterator_t* it);
|
||||||
|
|
||||||
/*! Converts C string \p str to float
|
/*! Converts C string \p str to float
|
||||||
*
|
*
|
||||||
* \retval 0 On success
|
* \retval 0 On success
|
||||||
@ -109,6 +114,7 @@ GMIO_INLINE gmio_float32_t gmio_to_float32(const char* str);
|
|||||||
#include "string_utils.h"
|
#include "string_utils.h"
|
||||||
#ifdef GMIO_STRINGPARSE_USE_FAST_ATOF
|
#ifdef GMIO_STRINGPARSE_USE_FAST_ATOF
|
||||||
# include "fast_atof.h"
|
# include "fast_atof.h"
|
||||||
|
# include "string_parse_fast_atof.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -148,7 +154,6 @@ gmio_string_stream_fwd_iterator_t* gmio_move_next_char(
|
|||||||
return 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)
|
||||||
{
|
{
|
||||||
@ -198,4 +203,16 @@ gmio_float32_t gmio_to_float32(const char* str)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gmio_float32_t gmio_parse_float32(gmio_string_stream_fwd_iterator_t* it)
|
||||||
|
{
|
||||||
|
#if defined(GMIO_STRINGPARSE_USE_FAST_ATOF)
|
||||||
|
return gmio_fast_atof(it);
|
||||||
|
#else
|
||||||
|
char strbuff_ptr[64];
|
||||||
|
gmio_string_t strbuff = { &strbuff_ptr[0], 0, sizeof(strbuff_ptr) };
|
||||||
|
gmio_eat_word(it, &strbuff);
|
||||||
|
return (gmio_float32_t)atof(strbuff_ptr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* GMIO_INTERNAL_STRING_PARSE_H */
|
#endif /* GMIO_INTERNAL_STRING_PARSE_H */
|
||||||
|
112
src/gmio_core/internal/string_parse_fast_atof.h
Normal file
112
src/gmio_core/internal/string_parse_fast_atof.h
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/* Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||||
|
* This file is part of the "Irrlicht Engine" and the "irrXML" project.
|
||||||
|
* For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||||
|
* and irrXML.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Adapted to ISO-C90 */
|
||||||
|
|
||||||
|
#ifndef GMIO_INTERNAL_STRING_PARSE_FAST_ATOF_H
|
||||||
|
#define GMIO_INTERNAL_STRING_PARSE_FAST_ATOF_H
|
||||||
|
|
||||||
|
#include "fast_atof.h"
|
||||||
|
#include "string_parse.h"
|
||||||
|
|
||||||
|
GMIO_INLINE uint32_t gmio_strtoul10(gmio_string_stream_fwd_iterator_t* it)
|
||||||
|
{
|
||||||
|
unsigned int value = 0;
|
||||||
|
const char* in = gmio_current_char(it);
|
||||||
|
for (; in != NULL && gmio_ascii_isdigit(*in); in = gmio_next_char(it))
|
||||||
|
value = (value * 10) + (*in - '0');
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
GMIO_INLINE int32_t gmio_strtol10(gmio_string_stream_fwd_iterator_t* it)
|
||||||
|
{
|
||||||
|
const char* in = gmio_current_char(it);
|
||||||
|
const gmio_bool_t inv = (*in == '-');
|
||||||
|
int value = 0;
|
||||||
|
if (inv || *in == '+')
|
||||||
|
in = gmio_next_char(it);
|
||||||
|
|
||||||
|
value = gmio_strtoul10(it);
|
||||||
|
if (inv)
|
||||||
|
value = -value;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct gmio_strtof10_result
|
||||||
|
{
|
||||||
|
float val;
|
||||||
|
unsigned char_diff;
|
||||||
|
};
|
||||||
|
typedef struct gmio_strtof10_result gmio_strtof10_result_t;
|
||||||
|
|
||||||
|
GMIO_INLINE gmio_strtof10_result_t gmio_strtof10(
|
||||||
|
gmio_string_stream_fwd_iterator_t* it)
|
||||||
|
{
|
||||||
|
const char* in = gmio_current_char(it);
|
||||||
|
const uint32_t MAX_SAFE_U32_VALUE = UINT_MAX / 10 - 10;
|
||||||
|
uint32_t int_val = 0;
|
||||||
|
float float_val = 0.f;
|
||||||
|
unsigned char_diff = 0;
|
||||||
|
gmio_strtof10_result_t result;
|
||||||
|
|
||||||
|
/* Use integer arithmetic for as long as possible, for speed and
|
||||||
|
* precision */
|
||||||
|
for (;
|
||||||
|
in != NULL && gmio_ascii_isdigit(*in) && int_val < MAX_SAFE_U32_VALUE;
|
||||||
|
in = gmio_next_char(it))
|
||||||
|
{
|
||||||
|
int_val = (int_val * 10) + (*in - '0');
|
||||||
|
++char_diff;
|
||||||
|
}
|
||||||
|
float_val = (float)int_val;
|
||||||
|
/* If there are any digits left to parse, then we need to use floating point
|
||||||
|
* arithmetic from here */
|
||||||
|
for (;
|
||||||
|
in != NULL && gmio_ascii_isdigit(*in) && float_val <= FLT_MAX;
|
||||||
|
in = gmio_next_char(it))
|
||||||
|
{
|
||||||
|
float_val = (float_val * 10) + (*in - '0');
|
||||||
|
++char_diff;
|
||||||
|
}
|
||||||
|
result.val = float_val;
|
||||||
|
result.char_diff = char_diff;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
GMIO_INLINE float gmio_fast_atof(gmio_string_stream_fwd_iterator_t* it)
|
||||||
|
{
|
||||||
|
const char* in = gmio_current_char(it);
|
||||||
|
const gmio_bool_t negative = ('-' == *in);
|
||||||
|
float value = 0.f;
|
||||||
|
|
||||||
|
/* Please run the regression test when making any modifications to this
|
||||||
|
* function. */
|
||||||
|
if (negative || ('+' == *in))
|
||||||
|
in = gmio_next_char(it);
|
||||||
|
value = gmio_strtof10(it).val;
|
||||||
|
in = gmio_current_char(it);
|
||||||
|
if (is_local_decimal_point(*in)) {
|
||||||
|
const gmio_strtof10_result_t decimal =
|
||||||
|
gmio_strtof10(gmio_move_next_char(it));
|
||||||
|
value += decimal.val * fast_atof_table[decimal.char_diff];
|
||||||
|
in = gmio_current_char(it);
|
||||||
|
}
|
||||||
|
if (in != NULL && ('e' == *in || 'E' == *in)) {
|
||||||
|
in = gmio_next_char(it);
|
||||||
|
/* Assume that the exponent is a whole number.
|
||||||
|
* strtol10() will deal with both + and - signs,
|
||||||
|
* but calculate as float to prevent overflow at FLT_MAX */
|
||||||
|
value *=
|
||||||
|
#ifdef GMIO_HAVE_POWF_FUNC
|
||||||
|
powf(10.f, (float)gmio_strtol10(it));
|
||||||
|
#else
|
||||||
|
(float)pow(10., (double)gmio_strtol10(it));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return negative ? -value : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* GMIO_INTERNAL_STRING_PARSE_FAST_ATOF_H */
|
@ -23,6 +23,7 @@ const char* test_core__stream();
|
|||||||
const char* test_internal__byte_swap();
|
const char* test_internal__byte_swap();
|
||||||
const char* test_internal__byte_codec();
|
const char* test_internal__byte_codec();
|
||||||
const char* test_internal__fast_atof();
|
const char* test_internal__fast_atof();
|
||||||
|
const char* test_internal__gmio_fast_atof();
|
||||||
const char* test_internal__safe_cast();
|
const char* test_internal__safe_cast();
|
||||||
const char* test_internal__string_parse();
|
const char* test_internal__string_parse();
|
||||||
const char* test_internal__string_utils();
|
const char* test_internal__string_utils();
|
||||||
@ -43,6 +44,7 @@ const char* all_tests()
|
|||||||
UTEST_RUN(test_internal__byte_swap);
|
UTEST_RUN(test_internal__byte_swap);
|
||||||
UTEST_RUN(test_internal__byte_codec);
|
UTEST_RUN(test_internal__byte_codec);
|
||||||
UTEST_RUN(test_internal__fast_atof);
|
UTEST_RUN(test_internal__fast_atof);
|
||||||
|
UTEST_RUN(test_internal__gmio_fast_atof);
|
||||||
UTEST_RUN(test_internal__safe_cast);
|
UTEST_RUN(test_internal__safe_cast);
|
||||||
UTEST_RUN(test_internal__string_parse);
|
UTEST_RUN(test_internal__string_parse);
|
||||||
UTEST_RUN(test_internal__string_utils);
|
UTEST_RUN(test_internal__string_utils);
|
||||||
|
@ -62,7 +62,7 @@ const char* test_internal__byte_codec()
|
|||||||
|
|
||||||
static gmio_bool_t gmio_test_calculation_atof(const char* value_str)
|
static gmio_bool_t gmio_test_calculation_atof(const char* value_str)
|
||||||
{
|
{
|
||||||
const gmio_float32_t fast_value = fast_atof(value_str, NULL);
|
const gmio_float32_t fast_value = fast_atof(value_str);
|
||||||
const gmio_float32_t std_value = (gmio_float32_t)strtod(value_str, NULL);
|
const gmio_float32_t std_value = (gmio_float32_t)strtod(value_str, NULL);
|
||||||
const gmio_bool_t accurate =
|
const gmio_bool_t accurate =
|
||||||
gmio_float32_equals_by_ulp(fast_value, std_value, 1);
|
gmio_float32_equals_by_ulp(fast_value, std_value, 1);
|
||||||
@ -124,6 +124,35 @@ const char* test_internal__fast_atof()
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* test_internal__gmio_fast_atof()
|
||||||
|
{
|
||||||
|
const char fstr[] = "1234.567E05";
|
||||||
|
const float f1 = fast_atof(fstr);
|
||||||
|
|
||||||
|
{
|
||||||
|
char strbuff[2048] = {0};
|
||||||
|
gmio_string_stream_fwd_iterator_t it = {0};
|
||||||
|
gmio_stream_buffer_t streambuff = {0};
|
||||||
|
gmio_stream_t stream = {0};
|
||||||
|
float f2;
|
||||||
|
|
||||||
|
streambuff.readonly_ptr = &fstr[0];
|
||||||
|
streambuff.len = sizeof(fstr) - 1;
|
||||||
|
gmio_stream_set_buffer(&stream, &streambuff);
|
||||||
|
|
||||||
|
it.stream = &stream;
|
||||||
|
it.strbuff.ptr = &strbuff[0];
|
||||||
|
it.strbuff.max_len = sizeof(strbuff) - 1;
|
||||||
|
gmio_string_stream_fwd_iterator_init(&it);
|
||||||
|
|
||||||
|
f2 = gmio_fast_atof(&it);
|
||||||
|
|
||||||
|
UTEST_ASSERT(gmio_float32_equals_by_ulp(f1, f2, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
const char* test_internal__safe_cast()
|
const char* test_internal__safe_cast()
|
||||||
{
|
{
|
||||||
#if GMIO_TARGET_ARCH_BIT_SIZE > 32
|
#if GMIO_TARGET_ARCH_BIT_SIZE > 32
|
||||||
|
Loading…
Reference in New Issue
Block a user