]> git.lizzy.rs Git - irrlicht.git/blob - include/fast_atof.h
Merging r5975 through r6036 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         // 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
19 \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
23         0.f,\r
24         0.1f,\r
25         0.01f,\r
26         0.001f,\r
27         0.0001f,\r
28         0.00001f,\r
29         0.000001f,\r
30         0.0000001f,\r
31         0.00000001f,\r
32         0.000000001f,\r
33         0.0000000001f,\r
34         0.00000000001f,\r
35         0.000000000001f,\r
36         0.0000000000001f,\r
37         0.00000000000001f,\r
38         0.000000000000001f,\r
39         0.0000000000000001f\r
40 };\r
41 \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
49 */\r
50 inline u32 strtoul10(const char* in, const char** out=0)\r
51 {\r
52         if (!in)\r
53         {\r
54                 if (out)\r
55                         *out = in;\r
56                 return 0;\r
57         }\r
58 \r
59         bool overflow=false;\r
60         u32 unsignedValue = 0;\r
61         while ( ( *in >= '0') && ( *in <= '9' ))\r
62         {\r
63                 const u32 tmp = ( unsignedValue * 10 ) + ( *in - '0' );\r
64                 if (tmp<unsignedValue)\r
65                 {\r
66                         unsignedValue=(u32)0xffffffff;\r
67                         overflow=true;\r
68                 }\r
69                 if (!overflow)\r
70                         unsignedValue = tmp;\r
71                 ++in;\r
72         }\r
73 \r
74         if (out)\r
75                 *out = in;\r
76 \r
77         return unsignedValue;\r
78 }\r
79 \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
83     non-digit.\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
88     returned.\r
89 */\r
90 inline s32 strtol10(const char* in, const char** out=0)\r
91 {\r
92         if (!in)\r
93         {\r
94                 if (out)\r
95                         *out = in;\r
96                 return 0;\r
97         }\r
98 \r
99         const bool negative = ('-' == *in);\r
100         if (negative || ('+' == *in))\r
101                 ++in;\r
102 \r
103         const u32 unsignedValue = strtoul10(in,out);\r
104         if (unsignedValue > (u32)INT_MAX)\r
105         {\r
106                 if (negative)\r
107                         return (s32)INT_MIN;\r
108                 else\r
109                         return (s32)INT_MAX;\r
110         }\r
111         else\r
112         {\r
113                 if (negative)\r
114                         return -((s32)unsignedValue);\r
115                 else\r
116                         return (s32)unsignedValue;\r
117         }\r
118 }\r
119 \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
124     not hex\r
125 */\r
126 inline u32 ctoul16(char in)\r
127 {\r
128         if (in >= '0' && in <= '9')\r
129                 return in - '0';\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
134         else\r
135                 return 0xffffffff;\r
136 }\r
137 \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
146 */\r
147 inline u32 strtoul16(const char* in, const char** out=0)\r
148 {\r
149         if (!in)\r
150         {\r
151                 if (out)\r
152                         *out = in;\r
153                 return 0;\r
154         }\r
155 \r
156         bool overflow=false;\r
157         u32 unsignedValue = 0;\r
158         while (true)\r
159         {\r
160                 u32 tmp = 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
167                 else\r
168                         break;\r
169                 if (tmp<unsignedValue)\r
170                 {\r
171                         unsignedValue=(u32)INT_MAX;\r
172                         overflow=true;\r
173                 }\r
174                 if (!overflow)\r
175                         unsignedValue = tmp;\r
176                 ++in;\r
177         }\r
178 \r
179         if (out)\r
180                 *out = in;\r
181 \r
182         return unsignedValue;\r
183 }\r
184 \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
188     char.\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
193 */\r
194 inline u32 strtoul8(const char* in, const char** out=0)\r
195 {\r
196         if (!in)\r
197         {\r
198                 if (out)\r
199                         *out = in;\r
200                 return 0;\r
201         }\r
202 \r
203         bool overflow=false;\r
204         u32 unsignedValue = 0;\r
205         while (true)\r
206         {\r
207                 u32 tmp = 0;\r
208                 if ((*in >= '0') && (*in <= '7'))\r
209                         tmp = (unsignedValue << 3u) + (*in - '0');\r
210                 else\r
211                         break;\r
212                 if (tmp<unsignedValue)\r
213                 {\r
214                         unsignedValue=(u32)INT_MAX;\r
215                         overflow=true;\r
216                 }\r
217                 if (!overflow)\r
218                         unsignedValue = tmp;\r
219                 ++in;\r
220         }\r
221 \r
222         if (out)\r
223                 *out = in;\r
224 \r
225         return unsignedValue;\r
226 }\r
227 \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
236 */\r
237 inline u32 strtoul_prefix(const char* in, const char** out=0)\r
238 {\r
239         if (!in)\r
240         {\r
241                 if (out)\r
242                         *out = in;\r
243                 return 0;\r
244         }\r
245         if ('0'==in[0])\r
246                 return ('x'==in[1] ? strtoul16(in+2,out) : strtoul8(in+1,out));\r
247         return strtoul10(in,out);\r
248 }\r
249 \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
255     character.\r
256     \return The whole positive floating point representation of the digit\r
257     sequence.\r
258 */\r
259 inline f32 strtof10(const char* in, const char** out = 0)\r
260 {\r
261         if (!in)\r
262         {\r
263                 if (out)\r
264                         *out = in;\r
265                 return 0.f;\r
266         }\r
267 \r
268         const u32 MAX_SAFE_U32_VALUE = UINT_MAX / 10 - 10;\r
269         u32 intValue = 0;\r
270 \r
271         // Use integer arithmetic for as long as possible, for speed\r
272         // and precision.\r
273         while ( ( *in >= '0') && ( *in <= '9' ) )\r
274         {\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
278                         break;\r
279 \r
280                 intValue = (intValue * 10) + (*in - '0');\r
281                 ++in;\r
282         }\r
283 \r
284         f32 floatValue = (f32)intValue;\r
285 \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
289         {\r
290                 floatValue = (floatValue * 10.f) + (f32)(*in - '0');\r
291                 ++in;\r
292                 if (floatValue > FLT_MAX) // Just give up.\r
293                         break;\r
294         }\r
295 \r
296         if (out)\r
297                 *out = in;\r
298 \r
299         return floatValue;\r
300 }\r
301 \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
309 */\r
310 inline const char* fast_atof_move(const char* in, f32& result)\r
311 {\r
312         // Please run the regression test when making any modifications to this function.\r
313 \r
314         result = 0.f;\r
315         if (!in)\r
316                 return 0;\r
317 \r
318         const bool negative = ('-' == *in);\r
319         if (negative || ('+'==*in))\r
320                 ++in;\r
321 \r
322         f32 value = strtof10(in, &in);\r
323 \r
324         if ( LOCALE_DECIMAL_POINTS.findFirst(*in) >= 0 )\r
325         {\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
330                 {\r
331                         value += decimal * fast_atof_table[numDecimals];\r
332                 }\r
333                 else\r
334                 {\r
335                         value += decimal * (f32)pow(10.f, -(float)numDecimals);\r
336                 }\r
337                 in = afterDecimal;\r
338         }\r
339 \r
340         if ('e' == *in || 'E' == *in)\r
341         {\r
342                 ++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
348         }\r
349 \r
350         result = negative?-value:value;\r
351         return in;\r
352 }\r
353 \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
359 */\r
360 inline float fast_atof(const char* floatAsString, const char** out=0)\r
361 {\r
362         float ret;\r
363         if (out)\r
364                 *out=fast_atof_move(floatAsString, ret);\r
365         else\r
366                 fast_atof_move(floatAsString, ret);\r
367         return ret;\r
368 }\r
369 \r
370 } // end namespace core\r
371 } // end namespace irr\r
372 \r
373 #endif\r
374 \r