@@ -1713,18 +1713,8 @@ impl EmitterWriter {
1713
1713
let max_line_num_len = if self . ui_testing {
1714
1714
ANONYMIZED_LINE_NUM . len ( )
1715
1715
} 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)
1728
1718
} ;
1729
1719
1730
1720
match self . emit_message_default ( span, message, code, level, max_line_num_len, false ) {
@@ -1952,6 +1942,30 @@ impl FileWithAnnotatedLines {
1952
1942
}
1953
1943
}
1954
1944
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
+
1955
1969
fn replace_tabs ( str : & str ) -> String {
1956
1970
str. replace ( '\t' , " " )
1957
1971
}
0 commit comments