1/* 2 * Copyright © 2019 Ebrahim Byagowi 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * 24 */ 25 26#ifndef HB_NUMBER_PARSER_HH 27#define HB_NUMBER_PARSER_HH 28 29#include "hb.hh" 30 31#include <float.h> 32 33%%{ 34 35machine double_parser; 36alphtype unsigned char; 37write data; 38 39action see_neg { neg = true; } 40action see_exp_neg { exp_neg = true; } 41 42action add_int { 43 value = value * 10. + (fc - '0'); 44} 45action add_frac { 46 if (likely (frac <= MAX_FRACT / 10)) 47 { 48 frac = frac * 10. + (fc - '0'); 49 ++frac_count; 50 } 51} 52action add_exp { 53 if (likely (exp * 10 + (fc - '0') <= MAX_EXP)) 54 exp = exp * 10 + (fc - '0'); 55 else 56 exp_overflow = true; 57} 58 59num = [0-9]+; 60 61main := ( 62 ( 63 (('+'|'-'@see_neg)? num @add_int) ('.' num @add_frac)? 64 | 65 (('+'|'-'@see_neg)? '.' num @add_frac) 66 ) 67 (('e'|'E') (('+'|'-'@see_exp_neg)? num @add_exp))? 68); 69 70}%% 71 72/* Works only for n < 512 */ 73static inline double 74_pow10 (unsigned int exponent) 75{ 76 static const double _powers_of_10[] = 77 { 78 1.0e+256, 79 1.0e+128, 80 1.0e+64, 81 1.0e+32, 82 1.0e+16, 83 1.0e+8, 84 10000., 85 100., 86 10. 87 }; 88 unsigned int mask = 1 << (ARRAY_LENGTH (_powers_of_10) - 1); 89 double result = 1; 90 for (const double *power = _powers_of_10; mask; ++power, mask >>= 1) 91 if (exponent & mask) result *= *power; 92 return result; 93} 94 95static inline double 96strtod_rl (const char *buf, char **end_ptr) 97{ 98 const char *p, *pe; 99 double value = 0; 100 double frac = 0; 101 double frac_count = 0; 102 unsigned int exp = 0; 103 bool neg = false, exp_neg = false, exp_overflow = false; 104 const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 1^52-1 */ 105 const unsigned int MAX_EXP = 0x7FFu; /* 1^11-1 */ 106 p = buf; 107 pe = p + strlen (p); 108 109 while (p < pe && ISSPACE (*p)) 110 p++; 111 112 int cs; 113 %%{ 114 write init; 115 write exec; 116 }%% 117 118 *end_ptr = (char *) p; 119 120 if (frac_count) value += frac / _pow10 (frac_count); 121 if (neg) value *= -1.; 122 123 if (unlikely (exp_overflow)) 124 { 125 if (value == 0) return value; 126 if (exp_neg) return neg ? -DBL_MIN : DBL_MIN; 127 else return neg ? -DBL_MAX : DBL_MAX; 128 } 129 130 if (exp) 131 { 132 if (exp_neg) value /= _pow10 (exp); 133 else value *= _pow10 (exp); 134 } 135 136 return value; 137} 138 139#endif /* HB_NUMBER_PARSER_HH */ 140