@@ -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+
19551969fn replace_tabs ( str : & str ) -> String {
19561970 str. replace ( '\t' , " " )
19571971}
0 commit comments