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