rev |
line source |
nuclear@0
|
1 // Copyright (C) 2002-2007 Nikolaus Gebhardt
|
nuclear@0
|
2 // This file is part of the "Irrlicht Engine" and the "irrXML" project.
|
nuclear@0
|
3 // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
|
nuclear@0
|
4
|
nuclear@0
|
5 // ------------------------------------------------------------------------------------
|
nuclear@0
|
6 // Original description: (Schrompf)
|
nuclear@0
|
7 // Adapted to the ASSIMP library because the builtin atof indeed takes AGES to parse a
|
nuclear@0
|
8 // float inside a large string. Before parsing, it does a strlen on the given point.
|
nuclear@0
|
9 // Changes:
|
nuclear@0
|
10 // 22nd October 08 (Aramis_acg): Added temporary cast to double, added strtoul10_64
|
nuclear@0
|
11 // to ensure long numbers are handled correctly
|
nuclear@0
|
12 // ------------------------------------------------------------------------------------
|
nuclear@0
|
13
|
nuclear@0
|
14
|
nuclear@0
|
15 #ifndef __FAST_A_TO_F_H_INCLUDED__
|
nuclear@0
|
16 #define __FAST_A_TO_F_H_INCLUDED__
|
nuclear@0
|
17
|
nuclear@0
|
18 #include <math.h>
|
nuclear@0
|
19
|
nuclear@0
|
20 namespace Assimp
|
nuclear@0
|
21 {
|
nuclear@0
|
22
|
nuclear@0
|
23 const float fast_atof_table[16] = { // we write [16] here instead of [] to work around a swig bug
|
nuclear@0
|
24 0.f,
|
nuclear@0
|
25 0.1f,
|
nuclear@0
|
26 0.01f,
|
nuclear@0
|
27 0.001f,
|
nuclear@0
|
28 0.0001f,
|
nuclear@0
|
29 0.00001f,
|
nuclear@0
|
30 0.000001f,
|
nuclear@0
|
31 0.0000001f,
|
nuclear@0
|
32 0.00000001f,
|
nuclear@0
|
33 0.000000001f,
|
nuclear@0
|
34 0.0000000001f,
|
nuclear@0
|
35 0.00000000001f,
|
nuclear@0
|
36 0.000000000001f,
|
nuclear@0
|
37 0.0000000000001f,
|
nuclear@0
|
38 0.00000000000001f,
|
nuclear@0
|
39 0.000000000000001f
|
nuclear@0
|
40 };
|
nuclear@0
|
41
|
nuclear@0
|
42
|
nuclear@0
|
43 // ------------------------------------------------------------------------------------
|
nuclear@0
|
44 // Convert a string in decimal format to a number
|
nuclear@0
|
45 // ------------------------------------------------------------------------------------
|
nuclear@0
|
46 inline unsigned int strtoul10( const char* in, const char** out=0)
|
nuclear@0
|
47 {
|
nuclear@0
|
48 unsigned int value = 0;
|
nuclear@0
|
49
|
nuclear@0
|
50 bool running = true;
|
nuclear@0
|
51 while ( running )
|
nuclear@0
|
52 {
|
nuclear@0
|
53 if ( *in < '0' || *in > '9' )
|
nuclear@0
|
54 break;
|
nuclear@0
|
55
|
nuclear@0
|
56 value = ( value * 10 ) + ( *in - '0' );
|
nuclear@0
|
57 ++in;
|
nuclear@0
|
58 }
|
nuclear@0
|
59 if (out)*out = in;
|
nuclear@0
|
60 return value;
|
nuclear@0
|
61 }
|
nuclear@0
|
62
|
nuclear@0
|
63 // ------------------------------------------------------------------------------------
|
nuclear@0
|
64 // Convert a string in octal format to a number
|
nuclear@0
|
65 // ------------------------------------------------------------------------------------
|
nuclear@0
|
66 inline unsigned int strtoul8( const char* in, const char** out=0)
|
nuclear@0
|
67 {
|
nuclear@0
|
68 unsigned int value = 0;
|
nuclear@0
|
69
|
nuclear@0
|
70 bool running = true;
|
nuclear@0
|
71 while ( running )
|
nuclear@0
|
72 {
|
nuclear@0
|
73 if ( *in < '0' || *in > '7' )
|
nuclear@0
|
74 break;
|
nuclear@0
|
75
|
nuclear@0
|
76 value = ( value << 3 ) + ( *in - '0' );
|
nuclear@0
|
77 ++in;
|
nuclear@0
|
78 }
|
nuclear@0
|
79 if (out)*out = in;
|
nuclear@0
|
80 return value;
|
nuclear@0
|
81 }
|
nuclear@0
|
82
|
nuclear@0
|
83 // ------------------------------------------------------------------------------------
|
nuclear@0
|
84 // Convert a string in hex format to a number
|
nuclear@0
|
85 // ------------------------------------------------------------------------------------
|
nuclear@0
|
86 inline unsigned int strtoul16( const char* in, const char** out=0)
|
nuclear@0
|
87 {
|
nuclear@0
|
88 unsigned int value = 0;
|
nuclear@0
|
89
|
nuclear@0
|
90 bool running = true;
|
nuclear@0
|
91 while ( running )
|
nuclear@0
|
92 {
|
nuclear@0
|
93 if ( *in >= '0' && *in <= '9' )
|
nuclear@0
|
94 {
|
nuclear@0
|
95 value = ( value << 4u ) + ( *in - '0' );
|
nuclear@0
|
96 }
|
nuclear@0
|
97 else if (*in >= 'A' && *in <= 'F')
|
nuclear@0
|
98 {
|
nuclear@0
|
99 value = ( value << 4u ) + ( *in - 'A' ) + 10;
|
nuclear@0
|
100 }
|
nuclear@0
|
101 else if (*in >= 'a' && *in <= 'f')
|
nuclear@0
|
102 {
|
nuclear@0
|
103 value = ( value << 4u ) + ( *in - 'a' ) + 10;
|
nuclear@0
|
104 }
|
nuclear@0
|
105 else break;
|
nuclear@0
|
106 ++in;
|
nuclear@0
|
107 }
|
nuclear@0
|
108 if (out)*out = in;
|
nuclear@0
|
109 return value;
|
nuclear@0
|
110 }
|
nuclear@0
|
111
|
nuclear@0
|
112 // ------------------------------------------------------------------------------------
|
nuclear@0
|
113 // Convert just one hex digit
|
nuclear@0
|
114 // Return value is UINT_MAX if the input character is not a hex digit.
|
nuclear@0
|
115 // ------------------------------------------------------------------------------------
|
nuclear@0
|
116 inline unsigned int HexDigitToDecimal(char in)
|
nuclear@0
|
117 {
|
nuclear@0
|
118 unsigned int out = UINT_MAX;
|
nuclear@0
|
119 if (in >= '0' && in <= '9')
|
nuclear@0
|
120 out = in - '0';
|
nuclear@0
|
121
|
nuclear@0
|
122 else if (in >= 'a' && in <= 'f')
|
nuclear@0
|
123 out = 10u + in - 'a';
|
nuclear@0
|
124
|
nuclear@0
|
125 else if (in >= 'A' && in <= 'F')
|
nuclear@0
|
126 out = 10u + in - 'A';
|
nuclear@0
|
127
|
nuclear@0
|
128 // return value is UINT_MAX if the input is not a hex digit
|
nuclear@0
|
129 return out;
|
nuclear@0
|
130 }
|
nuclear@0
|
131
|
nuclear@0
|
132 // ------------------------------------------------------------------------------------
|
nuclear@0
|
133 // Convert a hex-encoded octet (2 characters, i.e. df or 1a).
|
nuclear@0
|
134 // ------------------------------------------------------------------------------------
|
nuclear@0
|
135 inline uint8_t HexOctetToDecimal(const char* in)
|
nuclear@0
|
136 {
|
nuclear@0
|
137 return ((uint8_t)HexDigitToDecimal(in[0])<<4)+(uint8_t)HexDigitToDecimal(in[1]);
|
nuclear@0
|
138 }
|
nuclear@0
|
139
|
nuclear@0
|
140
|
nuclear@0
|
141 // ------------------------------------------------------------------------------------
|
nuclear@0
|
142 // signed variant of strtoul10
|
nuclear@0
|
143 // ------------------------------------------------------------------------------------
|
nuclear@0
|
144 inline int strtol10( const char* in, const char** out=0)
|
nuclear@0
|
145 {
|
nuclear@0
|
146 bool inv = (*in=='-');
|
nuclear@0
|
147 if (inv || *in=='+')
|
nuclear@0
|
148 ++in;
|
nuclear@0
|
149
|
nuclear@0
|
150 int value = strtoul10(in,out);
|
nuclear@0
|
151 if (inv) {
|
nuclear@0
|
152 value = -value;
|
nuclear@0
|
153 }
|
nuclear@0
|
154 return value;
|
nuclear@0
|
155 }
|
nuclear@0
|
156
|
nuclear@0
|
157 // ------------------------------------------------------------------------------------
|
nuclear@0
|
158 // Parse a C++-like integer literal - hex and oct prefixes.
|
nuclear@0
|
159 // 0xNNNN - hex
|
nuclear@0
|
160 // 0NNN - oct
|
nuclear@0
|
161 // NNN - dec
|
nuclear@0
|
162 // ------------------------------------------------------------------------------------
|
nuclear@0
|
163 inline unsigned int strtoul_cppstyle( const char* in, const char** out=0)
|
nuclear@0
|
164 {
|
nuclear@0
|
165 if ('0' == in[0])
|
nuclear@0
|
166 {
|
nuclear@0
|
167 return 'x' == in[1] ? strtoul16(in+2,out) : strtoul8(in+1,out);
|
nuclear@0
|
168 }
|
nuclear@0
|
169 return strtoul10(in, out);
|
nuclear@0
|
170 }
|
nuclear@0
|
171
|
nuclear@0
|
172 // ------------------------------------------------------------------------------------
|
nuclear@0
|
173 // Special version of the function, providing higher accuracy and safety
|
nuclear@0
|
174 // It is mainly used by fast_atof to prevent ugly and unwanted integer overflows.
|
nuclear@0
|
175 // ------------------------------------------------------------------------------------
|
nuclear@0
|
176 inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* max_inout=0)
|
nuclear@0
|
177 {
|
nuclear@0
|
178 unsigned int cur = 0;
|
nuclear@0
|
179 uint64_t value = 0;
|
nuclear@0
|
180
|
nuclear@0
|
181 bool running = true;
|
nuclear@0
|
182 while ( running )
|
nuclear@0
|
183 {
|
nuclear@0
|
184 if ( *in < '0' || *in > '9' )
|
nuclear@0
|
185 break;
|
nuclear@0
|
186
|
nuclear@0
|
187 const uint64_t new_value = ( value * 10 ) + ( *in - '0' );
|
nuclear@0
|
188
|
nuclear@0
|
189 if (new_value < value) /* numeric overflow, we rely on you */
|
nuclear@0
|
190 return value;
|
nuclear@0
|
191
|
nuclear@0
|
192 value = new_value;
|
nuclear@0
|
193
|
nuclear@0
|
194 ++in;
|
nuclear@0
|
195 ++cur;
|
nuclear@0
|
196
|
nuclear@0
|
197 if (max_inout && *max_inout == cur) {
|
nuclear@0
|
198
|
nuclear@0
|
199 if (out) { /* skip to end */
|
nuclear@0
|
200 while (*in >= '0' && *in <= '9')
|
nuclear@0
|
201 ++in;
|
nuclear@0
|
202 *out = in;
|
nuclear@0
|
203 }
|
nuclear@0
|
204
|
nuclear@0
|
205 return value;
|
nuclear@0
|
206 }
|
nuclear@0
|
207 }
|
nuclear@0
|
208 if (out)
|
nuclear@0
|
209 *out = in;
|
nuclear@0
|
210
|
nuclear@0
|
211 if (max_inout)
|
nuclear@0
|
212 *max_inout = cur;
|
nuclear@0
|
213
|
nuclear@0
|
214 return value;
|
nuclear@0
|
215 }
|
nuclear@0
|
216
|
nuclear@0
|
217 // Number of relevant decimals for floating-point parsing.
|
nuclear@0
|
218 #define AI_FAST_ATOF_RELAVANT_DECIMALS 15
|
nuclear@0
|
219
|
nuclear@0
|
220 // ------------------------------------------------------------------------------------
|
nuclear@0
|
221 //! Provides a fast function for converting a string into a float,
|
nuclear@0
|
222 //! about 6 times faster than atof in win32.
|
nuclear@0
|
223 // If you find any bugs, please send them to me, niko (at) irrlicht3d.org.
|
nuclear@0
|
224 // ------------------------------------------------------------------------------------
|
nuclear@0
|
225 template <typename Real>
|
nuclear@0
|
226 inline const char* fast_atoreal_move( const char* c, Real& out)
|
nuclear@0
|
227 {
|
nuclear@0
|
228 Real f;
|
nuclear@0
|
229
|
nuclear@0
|
230 bool inv = (*c=='-');
|
nuclear@0
|
231 if (inv || *c=='+') {
|
nuclear@0
|
232 ++c;
|
nuclear@0
|
233 }
|
nuclear@0
|
234
|
nuclear@0
|
235 f = static_cast<Real>( strtoul10_64 ( c, &c) );
|
nuclear@0
|
236 if (*c == '.' || (c[0] == ',' && c[1] >= '0' && c[1] <= '9')) // allow for commas, too
|
nuclear@0
|
237 {
|
nuclear@0
|
238 ++c;
|
nuclear@0
|
239
|
nuclear@0
|
240 // NOTE: The original implementation is highly inaccurate here. The precision of a single
|
nuclear@0
|
241 // IEEE 754 float is not high enough, everything behind the 6th digit tends to be more
|
nuclear@0
|
242 // inaccurate than it would need to be. Casting to double seems to solve the problem.
|
nuclear@0
|
243 // strtol_64 is used to prevent integer overflow.
|
nuclear@0
|
244
|
nuclear@0
|
245 // Another fix: this tends to become 0 for long numbers if we don't limit the maximum
|
nuclear@0
|
246 // number of digits to be read. AI_FAST_ATOF_RELAVANT_DECIMALS can be a value between
|
nuclear@0
|
247 // 1 and 15.
|
nuclear@0
|
248 unsigned int diff = AI_FAST_ATOF_RELAVANT_DECIMALS;
|
nuclear@0
|
249 double pl = static_cast<double>( strtoul10_64 ( c, &c, &diff ));
|
nuclear@0
|
250
|
nuclear@0
|
251 pl *= fast_atof_table[diff];
|
nuclear@0
|
252 f += static_cast<Real>( pl );
|
nuclear@0
|
253 }
|
nuclear@0
|
254
|
nuclear@0
|
255 // A major 'E' must be allowed. Necessary for proper reading of some DXF files.
|
nuclear@0
|
256 // Thanks to Zhao Lei to point out that this if() must be outside the if (*c == '.' ..)
|
nuclear@0
|
257 if (*c == 'e' || *c == 'E') {
|
nuclear@0
|
258
|
nuclear@0
|
259 ++c;
|
nuclear@0
|
260 const bool einv = (*c=='-');
|
nuclear@0
|
261 if (einv || *c=='+') {
|
nuclear@0
|
262 ++c;
|
nuclear@0
|
263 }
|
nuclear@0
|
264
|
nuclear@0
|
265 // The reason float constants are used here is that we've seen cases where compilers
|
nuclear@0
|
266 // would perform such casts on compile-time constants at runtime, which would be
|
nuclear@0
|
267 // bad considering how frequently fast_atoreal_move<float> is called in Assimp.
|
nuclear@0
|
268 Real exp = static_cast<Real>( strtoul10_64(c, &c) );
|
nuclear@0
|
269 if (einv) {
|
nuclear@0
|
270 exp = -exp;
|
nuclear@0
|
271 }
|
nuclear@0
|
272 f *= pow(static_cast<Real>(10.0f), exp);
|
nuclear@0
|
273 }
|
nuclear@0
|
274
|
nuclear@0
|
275 if (inv) {
|
nuclear@0
|
276 f = -f;
|
nuclear@0
|
277 }
|
nuclear@0
|
278 out = f;
|
nuclear@0
|
279 return c;
|
nuclear@0
|
280 }
|
nuclear@0
|
281
|
nuclear@0
|
282 // ------------------------------------------------------------------------------------
|
nuclear@0
|
283 // The same but more human.
|
nuclear@0
|
284 inline float fast_atof(const char* c)
|
nuclear@0
|
285 {
|
nuclear@0
|
286 float ret;
|
nuclear@0
|
287 fast_atoreal_move<float>(c, ret);
|
nuclear@0
|
288 return ret;
|
nuclear@0
|
289 }
|
nuclear@0
|
290
|
nuclear@0
|
291
|
nuclear@0
|
292 inline float fast_atof( const char* c, const char** cout)
|
nuclear@0
|
293 {
|
nuclear@0
|
294 float ret;
|
nuclear@0
|
295 *cout = fast_atoreal_move<float>(c, ret);
|
nuclear@0
|
296
|
nuclear@0
|
297 return ret;
|
nuclear@0
|
298 }
|
nuclear@0
|
299
|
nuclear@0
|
300 inline float fast_atof( const char** inout)
|
nuclear@0
|
301 {
|
nuclear@0
|
302 float ret;
|
nuclear@0
|
303 *inout = fast_atoreal_move<float>(*inout, ret);
|
nuclear@0
|
304
|
nuclear@0
|
305 return ret;
|
nuclear@0
|
306 }
|
nuclear@0
|
307
|
nuclear@0
|
308
|
nuclear@0
|
309 inline double fast_atod(const char* c)
|
nuclear@0
|
310 {
|
nuclear@0
|
311 double ret;
|
nuclear@0
|
312 fast_atoreal_move<double>(c, ret);
|
nuclear@0
|
313 return ret;
|
nuclear@0
|
314 }
|
nuclear@0
|
315
|
nuclear@0
|
316
|
nuclear@0
|
317 inline double fast_atod( const char* c, const char** cout)
|
nuclear@0
|
318 {
|
nuclear@0
|
319 double ret;
|
nuclear@0
|
320 *cout = fast_atoreal_move<double>(c, ret);
|
nuclear@0
|
321
|
nuclear@0
|
322 return ret;
|
nuclear@0
|
323 }
|
nuclear@0
|
324
|
nuclear@0
|
325 inline double fast_atod( const char** inout)
|
nuclear@0
|
326 {
|
nuclear@0
|
327 double ret;
|
nuclear@0
|
328 *inout = fast_atoreal_move<double>(*inout, ret);
|
nuclear@0
|
329
|
nuclear@0
|
330 return ret;
|
nuclear@0
|
331 }
|
nuclear@0
|
332
|
nuclear@0
|
333 } // end of namespace Assimp
|
nuclear@0
|
334
|
nuclear@0
|
335 #endif
|
nuclear@0
|
336
|