1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
\r
2 // This file is part of the "Irrlicht Engine" and the "irrXML" project.
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
\r
5 #ifndef __FAST_ATOF_H_INCLUDED__
\r
6 #define __FAST_ATOF_H_INCLUDED__
\r
9 #include "irrString.h"
\r
15 //! Selection of characters which count as decimal point in fast_atof
\r
16 // TODO: This should probably also be used in irr::core::string, but
\r
17 // the float-to-string code used there has to be rewritten first.
\r
18 IRRLICHT_API extern irr::core::stringc LOCALE_DECIMAL_POINTS;
\r
20 #define IRR_ATOF_TABLE_SIZE 17
\r
21 // we write [IRR_ATOF_TABLE_SIZE] here instead of [] to work around a swig bug
\r
22 const float fast_atof_table[17] = {
\r
42 //! Convert a simple string of base 10 digits into an unsigned 32 bit integer.
\r
43 /** \param[in] in: The string of digits to convert. No leading chars are
\r
44 allowed, only digits 0 to 9. Parsing stops at the first non-digit.
\r
45 \param[out] out: (optional) If provided, it will be set to point at the
\r
46 first character not used in the calculation.
\r
47 \return The unsigned integer value of the digits. If the string specifies
\r
48 too many digits to encode in an u32 then INT_MAX will be returned.
\r
50 inline u32 strtoul10(const char* in, const char** out=0)
\r
59 bool overflow=false;
\r
60 u32 unsignedValue = 0;
\r
61 while ( ( *in >= '0') && ( *in <= '9' ))
\r
63 const u32 tmp = ( unsignedValue * 10 ) + ( *in - '0' );
\r
64 if (tmp<unsignedValue)
\r
66 unsignedValue=(u32)0xffffffff;
\r
70 unsignedValue = tmp;
\r
77 return unsignedValue;
\r
80 //! Convert a simple string of base 10 digits into a signed 32 bit integer.
\r
81 /** \param[in] in: The string of digits to convert. Only a leading - or +
\r
82 followed by digits 0 to 9 will be considered. Parsing stops at the first
\r
84 \param[out] out: (optional) If provided, it will be set to point at the
\r
85 first character not used in the calculation.
\r
86 \return The signed integer value of the digits. If the string specifies
\r
87 too many digits to encode in an s32 then +INT_MAX or -INT_MAX will be
\r
90 inline s32 strtol10(const char* in, const char** out=0)
\r
99 const bool negative = ('-' == *in);
\r
100 if (negative || ('+' == *in))
\r
103 const u32 unsignedValue = strtoul10(in,out);
\r
104 if (unsignedValue > (u32)INT_MAX)
\r
107 return (s32)INT_MIN;
\r
109 return (s32)INT_MAX;
\r
114 return -((s32)unsignedValue);
\r
116 return (s32)unsignedValue;
\r
120 //! Convert a hex-encoded character to an unsigned integer.
\r
121 /** \param[in] in The digit to convert. Only digits 0 to 9 and chars A-F,a-f
\r
122 will be considered.
\r
123 \return The unsigned integer value of the digit. 0xffffffff if the input is
\r
126 inline u32 ctoul16(char in)
\r
128 if (in >= '0' && in <= '9')
\r
130 else if (in >= 'a' && in <= 'f')
\r
131 return 10u + in - 'a';
\r
132 else if (in >= 'A' && in <= 'F')
\r
133 return 10u + in - 'A';
\r
138 //! Convert a simple string of base 16 digits into an unsigned 32 bit integer.
\r
139 /** \param[in] in: The string of digits to convert. No leading chars are
\r
140 allowed, only digits 0 to 9 and chars A-F,a-f are allowed. Parsing stops
\r
141 at the first illegal char.
\r
142 \param[out] out: (optional) If provided, it will be set to point at the
\r
143 first character not used in the calculation.
\r
144 \return The unsigned integer value of the digits. If the string specifies
\r
145 too many digits to encode in an u32 then INT_MAX will be returned.
\r
147 inline u32 strtoul16(const char* in, const char** out=0)
\r
156 bool overflow=false;
\r
157 u32 unsignedValue = 0;
\r
161 if ((*in >= '0') && (*in <= '9'))
\r
162 tmp = (unsignedValue << 4u) + (*in - '0');
\r
163 else if ((*in >= 'A') && (*in <= 'F'))
\r
164 tmp = (unsignedValue << 4u) + (*in - 'A') + 10;
\r
165 else if ((*in >= 'a') && (*in <= 'f'))
\r
166 tmp = (unsignedValue << 4u) + (*in - 'a') + 10;
\r
169 if (tmp<unsignedValue)
\r
171 unsignedValue=(u32)INT_MAX;
\r
175 unsignedValue = tmp;
\r
182 return unsignedValue;
\r
185 //! Convert a simple string of base 8 digits into an unsigned 32 bit integer.
\r
186 /** \param[in] in The string of digits to convert. No leading chars are
\r
187 allowed, only digits 0 to 7 are allowed. Parsing stops at the first illegal
\r
189 \param[out] out (optional) If provided, it will be set to point at the
\r
190 first character not used in the calculation.
\r
191 \return The unsigned integer value of the digits. If the string specifies
\r
192 too many digits to encode in an u32 then INT_MAX will be returned.
\r
194 inline u32 strtoul8(const char* in, const char** out=0)
\r
203 bool overflow=false;
\r
204 u32 unsignedValue = 0;
\r
208 if ((*in >= '0') && (*in <= '7'))
\r
209 tmp = (unsignedValue << 3u) + (*in - '0');
\r
212 if (tmp<unsignedValue)
\r
214 unsignedValue=(u32)INT_MAX;
\r
218 unsignedValue = tmp;
\r
225 return unsignedValue;
\r
228 //! Convert a C-style prefixed string (hex, oct, integer) into an unsigned 32 bit integer.
\r
229 /** \param[in] in The string of digits to convert. If string starts with 0x the
\r
230 hex parser is used, if only leading 0 is used, oct parser is used. In all
\r
231 other cases, the usual unsigned parser is used.
\r
232 \param[out] out (optional) If provided, it will be set to point at the
\r
233 first character not used in the calculation.
\r
234 \return The unsigned integer value of the digits. If the string specifies
\r
235 too many digits to encode in an u32 then INT_MAX will be returned.
\r
237 inline u32 strtoul_prefix(const char* in, const char** out=0)
\r
246 return ('x'==in[1] ? strtoul16(in+2,out) : strtoul8(in+1,out));
\r
247 return strtoul10(in,out);
\r
250 //! Converts a sequence of digits into a whole positive floating point value.
\r
251 /** Only digits 0 to 9 are parsed. Parsing stops at any other character,
\r
252 including sign characters or a decimal point.
\r
253 \param in: the sequence of digits to convert.
\r
254 \param out: (optional) will be set to point at the first non-converted
\r
256 \return The whole positive floating point representation of the digit
\r
259 inline f32 strtof10(const char* in, const char** out = 0)
\r
268 const u32 MAX_SAFE_U32_VALUE = UINT_MAX / 10 - 10;
\r
271 // Use integer arithmetic for as long as possible, for speed
\r
273 while ( ( *in >= '0') && ( *in <= '9' ) )
\r
275 // If it looks like we're going to overflow, bail out
\r
276 // now and start using floating point.
\r
277 if (intValue >= MAX_SAFE_U32_VALUE)
\r
280 intValue = (intValue * 10) + (*in - '0');
\r
284 f32 floatValue = (f32)intValue;
\r
286 // If there are any digits left to parse, then we need to use
\r
287 // floating point arithmetic from here.
\r
288 while ( ( *in >= '0') && ( *in <= '9' ) )
\r
290 floatValue = (floatValue * 10.f) + (f32)(*in - '0');
\r
292 if (floatValue > FLT_MAX) // Just give up.
\r
302 //! Provides a fast function for converting a string into a float.
\r
303 /** This is not guaranteed to be as accurate as atof(), but is
\r
304 approximately 6 to 8 times as fast.
\r
305 \param[in] in The string to convert.
\r
306 \param[out] result The resultant float will be written here.
\r
307 \return Pointer to the first character in the string that wasn't used
\r
308 to create the float value.
\r
310 inline const char* fast_atof_move(const char* in, f32& result)
\r
312 // Please run the regression test when making any modifications to this function.
\r
318 const bool negative = ('-' == *in);
\r
319 if (negative || ('+'==*in))
\r
322 f32 value = strtof10(in, &in);
\r
324 if ( LOCALE_DECIMAL_POINTS.findFirst(*in) >= 0 )
\r
326 const char* afterDecimal = ++in;
\r
327 const f32 decimal = strtof10(in, &afterDecimal);
\r
328 const size_t numDecimals = afterDecimal - in;
\r
329 if (numDecimals < IRR_ATOF_TABLE_SIZE)
\r
331 value += decimal * fast_atof_table[numDecimals];
\r
335 value += decimal * (f32)pow(10.f, -(float)numDecimals);
\r
340 if ('e' == *in || 'E' == *in)
\r
343 // Assume that the exponent is a whole number.
\r
344 // strtol10() will deal with both + and - signs,
\r
345 // but calculate as f32 to prevent overflow at FLT_MAX
\r
346 // Using pow with float cast instead of powf as otherwise accuracy decreases.
\r
347 value *= (f32)pow(10.f, (f32)strtol10(in, &in));
\r
350 result = negative?-value:value;
\r
354 //! Convert a string to a floating point number
\r
355 /** \param floatAsString The string to convert.
\r
356 \param out Optional pointer to the first character in the string that
\r
357 wasn't used to create the float value.
\r
358 \result Float value parsed from the input string
\r
360 inline float fast_atof(const char* floatAsString, const char** out=0)
\r
364 *out=fast_atof_move(floatAsString, ret);
\r
366 fast_atof_move(floatAsString, ret);
\r
370 } // end namespace core
\r
371 } // end namespace irr
\r