Skip to content

Commit 8abc5fd

Browse files
committed
Even faster counting of digits for error line numbers
1 parent cecdb18 commit 8abc5fd

File tree

1 file changed

+26
-12
lines changed

1 file changed

+26
-12
lines changed

compiler/rustc_errors/src/emitter.rs

+26-12
Original file line numberDiff line numberDiff line change
@@ -1713,18 +1713,8 @@ impl EmitterWriter {
17131713
let max_line_num_len = if self.ui_testing {
17141714
ANONYMIZED_LINE_NUM.len()
17151715
} else {
1716-
// Instead of using .to_string().len(), we iteratively count the
1717-
// number of digits to avoid allocation. This strategy has sizable
1718-
// performance gains over the old string strategy.
1719-
let mut n = self.get_max_line_num(span, children);
1720-
let mut num_digits = 0;
1721-
loop {
1722-
num_digits += 1;
1723-
n /= 10;
1724-
if n == 0 {
1725-
break num_digits;
1726-
}
1727-
}
1716+
let n = self.get_max_line_num(span, children);
1717+
num_decimal_digits(n)
17281718
};
17291719

17301720
match self.emit_message_default(span, message, code, level, max_line_num_len, false) {
@@ -1952,6 +1942,30 @@ impl FileWithAnnotatedLines {
19521942
}
19531943
}
19541944

1945+
// instead of taking the String length or dividing by 10 while > 0, we multiply a limit by 10 until
1946+
// we're higher. If the loop isn't exited by the `return`, the last multiplication will wrap, which
1947+
// is OK, because while we cannot fit a higher power of 10 in a usize, the loop will end anyway.
1948+
// This is also why we need the max number of decimal digits within a `usize`.
1949+
fn num_decimal_digits(num: usize) -> usize {
1950+
#[cfg(target_pointer_width = "64")]
1951+
const MAX_DIGITS: usize = 20;
1952+
1953+
#[cfg(target_pointer_width = "32")]
1954+
const MAX_DIGITS: usize = 10;
1955+
1956+
#[cfg(target_pointer_width = "16")]
1957+
const MAX_DIGITS: usize = 5;
1958+
1959+
let mut lim = 10;
1960+
for num_digits in 1..MAX_DIGITS {
1961+
if num < lim {
1962+
return num_digits;
1963+
}
1964+
lim = lim.wrapping_mul(10);
1965+
}
1966+
MAX_DIGITS
1967+
}
1968+
19551969
fn replace_tabs(str: &str) -> String {
19561970
str.replace('\t', " ")
19571971
}

0 commit comments

Comments
 (0)