[number] Make hb_parse_double simpler now that we don't have to mimic strtod

This commit is contained in:
Ebrahim Byagowi 2020-05-10 16:57:45 +04:30
parent 44fe1c8ff1
commit dca8ba6b6d
4 changed files with 33 additions and 50 deletions

View File

@ -96,7 +96,7 @@ static const int double_parser_en_main = 1;
/* Works only for n < 512 */ /* Works only for n < 512 */
static inline double static inline double
_pow10 (unsigned int exponent) _pow10 (unsigned exponent)
{ {
static const double _powers_of_10[] = static const double _powers_of_10[] =
{ {
@ -110,38 +110,39 @@ _pow10 (unsigned int exponent)
100., 100.,
10. 10.
}; };
unsigned int mask = 1 << (ARRAY_LENGTH (_powers_of_10) - 1); unsigned mask = 1 << (ARRAY_LENGTH (_powers_of_10) - 1);
double result = 1; double result = 1;
for (const double *power = _powers_of_10; mask; ++power, mask >>= 1) for (const double *power = _powers_of_10; mask; ++power, mask >>= 1)
if (exponent & mask) result *= *power; if (exponent & mask) result *= *power;
return result; return result;
} }
/* a variant of strtod that also gets end of buffer in its second argument */
static inline double static inline double
strtod_rl (const char *buf, char **end_ptr) strtod_rl (const char *buf, const char **end_ptr /* IN/OUT */)
{ {
const char *p, *pe; const char *p, *pe;
double value = 0; double value = 0;
double frac = 0; double frac = 0;
double frac_count = 0; double frac_count = 0;
unsigned int exp = 0; unsigned exp = 0;
bool neg = false, exp_neg = false, exp_overflow = false; bool neg = false, exp_neg = false, exp_overflow = false;
const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 2^52-1 */ const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 2^52-1 */
const unsigned int MAX_EXP = 0x7FFu; /* 2^11-1 */ const unsigned MAX_EXP = 0x7FFu; /* 2^11-1 */
p = buf; p = buf;
pe = p + strlen (p); pe = *end_ptr;
while (p < pe && ISSPACE (*p)) while (p < pe && ISSPACE (*p))
p++; p++;
int cs; int cs;
#line 140 "hb-number-parser.hh" #line 141 "hb-number-parser.hh"
{ {
cs = double_parser_start; cs = double_parser_start;
} }
#line 145 "hb-number-parser.hh" #line 146 "hb-number-parser.hh"
{ {
int _slen; int _slen;
int _trans; int _trans;
@ -199,7 +200,7 @@ _resume:
exp_overflow = true; exp_overflow = true;
} }
break; break;
#line 203 "hb-number-parser.hh" #line 204 "hb-number-parser.hh"
} }
_again: _again:
@ -211,10 +212,10 @@ _again:
_out: {} _out: {}
} }
#line 114 "hb-number-parser.rl" #line 115 "hb-number-parser.rl"
*end_ptr = (char *) p; *end_ptr = (const char *) p;
if (frac_count) value += frac / _pow10 (frac_count); if (frac_count) value += frac / _pow10 (frac_count);
if (neg) value *= -1.; if (neg) value *= -1.;

View File

