@@ -10,9 +10,6 @@ use crate::{fmt, ptr, slice, str};
10
10
trait DisplayInt :
11
11
PartialEq + PartialOrd + Div < Output = Self > + Rem < Output = Self > + Sub < Output = Self > + Copy
12
12
{
13
- fn zero ( ) -> Self ;
14
- fn from_u8 ( u : u8 ) -> Self ;
15
- fn to_u8 ( & self ) -> u8 ;
16
13
#[ cfg( not( any( target_pointer_width = "64" , target_arch = "wasm32" ) ) ) ]
17
14
fn to_u32 ( & self ) -> u32 ;
18
15
fn to_u64 ( & self ) -> u64 ;
@@ -22,9 +19,6 @@ trait DisplayInt:
22
19
macro_rules! impl_int {
23
20
( $( $t: ident) * ) => (
24
21
$( 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 }
28
22
#[ cfg( not( any( target_pointer_width = "64" , target_arch = "wasm32" ) ) ) ]
29
23
fn to_u32( & self ) -> u32 { * self as u32 }
30
24
fn to_u64( & self ) -> u64 { * self as u64 }
@@ -38,137 +32,80 @@ impl_int! {
38
32
u8 u16 u32 u64 u128 usize
39
33
}
40
34
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( ) ;
78
45
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 ;
84
50
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
+ }
110
75
}
76
+
77
+ // SAFETY: Starting from `offset`, all elements of the slice have been set.
78
+ let digits = unsafe { slice_buffer_to_str( & buf, offset) } ;
79
+ f. pad_integral( true , $prefix, digits)
111
80
}
112
81
}
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 ) }
120
82
121
- macro_rules! int_base {
122
- ( fmt:: $Trait: ident for $T: ident -> $Radix: ident) => {
123
83
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
124
- impl fmt:: $Trait for $T {
84
+ impl fmt:: $Trait for $Signed {
85
+ /// Format signed integers in the two’s-complement form.
125
86
fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
126
- $Radix. fmt_int( * self , f)
87
+ assert!( $Signed:: MIN < 0 ) ;
88
+ fmt:: $Trait:: fmt( & ( * self as $Unsigned) , f)
127
89
}
128
90
}
129
91
} ;
130
92
}
131
93
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
- }
94
+ // Formatting of integers with a non-decimal radix.
95
+ macro_rules! radix_integers {
96
+ ( $Signed: ident, $Unsigned: ident) => {
97
+ radix_integer! { fmt:: Binary for $Signed and $Unsigned, "0b" , b"01" }
98
+ radix_integer! { fmt:: Octal for $Signed and $Unsigned, "0o" , b"01234567" }
99
+ radix_integer! { fmt:: LowerHex for $Signed and $Unsigned, "0x" , b"0123456789abcdef" }
100
+ radix_integer! { fmt:: UpperHex for $Signed and $Unsigned, "0x" , b"0123456789ABCDEF" }
164
101
} ;
165
102
}
166
- integer ! { isize , usize }
167
- integer ! { i8 , u8 }
168
- integer ! { i16 , u16 }
169
- integer ! { i32 , u32 }
170
- integer ! { i64 , u64 }
171
- integer ! { i128 , u128 }
103
+ radix_integers ! { isize , usize }
104
+ radix_integers ! { i8 , u8 }
105
+ radix_integers ! { i16 , u16 }
106
+ radix_integers ! { i32 , u32 }
107
+ radix_integers ! { i64 , u64 }
108
+ radix_integers ! { i128 , u128 }
172
109
173
110
macro_rules! impl_Debug {
174
111
( $( $T: ident) * ) => {
0 commit comments