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