1*c43cad87SWarner Losh #include "jemalloc/internal/jemalloc_preamble.h" 2*c43cad87SWarner Losh #include "jemalloc/internal/jemalloc_internal_includes.h" 3*c43cad87SWarner Losh 4*c43cad87SWarner Losh #include "jemalloc/internal/fxp.h" 5*c43cad87SWarner Losh 6*c43cad87SWarner Losh static bool 7*c43cad87SWarner Losh fxp_isdigit(char c) { 8*c43cad87SWarner Losh return '0' <= c && c <= '9'; 9*c43cad87SWarner Losh } 10*c43cad87SWarner Losh 11*c43cad87SWarner Losh bool 12*c43cad87SWarner Losh fxp_parse(fxp_t *result, const char *str, char **end) { 13*c43cad87SWarner Losh /* 14*c43cad87SWarner Losh * Using malloc_strtoumax in this method isn't as handy as you might 15*c43cad87SWarner Losh * expect (I tried). In the fractional part, significant leading zeros 16*c43cad87SWarner Losh * mean that you still need to do your own parsing, now with trickier 17*c43cad87SWarner Losh * math. In the integer part, the casting (uintmax_t to uint32_t) 18*c43cad87SWarner Losh * forces more reasoning about bounds than just checking for overflow as 19*c43cad87SWarner Losh * we parse. 20*c43cad87SWarner Losh */ 21*c43cad87SWarner Losh uint32_t integer_part = 0; 22*c43cad87SWarner Losh 23*c43cad87SWarner Losh const char *cur = str; 24*c43cad87SWarner Losh 25*c43cad87SWarner Losh /* The string must start with a digit or a decimal point. */ 26*c43cad87SWarner Losh if (*cur != '.' && !fxp_isdigit(*cur)) { 27*c43cad87SWarner Losh return true; 28*c43cad87SWarner Losh } 29*c43cad87SWarner Losh 30*c43cad87SWarner Losh while ('0' <= *cur && *cur <= '9') { 31*c43cad87SWarner Losh integer_part *= 10; 32*c43cad87SWarner Losh integer_part += *cur - '0'; 33*c43cad87SWarner Losh if (integer_part >= (1U << 16)) { 34*c43cad87SWarner Losh return true; 35*c43cad87SWarner Losh } 36*c43cad87SWarner Losh cur++; 37*c43cad87SWarner Losh } 38*c43cad87SWarner Losh 39*c43cad87SWarner Losh /* 40*c43cad87SWarner Losh * We've parsed all digits at the beginning of the string, without 41*c43cad87SWarner Losh * overflow. Either we're done, or there's a fractional part. 42*c43cad87SWarner Losh */ 43*c43cad87SWarner Losh if (*cur != '.') { 44*c43cad87SWarner Losh *result = (integer_part << 16); 45*c43cad87SWarner Losh if (end != NULL) { 46*c43cad87SWarner Losh *end = (char *)cur; 47*c43cad87SWarner Losh } 48*c43cad87SWarner Losh return false; 49*c43cad87SWarner Losh } 50*c43cad87SWarner Losh 51*c43cad87SWarner Losh /* There's a fractional part. */ 52*c43cad87SWarner Losh cur++; 53*c43cad87SWarner Losh if (!fxp_isdigit(*cur)) { 54*c43cad87SWarner Losh /* Shouldn't end on the decimal point. */ 55*c43cad87SWarner Losh return true; 56*c43cad87SWarner Losh } 57*c43cad87SWarner Losh 58*c43cad87SWarner Losh /* 59*c43cad87SWarner Losh * We use a lot of precision for the fractional part, even though we'll 60*c43cad87SWarner Losh * discard most of it; this lets us get exact values for the important 61*c43cad87SWarner Losh * special case where the denominator is a small power of 2 (for 62*c43cad87SWarner Losh * instance, 1/512 == 0.001953125 is exactly representable even with 63*c43cad87SWarner Losh * only 16 bits of fractional precision). We need to left-shift by 16 64*c43cad87SWarner Losh * before dividing so we pick the number of digits to be 65*c43cad87SWarner Losh * floor(log(2**48)) = 14. 66*c43cad87SWarner Losh */ 67*c43cad87SWarner Losh uint64_t fractional_part = 0; 68*c43cad87SWarner Losh uint64_t frac_div = 1; 69*c43cad87SWarner Losh for (int i = 0; i < FXP_FRACTIONAL_PART_DIGITS; i++) { 70*c43cad87SWarner Losh fractional_part *= 10; 71*c43cad87SWarner Losh frac_div *= 10; 72*c43cad87SWarner Losh if (fxp_isdigit(*cur)) { 73*c43cad87SWarner Losh fractional_part += *cur - '0'; 74*c43cad87SWarner Losh cur++; 75*c43cad87SWarner Losh } 76*c43cad87SWarner Losh } 77*c43cad87SWarner Losh /* 78*c43cad87SWarner Losh * We only parse the first maxdigits characters, but we can still ignore 79*c43cad87SWarner Losh * any digits after that. 80*c43cad87SWarner Losh */ 81*c43cad87SWarner Losh while (fxp_isdigit(*cur)) { 82*c43cad87SWarner Losh cur++; 83*c43cad87SWarner Losh } 84*c43cad87SWarner Losh 85*c43cad87SWarner Losh assert(fractional_part < frac_div); 86*c43cad87SWarner Losh uint32_t fractional_repr = (uint32_t)( 87*c43cad87SWarner Losh (fractional_part << 16) / frac_div); 88*c43cad87SWarner Losh 89*c43cad87SWarner Losh /* Success! */ 90*c43cad87SWarner Losh *result = (integer_part << 16) + fractional_repr; 91*c43cad87SWarner Losh if (end != NULL) { 92*c43cad87SWarner Losh *end = (char *)cur; 93*c43cad87SWarner Losh } 94*c43cad87SWarner Losh return false; 95*c43cad87SWarner Losh } 96*c43cad87SWarner Losh 97*c43cad87SWarner Losh void 98*c43cad87SWarner Losh fxp_print(fxp_t a, char buf[FXP_BUF_SIZE]) { 99*c43cad87SWarner Losh uint32_t integer_part = fxp_round_down(a); 100*c43cad87SWarner Losh uint32_t fractional_part = (a & ((1U << 16) - 1)); 101*c43cad87SWarner Losh 102*c43cad87SWarner Losh int leading_fraction_zeros = 0; 103*c43cad87SWarner Losh uint64_t fraction_digits = fractional_part; 104*c43cad87SWarner Losh for (int i = 0; i < FXP_FRACTIONAL_PART_DIGITS; i++) { 105*c43cad87SWarner Losh if (fraction_digits < (1U << 16) 106*c43cad87SWarner Losh && fraction_digits * 10 >= (1U << 16)) { 107*c43cad87SWarner Losh leading_fraction_zeros = i; 108*c43cad87SWarner Losh } 109*c43cad87SWarner Losh fraction_digits *= 10; 110*c43cad87SWarner Losh } 111*c43cad87SWarner Losh fraction_digits >>= 16; 112*c43cad87SWarner Losh while (fraction_digits > 0 && fraction_digits % 10 == 0) { 113*c43cad87SWarner Losh fraction_digits /= 10; 114*c43cad87SWarner Losh } 115*c43cad87SWarner Losh 116*c43cad87SWarner Losh size_t printed = malloc_snprintf(buf, FXP_BUF_SIZE, "%"FMTu32".", 117*c43cad87SWarner Losh integer_part); 118*c43cad87SWarner Losh for (int i = 0; i < leading_fraction_zeros; i++) { 119*c43cad87SWarner Losh buf[printed] = '0'; 120*c43cad87SWarner Losh printed++; 121*c43cad87SWarner Losh } 122*c43cad87SWarner Losh malloc_snprintf(&buf[printed], FXP_BUF_SIZE - printed, "%"FMTu64, 123*c43cad87SWarner Losh fraction_digits); 124*c43cad87SWarner Losh } 125