Move SMaterial std::hash impl to its header
[minetest.git] / irr / include / fast_atof.h
blob2b517d62d92cace98caecca3e3f915178ef40992
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine" and the "irrXML" project.
3 // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
5 #pragma once
7 #include "irrTypes.h"
8 #include <cfloat>
9 #include <climits>
10 #include <cmath>
12 namespace irr
14 namespace core
17 #define IRR_ATOF_TABLE_SIZE 17
18 // we write [IRR_ATOF_TABLE_SIZE] here instead of [] to work around a swig bug
19 const float fast_atof_table[17] = {
20 0.f,
21 0.1f,
22 0.01f,
23 0.001f,
24 0.0001f,
25 0.00001f,
26 0.000001f,
27 0.0000001f,
28 0.00000001f,
29 0.000000001f,
30 0.0000000001f,
31 0.00000000001f,
32 0.000000000001f,
33 0.0000000000001f,
34 0.00000000000001f,
35 0.000000000000001f,
36 0.0000000000000001f};
38 //! Convert a simple string of base 10 digits into an unsigned 32 bit integer.
39 /** \param[in] in: The string of digits to convert. No leading chars are
40 allowed, only digits 0 to 9. Parsing stops at the first non-digit.
41 \param[out] out: (optional) If provided, it will be set to point at the
42 first character not used in the calculation.
43 \return The unsigned integer value of the digits. If the string specifies
44 too many digits to encode in an u32 then INT_MAX will be returned.
46 inline u32 strtoul10(const char *in, const char **out = 0)
48 if (!in) {
49 if (out)
50 *out = in;
51 return 0;
54 bool overflow = false;
55 u32 unsignedValue = 0;
56 while ((*in >= '0') && (*in <= '9')) {
57 const u32 tmp = (unsignedValue * 10) + (*in - '0');
58 if (tmp < unsignedValue) {
59 unsignedValue = (u32)0xffffffff;
60 overflow = true;
62 if (!overflow)
63 unsignedValue = tmp;
64 ++in;
67 if (out)
68 *out = in;
70 return unsignedValue;
73 //! Convert a simple string of base 10 digits into a signed 32 bit integer.
74 /** \param[in] in: The string of digits to convert. Only a leading - or +
75 followed by digits 0 to 9 will be considered. Parsing stops at the first
76 non-digit.
77 \param[out] out: (optional) If provided, it will be set to point at the
78 first character not used in the calculation.
79 \return The signed integer value of the digits. If the string specifies
80 too many digits to encode in an s32 then +INT_MAX or -INT_MAX will be
81 returned.
83 inline s32 strtol10(const char *in, const char **out = 0)
85 if (!in) {
86 if (out)
87 *out = in;
88 return 0;
91 const bool negative = ('-' == *in);
92 if (negative || ('+' == *in))
93 ++in;
95 const u32 unsignedValue = strtoul10(in, out);
96 if (unsignedValue > (u32)INT_MAX) {
97 if (negative)
98 return (s32)INT_MIN;
99 else
100 return (s32)INT_MAX;
101 } else {
102 if (negative)
103 return -((s32)unsignedValue);
104 else
105 return (s32)unsignedValue;
109 //! Convert a hex-encoded character to an unsigned integer.
110 /** \param[in] in The digit to convert. Only digits 0 to 9 and chars A-F,a-f
111 will be considered.
112 \return The unsigned integer value of the digit. 0xffffffff if the input is
113 not hex
115 inline u32 ctoul16(char in)
117 if (in >= '0' && in <= '9')
118 return in - '0';
119 else if (in >= 'a' && in <= 'f')
120 return 10u + in - 'a';
121 else if (in >= 'A' && in <= 'F')
122 return 10u + in - 'A';
123 else
124 return 0xffffffff;
127 //! Convert a simple string of base 16 digits into an unsigned 32 bit integer.
128 /** \param[in] in: The string of digits to convert. No leading chars are
129 allowed, only digits 0 to 9 and chars A-F,a-f are allowed. Parsing stops
130 at the first illegal char.
131 \param[out] out: (optional) If provided, it will be set to point at the
132 first character not used in the calculation.
133 \return The unsigned integer value of the digits. If the string specifies
134 too many digits to encode in an u32 then INT_MAX will be returned.
136 inline u32 strtoul16(const char *in, const char **out = 0)
138 if (!in) {
139 if (out)
140 *out = in;
141 return 0;
144 bool overflow = false;
145 u32 unsignedValue = 0;
146 while (true) {
147 u32 tmp = 0;
148 if ((*in >= '0') && (*in <= '9'))
149 tmp = (unsignedValue << 4u) + (*in - '0');
150 else if ((*in >= 'A') && (*in <= 'F'))
151 tmp = (unsignedValue << 4u) + (*in - 'A') + 10;
152 else if ((*in >= 'a') && (*in <= 'f'))
153 tmp = (unsignedValue << 4u) + (*in - 'a') + 10;
154 else
155 break;
156 if (tmp < unsignedValue) {
157 unsignedValue = (u32)INT_MAX;
158 overflow = true;
160 if (!overflow)
161 unsignedValue = tmp;
162 ++in;
165 if (out)
166 *out = in;
168 return unsignedValue;
171 //! Convert a simple string of base 8 digits into an unsigned 32 bit integer.
172 /** \param[in] in The string of digits to convert. No leading chars are
173 allowed, only digits 0 to 7 are allowed. Parsing stops at the first illegal
174 char.
175 \param[out] out (optional) If provided, it will be set to point at the
176 first character not used in the calculation.
177 \return The unsigned integer value of the digits. If the string specifies
178 too many digits to encode in an u32 then INT_MAX will be returned.
180 inline u32 strtoul8(const char *in, const char **out = 0)
182 if (!in) {
183 if (out)
184 *out = in;
185 return 0;
188 bool overflow = false;
189 u32 unsignedValue = 0;
190 while (true) {
191 u32 tmp = 0;
192 if ((*in >= '0') && (*in <= '7'))
193 tmp = (unsignedValue << 3u) + (*in - '0');
194 else
195 break;
196 if (tmp < unsignedValue) {
197 unsignedValue = (u32)INT_MAX;
198 overflow = true;
200 if (!overflow)
201 unsignedValue = tmp;
202 ++in;
205 if (out)
206 *out = in;
208 return unsignedValue;
211 //! Convert a C-style prefixed string (hex, oct, integer) into an unsigned 32 bit integer.
212 /** \param[in] in The string of digits to convert. If string starts with 0x the
213 hex parser is used, if only leading 0 is used, oct parser is used. In all
214 other cases, the usual unsigned parser is used.
215 \param[out] out (optional) If provided, it will be set to point at the
216 first character not used in the calculation.
217 \return The unsigned integer value of the digits. If the string specifies
218 too many digits to encode in an u32 then INT_MAX will be returned.
220 inline u32 strtoul_prefix(const char *in, const char **out = 0)
222 if (!in) {
223 if (out)
224 *out = in;
225 return 0;
227 if ('0' == in[0])
228 return ('x' == in[1] ? strtoul16(in + 2, out) : strtoul8(in + 1, out));
229 return strtoul10(in, out);
232 //! Converts a sequence of digits into a whole positive floating point value.
233 /** Only digits 0 to 9 are parsed. Parsing stops at any other character,
234 including sign characters or a decimal point.
235 \param in: the sequence of digits to convert.
236 \param out: (optional) will be set to point at the first non-converted
237 character.
238 \return The whole positive floating point representation of the digit
239 sequence.
241 inline f32 strtof10(const char *in, const char **out = 0)
243 if (!in) {
244 if (out)
245 *out = in;
246 return 0.f;
249 const u32 MAX_SAFE_U32_VALUE = UINT_MAX / 10 - 10;
250 u32 intValue = 0;
252 // Use integer arithmetic for as long as possible, for speed
253 // and precision.
254 while ((*in >= '0') && (*in <= '9')) {
255 // If it looks like we're going to overflow, bail out
256 // now and start using floating point.
257 if (intValue >= MAX_SAFE_U32_VALUE)
258 break;
260 intValue = (intValue * 10) + (*in - '0');
261 ++in;
264 f32 floatValue = (f32)intValue;
266 // If there are any digits left to parse, then we need to use
267 // floating point arithmetic from here.
268 while ((*in >= '0') && (*in <= '9')) {
269 floatValue = (floatValue * 10.f) + (f32)(*in - '0');
270 ++in;
271 if (floatValue > FLT_MAX) // Just give up.
272 break;
275 if (out)
276 *out = in;
278 return floatValue;
281 //! Provides a fast function for converting a string into a float.
282 /** This is not guaranteed to be as accurate as atof(), but is
283 approximately 6 to 8 times as fast.
284 \param[in] in The string to convert.
285 \param[out] result The resultant float will be written here.
286 \return Pointer to the first character in the string that wasn't used
287 to create the float value.
289 inline const char *fast_atof_move(const char *in, f32 &result)
291 // Please run the regression test when making any modifications to this function.
293 result = 0.f;
294 if (!in)
295 return 0;
297 const bool negative = ('-' == *in);
298 if (negative || ('+' == *in))
299 ++in;
301 f32 value = strtof10(in, &in);
303 if (*in == '.') {
304 const char *afterDecimal = ++in;
305 const f32 decimal = strtof10(in, &afterDecimal);
306 const size_t numDecimals = afterDecimal - in;
307 if (numDecimals < IRR_ATOF_TABLE_SIZE) {
308 value += decimal * fast_atof_table[numDecimals];
309 } else {
310 value += decimal * std::pow(10.f, -(float)numDecimals);
312 in = afterDecimal;
315 if ('e' == *in || 'E' == *in) {
316 ++in;
317 // Assume that the exponent is a whole number.
318 // strtol10() will deal with both + and - signs,
319 // but calculate as f32 to prevent overflow at FLT_MAX
320 // Using pow with float cast instead of powf as otherwise accuracy decreases.
321 value *= std::pow(10.f, (f32)strtol10(in, &in));
324 result = negative ? -value : value;
325 return in;
328 //! Convert a string to a floating point number
329 /** \param floatAsString The string to convert.
330 \param out Optional pointer to the first character in the string that
331 wasn't used to create the float value.
332 \result Float value parsed from the input string
334 inline float fast_atof(const char *floatAsString, const char **out = 0)
336 float ret;
337 if (out)
338 *out = fast_atof_move(floatAsString, ret);
339 else
340 fast_atof_move(floatAsString, ret);
341 return ret;
344 } // end namespace core
345 } // end namespace irr