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