@@ -10,9 +10,6 @@ use crate::{fmt, ptr, slice, str};
1010trait DisplayInt :
1111 PartialEq + PartialOrd + Div < Output = Self > + Rem < Output = Self > + Sub < Output = Self > + Copy
1212{
13- fn zero ( ) -> Self ;
14- fn from_u8 ( u : u8 ) -> Self ;
15- fn to_u8 ( & self ) -> u8 ;
1613 #[ cfg( not( any( target_pointer_width = "64" , target_arch = "wasm32" ) ) ) ]
1714 fn to_u32 ( & self ) -> u32 ;
1815 fn to_u64 ( & self ) -> u64 ;
@@ -22,9 +19,6 @@ trait DisplayInt:
2219macro_rules! impl_int {
2320 ( $( $t: ident) * ) => (
2421 $( impl DisplayInt for $t {
25- fn zero( ) -> Self { 0 }
26- fn from_u8( u: u8 ) -> Self { u as Self }
27- fn to_u8( & self ) -> u8 { * self as u8 }
2822 #[ cfg( not( any( target_pointer_width = "64" , target_arch = "wasm32" ) ) ) ]
2923 fn to_u32( & self ) -> u32 { * self as u32 }
3024 fn to_u64( & self ) -> u64 { * self as u64 }
@@ -38,137 +32,76 @@ impl_int! {
3832 u8 u16 u32 u64 u128 usize
3933}
4034
41- /// A type that represents a specific radix
42- ///
43- /// # Safety
44- ///
45- /// `digit` must return an ASCII character.
46- #[ doc( hidden) ]
47- unsafe trait GenericRadix : Sized {
48- /// The number of digits.
49- const BASE : u8 ;
50-
51- /// A radix-specific prefix string.
52- const PREFIX : & ' static str ;
53-
54- /// Converts an integer to corresponding radix digit.
55- fn digit ( x : u8 ) -> u8 ;
56-
57- /// Format an unsigned integer using the radix using a formatter.
58- fn fmt_int < T : DisplayInt > ( & self , mut x : T , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
59- // The radix can be as low as 2, so we need a buffer of at least 128
60- // characters for a base 2 number.
61- let zero = T :: zero ( ) ;
62- let mut buf = [ MaybeUninit :: < u8 > :: uninit ( ) ; 128 ] ;
63- let mut offset = buf. len ( ) ;
64- let base = T :: from_u8 ( Self :: BASE ) ;
65-
66- // Accumulate each digit of the number from the least significant
67- // to the most significant figure.
68- loop {
69- let n = x % base; // Get the current place value.
70- x = x / base; // Deaccumulate the number.
71- offset -= 1 ;
72- buf[ offset] . write ( Self :: digit ( n. to_u8 ( ) ) ) ; // Store the digit in the buffer.
73- if x == zero {
74- // No more digits left to accumulate.
75- break ;
76- } ;
77- }
35+ /// Formatting of integers with a non-decimal radix.
36+ macro_rules! radix_integer {
37+ ( fmt:: $Trait: ident for $Signed: ident and $Unsigned: ident, $prefix: literal, $dig_tab: literal) => {
38+ #[ stable( feature = "rust1" , since = "1.0.0" ) ]
39+ impl fmt:: $Trait for $Unsigned {
40+ /// Format unsigned integers in the radix.
41+ fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
42+ // Check macro arguments at compile time.
43+ const {
44+ assert!( $Unsigned:: MIN == 0 , "need unsigned" ) ;
45+ assert!( $dig_tab. is_ascii( ) , "need single-byte entries" ) ;
46+ }
7847
79- // SAFETY: Starting from `offset`, all elements of the slice have been set.
80- let digits = unsafe { slice_buffer_to_str ( & buf, offset) } ;
81- f. pad_integral ( true , Self :: PREFIX , digits)
82- }
83- }
48+ // ASCII digits in ascending order are used as a lookup table.
49+ const DIG_TAB : & [ u8 ] = $dig_tab;
50+ const BASE : $Unsigned = DIG_TAB . len( ) as $Unsigned;
51+ const MAX_DIG_N : usize = $Unsigned:: MAX . ilog( BASE ) as usize + 1 ;
52+
53+ // Buffer digits of self with right alignment.
54+ let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; MAX_DIG_N ] ;
55+ // Count the number of bytes in buf that are not initialized.
56+ let mut offset = buf. len( ) ;
8457
85- /// A binary (base 2) radix
86- #[ derive( Clone , PartialEq ) ]
87- struct Binary ;
88-
89- /// An octal (base 8) radix
90- #[ derive( Clone , PartialEq ) ]
91- struct Octal ;
92-
93- /// A hexadecimal (base 16) radix, formatted with lower-case characters
94- #[ derive( Clone , PartialEq ) ]
95- struct LowerHex ;
96-
97- /// A hexadecimal (base 16) radix, formatted with upper-case characters
98- #[ derive( Clone , PartialEq ) ]
99- struct UpperHex ;
100-
101- macro_rules! radix {
102- ( $T: ident, $base: expr, $prefix: expr, $( $x: pat => $conv: expr) ,+) => {
103- unsafe impl GenericRadix for $T {
104- const BASE : u8 = $base;
105- const PREFIX : & ' static str = $prefix;
106- fn digit( x: u8 ) -> u8 {
107- match x {
108- $( $x => $conv, ) +
109- x => panic!( "number not in the range 0..={}: {}" , Self :: BASE - 1 , x) ,
58+ // Accumulate each digit of the number from the least
59+ // significant to the most significant figure.
60+ let mut remain = * self ;
61+ loop {
62+ let digit = remain % BASE ;
63+ remain /= BASE ;
64+
65+ offset -= 1 ;
66+ // SAFETY: `remain` will reach 0 and we will break before `offset` wraps
67+ unsafe { core:: hint:: assert_unchecked( offset < buf. len( ) ) }
68+ buf[ offset] . write( DIG_TAB [ digit as usize ] ) ;
69+ if remain == 0 {
70+ break ;
71+ }
11072 }
73+
74+ // SAFETY: Starting from `offset`, all elements of the slice have been set.
75+ let digits = unsafe { slice_buffer_to_str( & buf, offset) } ;
76+ f. pad_integral( true , $prefix, digits)
11177 }
11278 }
113- }
114- }
115-
116- radix ! { Binary , 2 , "0b" , x @ 0 ..= 1 => b'0' + x }
117- radix ! { Octal , 8 , "0o" , x @ 0 ..= 7 => b'0' + x }
118- radix ! { LowerHex , 16 , "0x" , x @ 0 ..= 9 => b'0' + x, x @ 10 ..= 15 => b'a' + ( x - 10 ) }
119- radix ! { UpperHex , 16 , "0x" , x @ 0 ..= 9 => b'0' + x, x @ 10 ..= 15 => b'A' + ( x - 10 ) }
12079
121- macro_rules! int_base {
122- ( fmt:: $Trait: ident for $T: ident -> $Radix: ident) => {
12380 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
124- impl fmt:: $Trait for $T {
81+ impl fmt:: $Trait for $Signed {
82+ /// Format signed integers in the two’s-complement form.
12583 fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
126- $Radix . fmt_int ( * self , f)
84+ fmt :: $Trait :: fmt ( & self . cast_unsigned ( ) , f)
12785 }
12886 }
12987 } ;
13088}
13189
132- macro_rules! integer {
133- ( $Int: ident, $Uint: ident) => {
134- int_base! { fmt:: Binary for $Uint -> Binary }
135- int_base! { fmt:: Octal for $Uint -> Octal }
136- int_base! { fmt:: LowerHex for $Uint -> LowerHex }
137- int_base! { fmt:: UpperHex for $Uint -> UpperHex }
138-
139- // Format signed integers as unsigned (two’s complement representation).
140- #[ stable( feature = "rust1" , since = "1.0.0" ) ]
141- impl fmt:: Binary for $Int {
142- fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
143- fmt:: Binary :: fmt( & self . cast_unsigned( ) , f)
144- }
145- }
146- #[ stable( feature = "rust1" , since = "1.0.0" ) ]
147- impl fmt:: Octal for $Int {
148- fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
149- fmt:: Octal :: fmt( & self . cast_unsigned( ) , f)
150- }
151- }
152- #[ stable( feature = "rust1" , since = "1.0.0" ) ]
153- impl fmt:: LowerHex for $Int {
154- fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
155- fmt:: LowerHex :: fmt( & self . cast_unsigned( ) , f)
156- }
157- }
158- #[ stable( feature = "rust1" , since = "1.0.0" ) ]
159- impl fmt:: UpperHex for $Int {
160- fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
161- fmt:: UpperHex :: fmt( & self . cast_unsigned( ) , f)
162- }
163- }
90+ /// Formatting of integers with a non-decimal radix.
91+ macro_rules! radix_integers {
92+ ( $Signed: ident, $Unsigned: ident) => {
93+ radix_integer! { fmt:: Binary for $Signed and $Unsigned, "0b" , b"01" }
94+ radix_integer! { fmt:: Octal for $Signed and $Unsigned, "0o" , b"01234567" }
95+ radix_integer! { fmt:: LowerHex for $Signed and $Unsigned, "0x" , b"0123456789abcdef" }
96+ radix_integer! { fmt:: UpperHex for $Signed and $Unsigned, "0x" , b"0123456789ABCDEF" }
16497 } ;
16598}
166- integer ! { isize , usize }
167- integer ! { i8 , u8 }
168- integer ! { i16 , u16 }
169- integer ! { i32 , u32 }
170- integer ! { i64 , u64 }
171- integer ! { i128 , u128 }
99+ radix_integers ! { isize , usize }
100+ radix_integers ! { i8 , u8 }
101+ radix_integers ! { i16 , u16 }
102+ radix_integers ! { i32 , u32 }
103+ radix_integers ! { i64 , u64 }
104+ radix_integers ! { i128 , u128 }
172105
173106macro_rules! impl_Debug {
174107 ( $( $T: ident) * ) => {
0 commit comments