fast_atof.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. // Copyright (C) 2002-2007 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
  4. // ------------------------------------------------------------------------------------
  5. // Original description: (Schrompf)
  6. // Adapted to the ASSIMP library because the builtin atof indeed takes AGES to parse a
  7. // float inside a large string. Before parsing, it does a strlen on the given point.
  8. // Changes:
  9. // 22nd October 08 (Aramis_acg): Added temporary cast to double, added strtol10_64
  10. // to ensure long numbers are handled correctly
  11. // ------------------------------------------------------------------------------------
  12. #ifndef __FAST_A_TO_F_H_INCLUDED__
  13. #define __FAST_A_TO_F_H_INCLUDED__
  14. #include <math.h>
  15. namespace Assimp
  16. {
  17. const float fast_atof_table[16] = { // we write [16] here instead of [] to work around a swig bug
  18. 0.f,
  19. 0.1f,
  20. 0.01f,
  21. 0.001f,
  22. 0.0001f,
  23. 0.00001f,
  24. 0.000001f,
  25. 0.0000001f,
  26. 0.00000001f,
  27. 0.000000001f,
  28. 0.0000000001f,
  29. 0.00000000001f,
  30. 0.000000000001f,
  31. 0.0000000000001f,
  32. 0.00000000000001f,
  33. 0.000000000000001f
  34. };
  35. // ------------------------------------------------------------------------------------
  36. // Convert a string in decimal format to a number
  37. // ------------------------------------------------------------------------------------
  38. inline unsigned int strtol10( const char* in, const char** out=0)
  39. {
  40. unsigned int value = 0;
  41. while ( 1 )
  42. {
  43. if ( *in < '0' || *in > '9' )
  44. break;
  45. value = ( value * 10 ) + ( *in - '0' );
  46. ++in;
  47. }
  48. if (out)*out = in;
  49. return value;
  50. }
  51. // ------------------------------------------------------------------------------------
  52. // Convert a string in octal format to a number
  53. // ------------------------------------------------------------------------------------
  54. inline unsigned int strtol8( const char* in, const char** out=0)
  55. {
  56. unsigned int value = 0;
  57. while ( 1 )
  58. {
  59. if ( *in < '0' || *in > '7' )
  60. break;
  61. value = ( value << 3 ) + ( *in - '0' );
  62. ++in;
  63. }
  64. if (out)*out = in;
  65. return value;
  66. }
  67. // ------------------------------------------------------------------------------------
  68. // Convert a string in hex format to a number
  69. // ------------------------------------------------------------------------------------
  70. inline unsigned int strtol16( const char* in, const char** out=0)
  71. {
  72. unsigned int value = 0;
  73. while ( 1 )
  74. {
  75. if ( *in >= '0' && *in <= '9' )
  76. {
  77. value = ( value << 4u ) + ( *in - '0' );
  78. }
  79. else if (*in >= 'A' && *in <= 'F')
  80. {
  81. value = ( value << 4u ) + ( *in - 'A' ) + 10;
  82. }
  83. else if (*in >= 'a' && *in <= 'f')
  84. {
  85. value = ( value << 4u ) + ( *in - 'a' ) + 10;
  86. }
  87. else break;
  88. ++in;
  89. }
  90. if (out)*out = in;
  91. return value;
  92. }
  93. // ------------------------------------------------------------------------------------
  94. // Convert just one hex digit
  95. // Return value is 0xffffffff if the input is not hex
  96. // ------------------------------------------------------------------------------------
  97. inline unsigned int HexDigitToDecimal(char in)
  98. {
  99. unsigned int out = 0xffffffff;
  100. if (in >= '0' && in <= '9')
  101. out = in - '0';
  102. else if (in >= 'a' && in <= 'f')
  103. out = 10u + in - 'a';
  104. else if (in >= 'A' && in <= 'F')
  105. out = 10u + in - 'A';
  106. // return value is 0xffffffff if the input is not a hex digit
  107. return out;
  108. }
  109. // ------------------------------------------------------------------------------------
  110. // Convert a hex-encoded octet (2 characters processed)
  111. // Return value is 0xffffffff if the input is not hex
  112. // ------------------------------------------------------------------------------------
  113. inline uint8_t HexOctetToDecimal(const char* in)
  114. {
  115. return ((uint8_t)HexDigitToDecimal(in[0])<<4)+(uint8_t)HexDigitToDecimal(in[1]);
  116. }
  117. // ------------------------------------------------------------------------------------
  118. // signed variant of strtol10
  119. // ------------------------------------------------------------------------------------
  120. inline int strtol10s( const char* in, const char** out=0)
  121. {
  122. bool inv = (*in=='-');
  123. if (inv || *in=='+')
  124. ++in;
  125. int value = strtol10(in,out);
  126. if (inv) {
  127. value = -value;
  128. }
  129. return value;
  130. }
  131. // ------------------------------------------------------------------------------------
  132. // Parse a C++-like integer literal - hex and oct prefixes.
  133. // 0xNNNN - hex
  134. // 0NNN - oct
  135. // NNN - dec
  136. // ------------------------------------------------------------------------------------
  137. inline unsigned int strtol_cppstyle( const char* in, const char** out=0)
  138. {
  139. if ('0' == in[0])
  140. {
  141. return 'x' == in[1] ? strtol16(in+2,out) : strtol8(in+1,out);
  142. }
  143. return strtol10(in, out);
  144. }
  145. // ------------------------------------------------------------------------------------
  146. // Special version of the function, providing higher accuracy and safety
  147. // It is mainly used by fast_atof to prevent ugly and unwanted integer overflows.
  148. // ------------------------------------------------------------------------------------
  149. inline uint64_t strtol10_64( const char* in, const char** out=0, unsigned int* max_inout=0)
  150. {
  151. unsigned int cur = 0;
  152. uint64_t value = 0;
  153. while ( 1 )
  154. {
  155. if ( *in < '0' || *in > '9' )
  156. break;
  157. const uint64_t new_value = ( value * 10 ) + ( *in - '0' );
  158. if (new_value < value) /* numeric overflow, we rely on you */
  159. return value;
  160. value = new_value;
  161. ++in;
  162. ++cur;
  163. if (max_inout && *max_inout == cur) {
  164. if (out) { /* skip to end */
  165. while (*in >= '0' && *in <= '9')
  166. ++in;
  167. *out = in;
  168. }
  169. return value;
  170. }
  171. }
  172. if (out)
  173. *out = in;
  174. if (max_inout)
  175. *max_inout = cur;
  176. return value;
  177. }
  178. // Number of relevant decimals for floating-point parsing.
  179. #define AI_FAST_ATOF_RELAVANT_DECIMALS 6
  180. // ------------------------------------------------------------------------------------
  181. //! Provides a fast function for converting a string into a float,
  182. //! about 6 times faster than atof in win32.
  183. // If you find any bugs, please send them to me, niko (at) irrlicht3d.org.
  184. // ------------------------------------------------------------------------------------
  185. inline const char* fast_atof_move( const char* c, float& out)
  186. {
  187. float f;
  188. bool inv = (*c=='-');
  189. if (inv || *c=='+')
  190. ++c;
  191. f = (float) strtol10_64 ( c, &c);
  192. if (*c == '.' || (c[0] == ',' && (c[1] >= '0' || c[1] <= '9'))) // allow for commas, too
  193. {
  194. ++c;
  195. // NOTE: The original implementation is highly unaccurate here. The precision of a single
  196. // IEEE 754 float is not high enough, everything behind the 6th digit tends to be more
  197. // inaccurate than it would need to be. Casting to double seems to solve the problem.
  198. // strtol_64 is used to prevent integer overflow.
  199. // Another fix: this tends to become 0 for long numbers if we don't limit the maximum
  200. // number of digits to be read. AI_FAST_ATOF_RELAVANT_DECIMALS can be a value between
  201. // 1 and 15.
  202. unsigned int diff = AI_FAST_ATOF_RELAVANT_DECIMALS;
  203. double pl = (double) strtol10_64 ( c, &c, &diff );
  204. pl *= fast_atof_table[diff];
  205. f += (float)pl;
  206. }
  207. // A major 'E' must be allowed. Necessary for proper reading of some DXF files.
  208. // Thanks to Zhao Lei to point out that this if() must be outside the if (*c == '.' ..)
  209. if (*c == 'e' || *c == 'E')
  210. {
  211. ++c;
  212. bool einv = (*c=='-');
  213. if (einv || *c=='+')
  214. ++c;
  215. float exp = (float)strtol10_64(c, &c);
  216. if (einv)
  217. exp *= -1.0f;
  218. f *= pow(10.0f, exp);
  219. }
  220. if (inv)
  221. f *= -1.0f;
  222. out = f;
  223. return c;
  224. }
  225. // ------------------------------------------------------------------------------------
  226. // The same but more human.
  227. inline float fast_atof(const char* c)
  228. {
  229. float ret;
  230. fast_atof_move(c, ret);
  231. return ret;
  232. }
  233. } // end of namespace Assimp
  234. #endif