IrrlichtEngine
fast_atof.h
Go to the documentation of this file.
00001 // Copyright (C) 2002-2011 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 
00010 namespace irr
00011 {
00012 namespace core
00013 {
00014 
00015 // we write [17] here instead of [] to work around a swig bug
00016 const float fast_atof_table[17] = {
00017         0.f,
00018         0.1f,
00019         0.01f,
00020         0.001f,
00021         0.0001f,
00022         0.00001f,
00023         0.000001f,
00024         0.0000001f,
00025         0.00000001f,
00026         0.000000001f,
00027         0.0000000001f,
00028         0.00000000001f,
00029         0.000000000001f,
00030         0.0000000000001f,
00031         0.00000000000001f,
00032         0.000000000000001f,
00033         0.0000000000000001f
00034 };
00035 
00037 
00044 inline u32 strtoul10(const char* in, const char** out=0)
00045 {
00046         if (!in)
00047         {
00048                 if (out)
00049                         *out = in;
00050                 return 0;
00051         }
00052 
00053         bool overflow=false;
00054         u32 unsignedValue = 0;
00055         while ( ( *in >= '0') && ( *in <= '9' ))
00056         {
00057                 const u32 tmp = ( unsignedValue * 10 ) + ( *in - '0' );
00058                 if (tmp<unsignedValue)
00059                 {
00060                         unsignedValue=(u32)0xffffffff;
00061                         overflow=true;
00062                 }
00063                 if (!overflow)
00064                         unsignedValue = tmp;
00065                 ++in;
00066         }
00067 
00068         if (out)
00069                 *out = in;
00070 
00071         return unsignedValue;
00072 }
00073 
00075 
00084 inline s32 strtol10(const char* in, const char** out=0)
00085 {
00086         if (!in)
00087         {
00088                 if (out)
00089                         *out = in;
00090                 return 0;
00091         }
00092 
00093         const bool negative = ('-' == *in);
00094         if (negative || ('+' == *in))
00095                 ++in;
00096 
00097         const u32 unsignedValue = strtoul10(in,out);
00098         if (unsignedValue > (u32)INT_MAX)
00099         {
00100                 if (negative)
00101                         return (s32)INT_MIN;
00102                 else
00103                         return (s32)INT_MAX;
00104         }
00105         else
00106         {
00107                 if (negative)
00108                         return -((s32)unsignedValue);
00109                 else
00110                         return (s32)unsignedValue;
00111         }
00112 }
00113 
00115 
00120 inline u32 ctoul16(char in)
00121 {
00122         if (in >= '0' && in <= '9')
00123                 return in - '0';
00124         else if (in >= 'a' && in <= 'f')
00125                 return 10u + in - 'a';
00126         else if (in >= 'A' && in <= 'F')
00127                 return 10u + in - 'A';
00128         else
00129                 return 0xffffffff;
00130 }
00131 
00133 
00141 inline u32 strtoul16(const char* in, const char** out=0)
00142 {
00143         if (!in)
00144         {
00145                 if (out)
00146                         *out = in;
00147                 return 0;
00148         }
00149 
00150         bool overflow=false;
00151         u32 unsignedValue = 0;
00152         while (true)
00153         {
00154                 u32 tmp = 0;
00155                 if ((*in >= '0') && (*in <= '9'))
00156                         tmp = (unsignedValue << 4u) + (*in - '0');
00157                 else if ((*in >= 'A') && (*in <= 'F'))
00158                         tmp = (unsignedValue << 4u) + (*in - 'A') + 10;
00159                 else if ((*in >= 'a') && (*in <= 'f'))
00160                         tmp = (unsignedValue << 4u) + (*in - 'a') + 10;
00161                 else
00162                         break;
00163                 if (tmp<unsignedValue)
00164                 {
00165                         unsignedValue=(u32)INT_MAX;
00166                         overflow=true;
00167                 }
00168                 if (!overflow)
00169                         unsignedValue = tmp;
00170                 ++in;
00171         }
00172 
00173         if (out)
00174                 *out = in;
00175 
00176         return unsignedValue;
00177 }
00178 
00180 
00188 inline u32 strtoul8(const char* in, const char** out=0)
00189 {
00190         if (!in)
00191         {
00192                 if (out)
00193                         *out = in;
00194                 return 0;
00195         }
00196 
00197         bool overflow=false;
00198         u32 unsignedValue = 0;
00199         while (true)
00200         {
00201                 u32 tmp = 0;
00202                 if ((*in >= '0') && (*in <= '7'))
00203                         tmp = (unsignedValue << 3u) + (*in - '0');
00204                 else
00205                         break;
00206                 if (tmp<unsignedValue)
00207                 {
00208                         unsignedValue=(u32)INT_MAX;
00209                         overflow=true;
00210                 }
00211                 if (!overflow)
00212                         unsignedValue = tmp;
00213                 ++in;
00214         }
00215 
00216         if (out)
00217                 *out = in;
00218 
00219         return unsignedValue;
00220 }
00221 
00223 
00231 inline u32 strtoul_prefix(const char* in, const char** out=0)
00232 {
00233         if (!in)
00234         {
00235                 if (out)
00236                         *out = in;
00237                 return 0;
00238         }
00239         if ('0'==in[0])
00240                 return ('x'==in[1] ? strtoul16(in+2,out) : strtoul8(in+1,out));
00241         return strtoul10(in,out);
00242 }
00243 
00245 
00253 inline f32 strtof10(const char* in, const char** out = 0)
00254 {
00255         if (!in)
00256         {
00257                 if (out)
00258                         *out = in;
00259                 return 0.f;
00260         }
00261 
00262         const u32 MAX_SAFE_U32_VALUE = UINT_MAX / 10 - 10;
00263         u32 intValue = 0;
00264 
00265         // Use integer arithmetic for as long as possible, for speed
00266         // and precision.
00267         while ( ( *in >= '0') && ( *in <= '9' ) )
00268         {
00269                 // If it looks like we're going to overflow, bail out
00270                 // now and start using floating point.
00271                 if (intValue >= MAX_SAFE_U32_VALUE)
00272                         break;
00273 
00274                 intValue = (intValue * 10) + (*in - '0');
00275                 ++in;
00276         }
00277 
00278         f32 floatValue = (f32)intValue;
00279 
00280         // If there are any digits left to parse, then we need to use
00281         // floating point arithmetic from here.
00282         while ( ( *in >= '0') && ( *in <= '9' ) )
00283         {
00284                 floatValue = (floatValue * 10.f) + (f32)(*in - '0');
00285                 ++in;
00286                 if (floatValue > FLT_MAX) // Just give up.
00287                         break;
00288         }
00289 
00290         if (out)
00291                 *out = in;
00292 
00293         return floatValue;
00294 }
00295 
00297 
00304 inline const char* fast_atof_move(const char* in, f32& result)
00305 {
00306         // Please run this regression test when making any modifications to this function:
00307         // https://sourceforge.net/tracker/download.php?group_id=74339&atid=540676&file_id=298968&aid=1865300
00308 
00309         result = 0.f;
00310         if (!in)
00311                 return 0;
00312 
00313         const bool negative = ('-' == *in);
00314         if (negative || ('+'==*in))
00315                 ++in;
00316 
00317         f32 value = strtof10(in, &in);
00318 
00319         if ('.' == *in)
00320         {
00321                 const char* afterDecimal = ++in;
00322                 const f32 decimal = strtof10(in, &afterDecimal);
00323                 value += decimal * fast_atof_table[afterDecimal - in];
00324                 in = afterDecimal;
00325         }
00326 
00327         if ('e' == *in || 'E' == *in)
00328         {
00329                 ++in;
00330                 // Assume that the exponent is a whole number.
00331                 // strtol10() will deal with both + and - signs,
00332                 // but calculate as f32 to prevent overflow at FLT_MAX
00333                 value *= powf(10.f, (f32)strtol10(in, &in));
00334         }
00335 
00336         result = negative?-value:value;
00337         return in;
00338 }
00339 
00341 
00346 inline float fast_atof(const char* floatAsString, const char** out=0)
00347 {
00348         float ret;
00349         if (out)
00350                 *out=fast_atof_move(floatAsString, ret);
00351         else
00352                 fast_atof_move(floatAsString, ret);
00353         return ret;
00354 }
00355 
00356 } // end namespace core
00357 } // end namespace irr
00358 
00359 #endif
00360