vrshoot

diff 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
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/libs/assimp/fast_atof.h	Sat Feb 01 19:58:19 2014 +0200
     1.3 @@ -0,0 +1,336 @@
     1.4 +// Copyright (C) 2002-2007 Nikolaus Gebhardt
     1.5 +// This file is part of the "Irrlicht Engine" and the "irrXML" project.
     1.6 +// For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
     1.7 +
     1.8 +// ------------------------------------------------------------------------------------
     1.9 +// Original description: (Schrompf)
    1.10 +// Adapted to the ASSIMP library because the builtin atof indeed takes AGES to parse a
    1.11 +// float inside a large string. Before parsing, it does a strlen on the given point.
    1.12 +// Changes:
    1.13 +//  22nd October 08 (Aramis_acg): Added temporary cast to double, added strtoul10_64
    1.14 +//     to ensure long numbers are handled correctly
    1.15 +// ------------------------------------------------------------------------------------
    1.16 +
    1.17 +
    1.18 +#ifndef __FAST_A_TO_F_H_INCLUDED__
    1.19 +#define __FAST_A_TO_F_H_INCLUDED__
    1.20 +
    1.21 +#include <math.h>
    1.22 +
    1.23 +namespace Assimp
    1.24 +{
    1.25 +
    1.26 +const float fast_atof_table[16] =	{  // we write [16] here instead of [] to work around a swig bug
    1.27 +	0.f,
    1.28 +	0.1f,
    1.29 +	0.01f,
    1.30 +	0.001f,
    1.31 +	0.0001f,
    1.32 +	0.00001f,
    1.33 +	0.000001f,
    1.34 +	0.0000001f,
    1.35 +	0.00000001f,
    1.36 +	0.000000001f,
    1.37 +	0.0000000001f,
    1.38 +	0.00000000001f,
    1.39 +	0.000000000001f,
    1.40 +	0.0000000000001f,
    1.41 +	0.00000000000001f,
    1.42 +	0.000000000000001f
    1.43 +};
    1.44 +
    1.45 +
    1.46 +// ------------------------------------------------------------------------------------
    1.47 +// Convert a string in decimal format to a number
    1.48 +// ------------------------------------------------------------------------------------
    1.49 +inline unsigned int strtoul10( const char* in, const char** out=0)
    1.50 +{
    1.51 +	unsigned int value = 0;
    1.52 +
    1.53 +	bool running = true;
    1.54 +	while ( running )
    1.55 +	{
    1.56 +		if ( *in < '0' || *in > '9' )
    1.57 +			break;
    1.58 +
    1.59 +		value = ( value * 10 ) + ( *in - '0' );
    1.60 +		++in;
    1.61 +	}
    1.62 +	if (out)*out = in;
    1.63 +	return value;
    1.64 +}
    1.65 +
    1.66 +// ------------------------------------------------------------------------------------
    1.67 +// Convert a string in octal format to a number
    1.68 +// ------------------------------------------------------------------------------------
    1.69 +inline unsigned int strtoul8( const char* in, const char** out=0)
    1.70 +{
    1.71 +	unsigned int value = 0;
    1.72 +
    1.73 +	bool running = true;
    1.74 +	while ( running )
    1.75 +	{
    1.76 +		if ( *in < '0' || *in > '7' )
    1.77 +			break;
    1.78 +
    1.79 +		value = ( value << 3 ) + ( *in - '0' );
    1.80 +		++in;
    1.81 +	}
    1.82 +	if (out)*out = in;
    1.83 +	return value;
    1.84 +}
    1.85 +
    1.86 +// ------------------------------------------------------------------------------------
    1.87 +// Convert a string in hex format to a number
    1.88 +// ------------------------------------------------------------------------------------
    1.89 +inline unsigned int strtoul16( const char* in, const char** out=0)
    1.90 +{
    1.91 +	unsigned int value = 0;
    1.92 +
    1.93 +	bool running = true;
    1.94 +	while ( running )
    1.95 +	{
    1.96 +		if ( *in >= '0' && *in <= '9' )
    1.97 +		{
    1.98 +			value = ( value << 4u ) + ( *in - '0' );
    1.99 +		}
   1.100 +		else if (*in >= 'A' && *in <= 'F')
   1.101 +		{
   1.102 +			value = ( value << 4u ) + ( *in - 'A' ) + 10;
   1.103 +		}
   1.104 +		else if (*in >= 'a' && *in <= 'f')
   1.105 +		{
   1.106 +			value = ( value << 4u ) + ( *in - 'a' ) + 10;
   1.107 +		}
   1.108 +		else break;
   1.109 +		++in;
   1.110 +	}
   1.111 +	if (out)*out = in;
   1.112 +	return value;
   1.113 +}
   1.114 +
   1.115 +// ------------------------------------------------------------------------------------
   1.116 +// Convert just one hex digit
   1.117 +// Return value is UINT_MAX if the input character is not a hex digit.
   1.118 +// ------------------------------------------------------------------------------------
   1.119 +inline unsigned int HexDigitToDecimal(char in)
   1.120 +{
   1.121 +	unsigned int out = UINT_MAX;
   1.122 +	if (in >= '0' && in <= '9')
   1.123 +		out = in - '0';
   1.124 +
   1.125 +	else if (in >= 'a' && in <= 'f')
   1.126 +		out = 10u + in - 'a';
   1.127 +
   1.128 +	else if (in >= 'A' && in <= 'F')
   1.129 +		out = 10u + in - 'A';
   1.130 +
   1.131 +	// return value is UINT_MAX if the input is not a hex digit
   1.132 +	return out;
   1.133 +}
   1.134 +
   1.135 +// ------------------------------------------------------------------------------------
   1.136 +// Convert a hex-encoded octet (2 characters, i.e. df or 1a).
   1.137 +// ------------------------------------------------------------------------------------
   1.138 +inline uint8_t HexOctetToDecimal(const char* in)
   1.139 +{
   1.140 +	return ((uint8_t)HexDigitToDecimal(in[0])<<4)+(uint8_t)HexDigitToDecimal(in[1]);
   1.141 +}
   1.142 +
   1.143 +
   1.144 +// ------------------------------------------------------------------------------------
   1.145 +// signed variant of strtoul10
   1.146 +// ------------------------------------------------------------------------------------
   1.147 +inline int strtol10( const char* in, const char** out=0)
   1.148 +{
   1.149 +	bool inv = (*in=='-');
   1.150 +	if (inv || *in=='+')
   1.151 +		++in;
   1.152 +
   1.153 +	int value = strtoul10(in,out);
   1.154 +	if (inv) {
   1.155 +		value = -value;
   1.156 +	}
   1.157 +	return value;
   1.158 +}
   1.159 +
   1.160 +// ------------------------------------------------------------------------------------
   1.161 +// Parse a C++-like integer literal - hex and oct prefixes.
   1.162 +// 0xNNNN - hex
   1.163 +// 0NNN   - oct
   1.164 +// NNN    - dec
   1.165 +// ------------------------------------------------------------------------------------
   1.166 +inline unsigned int strtoul_cppstyle( const char* in, const char** out=0)
   1.167 +{
   1.168 +	if ('0' == in[0])
   1.169 +	{
   1.170 +		return 'x' == in[1] ? strtoul16(in+2,out) : strtoul8(in+1,out);
   1.171 +	}
   1.172 +	return strtoul10(in, out);
   1.173 +}
   1.174 +
   1.175 +// ------------------------------------------------------------------------------------
   1.176 +// Special version of the function, providing higher accuracy and safety
   1.177 +// It is mainly used by fast_atof to prevent ugly and unwanted integer overflows.
   1.178 +// ------------------------------------------------------------------------------------
   1.179 +inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* max_inout=0)
   1.180 +{
   1.181 +	unsigned int cur = 0;
   1.182 +	uint64_t value = 0;
   1.183 +
   1.184 +	bool running = true;
   1.185 +	while ( running )
   1.186 +	{
   1.187 +		if ( *in < '0' || *in > '9' )
   1.188 +			break;
   1.189 +
   1.190 +		const uint64_t new_value = ( value * 10 ) + ( *in - '0' );
   1.191 +		
   1.192 +		if (new_value < value) /* numeric overflow, we rely on you */
   1.193 +			return value;
   1.194 +
   1.195 +		value = new_value;
   1.196 +
   1.197 +		++in;
   1.198 +		++cur;
   1.199 +
   1.200 +		if (max_inout && *max_inout == cur) {
   1.201 +					
   1.202 +			if (out) { /* skip to end */
   1.203 +				while (*in >= '0' && *in <= '9')
   1.204 +					++in;
   1.205 +				*out = in;
   1.206 +			}
   1.207 +
   1.208 +			return value;
   1.209 +		}
   1.210 +	}
   1.211 +	if (out)
   1.212 +		*out = in;
   1.213 +
   1.214 +	if (max_inout)
   1.215 +		*max_inout = cur;
   1.216 +
   1.217 +	return value;
   1.218 +}
   1.219 +
   1.220 +// Number of relevant decimals for floating-point parsing.
   1.221 +#define AI_FAST_ATOF_RELAVANT_DECIMALS 15
   1.222 +
   1.223 +// ------------------------------------------------------------------------------------
   1.224 +//! Provides a fast function for converting a string into a float,
   1.225 +//! about 6 times faster than atof in win32.
   1.226 +// If you find any bugs, please send them to me, niko (at) irrlicht3d.org.
   1.227 +// ------------------------------------------------------------------------------------
   1.228 +template <typename Real>
   1.229 +inline const char* fast_atoreal_move( const char* c, Real& out)
   1.230 +{
   1.231 +	Real f;
   1.232 +
   1.233 +	bool inv = (*c=='-');
   1.234 +	if (inv || *c=='+') {
   1.235 +		++c;
   1.236 +	}
   1.237 +
   1.238 +	f = static_cast<Real>( strtoul10_64 ( c, &c) );
   1.239 +	if (*c == '.' || (c[0] == ',' && c[1] >= '0' && c[1] <= '9')) // allow for commas, too
   1.240 +	{
   1.241 +		++c;
   1.242 +
   1.243 +		// NOTE: The original implementation is highly inaccurate here. The precision of a single
   1.244 +		// IEEE 754 float is not high enough, everything behind the 6th digit tends to be more 
   1.245 +		// inaccurate than it would need to be. Casting to double seems to solve the problem.
   1.246 +		// strtol_64 is used to prevent integer overflow.
   1.247 +
   1.248 +		// Another fix: this tends to become 0 for long numbers if we don't limit the maximum 
   1.249 +		// number of digits to be read. AI_FAST_ATOF_RELAVANT_DECIMALS can be a value between
   1.250 +		// 1 and 15.
   1.251 +		unsigned int diff = AI_FAST_ATOF_RELAVANT_DECIMALS;
   1.252 +		double pl = static_cast<double>( strtoul10_64 ( c, &c, &diff ));
   1.253 +
   1.254 +		pl *= fast_atof_table[diff];
   1.255 +		f += static_cast<Real>( pl );
   1.256 +	}
   1.257 +
   1.258 +	// A major 'E' must be allowed. Necessary for proper reading of some DXF files.
   1.259 +	// Thanks to Zhao Lei to point out that this if() must be outside the if (*c == '.' ..)
   1.260 +	if (*c == 'e' || *c == 'E')	{
   1.261 +
   1.262 +		++c;
   1.263 +		const bool einv = (*c=='-');
   1.264 +		if (einv || *c=='+') {
   1.265 +			++c;
   1.266 +		}
   1.267 +
   1.268 +		// The reason float constants are used here is that we've seen cases where compilers
   1.269 +		// would perform such casts on compile-time constants at runtime, which would be
   1.270 +		// bad considering how frequently fast_atoreal_move<float> is called in Assimp.
   1.271 +		Real exp = static_cast<Real>( strtoul10_64(c, &c) );
   1.272 +		if (einv) {
   1.273 +			exp = -exp;
   1.274 +		}
   1.275 +		f *= pow(static_cast<Real>(10.0f), exp);
   1.276 +	}
   1.277 +
   1.278 +	if (inv) {
   1.279 +		f = -f;
   1.280 +	}
   1.281 +	out = f;
   1.282 +	return c;
   1.283 +}
   1.284 +
   1.285 +// ------------------------------------------------------------------------------------
   1.286 +// The same but more human.
   1.287 +inline float fast_atof(const char* c)
   1.288 +{
   1.289 +	float ret;
   1.290 +	fast_atoreal_move<float>(c, ret);
   1.291 +	return ret;
   1.292 +}
   1.293 +
   1.294 +
   1.295 +inline float fast_atof( const char* c, const char** cout)
   1.296 +{
   1.297 +	float ret;
   1.298 +	*cout = fast_atoreal_move<float>(c, ret);
   1.299 +
   1.300 +	return ret;
   1.301 +}
   1.302 +
   1.303 +inline float fast_atof( const char** inout)
   1.304 +{
   1.305 +	float ret;
   1.306 +	*inout = fast_atoreal_move<float>(*inout, ret);
   1.307 +
   1.308 +	return ret;
   1.309 +}
   1.310 +
   1.311 +
   1.312 +inline double fast_atod(const char* c)
   1.313 +{
   1.314 +	double ret;
   1.315 +	fast_atoreal_move<double>(c, ret);
   1.316 +	return ret;
   1.317 +}
   1.318 +
   1.319 +
   1.320 +inline double fast_atod( const char* c, const char** cout)
   1.321 +{
   1.322 +	double ret;
   1.323 +	*cout = fast_atoreal_move<double>(c, ret);
   1.324 +
   1.325 +	return ret;
   1.326 +}
   1.327 +
   1.328 +inline double fast_atod( const char** inout)
   1.329 +{
   1.330 +	double ret;
   1.331 +	*inout = fast_atoreal_move<double>(*inout, ret);
   1.332 +
   1.333 +	return ret;
   1.334 +}
   1.335 +
   1.336 +} // end of namespace Assimp
   1.337 +
   1.338 +#endif
   1.339 +