// 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 #ifndef __FAST_ATOF_H_INCLUDED__ #define __FAST_ATOF_H_INCLUDED__ #include "irrMath.h" #include "irrString.h" namespace irr { namespace core { //! Selection of characters which count as decimal point in fast_atof // TODO: This should probably also be used in irr::core::string, but the float-to-string code // used there has to be rewritten first. IRRLICHT_API extern irr::core::stringc LOCALE_DECIMAL_POINTS; // we write [17] here instead of [] to work around a swig bug const float fast_atof_table[17] = { 0.f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f, 0.0000000001f, 0.00000000001f, 0.000000000001f, 0.0000000000001f, 0.00000000000001f, 0.000000000000001f, 0.0000000000000001f }; //! Convert a simple string of base 10 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. Parsing stops at the first non-digit. \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 u32 then INT_MAX will be returned. */ inline u32 strtoul10(const char* in, const char** out=0) { if (!in) { if (out) *out = in; return 0; } bool overflow=false; u32 unsignedValue = 0; while ( ( *in >= '0') && ( *in <= '9' )) { const u32 tmp = ( unsignedValue * 10 ) + ( *in - '0' ); if (tmp (u32)INT_MAX) { if (negative) return (s32)INT_MIN; else return (s32)INT_MAX; } else { if (negative) return -((s32)unsignedValue); else return (s32)unsignedValue; } } //! Convert a hex-encoded character to an unsigned integer. /** \param[in] in The digit to convert. Only digits 0 to 9 and chars A-F,a-f will be considered. \return The unsigned integer value of the digit. 0xffffffff if the input is not hex */ inline u32 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 u32 then INT_MAX will be returned. */ inline u32 strtoul16(const char* in, const char** out=0) { if (!in) { if (out) *out = in; return 0; } bool overflow=false; u32 unsignedValue = 0; while (true) { u32 tmp = 0; if ((*in >= '0') && (*in <= '9')) 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= '0') && (*in <= '7')) tmp = (unsignedValue << 3u) + (*in - '0'); else break; if (tmp= '0') && ( *in <= '9' ) ) { // If it looks like we're going to overflow, bail out // now and start using floating point. if (intValue >= MAX_SAFE_U32_VALUE) break; intValue = (intValue * 10) + (*in - '0'); ++in; } f32 floatValue = (f32)intValue; // If there are any digits left to parse, then we need to use // floating point arithmetic from here. while ( ( *in >= '0') && ( *in <= '9' ) ) { floatValue = (floatValue * 10.f) + (f32)(*in - '0'); ++in; if (floatValue > FLT_MAX) // Just give up. break; } if (out) *out = in; return floatValue; } //! Provides a fast function for converting a string into a float. /** This is not guaranteed to be as accurate as atof(), but is approximately 6 to 8 times as fast. \param[in] in The string to convert. \param[out] result The resultant float will be written here. \return Pointer to the first character in the string that wasn't used to create the float value. */ inline const char* fast_atof_move(const char* in, f32& result) { // Please run the regression test when making any modifications to this function. result = 0.f; if (!in) return 0; const bool negative = ('-' == *in); if (negative || ('+'==*in)) ++in; f32 value = strtof10(in, &in); if ( LOCALE_DECIMAL_POINTS.findFirst(*in) >= 0 ) { const char* afterDecimal = ++in; const f32 decimal = strtof10(in, &afterDecimal); value += decimal * fast_atof_table[afterDecimal - in]; in = afterDecimal; } if ('e' == *in || 'E' == *in) { ++in; // Assume that the exponent is a whole number. // strtol10() will deal with both + and - signs, // but calculate as f32 to prevent overflow at FLT_MAX value *= powf(10.f, (f32)strtol10(in, &in)); } result = negative?-value:value; return in; } //! Convert a string to a floating point number /** \param floatAsString The string to convert. \param out Optional pointer to the first character in the string that wasn't used to create the float value. \result Float value parsed from the input string */ inline float fast_atof(const char* floatAsString, const char** out=0) { float ret; if (out) *out=fast_atof_move(floatAsString, ret); else fast_atof_move(floatAsString, ret); return ret; } } // end namespace core } // end namespace irr #endif