nuclear@0: // Copyright (C) 2002-2007 Nikolaus Gebhardt nuclear@0: // This file is part of the "Irrlicht Engine" and the "irrXML" project. nuclear@0: // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: // Original description: (Schrompf) nuclear@0: // Adapted to the ASSIMP library because the builtin atof indeed takes AGES to parse a nuclear@0: // float inside a large string. Before parsing, it does a strlen on the given point. nuclear@0: // Changes: nuclear@0: // 22nd October 08 (Aramis_acg): Added temporary cast to double, added strtoul10_64 nuclear@0: // to ensure long numbers are handled correctly nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: nuclear@0: nuclear@0: #ifndef __FAST_A_TO_F_H_INCLUDED__ nuclear@0: #define __FAST_A_TO_F_H_INCLUDED__ nuclear@0: nuclear@0: #include nuclear@0: nuclear@0: namespace Assimp nuclear@0: { nuclear@0: nuclear@0: const float fast_atof_table[16] = { // we write [16] here instead of [] to work around a swig bug nuclear@0: 0.f, nuclear@0: 0.1f, nuclear@0: 0.01f, nuclear@0: 0.001f, nuclear@0: 0.0001f, nuclear@0: 0.00001f, nuclear@0: 0.000001f, nuclear@0: 0.0000001f, nuclear@0: 0.00000001f, nuclear@0: 0.000000001f, nuclear@0: 0.0000000001f, nuclear@0: 0.00000000001f, nuclear@0: 0.000000000001f, nuclear@0: 0.0000000000001f, nuclear@0: 0.00000000000001f, nuclear@0: 0.000000000000001f nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: // Convert a string in decimal format to a number nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: inline unsigned int strtoul10( const char* in, const char** out=0) nuclear@0: { nuclear@0: unsigned int value = 0; nuclear@0: nuclear@0: bool running = true; nuclear@0: while ( running ) nuclear@0: { nuclear@0: if ( *in < '0' || *in > '9' ) nuclear@0: break; nuclear@0: nuclear@0: value = ( value * 10 ) + ( *in - '0' ); nuclear@0: ++in; nuclear@0: } nuclear@0: if (out)*out = in; nuclear@0: return value; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: // Convert a string in octal format to a number nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: inline unsigned int strtoul8( const char* in, const char** out=0) nuclear@0: { nuclear@0: unsigned int value = 0; nuclear@0: nuclear@0: bool running = true; nuclear@0: while ( running ) nuclear@0: { nuclear@0: if ( *in < '0' || *in > '7' ) nuclear@0: break; nuclear@0: nuclear@0: value = ( value << 3 ) + ( *in - '0' ); nuclear@0: ++in; nuclear@0: } nuclear@0: if (out)*out = in; nuclear@0: return value; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: // Convert a string in hex format to a number nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: inline unsigned int strtoul16( const char* in, const char** out=0) nuclear@0: { nuclear@0: unsigned int value = 0; nuclear@0: nuclear@0: bool running = true; nuclear@0: while ( running ) nuclear@0: { nuclear@0: if ( *in >= '0' && *in <= '9' ) nuclear@0: { nuclear@0: value = ( value << 4u ) + ( *in - '0' ); nuclear@0: } nuclear@0: else if (*in >= 'A' && *in <= 'F') nuclear@0: { nuclear@0: value = ( value << 4u ) + ( *in - 'A' ) + 10; nuclear@0: } nuclear@0: else if (*in >= 'a' && *in <= 'f') nuclear@0: { nuclear@0: value = ( value << 4u ) + ( *in - 'a' ) + 10; nuclear@0: } nuclear@0: else break; nuclear@0: ++in; nuclear@0: } nuclear@0: if (out)*out = in; nuclear@0: return value; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: // Convert just one hex digit nuclear@0: // Return value is UINT_MAX if the input character is not a hex digit. nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: inline unsigned int HexDigitToDecimal(char in) nuclear@0: { nuclear@0: unsigned int out = UINT_MAX; nuclear@0: if (in >= '0' && in <= '9') nuclear@0: out = in - '0'; nuclear@0: nuclear@0: else if (in >= 'a' && in <= 'f') nuclear@0: out = 10u + in - 'a'; nuclear@0: nuclear@0: else if (in >= 'A' && in <= 'F') nuclear@0: out = 10u + in - 'A'; nuclear@0: nuclear@0: // return value is UINT_MAX if the input is not a hex digit nuclear@0: return out; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: // Convert a hex-encoded octet (2 characters, i.e. df or 1a). nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: inline uint8_t HexOctetToDecimal(const char* in) nuclear@0: { nuclear@0: return ((uint8_t)HexDigitToDecimal(in[0])<<4)+(uint8_t)HexDigitToDecimal(in[1]); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: // signed variant of strtoul10 nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: inline int strtol10( const char* in, const char** out=0) nuclear@0: { nuclear@0: bool inv = (*in=='-'); nuclear@0: if (inv || *in=='+') nuclear@0: ++in; nuclear@0: nuclear@0: int value = strtoul10(in,out); nuclear@0: if (inv) { nuclear@0: value = -value; nuclear@0: } nuclear@0: return value; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: // Parse a C++-like integer literal - hex and oct prefixes. nuclear@0: // 0xNNNN - hex nuclear@0: // 0NNN - oct nuclear@0: // NNN - dec nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: inline unsigned int strtoul_cppstyle( const char* in, const char** out=0) nuclear@0: { nuclear@0: if ('0' == in[0]) nuclear@0: { nuclear@0: return 'x' == in[1] ? strtoul16(in+2,out) : strtoul8(in+1,out); nuclear@0: } nuclear@0: return strtoul10(in, out); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: // Special version of the function, providing higher accuracy and safety nuclear@0: // It is mainly used by fast_atof to prevent ugly and unwanted integer overflows. nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* max_inout=0) nuclear@0: { nuclear@0: unsigned int cur = 0; nuclear@0: uint64_t value = 0; nuclear@0: nuclear@0: bool running = true; nuclear@0: while ( running ) nuclear@0: { nuclear@0: if ( *in < '0' || *in > '9' ) nuclear@0: break; nuclear@0: nuclear@0: const uint64_t new_value = ( value * 10 ) + ( *in - '0' ); nuclear@0: nuclear@0: if (new_value < value) /* numeric overflow, we rely on you */ nuclear@0: return value; nuclear@0: nuclear@0: value = new_value; nuclear@0: nuclear@0: ++in; nuclear@0: ++cur; nuclear@0: nuclear@0: if (max_inout && *max_inout == cur) { nuclear@0: nuclear@0: if (out) { /* skip to end */ nuclear@0: while (*in >= '0' && *in <= '9') nuclear@0: ++in; nuclear@0: *out = in; nuclear@0: } nuclear@0: nuclear@0: return value; nuclear@0: } nuclear@0: } nuclear@0: if (out) nuclear@0: *out = in; nuclear@0: nuclear@0: if (max_inout) nuclear@0: *max_inout = cur; nuclear@0: nuclear@0: return value; nuclear@0: } nuclear@0: nuclear@0: // Number of relevant decimals for floating-point parsing. nuclear@0: #define AI_FAST_ATOF_RELAVANT_DECIMALS 15 nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: //! Provides a fast function for converting a string into a float, nuclear@0: //! about 6 times faster than atof in win32. nuclear@0: // If you find any bugs, please send them to me, niko (at) irrlicht3d.org. nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: template nuclear@0: inline const char* fast_atoreal_move( const char* c, Real& out) nuclear@0: { nuclear@0: Real f; nuclear@0: nuclear@0: bool inv = (*c=='-'); nuclear@0: if (inv || *c=='+') { nuclear@0: ++c; nuclear@0: } nuclear@0: nuclear@0: f = static_cast( strtoul10_64 ( c, &c) ); nuclear@0: if (*c == '.' || (c[0] == ',' && c[1] >= '0' && c[1] <= '9')) // allow for commas, too nuclear@0: { nuclear@0: ++c; nuclear@0: nuclear@0: // NOTE: The original implementation is highly inaccurate here. The precision of a single nuclear@0: // IEEE 754 float is not high enough, everything behind the 6th digit tends to be more nuclear@0: // inaccurate than it would need to be. Casting to double seems to solve the problem. nuclear@0: // strtol_64 is used to prevent integer overflow. nuclear@0: nuclear@0: // Another fix: this tends to become 0 for long numbers if we don't limit the maximum nuclear@0: // number of digits to be read. AI_FAST_ATOF_RELAVANT_DECIMALS can be a value between nuclear@0: // 1 and 15. nuclear@0: unsigned int diff = AI_FAST_ATOF_RELAVANT_DECIMALS; nuclear@0: double pl = static_cast( strtoul10_64 ( c, &c, &diff )); nuclear@0: nuclear@0: pl *= fast_atof_table[diff]; nuclear@0: f += static_cast( pl ); nuclear@0: } nuclear@0: nuclear@0: // A major 'E' must be allowed. Necessary for proper reading of some DXF files. nuclear@0: // Thanks to Zhao Lei to point out that this if() must be outside the if (*c == '.' ..) nuclear@0: if (*c == 'e' || *c == 'E') { nuclear@0: nuclear@0: ++c; nuclear@0: const bool einv = (*c=='-'); nuclear@0: if (einv || *c=='+') { nuclear@0: ++c; nuclear@0: } nuclear@0: nuclear@0: // The reason float constants are used here is that we've seen cases where compilers nuclear@0: // would perform such casts on compile-time constants at runtime, which would be nuclear@0: // bad considering how frequently fast_atoreal_move is called in Assimp. nuclear@0: Real exp = static_cast( strtoul10_64(c, &c) ); nuclear@0: if (einv) { nuclear@0: exp = -exp; nuclear@0: } nuclear@0: f *= pow(static_cast(10.0f), exp); nuclear@0: } nuclear@0: nuclear@0: if (inv) { nuclear@0: f = -f; nuclear@0: } nuclear@0: out = f; nuclear@0: return c; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------ nuclear@0: // The same but more human. nuclear@0: inline float fast_atof(const char* c) nuclear@0: { nuclear@0: float ret; nuclear@0: fast_atoreal_move(c, ret); nuclear@0: return ret; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: inline float fast_atof( const char* c, const char** cout) nuclear@0: { nuclear@0: float ret; nuclear@0: *cout = fast_atoreal_move(c, ret); nuclear@0: nuclear@0: return ret; nuclear@0: } nuclear@0: nuclear@0: inline float fast_atof( const char** inout) nuclear@0: { nuclear@0: float ret; nuclear@0: *inout = fast_atoreal_move(*inout, ret); nuclear@0: nuclear@0: return ret; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: inline double fast_atod(const char* c) nuclear@0: { nuclear@0: double ret; nuclear@0: fast_atoreal_move(c, ret); nuclear@0: return ret; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: inline double fast_atod( const char* c, const char** cout) nuclear@0: { nuclear@0: double ret; nuclear@0: *cout = fast_atoreal_move(c, ret); nuclear@0: nuclear@0: return ret; nuclear@0: } nuclear@0: nuclear@0: inline double fast_atod( const char** inout) nuclear@0: { nuclear@0: double ret; nuclear@0: *inout = fast_atoreal_move(*inout, ret); nuclear@0: nuclear@0: return ret; nuclear@0: } nuclear@0: nuclear@0: } // end of namespace Assimp nuclear@0: nuclear@0: #endif nuclear@0: