]> git.lizzy.rs Git - irrlicht.git/blob - include/fast_atof.h
Merging r6196 through r6248 from trunk to ogl-es branch
[irrlicht.git] / include / fast_atof.h
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
4 \r
5 #ifndef __FAST_ATOF_H_INCLUDED__\r
6 #define __FAST_ATOF_H_INCLUDED__\r
7 \r
8 #include "irrMath.h"\r
9 #include "irrString.h"\r
10 \r
11 namespace irr\r
12 {\r
13 namespace core\r
14 {\r
15         //! Selection of characters which count as decimal point in fast_atof\r
16         //! By default Irrlicht considers "." as the decimal point in numbers.\r
17         //! But sometimes you might run into situations where floats were written in \r
18         //! a local format with another decimal point like ",".\r
19         //! Best solution is usually to fix those cases by converting the input.\r
20         //! But if you don't have that choice you can set this to ".,".\r
21         //! WARNING: This is not thread-safe, so don't change while there's a chance \r
22         //! of another thread using fast_atof functions at the same time.\r
23         // TODO: This should probably also be used in irr::core::string, but\r
24         // the float-to-string code used there has to be rewritten first.\r
25         IRRLICHT_API extern irr::core::stringc LOCALE_DECIMAL_POINTS;\r
26 \r
27 #define IRR_ATOF_TABLE_SIZE 17\r
28 // we write [IRR_ATOF_TABLE_SIZE] here instead of [] to work around a swig bug\r
29 const float fast_atof_table[17] = {\r
30         0.f,\r
31         0.1f,\r
32         0.01f,\r
33         0.001f,\r
34         0.0001f,\r
35         0.00001f,\r
36         0.000001f,\r
37         0.0000001f,\r
38         0.00000001f,\r
39         0.000000001f,\r
40         0.0000000001f,\r
41         0.00000000001f,\r
42         0.000000000001f,\r
43         0.0000000000001f,\r
44         0.00000000000001f,\r
45         0.000000000000001f,\r
46         0.0000000000000001f\r
47 };\r
48 \r
49 //! Convert a simple string of base 10 digits into an unsigned 32 bit integer.\r
50 /** \param[in] in: The string of digits to convert. No leading chars are\r
51     allowed, only digits 0 to 9. Parsing stops at the first non-digit.\r
52     \param[out] out: (optional) If provided, it will be set to point at the\r
53     first character not used in the calculation.\r
54     \return The unsigned integer value of the digits. If the string specifies\r
55     too many digits to encode in an u32 then INT_MAX will be returned.\r
56 */\r
57 inline u32 strtoul10(const char* in, const char** out=0)\r
58 {\r
59         if (!in)\r
60         {\r
61                 if (out)\r
62                         *out = in;\r
63                 return 0;\r
64         }\r
65 \r
66         bool overflow=false;\r
67         u32 unsignedValue = 0;\r
68         while ( ( *in >= '0') && ( *in <= '9' ))\r
69         {\r
70                 const u32 tmp = ( unsignedValue * 10 ) + ( *in - '0' );\r
71                 if (tmp<unsignedValue)\r
72                 {\r
73                         unsignedValue=(u32)0xffffffff;\r
74                         overflow=true;\r
75                 }\r
76                 if (!overflow)\r
77                         unsignedValue = tmp;\r
78                 ++in;\r
79         }\r
80 \r
81         if (out)\r
82                 *out = in;\r
83 \r
84         return unsignedValue;\r
85 }\r
86 \r
87 //! Convert a simple string of base 10 digits into a signed 32 bit integer.\r
88 /** \param[in] in: The string of digits to convert. Only a leading - or +\r
89     followed by digits 0 to 9 will be considered. Parsing stops at the first\r
90     non-digit.\r
91     \param[out] out: (optional) If provided, it will be set to point at the\r
92     first character not used in the calculation.\r
93     \return The signed integer value of the digits. If the string specifies\r
94     too many digits to encode in an s32 then +INT_MAX or -INT_MAX will be\r
95     returned.\r
96 */\r
97 inline s32 strtol10(const char* in, const char** out=0)\r
98 {\r
99         if (!in)\r
100         {\r
101                 if (out)\r
102                         *out = in;\r
103                 return 0;\r
104         }\r
105 \r
106         const bool negative = ('-' == *in);\r
107         if (negative || ('+' == *in))\r
108                 ++in;\r
109 \r
110         const u32 unsignedValue = strtoul10(in,out);\r
111         if (unsignedValue > (u32)INT_MAX)\r
112         {\r
113                 if (negative)\r
114                         return (s32)INT_MIN;\r
115                 else\r
116                         return (s32)INT_MAX;\r
117         }\r
118         else\r
119         {\r
120                 if (negative)\r
121                         return -((s32)unsignedValue);\r
122                 else\r
123                         return (s32)unsignedValue;\r
124         }\r
125 }\r
126 \r
127 //! Convert a hex-encoded character to an unsigned integer.\r
128 /** \param[in] in The digit to convert. Only digits 0 to 9 and chars A-F,a-f\r
129     will be considered.\r
130     \return The unsigned integer value of the digit. 0xffffffff if the input is\r
131     not hex\r
132 */\r
133 inline u32 ctoul16(char in)\r
134 {\r
135         if (in >= '0' && in <= '9')\r
136                 return in - '0';\r
137         else if (in >= 'a' && in <= 'f')\r
138                 return 10u + in - 'a';\r
139         else if (in >= 'A' && in <= 'F')\r
140                 return 10u + in - 'A';\r
141         else\r
142                 return 0xffffffff;\r
143 }\r
144 \r
145 //! Convert a simple string of base 16 digits into an unsigned 32 bit integer.\r
146 /** \param[in] in: The string of digits to convert. No leading chars are\r
147     allowed, only digits 0 to 9 and chars A-F,a-f are allowed. Parsing stops\r
148     at the first illegal char.\r
149     \param[out] out: (optional) If provided, it will be set to point at the\r
150     first character not used in the calculation.\r
151     \return The unsigned integer value of the digits. If the string specifies\r
152     too many digits to encode in an u32 then INT_MAX will be returned.\r
153 */\r
154 inline u32 strtoul16(const char* in, const char** out=0)\r
155 {\r
156         if (!in)\r
157         {\r
158                 if (out)\r
159                         *out = in;\r
160                 return 0;\r
161         }\r
162 \r
163         bool overflow=false;\r
164         u32 unsignedValue = 0;\r
165         while (true)\r
166         {\r
167                 u32 tmp = 0;\r
168                 if ((*in >= '0') && (*in <= '9'))\r
169                         tmp = (unsignedValue << 4u) + (*in - '0');\r
170                 else if ((*in >= 'A') && (*in <= 'F'))\r
171                         tmp = (unsignedValue << 4u) + (*in - 'A') + 10;\r
172                 else if ((*in >= 'a') && (*in <= 'f'))\r
173                         tmp = (unsignedValue << 4u) + (*in - 'a') + 10;\r
174                 else\r
175                         break;\r
176                 if (tmp<unsignedValue)\r
177                 {\r
178                         unsignedValue=(u32)INT_MAX;\r
179                         overflow=true;\r
180                 }\r
181                 if (!overflow)\r
182                         unsignedValue = tmp;\r
183                 ++in;\r
184         }\r
185 \r
186         if (out)\r
187                 *out = in;\r
188 \r
189         return unsignedValue;\r
190 }\r
191 \r
192 //! Convert a simple string of base 8 digits into an unsigned 32 bit integer.\r
193 /** \param[in] in The string of digits to convert. No leading chars are\r
194     allowed, only digits 0 to 7 are allowed. Parsing stops at the first illegal\r
195     char.\r
196     \param[out] out (optional) If provided, it will be set to point at the\r
197     first character not used in the calculation.\r
198     \return The unsigned integer value of the digits. If the string specifies\r
199     too many digits to encode in an u32 then INT_MAX will be returned.\r
200 */\r
201 inline u32 strtoul8(const char* in, const char** out=0)\r
202 {\r
203         if (!in)\r
204         {\r
205                 if (out)\r
206                         *out = in;\r
207                 return 0;\r
208         }\r
209 \r
210         bool overflow=false;\r
211         u32 unsignedValue = 0;\r
212         while (true)\r
213         {\r
214                 u32 tmp = 0;\r
215                 if ((*in >= '0') && (*in <= '7'))\r
216                         tmp = (unsignedValue << 3u) + (*in - '0');\r
217                 else\r
218                         break;\r
219                 if (tmp<unsignedValue)\r
220                 {\r
221                         unsignedValue=(u32)INT_MAX;\r
222                         overflow=true;\r
223                 }\r
224                 if (!overflow)\r
225                         unsignedValue = tmp;\r
226                 ++in;\r
227         }\r
228 \r
229         if (out)\r
230                 *out = in;\r
231 \r
232         return unsignedValue;\r
233 }\r
234 \r
235 //! Convert a C-style prefixed string (hex, oct, integer) into an unsigned 32 bit integer.\r
236 /** \param[in] in The string of digits to convert. If string starts with 0x the\r
237     hex parser is used, if only leading 0 is used, oct parser is used. In all\r
238     other cases, the usual unsigned parser is used.\r
239     \param[out] out (optional) If provided, it will be set to point at the\r
240     first character not used in the calculation.\r
241     \return The unsigned integer value of the digits. If the string specifies\r
242     too many digits to encode in an u32 then INT_MAX will be returned.\r
243 */\r
244 inline u32 strtoul_prefix(const char* in, const char** out=0)\r
245 {\r
246         if (!in)\r
247         {\r
248                 if (out)\r
249                         *out = in;\r
250                 return 0;\r
251         }\r
252         if ('0'==in[0])\r
253                 return ('x'==in[1] ? strtoul16(in+2,out) : strtoul8(in+1,out));\r
254         return strtoul10(in,out);\r
255 }\r
256 \r
257 //! Converts a sequence of digits into a whole positive floating point value.\r
258 /** Only digits 0 to 9 are parsed.  Parsing stops at any other character,\r
259     including sign characters or a decimal point.\r
260     \param in: the sequence of digits to convert.\r
261     \param out: (optional) will be set to point at the first non-converted\r
262     character.\r
263     \return The whole positive floating point representation of the digit\r
264     sequence.\r
265 */\r
266 inline f32 strtof10(const char* in, const char** out = 0)\r
267 {\r
268         if (!in)\r
269         {\r
270                 if (out)\r
271                         *out = in;\r
272                 return 0.f;\r
273         }\r
274 \r
275         const u32 MAX_SAFE_U32_VALUE = UINT_MAX / 10 - 10;\r
276         u32 intValue = 0;\r
277 \r
278         // Use integer arithmetic for as long as possible, for speed\r
279         // and precision.\r
280         while ( ( *in >= '0') && ( *in <= '9' ) )\r
281         {\r
282                 // If it looks like we're going to overflow, bail out\r
283                 // now and start using floating point.\r
284                 if (intValue >= MAX_SAFE_U32_VALUE)\r
285                         break;\r
286 \r
287                 intValue = (intValue * 10) + (*in - '0');\r
288                 ++in;\r
289         }\r
290 \r
291         f32 floatValue = (f32)intValue;\r
292 \r
293         // If there are any digits left to parse, then we need to use\r
294         // floating point arithmetic from here.\r
295         while ( ( *in >= '0') && ( *in <= '9' ) )\r
296         {\r
297                 floatValue = (floatValue * 10.f) + (f32)(*in - '0');\r
298                 ++in;\r
299                 if (floatValue > FLT_MAX) // Just give up.\r
300                         break;\r
301         }\r
302 \r
303         if (out)\r
304                 *out = in;\r
305 \r
306         return floatValue;\r
307 }\r
308 \r
309 //! Provides a fast function for converting a string into a float.\r
310 /** This is not guaranteed to be as accurate as atof(), but is\r
311     approximately 6 to 8 times as fast.\r
312     \param[in] in The string to convert.\r
313     \param[out] result The resultant float will be written here.\r
314     \return Pointer to the first character in the string that wasn't used\r
315     to create the float value.\r
316 */\r
317 inline const char* fast_atof_move(const char* in, f32& result)\r
318 {\r
319         // Please run the regression test when making any modifications to this function.\r
320 \r
321         result = 0.f;\r
322         if (!in)\r
323                 return 0;\r
324 \r
325         const bool negative = ('-' == *in);\r
326         if (negative || ('+'==*in))\r
327                 ++in;\r
328 \r
329         f32 value = strtof10(in, &in);\r
330 \r
331         if ( LOCALE_DECIMAL_POINTS.findFirst(*in) >= 0 )\r
332         {\r
333                 const char* afterDecimal = ++in;\r
334                 const f32 decimal = strtof10(in, &afterDecimal);\r
335                 const size_t numDecimals = afterDecimal - in;\r
336                 if (numDecimals < IRR_ATOF_TABLE_SIZE)\r
337                 {\r
338                         value += decimal * fast_atof_table[numDecimals];\r
339                 }\r
340                 else\r
341                 {\r
342                         value += decimal * (f32)pow(10.f, -(float)numDecimals);\r
343                 }\r
344                 in = afterDecimal;\r
345         }\r
346 \r
347         if ('e' == *in || 'E' == *in)\r
348         {\r
349                 ++in;\r
350                 // Assume that the exponent is a whole number.\r
351                 // strtol10() will deal with both + and - signs,\r
352                 // but calculate as f32 to prevent overflow at FLT_MAX\r
353                 // Using pow with float cast instead of powf as otherwise accuracy decreases.\r
354                 value *= (f32)pow(10.f, (f32)strtol10(in, &in));\r
355         }\r
356 \r
357         result = negative?-value:value;\r
358         return in;\r
359 }\r
360 \r
361 //! Convert a string to a floating point number\r
362 /** \param floatAsString The string to convert.\r
363     \param out Optional pointer to the first character in the string that\r
364     wasn't used to create the float value.\r
365     \result Float value parsed from the input string\r
366 */\r
367 inline float fast_atof(const char* floatAsString, const char** out=0)\r
368 {\r
369         float ret;\r
370         if (out)\r
371                 *out=fast_atof_move(floatAsString, ret);\r
372         else\r
373                 fast_atof_move(floatAsString, ret);\r
374         return ret;\r
375 }\r
376 \r
377 } // end namespace core\r
378 } // end namespace irr\r
379 \r
380 #endif\r
381 \r