@@ -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,87 @@ 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- curr -= 1 ;
72- buf[ curr] . 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: expr, $dig_tab: expr) => {
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 arguments at compile time.
43+ assert!( $Unsigned:: MIN == 0 ) ;
44+ $dig_tab. as_ascii( ) . unwrap( ) ;
7845
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 ( is_nonnegative, Self :: PREFIX , digits)
82- }
83- }
46+ // ASCII digits in ascending order are used as a lookup table.
47+ const DIG_TAB : & [ u8 ] = $dig_tab;
48+ const BASE : $Unsigned = DIG_TAB . len( ) as $Unsigned;
49+ const MAX_DIG_N : usize = $Unsigned:: MAX . ilog( BASE ) as usize + 1 ;
8450
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) ,
51+ // Buffer digits of self with right alignment.
52+ let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; MAX_DIG_N ] ;
53+ // Count the number of bytes in buf that are not initialized.
54+ let mut offset = buf. len( ) ;
55+
56+ // Accumulate each digit of the number from the least
57+ // significant to the most significant figure.
58+ let mut remain = * self ;
59+ loop {
60+ let digit = remain % BASE ;
61+ remain /= BASE ;
62+
63+ // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
64+ // and the break condition below ensures at least 1 more
65+ // decimal.
66+ unsafe { core:: hint:: assert_unchecked( offset >= 1 ) }
67+ // SAFETY: The offset counts down from its initial buf.len()
68+ // without underflow due to the previous precondition.
69+ unsafe { core:: hint:: assert_unchecked( offset <= buf. len( ) ) }
70+ offset -= 1 ;
71+ buf[ offset] . write( DIG_TAB [ digit as usize ] ) ;
72+ if remain == 0 {
73+ break ;
74+ }
11075 }
76+
77+ // SAFETY: All buf content since offset is set.
78+ let written = unsafe { buf. get_unchecked( offset..) } ;
79+ // SAFETY: Writes are ASCII numbers exclusively.
80+ let as_str = unsafe {
81+ str :: from_utf8_unchecked( slice:: from_raw_parts(
82+ MaybeUninit :: slice_as_ptr( written) ,
83+ written. len( ) ,
84+ ) )
85+ } ;
86+ f. pad_integral( true , $prefix, as_str)
11187 }
11288 }
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 ) }
12089
121- macro_rules! int_base {
122- ( fmt:: $Trait: ident for $T: ident -> $Radix: ident) => {
12390 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
124- impl fmt:: $Trait for $T {
91+ impl fmt:: $Trait for $Signed {
92+ /// Format signed integers in the two’s-complement form.
12593 fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
126- $Radix. fmt_int( * self , f)
94+ assert!( $Signed:: MIN < 0 ) ;
95+ fmt:: $Trait:: fmt( & ( * self as $Unsigned) , f)
12796 }
12897 }
12998 } ;
13099}
131100
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 as $Uint) , 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 as $Uint) , 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 as $Uint) , 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 as $Uint) , f)
162- }
163- }
101+ // Formatting of integers with a non-decimal radix.
102+ macro_rules! radix_integers {
103+ ( $Signed: ident, $Unsigned: ident) => {
104+ radix_integer! { fmt:: Binary for $Signed and $Unsigned, "0b" , b"01" }
105+ radix_integer! { fmt:: Octal for $Signed and $Unsigned, "0o" , b"01234567" }
106+ radix_integer! { fmt:: LowerHex for $Signed and $Unsigned, "0x" , b"0123456789abcdef" }
107+ radix_integer! { fmt:: UpperHex for $Signed and $Unsigned, "0x" , b"0123456789ABCDEF" }
164108 } ;
165109}
166- integer ! { isize , usize }
167- integer ! { i8 , u8 }
168- integer ! { i16 , u16 }
169- integer ! { i32 , u32 }
170- integer ! { i64 , u64 }
171- integer ! { i128 , u128 }
110+ radix_integers ! { isize , usize }
111+ radix_integers ! { i8 , u8 }
112+ radix_integers ! { i16 , u16 }
113+ radix_integers ! { i32 , u32 }
114+ radix_integers ! { i64 , u64 }
115+ radix_integers ! { i128 , u128 }
172116
173117macro_rules! impl_Debug {
174118 ( $( $T: ident) * ) => {
0 commit comments