vrshoot

annotate libs/assimp/fast_atof.h @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
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