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