| 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 // we write [17] here instead of [] to work around a swig bug
    00021 const float fast_atof_table[17] = {
    00022     0.f,
    00023     0.1f,
    00024     0.01f,
    00025     0.001f,
    00026     0.0001f,
    00027     0.00001f,
    00028     0.000001f,
    00029     0.0000001f,
    00030     0.00000001f,
    00031     0.000000001f,
    00032     0.0000000001f,
    00033     0.00000000001f,
    00034     0.000000000001f,
    00035     0.0000000000001f,
    00036     0.00000000000001f,
    00037     0.000000000000001f,
    00038     0.0000000000000001f
    00039 };
    00040
    00042
    00049 inline u32 strtoul10(const char* in, const char** out=0)
    00050 {
    00051     if (!in)
    00052     {
    00053         if (out)
    00054             *out = in;
    00055         return 0;
    00056     }
    00057
    00058     bool overflow=false;
    00059     u32 unsignedValue = 0;
    00060     while ( ( *in >= '0') && ( *in <= '9' ))
    00061     {
    00062         const u32 tmp = ( unsignedValue * 10 ) + ( *in - '0' );
    00063         if (tmp<unsignedValue)
    00064         {
    00065             unsignedValue=(u32)0xffffffff;
    00066             overflow=true;
    00067         }
    00068         if (!overflow)
    00069             unsignedValue = tmp;
    00070         ++in;
    00071     }
    00072
    00073     if (out)
    00074         *out = in;
    00075
    00076     return unsignedValue;
    00077 }
    00078
    00080
    00089 inline s32 strtol10(const char* in, const char** out=0)
    00090 {
    00091     if (!in)
    00092     {
    00093         if (out)
    00094             *out = in;
    00095         return 0;
    00096     }
    00097
    00098     const bool negative = ('-' == *in);
    00099     if (negative || ('+' == *in))
    00100         ++in;
    00101
    00102     const u32 unsignedValue = strtoul10(in,out);
    00103     if (unsignedValue > (u32)INT_MAX)
    00104     {
    00105         if (negative)
    00106             return (s32)INT_MIN;
    00107         else
    00108             return (s32)INT_MAX;
    00109     }
    00110     else
    00111     {
    00112         if (negative)
    00113             return -((s32)unsignedValue);
    00114         else
    00115             return (s32)unsignedValue;
    00116     }
    00117 }
    00118
    00120
    00125 inline u32 ctoul16(char in)
    00126 {
    00127     if (in >= '0' && in <= '9')
    00128         return in - '0';
    00129     else if (in >= 'a' && in <= 'f')
    00130         return 10u + in - 'a';
    00131     else if (in >= 'A' && in <= 'F')
    00132         return 10u + in - 'A';
    00133     else
    00134         return 0xffffffff;
    00135 }
    00136
    00138
    00146 inline u32 strtoul16(const char* in, const char** out=0)
    00147 {
    00148     if (!in)
    00149     {
    00150         if (out)
    00151             *out = in;
    00152         return 0;
    00153     }
    00154
    00155     bool overflow=false;
    00156     u32 unsignedValue = 0;
    00157     while (true)
    00158     {
    00159         u32 tmp = 0;
    00160         if ((*in >= '0') && (*in <= '9'))
    00161             tmp = (unsignedValue << 4u) + (*in - '0');
    00162         else if ((*in >= 'A') && (*in <= 'F'))
    00163             tmp = (unsignedValue << 4u) + (*in - 'A') + 10;
    00164         else if ((*in >= 'a') && (*in <= 'f'))
    00165             tmp = (unsignedValue << 4u) + (*in - 'a') + 10;
    00166         else
    00167             break;
    00168         if (tmp<unsignedValue)
    00169         {
    00170             unsignedValue=(u32)INT_MAX;
    00171             overflow=true;
    00172         }
    00173         if (!overflow)
    00174             unsignedValue = tmp;
    00175         ++in;
    00176     }
    00177
    00178     if (out)
    00179         *out = in;
    00180
    00181     return unsignedValue;
    00182 }
    00183
    00185
    00193 inline u32 strtoul8(const char* in, const char** out=0)
    00194 {
    00195     if (!in)
    00196     {
    00197         if (out)
    00198             *out = in;
    00199         return 0;
    00200     }
    00201
    00202     bool overflow=false;
    00203     u32 unsignedValue = 0;
    00204     while (true)
    00205     {
    00206         u32 tmp = 0;
    00207         if ((*in >= '0') && (*in <= '7'))
    00208             tmp = (unsignedValue << 3u) + (*in - '0');
    00209         else
    00210             break;
    00211         if (tmp<unsignedValue)
    00212         {
    00213             unsignedValue=(u32)INT_MAX;
    00214             overflow=true;
    00215         }
    00216         if (!overflow)
    00217             unsignedValue = tmp;
    00218         ++in;
    00219     }
    00220
    00221     if (out)
    00222         *out = in;
    00223
    00224     return unsignedValue;
    00225 }
    00226
    00228
    00236 inline u32 strtoul_prefix(const char* in, const char** out=0)
    00237 {
    00238     if (!in)
    00239     {
    00240         if (out)
    00241             *out = in;
    00242         return 0;
    00243     }
    00244     if ('0'==in[0])
    00245         return ('x'==in[1] ? strtoul16(in+2,out) : strtoul8(in+1,out));
    00246     return strtoul10(in,out);
    00247 }
    00248
    00250
    00258 inline f32 strtof10(const char* in, const char** out = 0)
    00259 {
    00260     if (!in)
    00261     {
    00262         if (out)
    00263             *out = in;
    00264         return 0.f;
    00265     }
    00266
    00267     const u32 MAX_SAFE_U32_VALUE = UINT_MAX / 10 - 10;
    00268     u32 intValue = 0;
    00269
    00270     // Use integer arithmetic for as long as possible, for speed
    00271     // and precision.
    00272     while ( ( *in >= '0') && ( *in <= '9' ) )
    00273     {
    00274         // If it looks like we're going to overflow, bail out
    00275         // now and start using floating point.
    00276         if (intValue >= MAX_SAFE_U32_VALUE)
    00277             break;
    00278
    00279         intValue = (intValue * 10) + (*in - '0');
    00280         ++in;
    00281     }
    00282
    00283     f32 floatValue = (f32)intValue;
    00284
    00285     // If there are any digits left to parse, then we need to use
    00286     // floating point arithmetic from here.
    00287     while ( ( *in >= '0') && ( *in <= '9' ) )
    00288     {
    00289         floatValue = (floatValue * 10.f) + (f32)(*in - '0');
    00290         ++in;
    00291         if (floatValue > FLT_MAX) // Just give up.
    00292             break;
    00293     }
    00294
    00295     if (out)
    00296         *out = in;
    00297
    00298     return floatValue;
    00299 }
    00300
    00302
    00309 inline const char* fast_atof_move(const char* in, f32& result)
    00310 {
    00311     // Please run the regression test when making any modifications to this function.
    00312
    00313     result = 0.f;
    00314     if (!in)
    00315         return 0;
    00316
    00317     const bool negative = ('-' == *in);
    00318     if (negative || ('+'==*in))
    00319         ++in;
    00320
    00321     f32 value = strtof10(in, &in);
    00322
    00323     if ( LOCALE_DECIMAL_POINTS.findFirst(*in) >= 0 )
    00324     {
    00325         const char* afterDecimal = ++in;
    00326         const f32 decimal = strtof10(in, &afterDecimal);
    00327         value += decimal * fast_atof_table[afterDecimal - in];
    00328         in = afterDecimal;
    00329     }
    00330
    00331     if ('e' == *in || 'E' == *in)
    00332     {
    00333         ++in;
    00334         // Assume that the exponent is a whole number.
    00335         // strtol10() will deal with both + and - signs,
    00336         // but calculate as f32 to prevent overflow at FLT_MAX
    00337         value *= powf(10.f, (f32)strtol10(in, &in));
    00338     }
    00339
    00340     result = negative?-value:value;
    00341     return in;
    00342 }
    00343
    00345
    00350 inline float fast_atof(const char* floatAsString, const char** out=0)
    00351 {
    00352     float ret;
    00353     if (out)
    00354         *out=fast_atof_move(floatAsString, ret);
    00355     else
    00356         fast_atof_move(floatAsString, ret);
    00357     return ret;
    00358 }
    00359
    00360 } // end namespace core
    00361 } // end namespace irr
    00362
    00363 #endif
    00364