Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit a96d8d6

Browse files
fmt with table lookup for binary, octal and hex
* correct buffer size * no trait abstraction * similar to decimal
1 parent 7704a39 commit a96d8d6

File tree

1 file changed

+58
-122
lines changed

1 file changed

+58
-122
lines changed

‎library/core/src/fmt/num.rs‎

Lines changed: 58 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ use crate::{fmt, ptr, slice, str};
1010
trait 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:
2219
macro_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,79 @@ 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: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 macro arguments at compile time.
43+
assert!($Unsigned::MIN == 0, "need unsigned");
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(true, 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: 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)
11180
}
11281
}
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) }
12082

121-
macro_rules! int_base {
122-
(fmt::$Trait:ident for $T:ident -> $Radix:ident) => {
12383
#[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.
12586
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126-
$Radix.fmt_int(*self, f)
87+
fmt::$Trait::fmt(&self.cast_unsigned(), f)
12788
}
12889
}
12990
};
13091
}
13192

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-
}
93+
/// Formatting of integers with a non-decimal radix.
94+
macro_rules! radix_integers {
95+
($Signed:ident, $Unsigned:ident) => {
96+
radix_integer! { fmt::Binary for $Signed and $Unsigned, "0b", b"01" }
97+
radix_integer! { fmt::Octal for $Signed and $Unsigned, "0o", b"01234567" }
98+
radix_integer! { fmt::LowerHex for $Signed and $Unsigned, "0x", b"0123456789abcdef" }
99+
radix_integer! { fmt::UpperHex for $Signed and $Unsigned, "0x", b"0123456789ABCDEF" }
164100
};
165101
}
166-
integer! { isize, usize }
167-
integer! { i8, u8 }
168-
integer! { i16, u16 }
169-
integer! { i32, u32 }
170-
integer! { i64, u64 }
171-
integer! { i128, u128 }
102+
radix_integers! { isize, usize }
103+
radix_integers! { i8, u8 }
104+
radix_integers! { i16, u16 }
105+
radix_integers! { i32, u32 }
106+
radix_integers! { i64, u64 }
107+
radix_integers! { i128, u128 }
172108

173109
macro_rules! impl_Debug {
174110
($($T:ident)*) => {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /