Skip to content

Commit 3841805

Browse files
committed
Tidy up write_scientific_big buffer handling and names
Add a write_upto helper to truncate directly into the caller buffer, collapsing the repeated bounded memcpy sites. Rename num_sig/avail to num_req_digits/num_avail_digits, frac to num_frac_digits, and drop the now-redundant min when computing available digits.
1 parent 1b0bd43 commit 3841805

1 file changed

Lines changed: 30 additions & 28 deletions

File tree

zmij.cc

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,15 @@ auto write_inf_nan(char* buffer, bool is_nan) noexcept -> char* {
11151115
return memcpy(buffer, is_nan ? "nan" : "inf", 4), buffer + 3;
11161116
}
11171117

1118+
// Copies at most `end - dst` bytes of `src[0..n)` to `dst`, returning the end
1119+
// of the written range.
1120+
ZMIJ_INLINE auto write_upto(char* dst, char* end, const char* src,
1121+
size_t n) noexcept -> char* {
1122+
size_t take = n < size_t(end - dst) ? n : size_t(end - dst);
1123+
memcpy(dst, src, take);
1124+
return dst + take;
1125+
}
1126+
11181127
// Writes zero in fixed notation, e.g. "0.000" (or "0" when precision is 0).
11191128
ZMIJ_INLINE auto write_zero(char* buffer, int precision) noexcept -> char* {
11201129
*buffer++ = '0';
@@ -1662,17 +1671,13 @@ auto write_scientific_big(double value, int precision, char* out,
16621671
char digits[805]; // num < 2**2668 has at most 804 digits, plus a carry digit.
16631672
digits[0] = '0';
16641673
char* p = digits;
1665-
int num_sig = precision + 1; // significant digits requested
1666-
int avail = 1; // significant digits available to emit (>= 1)
1667-
int lead_exp = 0; // exponent of the leading digit
1674+
int num_avail_digits = 1; // significant digits to emit (>= 1)
1675+
int lead_exp = 0; // exponent of the leading digit
16681676

16691677
bool is_normal = unsigned(raw_exp - 1) < unsigned(traits::exp_mask - 1);
16701678
if (!is_normal) [[ZMIJ_UNLIKELY]] {
1671-
if (raw_exp != 0) { // inf or nan
1672-
size_t size = size_t(end - dst) < 3 ? size_t(end - dst) : 3;
1673-
memcpy(dst, bin_sig != 0 ? "nan" : "inf", size);
1674-
return dst + size;
1675-
}
1679+
if (raw_exp != 0) // inf or nan
1680+
return write_upto(dst, end, bin_sig != 0 ? "nan" : "inf", 3);
16761681
if (bin_sig != 0) normalize<double>(bin_sig, raw_exp);
16771682
}
16781683

@@ -1696,23 +1701,24 @@ auto write_scientific_big(double value, int precision, char* out,
16961701
int num_digits = int(digits + sizeof(digits) - p);
16971702
lead_exp = num_digits - 1 + base_exp;
16981703

1699-
// Round to num_sig significant digits, ties to even.
1700-
if (num_digits > num_sig) {
1701-
char dropped = p[num_sig];
1704+
int num_req_digits = precision + 1;
1705+
// Round to num_req_digits significant digits, ties to even.
1706+
if (num_digits > num_req_digits) {
1707+
char dropped = p[num_req_digits];
17021708
bool round_up = dropped > '5';
17031709
// A dropped 5 is a tie unless a lower nonzero digit makes it sticky.
17041710
if (dropped == '5') {
1705-
round_up = (p[num_sig - 1] - '0') & 1;
1706-
for (char* q = p + num_sig + 1; q < p + num_digits; ++q) {
1711+
round_up = (p[num_req_digits - 1] - '0') & 1;
1712+
for (char* q = p + num_req_digits + 1; q < p + num_digits; ++q) {
17071713
if (*q != '0') {
17081714
round_up = true;
17091715
break;
17101716
}
17111717
}
17121718
}
1713-
num_digits = num_sig;
1719+
num_digits = num_req_digits;
17141720
if (round_up) {
1715-
char* q = p + num_sig - 1;
1721+
char* q = p + num_req_digits - 1;
17161722
// Propagate the carry over trailing nines.
17171723
while (*q == '9') *q-- = '0';
17181724
// 999.. rolling over to 1000.. adds a significant digit.
@@ -1724,26 +1730,22 @@ auto write_scientific_big(double value, int precision, char* out,
17241730
}
17251731
}
17261732
}
1727-
avail = num_digits < num_sig ? num_digits : num_sig;
1733+
num_avail_digits = num_digits;
17281734
}
17291735

17301736
// Emit d.ddd...e±XX with `precision` fractional digits, zero-padded, writing
17311737
// at most `end - dst` characters.
17321738
if (dst < end) *dst++ = p[0];
17331739
if (dst < end) *dst++ = '.';
1734-
size_t frac = size_t(avail - 1);
1735-
size_t take = frac < size_t(end - dst) ? frac : size_t(end - dst);
1736-
memcpy(dst, p + 1, take);
1737-
dst += take;
1738-
size_t zeros = size_t(precision) - frac;
1739-
take = zeros < size_t(end - dst) ? zeros : size_t(end - dst);
1740-
memset(dst, '0', take);
1741-
dst += take;
1740+
int num_frac_digits = num_avail_digits - 1;
1741+
dst = write_upto(dst, end, p + 1, size_t(num_frac_digits));
1742+
int num_zeros = precision - num_frac_digits;
1743+
if (num_zeros > end - dst) num_zeros = int(end - dst);
1744+
memset(dst, '0', num_zeros);
1745+
dst += num_zeros;
17421746
char exp[8];
1743-
size_t exp_len = size_t(write_exp<double>(exp, lead_exp) - exp);
1744-
take = exp_len < size_t(end - dst) ? exp_len : size_t(end - dst);
1745-
memcpy(dst, exp, take);
1746-
return dst + take;
1747+
char* exp_end = write_exp<double>(exp, lead_exp);
1748+
return write_upto(dst, end, exp, size_t(exp_end - exp));
17471749
}
17481750

17491751
template <typename Float>

0 commit comments

Comments
 (0)