diff options
Diffstat (limited to 'src/3rdparty/assimp/code/fast_atof.h')
-rw-r--r-- | src/3rdparty/assimp/code/fast_atof.h | 469 |
1 files changed, 267 insertions, 202 deletions
diff --git a/src/3rdparty/assimp/code/fast_atof.h b/src/3rdparty/assimp/code/fast_atof.h index 3cdb1e81f..f65d72ae0 100644 --- a/src/3rdparty/assimp/code/fast_atof.h +++ b/src/3rdparty/assimp/code/fast_atof.h @@ -15,29 +15,40 @@ #ifndef __FAST_A_TO_F_H_INCLUDED__ #define __FAST_A_TO_F_H_INCLUDED__ -#include <math.h> -#include <limits.h> +#include <cmath> +#include <limits> +#include <stdint.h> +#include <stdexcept> + +#include "StringComparison.h" + + +#ifdef _MSC_VER +# include <stdint.h> +#else +# include <assimp/Compiler/pstdint.h> +#endif namespace Assimp { -const double fast_atof_table[16] = { // we write [16] here instead of [] to work around a swig bug - 0.0, - 0.1, - 0.01, - 0.001, - 0.0001, - 0.00001, - 0.000001, - 0.0000001, - 0.00000001, - 0.000000001, - 0.0000000001, - 0.00000000001, - 0.000000000001, - 0.0000000000001, - 0.00000000000001, - 0.000000000000001 +const double fast_atof_table[16] = { // we write [16] here instead of [] to work around a swig bug + 0.0, + 0.1, + 0.01, + 0.001, + 0.0001, + 0.00001, + 0.000001, + 0.0000001, + 0.00000001, + 0.000000001, + 0.0000000001, + 0.00000000001, + 0.000000000001, + 0.0000000000001, + 0.00000000000001, + 0.000000000000001 }; @@ -46,19 +57,19 @@ const double fast_atof_table[16] = { // we write [16] here instead of [] to wor // ------------------------------------------------------------------------------------ inline unsigned int strtoul10( const char* in, const char** out=0) { - unsigned int value = 0; - - bool running = true; - while ( running ) - { - if ( *in < '0' || *in > '9' ) - break; - - value = ( value * 10 ) + ( *in - '0' ); - ++in; - } - if (out)*out = in; - return value; + unsigned int value = 0; + + bool running = true; + while ( running ) + { + if ( *in < '0' || *in > '9' ) + break; + + value = ( value * 10 ) + ( *in - '0' ); + ++in; + } + if (out)*out = in; + return value; } // ------------------------------------------------------------------------------------ @@ -66,19 +77,19 @@ inline unsigned int strtoul10( const char* in, const char** out=0) // ------------------------------------------------------------------------------------ inline unsigned int strtoul8( const char* in, const char** out=0) { - unsigned int value = 0; - - bool running = true; - while ( running ) - { - if ( *in < '0' || *in > '7' ) - break; - - value = ( value << 3 ) + ( *in - '0' ); - ++in; - } - if (out)*out = in; - return value; + unsigned int value = 0; + + bool running = true; + while ( running ) + { + if ( *in < '0' || *in > '7' ) + break; + + value = ( value << 3 ) + ( *in - '0' ); + ++in; + } + if (out)*out = in; + return value; } // ------------------------------------------------------------------------------------ @@ -86,28 +97,28 @@ inline unsigned int strtoul8( const char* in, const char** out=0) // ------------------------------------------------------------------------------------ inline unsigned int strtoul16( const char* in, const char** out=0) { - unsigned int value = 0; - - bool running = true; - while ( running ) - { - if ( *in >= '0' && *in <= '9' ) - { - value = ( value << 4u ) + ( *in - '0' ); - } - else if (*in >= 'A' && *in <= 'F') - { - value = ( value << 4u ) + ( *in - 'A' ) + 10; - } - else if (*in >= 'a' && *in <= 'f') - { - value = ( value << 4u ) + ( *in - 'a' ) + 10; - } - else break; - ++in; - } - if (out)*out = in; - return value; + unsigned int value = 0; + + bool running = true; + while ( running ) + { + if ( *in >= '0' && *in <= '9' ) + { + value = ( value << 4u ) + ( *in - '0' ); + } + else if (*in >= 'A' && *in <= 'F') + { + value = ( value << 4u ) + ( *in - 'A' ) + 10; + } + else if (*in >= 'a' && *in <= 'f') + { + value = ( value << 4u ) + ( *in - 'a' ) + 10; + } + else break; + ++in; + } + if (out)*out = in; + return value; } // ------------------------------------------------------------------------------------ @@ -116,18 +127,18 @@ inline unsigned int strtoul16( const char* in, const char** out=0) // ------------------------------------------------------------------------------------ inline unsigned int HexDigitToDecimal(char in) { - unsigned int out = UINT_MAX; - if (in >= '0' && in <= '9') - out = in - '0'; + unsigned int out = UINT_MAX; + if (in >= '0' && in <= '9') + out = in - '0'; - else if (in >= 'a' && in <= 'f') - out = 10u + in - 'a'; + else if (in >= 'a' && in <= 'f') + out = 10u + in - 'a'; - else if (in >= 'A' && in <= 'F') - out = 10u + in - 'A'; + else if (in >= 'A' && in <= 'F') + out = 10u + in - 'A'; - // return value is UINT_MAX if the input is not a hex digit - return out; + // return value is UINT_MAX if the input is not a hex digit + return out; } // ------------------------------------------------------------------------------------ @@ -135,7 +146,7 @@ inline unsigned int HexDigitToDecimal(char in) // ------------------------------------------------------------------------------------ inline uint8_t HexOctetToDecimal(const char* in) { - return ((uint8_t)HexDigitToDecimal(in[0])<<4)+(uint8_t)HexDigitToDecimal(in[1]); + return ((uint8_t)HexDigitToDecimal(in[0])<<4)+(uint8_t)HexDigitToDecimal(in[1]); } @@ -144,15 +155,15 @@ inline uint8_t HexOctetToDecimal(const char* in) // ------------------------------------------------------------------------------------ inline int strtol10( const char* in, const char** out=0) { - bool inv = (*in=='-'); - if (inv || *in=='+') - ++in; - - int value = strtoul10(in,out); - if (inv) { - value = -value; - } - return value; + bool inv = (*in=='-'); + if (inv || *in=='+') + ++in; + + int value = strtoul10(in,out); + if (inv) { + value = -value; + } + return value; } // ------------------------------------------------------------------------------------ @@ -163,11 +174,11 @@ inline int strtol10( const char* in, const char** out=0) // ------------------------------------------------------------------------------------ inline unsigned int strtoul_cppstyle( const char* in, const char** out=0) { - if ('0' == in[0]) - { - return 'x' == in[1] ? strtoul16(in+2,out) : strtoul8(in+1,out); - } - return strtoul10(in, out); + if ('0' == in[0]) + { + return 'x' == in[1] ? strtoul16(in+2,out) : strtoul8(in+1,out); + } + return strtoul10(in, out); } // ------------------------------------------------------------------------------------ @@ -176,48 +187,65 @@ inline unsigned int strtoul_cppstyle( const char* in, const char** out=0) // ------------------------------------------------------------------------------------ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* max_inout=0) { - unsigned int cur = 0; - uint64_t value = 0; - - if ( *in < '0' || *in > '9' ) - throw std::invalid_argument(std::string("The string \"") + in + "\" cannot be converted into a value."); - - bool running = true; - while ( running ) - { - if ( *in < '0' || *in > '9' ) - break; - - const uint64_t new_value = ( value * 10 ) + ( *in - '0' ); - - if (new_value < value) /* numeric overflow, we rely on you */ - throw std::overflow_error(std::string("Converting the string \"") + in + "\" into a value resulted in overflow."); - - value = new_value; - - ++in; - ++cur; - - if (max_inout && *max_inout == cur) { - - if (out) { /* skip to end */ - while (*in >= '0' && *in <= '9') - ++in; - *out = in; - } - - return value; - } - } - if (out) - *out = in; - - if (max_inout) - *max_inout = cur; - - return value; + unsigned int cur = 0; + uint64_t value = 0; + + if ( *in < '0' || *in > '9' ) + throw std::invalid_argument(std::string("The string \"") + in + "\" cannot be converted into a value."); + + bool running = true; + while ( running ) + { + if ( *in < '0' || *in > '9' ) + break; + + const uint64_t new_value = ( value * 10 ) + ( *in - '0' ); + + if (new_value < value) /* numeric overflow, we rely on you */ + throw std::overflow_error(std::string("Converting the string \"") + in + "\" into a value resulted in overflow."); + + value = new_value; + + ++in; + ++cur; + + if (max_inout && *max_inout == cur) { + + if (out) { /* skip to end */ + while (*in >= '0' && *in <= '9') + ++in; + *out = in; + } + + return value; + } + } + if (out) + *out = in; + + if (max_inout) + *max_inout = cur; + + return value; +} + +// ------------------------------------------------------------------------------------ +// signed variant of strtoul10_64 +// ------------------------------------------------------------------------------------ +inline int64_t strtol10_64(const char* in, const char** out = 0, unsigned int* max_inout = 0) +{ + bool inv = (*in == '-'); + if (inv || *in == '+') + ++in; + + int64_t value = strtoul10_64(in, out, max_inout); + if (inv) { + value = -value; + } + return value; } + // Number of relevant decimals for floating-point parsing. #define AI_FAST_ATOF_RELAVANT_DECIMALS 15 @@ -227,111 +255,148 @@ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* // If you find any bugs, please send them to me, niko (at) irrlicht3d.org. // ------------------------------------------------------------------------------------ template <typename Real> -inline const char* fast_atoreal_move( const char* c, Real& out, bool check_comma = true) +inline const char* fast_atoreal_move(const char* c, Real& out, bool check_comma = true) { - Real f; - - bool inv = (*c=='-'); - if (inv || *c=='+') { - ++c; - } - - f = static_cast<Real>( strtoul10_64 ( c, &c) ); - if (*c == '.' || (check_comma && c[0] == ',' && c[1] >= '0' && c[1] <= '9')) // allow for commas, too - { - ++c; - - // NOTE: The original implementation is highly inaccurate here. The precision of a single - // IEEE 754 float is not high enough, everything behind the 6th digit tends to be more - // inaccurate than it would need to be. Casting to double seems to solve the problem. - // strtol_64 is used to prevent integer overflow. - - // Another fix: this tends to become 0 for long numbers if we don't limit the maximum - // number of digits to be read. AI_FAST_ATOF_RELAVANT_DECIMALS can be a value between - // 1 and 15. - unsigned int diff = AI_FAST_ATOF_RELAVANT_DECIMALS; - double pl = static_cast<double>( strtoul10_64 ( c, &c, &diff )); - - pl *= fast_atof_table[diff]; - f += static_cast<Real>( pl ); - } - - // A major 'E' must be allowed. Necessary for proper reading of some DXF files. - // Thanks to Zhao Lei to point out that this if() must be outside the if (*c == '.' ..) - if (*c == 'e' || *c == 'E') { - - ++c; - const bool einv = (*c=='-'); - if (einv || *c=='+') { - ++c; - } - - // The reason float constants are used here is that we've seen cases where compilers - // would perform such casts on compile-time constants at runtime, which would be - // bad considering how frequently fast_atoreal_move<float> is called in Assimp. - Real exp = static_cast<Real>( strtoul10_64(c, &c) ); - if (einv) { - exp = -exp; - } - f *= std::pow(static_cast<Real>(10.0), exp); - } - - if (inv) { - f = -f; - } - out = f; - return c; + Real f = 0; + + bool inv = (*c == '-'); + if (inv || *c == '+') { + ++c; + } + + if ((c[0] == 'N' || c[0] == 'n') && ASSIMP_strincmp(c, "nan", 3) == 0) + { + out = std::numeric_limits<Real>::quiet_NaN(); + c += 3; + return c; + } + + if ((c[0] == 'I' || c[0] == 'i') && ASSIMP_strincmp(c, "inf", 3) == 0) + { + out = std::numeric_limits<Real>::infinity(); + if (inv) { + out = -out; + } + c += 3; + if ((c[0] == 'I' || c[0] == 'i') && ASSIMP_strincmp(c, "inity", 5) == 0) + { + c += 5; + } + return c; + } + + if (!(c[0] >= '0' && c[0] <= '9') && + !((c[0] == '.' || (check_comma && c[0] == ',')) && c[1] >= '0' && c[1] <= '9')) + { + throw std::invalid_argument("Cannot parse string " + "as real number: does not start with digit " + "or decimal point followed by digit."); + } + + if (*c != '.' && (! check_comma || c[0] != ',')) + { + f = static_cast<Real>( strtoul10_64 ( c, &c) ); + } + + if ((*c == '.' || (check_comma && c[0] == ',')) && c[1] >= '0' && c[1] <= '9') + { + ++c; + + // NOTE: The original implementation is highly inaccurate here. The precision of a single + // IEEE 754 float is not high enough, everything behind the 6th digit tends to be more + // inaccurate than it would need to be. Casting to double seems to solve the problem. + // strtol_64 is used to prevent integer overflow. + + // Another fix: this tends to become 0 for long numbers if we don't limit the maximum + // number of digits to be read. AI_FAST_ATOF_RELAVANT_DECIMALS can be a value between + // 1 and 15. + unsigned int diff = AI_FAST_ATOF_RELAVANT_DECIMALS; + double pl = static_cast<double>( strtoul10_64 ( c, &c, &diff )); + + pl *= fast_atof_table[diff]; + f += static_cast<Real>( pl ); + } + // For backwards compatibility: eat trailing dots, but not trailing commas. + else if (*c == '.') { + ++c; + } + + // A major 'E' must be allowed. Necessary for proper reading of some DXF files. + // Thanks to Zhao Lei to point out that this if() must be outside the if (*c == '.' ..) + if (*c == 'e' || *c == 'E') { + + ++c; + const bool einv = (*c=='-'); + if (einv || *c=='+') { + ++c; + } + + // The reason float constants are used here is that we've seen cases where compilers + // would perform such casts on compile-time constants at runtime, which would be + // bad considering how frequently fast_atoreal_move<float> is called in Assimp. + Real exp = static_cast<Real>( strtoul10_64(c, &c) ); + if (einv) { + exp = -exp; + } + f *= std::pow(static_cast<Real>(10.0), exp); + } + + if (inv) { + f = -f; + } + out = f; + return c; } // ------------------------------------------------------------------------------------ // The same but more human. inline float fast_atof(const char* c) { - float ret; - fast_atoreal_move<float>(c, ret); - return ret; + float ret; + fast_atoreal_move<float>(c, ret); + return ret; } inline float fast_atof( const char* c, const char** cout) { - float ret; - *cout = fast_atoreal_move<float>(c, ret); + float ret; + *cout = fast_atoreal_move<float>(c, ret); - return ret; + return ret; } inline float fast_atof( const char** inout) { - float ret; - *inout = fast_atoreal_move<float>(*inout, ret); + float ret; + *inout = fast_atoreal_move<float>(*inout, ret); - return ret; + return ret; } inline double fast_atod(const char* c) { - double ret; - fast_atoreal_move<double>(c, ret); - return ret; + double ret; + fast_atoreal_move<double>(c, ret); + return ret; } inline double fast_atod( const char* c, const char** cout) { - double ret; - *cout = fast_atoreal_move<double>(c, ret); + double ret; + *cout = fast_atoreal_move<double>(c, ret); - return ret; + return ret; } inline double fast_atod( const char** inout) { - double ret; - *inout = fast_atoreal_move<double>(*inout, ret); + double ret; + *inout = fast_atoreal_move<double>(*inout, ret); - return ret; + return ret; } } // end of namespace Assimp |