From ef9a92826f3b85b5644222614ccc7f85bf6529b7 Mon Sep 17 00:00:00 2001 From: calderpg-tri <32444241+calderpg-tri@users.noreply.github.com> Date: Tue, 16 Feb 2021 20:39:59 -0500 Subject: [PATCH 1/4] Replace body of tryParseDouble with strtod --- tiny_obj_loader.h | 126 ++++------------------------------------------ 1 file changed, 9 insertions(+), 117 deletions(-) diff --git a/tiny_obj_loader.h b/tiny_obj_loader.h index 99213f6d..24971b10 100644 --- a/tiny_obj_loader.h +++ b/tiny_obj_loader.h @@ -62,6 +62,7 @@ THE SOFTWARE. #include #include #include +#include namespace tinyobj { @@ -839,125 +840,16 @@ static bool tryParseDouble(const char *s, const char *s_end, double *result) { return false; } - double mantissa = 0.0; - // This exponent is base 2 rather than 10. - // However the exponent we parse is supposed to be one of ten, - // thus we must take care to convert the exponent/and or the - // mantissa to a * 2^E, where a is the mantissa and E is the - // exponent. - // To get the final double we will use ldexp, it requires the - // exponent to be in base 2. - int exponent = 0; - - // NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED - // TO JUMP OVER DEFINITIONS. - char sign = '+'; - char exp_sign = '+'; - char const *curr = s; - - // How many characters were read in a loop. - int read = 0; - // Tells whether a loop terminated due to reaching s_end. - bool end_not_reached = false; - bool leading_decimal_dots = false; - - /* - BEGIN PARSING. - */ - - // Find out what sign we've got. - if (*curr == '+' || *curr == '-') { - sign = *curr; - curr++; - if ((curr != s_end) && (*curr == '.')) { - // accept. Somethig like `.7e+2`, `-.5234` - leading_decimal_dots = true; - } - } else if (IS_DIGIT(*curr)) { /* Pass through. */ - } else if (*curr == '.') { - // accept. Somethig like `.7e+2`, `-.5234` - leading_decimal_dots = true; - } else { - goto fail; - } - - // Read the integer part. - end_not_reached = (curr != s_end); - if (!leading_decimal_dots) { - while (end_not_reached && IS_DIGIT(*curr)) { - mantissa *= 10; - mantissa += static_cast(*curr - 0x30); - curr++; - read++; - end_not_reached = (curr != s_end); - } - - // We must make sure we actually got something. - if (read == 0) goto fail; - } - - // We allow numbers of form "#", "###" etc. - if (!end_not_reached) goto assemble; - - // Read the decimal part. - if (*curr == '.') { - curr++; - read = 1; - end_not_reached = (curr != s_end); - while (end_not_reached && IS_DIGIT(*curr)) { - static const double pow_lut[] = { - 1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, - }; - const int lut_entries = sizeof pow_lut / sizeof pow_lut[0]; - - // NOTE: Don't use powf here, it will absolutely murder precision. - mantissa += static_cast(*curr - 0x30) * - (read < lut_entries ? pow_lut[read] : std::pow(10.0, -read)); - read++; - curr++; - end_not_reached = (curr != s_end); - } - } else if (*curr == 'e' || *curr == 'E') { + errno = 0; + char *str_end = NULL; + const double val = strtod(s, &str_end); + if (str_end != s && errno != ERANGE && isfinite(val)) { + errno = 0; + *result = val; + return true; } else { - goto assemble; - } - - if (!end_not_reached) goto assemble; - - // Read the exponent part. - if (*curr == 'e' || *curr == 'E') { - curr++; - // Figure out if a sign is present and if it is. - end_not_reached = (curr != s_end); - if (end_not_reached && (*curr == '+' || *curr == '-')) { - exp_sign = *curr; - curr++; - } else if (IS_DIGIT(*curr)) { /* Pass through. */ - } else { - // Empty E is not allowed. - goto fail; - } - - read = 0; - end_not_reached = (curr != s_end); - while (end_not_reached && IS_DIGIT(*curr)) { - exponent *= 10; - exponent += static_cast(*curr - 0x30); - curr++; - read++; - end_not_reached = (curr != s_end); - } - exponent *= (exp_sign == '+' ? 1 : -1); - if (read == 0) goto fail; + return false; } - -assemble: - *result = (sign == '+' ? 1 : -1) * - (exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent) - : mantissa); - return true; -fail: - return false; } static inline real_t parseReal(const char **token, double default_value = 0.0) { From 129a88b40f115951163c284dc9d62de5bbfc3bd1 Mon Sep 17 00:00:00 2001 From: calderpg-tri <32444241+calderpg-tri@users.noreply.github.com> Date: Tue, 16 Feb 2021 21:03:19 -0500 Subject: [PATCH 2/4] Fix missing math include --- tiny_obj_loader.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tiny_obj_loader.h b/tiny_obj_loader.h index 24971b10..092f9127 100644 --- a/tiny_obj_loader.h +++ b/tiny_obj_loader.h @@ -62,6 +62,7 @@ THE SOFTWARE. #include #include #include +#include #include namespace tinyobj { From f11dd777c09889530945ced9a39aa3d145a2f40e Mon Sep 17 00:00:00 2001 From: calderpg-tri <32444241+calderpg-tri@users.noreply.github.com> Date: Wed, 17 Feb 2021 09:25:42 -0500 Subject: [PATCH 3/4] Make double parsing locale-independent --- tiny_obj_loader.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tiny_obj_loader.h b/tiny_obj_loader.h index 092f9127..c17dcf64 100644 --- a/tiny_obj_loader.h +++ b/tiny_obj_loader.h @@ -65,6 +65,12 @@ THE SOFTWARE. #include #include +#if defined(__APPLE__) +#include +#else +#include +#endif + namespace tinyobj { // TODO(syoyo): Better C++11 detection for older compiler @@ -840,10 +846,16 @@ static bool tryParseDouble(const char *s, const char *s_end, double *result) { if (s >= s_end) { return false; } + +#if defined(__APPLE__) + static locale_t c_locale = newlocale(LC_ALL_MASK, NULL, NULL); +#else + static locale_t c_locale = newlocale(LC_ALL_MASK, "C", (locale_t)0); +#endif errno = 0; char *str_end = NULL; - const double val = strtod(s, &str_end); + const double val = strtod_l(s, &str_end, c_locale); if (str_end != s && errno != ERANGE && isfinite(val)) { errno = 0; *result = val; From 36cd3258ac1cc70962be4576e05de628aec6a04f Mon Sep 17 00:00:00 2001 From: calderpg-tri <32444241+calderpg-tri@users.noreply.github.com> Date: Thu, 18 Feb 2021 12:23:27 -0500 Subject: [PATCH 4/4] Remove errno handling --- tiny_obj_loader.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tiny_obj_loader.h b/tiny_obj_loader.h index c17dcf64..fe46c5ff 100644 --- a/tiny_obj_loader.h +++ b/tiny_obj_loader.h @@ -846,18 +846,16 @@ static bool tryParseDouble(const char *s, const char *s_end, double *result) { if (s >= s_end) { return false; } - + #if defined(__APPLE__) static locale_t c_locale = newlocale(LC_ALL_MASK, NULL, NULL); #else static locale_t c_locale = newlocale(LC_ALL_MASK, "C", (locale_t)0); #endif - errno = 0; char *str_end = NULL; const double val = strtod_l(s, &str_end, c_locale); - if (str_end != s && errno != ERANGE && isfinite(val)) { - errno = 0; + if (str_end != s && isfinite(val)) { *result = val; return true; } else {