| Irrlicht 3D Engine |

fast_atof.h
Go to the documentation of this file.

    00001 // Copyright (C) 2002-2012 Nikolaus Gebhardt
    00002 // This file is part of the "Irrlicht Engine" and the "irrXML" project.
    00003 // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
    00004
    00005 #ifndef __FAST_ATOF_H_INCLUDED__
    00006 #define __FAST_ATOF_H_INCLUDED__
    00007
    00008 #include "irrMath.h"
    00009 #include "irrString.h"
    00010
    00011 namespace irr
    00012 {
    00013 namespace core
    00014 {
    00016     // TODO: This should probably also be used in irr::core::string, but the float-to-string code
    00017     //      used there has to be rewritten first.
    00018     IRRLICHT_API extern irr::core::stringc LOCALE_DECIMAL_POINTS;
    00019
    00020 #define IRR_ATOF_TABLE_SIZE 17
    00021 // we write [IRR_ATOF_TABLE_SIZE] here instead of [] to work around a swig bug
    00022 const float fast_atof_table[17] = {
    00023     0.f,
    00024     0.1f,
    00025     0.01f,
    00026     0.001f,
    00027     0.0001f,
    00028     0.00001f,
    00029     0.000001f,
    00030     0.0000001f,
    00031     0.00000001f,
    00032     0.000000001f,
    00033     0.0000000001f,
    00034     0.00000000001f,
    00035     0.000000000001f,
    00036     0.0000000000001f,
    00037     0.00000000000001f,
    00038     0.000000000000001f,
    00039     0.0000000000000001f
    00040 };
    00041
    00043
    00050 inline u32 strtoul10(const char* in, const char** out=0)
    00051 {
    00052     if (!in)
    00053     {
    00054         if (out)
    00055             *out = in;
    00056         return 0;
    00057     }
    00058
    00059     bool overflow=false;
    00060     u32 unsignedValue = 0;
    00061     while ( ( *in >= '0') && ( *in <= '9' ))
    00062     {
    00063         const u32 tmp = ( unsignedValue * 10 ) + ( *in - '0' );
    00064         if (tmp<unsignedValue)
    00065         {
    00066             unsignedValue=(u32)0xffffffff;
    00067             overflow=true;
    00068         }
    00069         if (!overflow)
    00070             unsignedValue = tmp;
    00071         ++in;
    00072     }
    00073
    00074     if (out)
    00075         *out = in;
    00076
    00077     return unsignedValue;
    00078 }
    00079
    00081
    00090 inline s32 strtol10(const char* in, const char** out=0)
    00091 {
    00092     if (!in)
    00093     {
    00094         if (out)
    00095             *out = in;
    00096         return 0;
    00097     }
    00098
    00099     const bool negative = ('-' == *in);
    00100     if (negative || ('+' == *in))
    00101         ++in;
    00102
    00103     const u32 unsignedValue = strtoul10(in,out);
    00104     if (unsignedValue > (u32)INT_MAX)
    00105     {
    00106         if (negative)
    00107             return (s32)INT_MIN;
    00108         else
    00109             return (s32)INT_MAX;
    00110     }
    00111     else
    00112     {
    00113         if (negative)
    00114             return -((s32)unsignedValue);
    00115         else
    00116             return (s32)unsignedValue;
    00117     }
    00118 }
    00119
    00121
    00126 inline u32 ctoul16(char in)
    00127 {
    00128     if (in >= '0' && in <= '9')
    00129         return in - '0';
    00130     else if (in >= 'a' && in <= 'f')
    00131         return 10u + in - 'a';
    00132     else if (in >= 'A' && in <= 'F')
    00133         return 10u + in - 'A';
    00134     else
    00135         return 0xffffffff;
    00136 }
    00137
    00139
    00147 inline u32 strtoul16(const char* in, const char** out=0)
    00148 {
    00149     if (!in)
    00150     {
    00151         if (out)
    00152             *out = in;
    00153         return 0;
    00154     }
    00155
    00156     bool overflow=false;
    00157     u32 unsignedValue = 0;
    00158     while (true)
    00159     {
    00160         u32 tmp = 0;
    00161         if ((*in >= '0') && (*in <= '9'))
    00162             tmp = (unsignedValue << 4u) + (*in - '0');
    00163         else if ((*in >= 'A') && (*in <= 'F'))
    00164             tmp = (unsignedValue << 4u) + (*in - 'A') + 10;
    00165         else if ((*in >= 'a') && (*in <= 'f'))
    00166             tmp = (unsignedValue << 4u) + (*in - 'a') + 10;
    00167         else
    00168             break;
    00169         if (tmp<unsignedValue)
    00170         {
    00171             unsignedValue=(u32)INT_MAX;
    00172             overflow=true;
    00173         }
    00174         if (!overflow)
    00175             unsignedValue = tmp;
    00176         ++in;
    00177     }
    00178
    00179     if (out)
    00180         *out = in;
    00181
    00182     return unsignedValue;
    00183 }
    00184
    00186
    00194 inline u32 strtoul8(const char* in, const char** out=0)
    00195 {
    00196     if (!in)
    00197     {
    00198         if (out)
    00199             *out = in;
    00200         return 0;
    00201     }
    00202
    00203     bool overflow=false;
    00204     u32 unsignedValue = 0;
    00205     while (true)
    00206     {
    00207         u32 tmp = 0;
    00208         if ((*in >= '0') && (*in <= '7'))
    00209             tmp = (unsignedValue << 3u) + (*in - '0');
    00210         else
    00211             break;
    00212         if (tmp<unsignedValue)
    00213         {
    00214             unsignedValue=(u32)INT_MAX;
    00215             overflow=true;
    00216         }
    00217         if (!overflow)
    00218             unsignedValue = tmp;
    00219         ++in;
    00220     }
    00221
    00222     if (out)
    00223         *out = in;
    00224
    00225     return unsignedValue;
    00226 }
    00227
    00229
    00237 inline u32 strtoul_prefix(const char* in, const char** out=0)
    00238 {
    00239     if (!in)
    00240     {
    00241         if (out)
    00242             *out = in;
    00243         return 0;
    00244     }
    00245     if ('0'==in[0])
    00246         return ('x'==in[1] ? strtoul16(in+2,out) : strtoul8(in+1,out));
    00247     return strtoul10(in,out);
    00248 }
    00249
    00251
    00259 inline f32 strtof10(const char* in, const char** out = 0)
    00260 {
    00261     if (!in)
    00262     {
    00263         if (out)
    00264             *out = in;
    00265         return 0.f;
    00266     }
    00267
    00268     const u32 MAX_SAFE_U32_VALUE = UINT_MAX / 10 - 10;
    00269     u32 intValue = 0;
    00270
    00271     // Use integer arithmetic for as long as possible, for speed
    00272     // and precision.
    00273     while ( ( *in >= '0') && ( *in <= '9' ) )
    00274     {
    00275         // If it looks like we're going to overflow, bail out
    00276         // now and start using floating point.
    00277         if (intValue >= MAX_SAFE_U32_VALUE)
    00278             break;
    00279
    00280         intValue = (intValue * 10) + (*in - '0');
    00281         ++in;
    00282     }
    00283
    00284     f32 floatValue = (f32)intValue;
    00285
    00286     // If there are any digits left to parse, then we need to use
    00287     // floating point arithmetic from here.
    00288     while ( ( *in >= '0') && ( *in <= '9' ) )
    00289     {
    00290         floatValue = (floatValue * 10.f) + (f32)(*in - '0');
    00291         ++in;
    00292         if (floatValue > FLT_MAX) // Just give up.
    00293             break;
    00294     }
    00295
    00296     if (out)
    00297         *out = in;
    00298
    00299     return floatValue;
    00300 }
    00301
    00303
    00310 inline const char* fast_atof_move(const char* in, f32& result)
    00311 {
    00312     // Please run the regression test when making any modifications to this function.
    00313
    00314     result = 0.f;
    00315     if (!in)
    00316         return 0;
    00317
    00318     const bool negative = ('-' == *in);
    00319     if (negative || ('+'==*in))
    00320         ++in;
    00321
    00322     f32 value = strtof10(in, &in);
    00323
    00324     if ( LOCALE_DECIMAL_POINTS.findFirst(*in) >= 0 )
    00325     {
    00326         const char* afterDecimal = ++in;
    00327         f32 decimal = strtof10(in, &afterDecimal);
    00328         size_t numDecimals = afterDecimal - in;
    00329         if (numDecimals < IRR_ATOF_TABLE_SIZE)
    00330         {
    00331             value += decimal * fast_atof_table[numDecimals];
    00332         }
    00333         else
    00334         {
    00335             value += decimal * (f32)pow(10.f, -(float)numDecimals);
    00336         }
    00337         in = afterDecimal;
    00338     }
    00339
    00340     if ('e' == *in || 'E' == *in)
    00341     {
    00342         ++in;
    00343         // Assume that the exponent is a whole number.
    00344         // strtol10() will deal with both + and - signs,
    00345         // but calculate as f32 to prevent overflow at FLT_MAX
    00346         // Using pow with float cast instead of powf as otherwise accuracy decreases.
    00347         value *= (f32)pow(10.f, (f32)strtol10(in, &in));
    00348     }
    00349
    00350     result = negative?-value:value;
    00351     return in;
    00352 }
    00353
    00355
    00360 inline float fast_atof(const char* floatAsString, const char** out=0)
    00361 {
    00362     float ret;
    00363     if (out)
    00364         *out=fast_atof_move(floatAsString, ret);
    00365     else
    00366         fast_atof_move(floatAsString, ret);
    00367     return ret;
    00368 }
    00369
    00370 } // end namespace core
    00371 } // end namespace irr
    00372
    00373 #endif
    00374