@@ -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,81 @@ 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
- 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
+ }
78
47
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( ) ;
57
+
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 ;
84
64
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) ,
65
+ // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
66
+ // and the break condition below ensures at least 1 more
67
+ // decimal.
68
+ unsafe { core:: hint:: assert_unchecked( offset >= 1 ) }
69
+ // SAFETY: The offset counts down from its initial buf.len()
70
+ // without underflow due to the previous precondition.
71
+ unsafe { core:: hint:: assert_unchecked( offset <= buf. len( ) ) }
72
+ offset -= 1 ;
73
+ buf[ offset] . write( DIG_TAB [ digit as usize ] ) ;
74
+ if remain == 0 {
75
+ break ;
76
+ }
110
77
}
78
+
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 , $prefix, digits)
111
82
}
112
83
}
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
84
121
- macro_rules! int_base {
122
- ( fmt:: $Trait: ident for $T: ident -> $Radix: ident) => {
123
85
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
124
- impl fmt:: $Trait for $T {
86
+ impl fmt:: $Trait for $Signed {
87
+ /// Format signed integers in the two’s-complement form.
125
88
fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
126
- $Radix . fmt_int ( * self , f)
89
+ fmt :: $Trait :: fmt ( & self . cast_unsigned ( ) , f)
127
90
}
128
91
}
129
92
} ;
130
93
}
131
94
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
- }
95
+ /// Formatting of integers with a non-decimal radix.
96
+ macro_rules! radix_integers {
97
+ ( $Signed: ident, $Unsigned: ident) => {
98
+ radix_integer! { fmt:: Binary for $Signed and $Unsigned, "0b" , b"01" }
99
+ radix_integer! { fmt:: Octal for $Signed and $Unsigned, "0o" , b"01234567" }
100
+ radix_integer! { fmt:: LowerHex for $Signed and $Unsigned, "0x" , b"0123456789abcdef" }
101
+ radix_integer! { fmt:: UpperHex for $Signed and $Unsigned, "0x" , b"0123456789ABCDEF" }
164
102
} ;
165
103
}
166
- integer ! { isize , usize }
167
- integer ! { i8 , u8 }
168
- integer ! { i16 , u16 }
169
- integer ! { i32 , u32 }
170
- integer ! { i64 , u64 }
171
- integer ! { i128 , u128 }
104
+ radix_integers ! { isize , usize }
105
+ radix_integers ! { i8 , u8 }
106
+ radix_integers ! { i16 , u16 }
107
+ radix_integers ! { i32 , u32 }
108
+ radix_integers ! { i64 , u64 }
109
+ radix_integers ! { i128 , u128 }
172
110
173
111
macro_rules! impl_Debug {
174
112
( $( $T: ident) * ) => {
0 commit comments