@ -69,7 +69,7 @@ main := (
/* Works only for n < 512 */ /* Works only for n < 512 */
static inline double static inline double
_pow10 (unsigned int exponent) _pow10 (unsigned exponent)
{ {
static const double _powers_of_10[] = static const double _powers_of_10[] =
{ {
@ -83,26 +83,27 @@ _pow10 (unsigned int exponent)
100., 100.,
10. 10.
}; };
unsigned int mask = 1 << (ARRAY_LENGTH (_powers_of_10) - 1); unsigned mask = 1 << (ARRAY_LENGTH (_powers_of_10) - 1);
double result = 1; double result = 1;
for (const double *power = _powers_of_10; mask; ++power, mask >>= 1) for (const double *power = _powers_of_10; mask; ++power, mask >>= 1)
if (exponent & mask) result *= *power; if (exponent & mask) result *= *power;
return result; return result;
} }
/* a variant of strtod that also gets end of buffer in its second argument */
static inline double static inline double
strtod_rl (const char *buf, char **end_ptr) strtod_rl (const char *buf, const char **end_ptr /* IN/OUT */)
{ {
const char *p, *pe; const char *p, *pe;
double value = 0; double value = 0;
double frac = 0; double frac = 0;
double frac_count = 0; double frac_count = 0;
unsigned int exp = 0; unsigned exp = 0;
bool neg = false, exp_neg = false, exp_overflow = false; bool neg = false, exp_neg = false, exp_overflow = false;
const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 2^52-1 */ const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 2^52-1 */
const unsigned int MAX_EXP = 0x7FFu; /* 2^11-1 */ const unsigned MAX_EXP = 0x7FFu; /* 2^11-1 */
p = buf; p = buf;
pe = p + strlen (p); pe = *end_ptr;
while (p < pe && ISSPACE (*p)) while (p < pe && ISSPACE (*p))
p++; p++;
@ -113,7 +114,7 @@ strtod_rl (const char *buf, char **end_ptr)
write exec; write exec;
}%% }%%
*end_ptr = (char *) p; *end_ptr = (const char *) p;
if (frac_count) value += frac / _pow10 (frac_count); if (frac_count) value += frac / _pow10 (frac_count);
if (neg) value *= -1.; if (neg) value *= -1.;

View File

@ -34,8 +34,7 @@ _parse_number (const char **pp, const char *end, T *pv,
bool whole_buffer, Func f) bool whole_buffer, Func f)
{ {
char buf[32]; char buf[32];
unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1, unsigned len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned) (end - *pp));
(unsigned int) (end - *pp));
strncpy (buf, *pp, len); strncpy (buf, *pp, len);
buf[len] = '\0'; buf[len] = '\0';
@ -46,7 +45,8 @@ _parse_number (const char **pp, const char *end, T *pv,
*pv = f (p, &pend); *pv = f (p, &pend);
if (unlikely (errno || p == pend || if (unlikely (errno || p == pend ||
/* Check if consumed whole buffer if is requested */ /* Check if consumed whole buffer if is requested */
(whole_buffer && pend - p != end - *pp))) return false; (whole_buffer && pend - p != end - *pp)))
return false;
*pp += pend - p; *pp += pend - p;
return true; return true;
@ -61,19 +61,20 @@ hb_parse_int (const char **pp, const char *end, int *pv, bool whole_buffer)
} }
bool bool
hb_parse_uint (const char **pp, const char *end, unsigned int *pv, hb_parse_uint (const char **pp, const char *end, unsigned *pv,
bool whole_buffer, int base) bool whole_buffer, int base)
{ {
return _parse_number<unsigned int> (pp, end, pv, whole_buffer, return _parse_number<unsigned> (pp, end, pv, whole_buffer,
[base] (const char *p, char **end) [base] (const char *p, char **end)
{ return strtoul (p, end, base); }); { return strtoul (p, end, base); });
} }
bool bool
hb_parse_double (const char **pp, const char *end, double *pv, hb_parse_double (const char **pp, const char *end, double *pv, bool whole_buffer)
bool whole_buffer)
{ {
return _parse_number<double> (pp, end, pv, whole_buffer, const char *pend = end;
[] (const char *p, char **end) *pv = strtod_rl (*pp, &pend);
{ return strtod_rl (p, end); }); if (unlikely (*pp == pend)) return false;
*pp = pend;
return !whole_buffer || end == pend;
} }

View File

@ -25,7 +25,6 @@
#include "hb.hh" #include "hb.hh"
#include "hb-number.hh" #include "hb-number.hh"
#include "hb-number-parser.hh"
int int
@ -170,10 +169,6 @@ main (int argc, char **argv)
assert ((int) roundf (pv * 1000.) == 123); assert ((int) roundf (pv * 1000.) == 123);
assert (pp - str == 7); assert (pp - str == 7);
assert (end - pp == 0); assert (end - pp == 0);
char *pend;
assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == 123);
assert (pend - str == 7);
} }
{ {
@ -186,10 +181,6 @@ main (int argc, char **argv)
assert ((int) roundf (pv * 1000.) == 123); assert ((int) roundf (pv * 1000.) == 123);
assert (pp - str == 6); assert (pp - str == 6);
assert (end - pp == 0); assert (end - pp == 0);
char *pend;
assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == 123);
assert (pend - str == 6);
} }
{ {
@ -202,10 +193,6 @@ main (int argc, char **argv)
assert ((int) roundf (pv * 1000.) == 123); assert ((int) roundf (pv * 1000.) == 123);
assert (pp - str == 10); assert (pp - str == 10);
assert (end - pp == 0); assert (end - pp == 0);
char *pend;
assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == 123);
assert (pend - str == 10);
} }
{ {
@ -219,9 +206,6 @@ main (int argc, char **argv)
assert (pp - str == 13); assert (pp - str == 13);
assert (end - pp == 0); assert (end - pp == 0);
char *pend;
assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == -123);
assert (pend - str == 13);
} }
{ {
@ -234,10 +218,6 @@ main (int argc, char **argv)
assert ((int) roundf (pv * 1000.) == -123); assert ((int) roundf (pv * 1000.) == -123);
assert (pp - str == 8); assert (pp - str == 8);
assert (end - pp == 0); assert (end - pp == 0);
char *pend;
assert ((int) roundf (strtod_rl (str, &pend) * 1000.) == -123);
assert (pend - str == 8);
} }
return 0; return 0;