about summary refs log tree commit diff
path: root/compiler/rustc_errors
diff options
context:
space:
mode:
authorAndre Bogus <bogusandre@gmail.com>2021-02-26 22:00:16 +0100
committerAndre Bogus <bogusandre@gmail.com>2021-02-27 15:28:58 +0100
commit8abc5fd3be35c39fdb93335acebf15dbbac180be (patch)
tree5d3cf092fa1d8c5d2d00b84bd2b76795d5195c79 /compiler/rustc_errors
parentcecdb181ade91c0a5ffab9a148dba68fc7d00ee3 (diff)
downloadrust-8abc5fd3be35c39fdb93335acebf15dbbac180be.tar.gz
rust-8abc5fd3be35c39fdb93335acebf15dbbac180be.zip
Even faster counting of digits for error line numbers
Diffstat (limited to 'compiler/rustc_errors')
-rw-r--r--compiler/rustc_errors/src/emitter.rs38
1 files changed, 26 insertions, 12 deletions
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 42c3d5e48fe..9b6f67166bd 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -1713,18 +1713,8 @@ impl EmitterWriter {
         let max_line_num_len = if self.ui_testing {
             ANONYMIZED_LINE_NUM.len()
         } else {
-            // Instead of using .to_string().len(), we iteratively count the
-            // number of digits to avoid allocation. This strategy has sizable
-            // performance gains over the old string strategy.
-            let mut n = self.get_max_line_num(span, children);
-            let mut num_digits = 0;
-            loop {
-                num_digits += 1;
-                n /= 10;
-                if n == 0 {
-                    break num_digits;
-                }
-            }
+            let n = self.get_max_line_num(span, children);
+            num_decimal_digits(n)
         };
 
         match self.emit_message_default(span, message, code, level, max_line_num_len, false) {
@@ -1952,6 +1942,30 @@ impl FileWithAnnotatedLines {
     }
 }
 
+// instead of taking the String length or dividing by 10 while > 0, we multiply a limit by 10 until
+// we're higher. If the loop isn't exited by the `return`, the last multiplication will wrap, which
+// is OK, because while we cannot fit a higher power of 10 in a usize, the loop will end anyway.
+// This is also why we need the max number of decimal digits within a `usize`.
+fn num_decimal_digits(num: usize) -> usize {
+    #[cfg(target_pointer_width = "64")]
+    const MAX_DIGITS: usize = 20;
+
+    #[cfg(target_pointer_width = "32")]
+    const MAX_DIGITS: usize = 10;
+
+    #[cfg(target_pointer_width = "16")]
+    const MAX_DIGITS: usize = 5;
+
+    let mut lim = 10;
+    for num_digits in 1..MAX_DIGITS {
+        if num < lim {
+            return num_digits;
+        }
+        lim = lim.wrapping_mul(10);
+    }
+    MAX_DIGITS
+}
+
 fn replace_tabs(str: &str) -> String {
     str.replace('\t', "    ")
 }