core/fmt/num.rs
1//! Integer and floating-point number formatting
2
3use crate::fmt::NumBuffer;
4use crate::mem::MaybeUninit;
5use crate::num::imp::fmt as numfmt;
6use crate::{fmt, str};
7
8/// Formatting of integers with a non-decimal radix.
9macro_rules! radix_integer {
10 (fmt::$Trait:ident for $Signed:ident and $Unsigned:ident, $prefix:literal, $dig_tab:literal) => {
11 #[stable(feature = "rust1", since = "1.0.0")]
12 impl fmt::$Trait for $Unsigned {
13 /// Format unsigned integers in the radix.
14 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15 // Check macro arguments at compile time.
16 const {
17 assert!($Unsigned::MIN == 0, "need unsigned");
18 assert!($dig_tab.is_ascii(), "need single-byte entries");
19 }
20
21 // ASCII digits in ascending order are used as a lookup table.
22 const DIG_TAB: &[u8] = $dig_tab;
23 const BASE: $Unsigned = DIG_TAB.len() as $Unsigned;
24 const MAX_DIG_N: usize = $Unsigned::MAX.ilog(BASE) as usize + 1;
25
26 // Buffer digits of self with right alignment.
27 let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DIG_N];
28 // Count the number of bytes in buf that are not initialized.
29 let mut offset = buf.len();
30
31 // Accumulate each digit of the number from the least
32 // significant to the most significant figure.
33 let mut remain = *self;
34 loop {
35 let digit = remain % BASE;
36 remain /= BASE;
37
38 offset -= 1;
39 // SAFETY: `remain` will reach 0 and we will break before `offset` wraps
40 unsafe { core::hint::assert_unchecked(offset < buf.len()) }
41 buf[offset].write(DIG_TAB[digit as usize]);
42 if remain == 0 {
43 break;
44 }
45 }
46
47 // SAFETY: Starting from `offset`, all elements of the slice have been set.
48 let digits = unsafe { slice_buffer_to_str(&buf, offset) };
49 f.pad_integral(true, $prefix, digits)
50 }
51 }
52
53 #[stable(feature = "rust1", since = "1.0.0")]
54 impl fmt::$Trait for $Signed {
55 /// Format signed integers in the two’s-complement form.
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 fmt::$Trait::fmt(&self.cast_unsigned(), f)
58 }
59 }
60 };
61}
62
63/// Formatting of integers with a non-decimal radix.
64macro_rules! radix_integers {
65 ($Signed:ident, $Unsigned:ident) => {
66 radix_integer! { fmt::Binary for $Signed and $Unsigned, "0b", b"01" }
67 radix_integer! { fmt::Octal for $Signed and $Unsigned, "0o", b"01234567" }
68 radix_integer! { fmt::LowerHex for $Signed and $Unsigned, "0x", b"0123456789abcdef" }
69 radix_integer! { fmt::UpperHex for $Signed and $Unsigned, "0x", b"0123456789ABCDEF" }
70 };
71}
72radix_integers! { isize, usize }
73radix_integers! { i8, u8 }
74radix_integers! { i16, u16 }
75radix_integers! { i32, u32 }
76radix_integers! { i64, u64 }
77radix_integers! { i128, u128 }
78
79macro_rules! impl_Debug {
80 ($($T:ident)*) => {
81 $(
82 #[stable(feature = "rust1", since = "1.0.0")]
83 impl fmt::Debug for $T {
84 #[inline]
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 if f.debug_lower_hex() {
87 fmt::LowerHex::fmt(self, f)
88 } else if f.debug_upper_hex() {
89 fmt::UpperHex::fmt(self, f)
90 } else {
91 fmt::Display::fmt(self, f)
92 }
93 }
94 }
95 )*
96 };
97}
98
99// The string of all two-digit numbers in range 00..99 is used as a lookup table.
100static DECIMAL_PAIRS: &[u8; 200] = b"\
101 0001020304050607080910111213141516171819\
102 2021222324252627282930313233343536373839\
103 4041424344454647484950515253545556575859\
104 6061626364656667686970717273747576777879\
105 8081828384858687888990919293949596979899";
106
107/// This function converts a slice of ascii characters into a `&str` starting from `offset`.
108///
109/// # Safety
110///
111/// `buf` content starting from `offset` index MUST BE initialized and MUST BE ascii
112/// characters.
113unsafe fn slice_buffer_to_str(buf: &[MaybeUninit<u8>], offset: usize) -> &str {
114 // SAFETY: `offset` is always included between 0 and `buf`'s length.
115 let written = unsafe { buf.get_unchecked(offset..) };
116 // SAFETY: (`assume_init_ref`) All buf content since offset is set.
117 // SAFETY: (`from_utf8_unchecked`) Writes use ASCII from the lookup table exclusively.
118 unsafe { str::from_utf8_unchecked(written.assume_init_ref()) }
119}
120
121macro_rules! impl_Display {
122 ($($Signed:ident, $Unsigned:ident),* ; as $T:ident into $fmt_fn:ident) => {
123
124 $(
125 const _: () = {
126 assert!($Signed::MIN < 0, "need signed");
127 assert!($Unsigned::MIN == 0, "need unsigned");
128 assert!($Signed::BITS == $Unsigned::BITS, "need counterparts");
129 assert!($Signed::BITS <= $T::BITS, "need lossless conversion");
130 assert!($Unsigned::BITS <= $T::BITS, "need lossless conversion");
131 };
132
133 #[stable(feature = "rust1", since = "1.0.0")]
134 impl fmt::Display for $Unsigned {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 #[cfg(not(feature = "optimize_for_size"))]
137 {
138 const MAX_DEC_N: usize = $Unsigned::MAX.ilog10() as usize + 1;
139 // Buffer decimals for self with right alignment.
140 let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
141
142 // SAFETY: `buf` is always big enough to contain all the digits.
143 unsafe { f.pad_integral(true, "", self._fmt(&mut buf)) }
144 }
145 #[cfg(feature = "optimize_for_size")]
146 {
147 // Lossless conversion (with as) is asserted at the top of
148 // this macro.
149 ${concat($fmt_fn, _small)}(*self as $T, true, f)
150 }
151 }
152 }
153
154 #[stable(feature = "rust1", since = "1.0.0")]
155 impl fmt::Display for $Signed {
156 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157 #[cfg(not(feature = "optimize_for_size"))]
158 {
159 const MAX_DEC_N: usize = $Unsigned::MAX.ilog10() as usize + 1;
160 // Buffer decimals for self with right alignment.
161 let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
162
163 // SAFETY: `buf` is always big enough to contain all the digits.
164 unsafe { f.pad_integral(*self >= 0, "", self.unsigned_abs()._fmt(&mut buf)) }
165 }
166 #[cfg(feature = "optimize_for_size")]
167 {
168 // Lossless conversion (with as) is asserted at the top of
169 // this macro.
170 return ${concat($fmt_fn, _small)}(self.unsigned_abs() as $T, *self >= 0, f);
171 }
172 }
173 }
174
175 #[cfg(not(feature = "optimize_for_size"))]
176 impl $Unsigned {
177 #[doc(hidden)]
178 #[unstable(
179 feature = "fmt_internals",
180 reason = "specialized method meant to only be used by `SpecToString` implementation",
181 issue = "none"
182 )]
183 pub unsafe fn _fmt<'a>(self, buf: &'a mut [MaybeUninit::<u8>]) -> &'a str {
184 // SAFETY: `buf` will always be big enough to contain all digits.
185 let offset = unsafe { self._fmt_inner(buf) };
186 // SAFETY: Starting from `offset`, all elements of the slice have been set.
187 unsafe { slice_buffer_to_str(buf, offset) }
188 }
189
190 unsafe fn _fmt_inner(self, buf: &mut [MaybeUninit::<u8>]) -> usize {
191 // Count the number of bytes in buf that are not initialized.
192 let mut offset = buf.len();
193 // Consume the least-significant decimals from a working copy.
194 let mut remain = self;
195
196 // Format per four digits from the lookup table.
197 // Four digits need a 16-bit $Unsigned or wider.
198 while size_of::<Self>() > 1 && remain > 999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)") {
199 // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
200 // and the while condition ensures at least 4 more decimals.
201 unsafe { core::hint::assert_unchecked(offset >= 4) }
202 // SAFETY: The offset counts down from its initial buf.len()
203 // without underflow due to the previous precondition.
204 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
205 offset -= 4;
206
207 // pull two pairs
208 let scale: Self = 1_00_00.try_into().expect("branch is not hit for types that cannot fit 1E4 (u8)");
209 let quad = remain % scale;
210 remain /= scale;
211 let pair1 = (quad / 100) as usize;
212 let pair2 = (quad % 100) as usize;
213 buf[offset + 0].write(DECIMAL_PAIRS[pair1 * 2 + 0]);
214 buf[offset + 1].write(DECIMAL_PAIRS[pair1 * 2 + 1]);
215 buf[offset + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]);
216 buf[offset + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]);
217 }
218
219 // Format per two digits from the lookup table.
220 if remain > 9 {
221 // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
222 // and the if condition ensures at least 2 more decimals.
223 unsafe { core::hint::assert_unchecked(offset >= 2) }
224 // SAFETY: The offset counts down from its initial buf.len()
225 // without underflow due to the previous precondition.
226 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
227 offset -= 2;
228
229 let pair = (remain % 100) as usize;
230 remain /= 100;
231 buf[offset + 0].write(DECIMAL_PAIRS[pair * 2 + 0]);
232 buf[offset + 1].write(DECIMAL_PAIRS[pair * 2 + 1]);
233 }
234
235 // Format the last remaining digit, if any.
236 if remain != 0 || self == 0 {
237 // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
238 // and the if condition ensures (at least) 1 more decimals.
239 unsafe { core::hint::assert_unchecked(offset >= 1) }
240 // SAFETY: The offset counts down from its initial buf.len()
241 // without underflow due to the previous precondition.
242 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
243 offset -= 1;
244
245 // Either the compiler sees that remain < 10, or it prevents
246 // a boundary check up next.
247 let last = (remain & 15) as usize;
248 buf[offset].write(DECIMAL_PAIRS[last * 2 + 1]);
249 // not used: remain = 0;
250 }
251
252 offset
253 }
254 }
255
256 impl $Signed {
257 /// Formats this integer as a signed decimal number, using the memory pointed to by
258 /// `buf` as storage for the returned string slice.
259 ///
260 /// This method can be used to convert integers to strings without involving the
261 /// dynamic dispatch that using [`Display`][fmt::Display] would.
262 /// This may be more efficient in situations where [`fmt`] is not otherwise used.
263 ///
264 /// # Examples
265 ///
266 /// ```
267 /// use core::fmt::NumBuffer;
268 ///
269 #[doc = concat!("let n = 0", stringify!($Signed), ";")]
270 /// let mut buf = NumBuffer::new();
271 /// assert_eq!(n.format_into(&mut buf), "0");
272 ///
273 #[doc = concat!("let n1 = 32", stringify!($Signed), ";")]
274 /// assert_eq!(n1.format_into(&mut buf), "32");
275 ///
276 #[doc = concat!("let n2 = ", stringify!($Signed::MAX), ";")]
277 #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Signed::MAX), ".to_string());")]
278 /// ```
279 #[stable(feature = "int_format_into", since = "1.98.0")]
280 pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
281 let mut offset;
282
283 #[cfg(not(feature = "optimize_for_size"))]
284 // SAFETY: `buf` will always be big enough to contain all digits.
285 unsafe {
286 offset = self.unsigned_abs()._fmt_inner(&mut buf.buf);
287 }
288 #[cfg(feature = "optimize_for_size")]
289 {
290 // Lossless conversion (with as) is asserted at the top of
291 // this macro.
292 offset = ${concat($fmt_fn, _in_buf_small)}(self.unsigned_abs() as $T, &mut buf.buf);
293 }
294 // Only difference between signed and unsigned are these 4 lines.
295 if self < 0 {
296 offset -= 1;
297 buf.buf[offset].write(b'-');
298 }
299 // SAFETY: Starting from `offset`, all elements of the slice have been set.
300 unsafe { slice_buffer_to_str(&buf.buf, offset) }
301 }
302 }
303
304 impl $Unsigned {
305 /// Formats this integer as an unsigned decimal number, using the memory pointed to by
306 /// `buf` as storage for the returned string slice.
307 ///
308 /// This method can be used to convert integers to strings without involving the
309 /// dynamic dispatch that using [`Display`][fmt::Display] would.
310 /// This may be more efficient in situations where [`fmt`] is not otherwise used.
311 ///
312 /// # Examples
313 ///
314 /// ```
315 /// use core::fmt::NumBuffer;
316 ///
317 #[doc = concat!("let n = 0", stringify!($Unsigned), ";")]
318 /// let mut buf = NumBuffer::new();
319 /// assert_eq!(n.format_into(&mut buf), "0");
320 ///
321 #[doc = concat!("let n1 = 32", stringify!($Unsigned), ";")]
322 /// assert_eq!(n1.format_into(&mut buf), "32");
323 ///
324 #[doc = concat!("let n2 = ", stringify!($Unsigned::MAX), ";")]
325 #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Unsigned::MAX), ".to_string());")]
326 /// ```
327 #[stable(feature = "int_format_into", since = "1.98.0")]
328 pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
329 let offset;
330
331 #[cfg(not(feature = "optimize_for_size"))]
332 // SAFETY: `buf` will always be big enough to contain all digits.
333 unsafe {
334 offset = self._fmt_inner(&mut buf.buf);
335 }
336 #[cfg(feature = "optimize_for_size")]
337 {
338 // Lossless conversion (with as) is asserted at the top of
339 // this macro.
340 offset = ${concat($fmt_fn, _in_buf_small)}(self as $T, &mut buf.buf);
341 }
342 // SAFETY: Starting from `offset`, all elements of the slice have been set.
343 unsafe { slice_buffer_to_str(&buf.buf, offset) }
344 }
345 }
346
347 )*
348
349 #[cfg(feature = "optimize_for_size")]
350 fn ${concat($fmt_fn, _in_buf_small)}(mut n: $T, buf: &mut [MaybeUninit::<u8>]) -> usize {
351 let mut curr = buf.len();
352
353 // SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning
354 // `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at
355 // each step this is kept the same as `n` is divided. Since `n` is always
356 // non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]`
357 // is safe to access.
358 loop {
359 curr -= 1;
360 buf[curr].write((n % 10) as u8 + b'0');
361 n /= 10;
362
363 if n == 0 {
364 break;
365 }
366 }
367 curr
368 }
369
370 #[cfg(feature = "optimize_for_size")]
371 fn ${concat($fmt_fn, _small)}(n: $T, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
372 const MAX_DEC_N: usize = $T::MAX.ilog10() as usize + 1;
373 let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
374
375 let offset = ${concat($fmt_fn, _in_buf_small)}(n, &mut buf);
376 // SAFETY: Starting from `offset`, all elements of the slice have been set.
377 let buf_slice = unsafe { slice_buffer_to_str(&buf, offset) };
378 f.pad_integral(is_nonnegative, "", buf_slice)
379 }
380 };
381}
382
383macro_rules! impl_Exp {
384 ($($Signed:ident, $Unsigned:ident),* ; as $T:ident into $fmt_fn:ident) => {
385 const _: () = assert!($T::MIN == 0, "need unsigned");
386
387 fn $fmt_fn(
388 f: &mut fmt::Formatter<'_>,
389 n: $T,
390 is_nonnegative: bool,
391 letter_e: u8
392 ) -> fmt::Result {
393 debug_assert!(letter_e.is_ascii_alphabetic(), "single-byte character");
394
395 // Print the integer as a coefficient in range (-10, 10).
396 let mut exp = n.checked_ilog10().unwrap_or(0) as usize;
397 debug_assert!(n / (10 as $T).pow(exp as u32) < 10);
398
399 // Precisison is counted as the number of digits in the fraction.
400 let mut coef_prec = exp;
401 // Keep the digits as an integer (paired with its coef_prec count).
402 let mut coef = n;
403
404 // A Formatter may set the precision to a fixed number of decimals.
405 let more_prec = match f.precision() {
406 None => {
407 // Omit any and all trailing zeroes.
408 while coef_prec != 0 && coef % 10 == 0 {
409 coef /= 10;
410 coef_prec -= 1;
411 }
412 0
413 },
414
415 Some(fmt_prec) if fmt_prec >= coef_prec => {
416 // Count the number of additional zeroes needed.
417 fmt_prec - coef_prec
418 },
419
420 Some(fmt_prec) => {
421 // Count the number of digits to drop.
422 let less_prec = coef_prec - fmt_prec;
423 assert!(less_prec > 0);
424 // Scale down the coefficient/precision pair. For example,
425 // coef 123456 gets coef_prec 5 (to make 1.23456). To format
426 // the number with 2 decimals, i.e., fmt_prec 2, coef should
427 // be scaled by 10⁵⁻²=1000 to get coef 123 with coef_prec 2.
428
429 // SAFETY: Any precision less than coef_prec will cause a
430 // power of ten below the coef value.
431 let scale = unsafe {
432 (10 as $T).checked_pow(less_prec as u32).unwrap_unchecked()
433 };
434 let floor = coef / scale;
435 // Round half to even conform documentation.
436 let over = coef % scale;
437 let half = scale / 2;
438 let round_up = if over < half {
439 0
440 } else if over > half {
441 1
442 } else {
443 floor & 1 // round odd up to even
444 };
445 // Adding one to a scale down of at least 10 won't overflow.
446 coef = floor + round_up;
447 coef_prec = fmt_prec;
448
449 // The round_up may have caused the coefficient to reach 10
450 // (which is not permitted). For example, anything in range
451 // [9.95, 10) becomes 10.0 when adjusted to precision 1.
452 if round_up != 0 && coef.checked_ilog10().unwrap_or(0) as usize > coef_prec {
453 debug_assert_eq!(coef, (10 as $T).pow(coef_prec as u32 + 1));
454 coef /= 10; // drop one trailing zero
455 exp += 1; // one power of ten higher
456 }
457 0
458 },
459 };
460
461 // Allocate a text buffer with lazy initialization.
462 const MAX_DEC_N: usize = $T::MAX.ilog10() as usize + 1;
463 const MAX_COEF_LEN: usize = MAX_DEC_N + ".".len();
464 const MAX_TEXT_LEN: usize = MAX_COEF_LEN + "e99".len();
465 let mut buf = [MaybeUninit::<u8>::uninit(); MAX_TEXT_LEN];
466
467 // Encode the coefficient in buf[..coef_len].
468 let (lead_dec, coef_len) = if coef_prec == 0 && more_prec == 0 {
469 (coef, 1_usize) // single digit; no fraction
470 } else {
471 buf[1].write(b'.');
472 let fraction_range = 2..(2 + coef_prec);
473
474 // Consume the least-significant decimals from a working copy.
475 let mut remain = coef;
476 #[cfg(feature = "optimize_for_size")] {
477 for i in fraction_range.clone().rev() {
478 let digit = (remain % 10) as usize;
479 remain /= 10;
480 buf[i].write(b'0' + digit as u8);
481 }
482 }
483 #[cfg(not(feature = "optimize_for_size"))] {
484 // Write digits per two at a time with a lookup table.
485 for i in fraction_range.clone().skip(1).rev().step_by(2) {
486 let pair = (remain % 100) as usize;
487 remain /= 100;
488 buf[i - 1].write(DECIMAL_PAIRS[pair * 2 + 0]);
489 buf[i - 0].write(DECIMAL_PAIRS[pair * 2 + 1]);
490 }
491 // An odd number of digits leave one digit remaining.
492 if coef_prec & 1 != 0 {
493 let digit = (remain % 10) as usize;
494 remain /= 10;
495 buf[fraction_range.start].write(b'0' + digit as u8);
496 }
497 }
498
499 (remain, fraction_range.end)
500 };
501 debug_assert!(lead_dec < 10);
502 debug_assert!(lead_dec != 0 || coef == 0, "significant digits only");
503 buf[0].write(b'0' + lead_dec as u8);
504
505 // SAFETY: The number of decimals is limited, captured by MAX.
506 unsafe { core::hint::assert_unchecked(coef_len <= MAX_COEF_LEN) }
507 // Encode the scale factor in buf[coef_len..text_len].
508 buf[coef_len].write(letter_e);
509 let text_len: usize = match exp {
510 ..10 => {
511 buf[coef_len + 1].write(b'0' + exp as u8);
512 coef_len + 2
513 },
514 10..100 => {
515 #[cfg(feature = "optimize_for_size")] {
516 buf[coef_len + 1].write(b'0' + (exp / 10) as u8);
517 buf[coef_len + 2].write(b'0' + (exp % 10) as u8);
518 }
519 #[cfg(not(feature = "optimize_for_size"))] {
520 buf[coef_len + 1].write(DECIMAL_PAIRS[exp * 2 + 0]);
521 buf[coef_len + 2].write(DECIMAL_PAIRS[exp * 2 + 1]);
522 }
523 coef_len + 3
524 },
525 _ => {
526 const { assert!($T::MAX.ilog10() < 100) };
527 // SAFETY: A `u256::MAX` would get exponent 77.
528 unsafe { core::hint::unreachable_unchecked() }
529 }
530 };
531 // SAFETY: All bytes up until text_len have been set.
532 let text = unsafe { buf[..text_len].assume_init_ref() };
533
534 if more_prec == 0 {
535 // SAFETY: Text is set with ASCII exclusively: either a decimal,
536 // or a LETTER_E, or a dot. ASCII implies valid UTF-8.
537 let as_str = unsafe { str::from_utf8_unchecked(text) };
538 f.pad_integral(is_nonnegative, "", as_str)
539 } else {
540 let parts = &[
541 numfmt::Part::Copy(&text[..coef_len]),
542 numfmt::Part::Zero(more_prec),
543 numfmt::Part::Copy(&text[coef_len..]),
544 ];
545 let sign = if !is_nonnegative {
546 "-"
547 } else if f.sign_plus() {
548 "+"
549 } else {
550 ""
551 };
552 // SAFETY: Text is set with ASCII exclusively: either a decimal,
553 // or a LETTER_E, or a dot. ASCII implies valid UTF-8.
554 unsafe { f.pad_formatted_parts(&numfmt::Formatted { sign, parts }) }
555 }
556 }
557
558 $(
559 const _: () = {
560 assert!($Signed::MIN < 0, "need signed");
561 assert!($Unsigned::MIN == 0, "need unsigned");
562 assert!($Signed::BITS == $Unsigned::BITS, "need counterparts");
563 assert!($Signed::BITS <= $T::BITS, "need lossless conversion");
564 assert!($Unsigned::BITS <= $T::BITS, "need lossless conversion");
565 };
566 #[stable(feature = "integer_exp_format", since = "1.42.0")]
567 impl fmt::LowerExp for $Signed {
568 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
569 $fmt_fn(f, self.unsigned_abs() as $T, *self >= 0, b'e')
570 }
571 }
572 #[stable(feature = "integer_exp_format", since = "1.42.0")]
573 impl fmt::LowerExp for $Unsigned {
574 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
575 $fmt_fn(f, *self as $T, true, b'e')
576 }
577 }
578 #[stable(feature = "integer_exp_format", since = "1.42.0")]
579 impl fmt::UpperExp for $Signed {
580 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
581 $fmt_fn(f, self.unsigned_abs() as $T, *self >= 0, b'E')
582 }
583 }
584 #[stable(feature = "integer_exp_format", since = "1.42.0")]
585 impl fmt::UpperExp for $Unsigned {
586 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
587 $fmt_fn(f, *self as $T, true, b'E')
588 }
589 }
590 )*
591
592 };
593}
594
595impl_Debug! {
596 i8 i16 i32 i64 i128 isize
597 u8 u16 u32 u64 u128 usize
598}
599
600// Include wasm32 in here since it doesn't reflect the native pointer size, and
601// often cares strongly about getting a smaller code size.
602#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))]
603#[doc(auto_cfg = false)]
604mod imp {
605 use super::*;
606 impl_Display!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize; as u64 into display_u64);
607 impl_Exp!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize; as u64 into exp_u64);
608}
609
610#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
611#[doc(auto_cfg = false)]
612mod imp {
613 use super::*;
614 impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize; as u32 into display_u32);
615 impl_Display!(i64, u64; as u64 into display_u64);
616
617 impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize; as u32 into exp_u32);
618 impl_Exp!(i64, u64; as u64 into exp_u64);
619}
620impl_Exp!(i128, u128; as u128 into exp_u128);
621
622const U128_MAX_DEC_N: usize = u128::MAX.ilog10() as usize + 1;
623
624#[stable(feature = "rust1", since = "1.0.0")]
625impl fmt::Display for u128 {
626 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
627 let mut buf = [MaybeUninit::<u8>::uninit(); U128_MAX_DEC_N];
628
629 // SAFETY: `buf` is always big enough to contain all the digits.
630 unsafe { f.pad_integral(true, "", self._fmt(&mut buf)) }
631 }
632}
633
634#[stable(feature = "rust1", since = "1.0.0")]
635impl fmt::Display for i128 {
636 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
637 // This is not a typo, we use the maximum number of digits of `u128`, hence why we use
638 // `U128_MAX_DEC_N`.
639 let mut buf = [MaybeUninit::<u8>::uninit(); U128_MAX_DEC_N];
640
641 let is_nonnegative = *self >= 0;
642 // SAFETY: `buf` is always big enough to contain all the digits.
643 unsafe { f.pad_integral(is_nonnegative, "", self.unsigned_abs()._fmt(&mut buf)) }
644 }
645}
646
647impl u128 {
648 /// Format optimized for u128. Computation of 128 bits is limited by processing
649 /// in batches of 16 decimals at a time.
650 #[doc(hidden)]
651 #[unstable(
652 feature = "fmt_internals",
653 reason = "specialized method meant to only be used by `SpecToString` implementation",
654 issue = "none"
655 )]
656 pub unsafe fn _fmt<'a>(self, buf: &'a mut [MaybeUninit<u8>]) -> &'a str {
657 // SAFETY: `buf` will always be big enough to contain all digits.
658 let offset = unsafe { self._fmt_inner(buf) };
659 // SAFETY: Starting from `offset`, all elements of the slice have been set.
660 unsafe { slice_buffer_to_str(buf, offset) }
661 }
662
663 unsafe fn _fmt_inner(self, buf: &mut [MaybeUninit<u8>]) -> usize {
664 // Optimize common-case zero, which would also need special treatment due to
665 // its "leading" zero.
666 if self == 0 {
667 let offset = buf.len() - 1;
668 buf[offset].write(b'0');
669 return offset;
670 }
671 // Take the 16 least-significant decimals.
672 let (quot_1e16, mod_1e16) = div_rem_1e16(self);
673 let (mut remain, mut offset) = if quot_1e16 == 0 {
674 (mod_1e16, U128_MAX_DEC_N)
675 } else {
676 // Write digits at buf[23..39].
677 //
678 // SAFETY: `mod_1e16 < 1e16` (remainder), and `U128_MAX_DEC_N - 16 + 16 == buf.len()`.
679 unsafe { enc_16lsd::<{ U128_MAX_DEC_N - 16 }>(buf, mod_1e16) };
680
681 // Take another 16 decimals.
682 let (quot2, mod2) = div_rem_1e16(quot_1e16);
683 if quot2 == 0 {
684 (mod2, U128_MAX_DEC_N - 16)
685 } else {
686 // Write digits at buf[7..23].
687 //
688 // SAFETY: `mod2 < 1e16` (remainder), and `U128_MAX_DEC_N - 32 + 16 <= buf.len()`.
689 unsafe { enc_16lsd::<{ U128_MAX_DEC_N - 32 }>(buf, mod2) };
690
691 // Quot2 has at most 7 decimals remaining after two 1e16 divisions.
692 (quot2 as u64, U128_MAX_DEC_N - 32)
693 }
694 };
695
696 // Format per four digits from the lookup table.
697 while remain > 999 {
698 // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N
699 // and the while condition ensures at least 4 more decimals.
700 unsafe { core::hint::assert_unchecked(offset >= 4) }
701 // SAFETY: The offset counts down from its initial buf.len()
702 // without underflow due to the previous precondition.
703 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
704 offset -= 4;
705
706 let quad = remain % 1_00_00;
707 remain /= 1_00_00;
708
709 // SAFETY: quad is a remainder modulo 10_000. The offset checks
710 // above reserve exactly four bytes in buf.
711 unsafe {
712 write_quad(buf.get_unchecked_mut(offset..offset + 4), quad);
713 }
714 }
715
716 // Format per two digits from the lookup table.
717 if remain > 9 {
718 // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N
719 // and the if condition ensures at least 2 more decimals.
720 unsafe { core::hint::assert_unchecked(offset >= 2) }
721 // SAFETY: The offset counts down from its initial buf.len()
722 // without underflow due to the previous precondition.
723 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
724 offset -= 2;
725
726 let pair = (remain % 100) as usize;
727 remain /= 100;
728 buf[offset + 0].write(DECIMAL_PAIRS[pair * 2 + 0]);
729 buf[offset + 1].write(DECIMAL_PAIRS[pair * 2 + 1]);
730 }
731
732 // Format the last remaining digit, if any.
733 if remain != 0 {
734 // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N
735 // and the if condition ensures (at least) 1 more decimals.
736 unsafe { core::hint::assert_unchecked(offset >= 1) }
737 // SAFETY: The offset counts down from its initial buf.len()
738 // without underflow due to the previous precondition.
739 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
740 offset -= 1;
741
742 // Either the compiler sees that remain < 10, or it prevents
743 // a boundary check up next.
744 let last = (remain & 15) as usize;
745 buf[offset].write(DECIMAL_PAIRS[last * 2 + 1]);
746 // not used: remain = 0;
747 }
748 offset
749 }
750
751 /// Formats this integer as an unsigned decimal number, using the memory pointed to by
752 /// `buf` as storage for the returned string slice.
753 ///
754 /// This method can be used to convert integers to strings without involving the
755 /// dynamic dispatch that using [`Display`][fmt::Display] would.
756 /// This may be more efficient in situations where [`fmt`] is not otherwise used.
757 ///
758 /// # Examples
759 ///
760 /// ```
761 /// use core::fmt::NumBuffer;
762 ///
763 /// let n = 0u128;
764 /// let mut buf = NumBuffer::new();
765 /// assert_eq!(n.format_into(&mut buf), "0");
766 ///
767 /// let n1 = 32u128;
768 /// let mut buf1 = NumBuffer::new();
769 /// assert_eq!(n1.format_into(&mut buf1), "32");
770 ///
771 /// let n2 = u128::MAX;
772 /// let mut buf2 = NumBuffer::new();
773 /// assert_eq!(n2.format_into(&mut buf2), u128::MAX.to_string());
774 /// ```
775 #[stable(feature = "int_format_into", since = "1.98.0")]
776 pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
777 let diff = buf.buf.len() - U128_MAX_DEC_N;
778 // FIXME: Once const generics are better, use `NumberBufferTrait::BUF_SIZE` as generic const
779 // for `fmt_u128_inner`.
780 //
781 // In the meantime, we have to use a slice starting at index 1 and add 1 to the returned
782 // offset to ensure the number is correctly generated at the end of the buffer.
783 // SAFETY: `diff` will always be between 0 and its initial value.
784 unsafe { self._fmt(buf.buf.get_unchecked_mut(diff..)) }
785 }
786}
787
788impl i128 {
789 /// Formats this integer as a signed decimal number, using the memory pointed to by
790 /// `buf` as storage for the returned string slice.
791 ///
792 /// This method can be used to convert integers to strings without involving the
793 /// dynamic dispatch that using [`Display`][fmt::Display] would.
794 /// This may be more efficient in situations where [`fmt`] is not otherwise used.
795 ///
796 /// # Examples
797 ///
798 /// ```
799 /// use core::fmt::NumBuffer;
800 ///
801 /// let n = 0i128;
802 /// let mut buf = NumBuffer::new();
803 /// assert_eq!(n.format_into(&mut buf), "0");
804 ///
805 /// let n1 = i128::MIN;
806 /// assert_eq!(n1.format_into(&mut buf), i128::MIN.to_string());
807 ///
808 /// let n2 = i128::MAX;
809 /// assert_eq!(n2.format_into(&mut buf), i128::MAX.to_string());
810 /// ```
811 #[stable(feature = "int_format_into", since = "1.98.0")]
812 pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
813 let diff = buf.buf.len() - U128_MAX_DEC_N;
814 // FIXME: Once const generics are better, use `NumberBufferTrait::BUF_SIZE` as generic const
815 // for `fmt_u128_inner`.
816 //
817 // In the meantime, we have to use a slice starting at index 1 and add 1 to the returned
818 // offset to ensure the number is correctly generated at the end of the buffer.
819 let mut offset =
820 // SAFETY: `buf` will always be big enough to contain all digits.
821 unsafe { self.unsigned_abs()._fmt_inner(buf.buf.get_unchecked_mut(diff..)) };
822 // We put back the offset at the right position.
823 offset += diff;
824 // Only difference between signed and unsigned are these 4 lines.
825 if self < 0 {
826 offset -= 1;
827 // SAFETY: `buf` will always be big enough to contain all digits plus the minus sign.
828 unsafe {
829 buf.buf.get_unchecked_mut(offset).write(b'-');
830 }
831 }
832 // SAFETY: Starting from `offset`, all elements of the slice have been set.
833 unsafe { slice_buffer_to_str(&buf.buf, offset) }
834 }
835}
836
837/// Writes `quad` as exactly four digits (for example: `42` becomes `"0042"`).
838///
839/// # Safety
840///
841/// `quad` must be below 10_000 and `buf` must contain exactly four bytes.
842#[inline(always)]
843unsafe fn write_quad(buf: &mut [MaybeUninit<u8>], quad: u64) {
844 // SAFETY: These are this function's caller-provided invariants.
845 unsafe {
846 core::hint::assert_unchecked(quad < 10_000);
847 core::hint::assert_unchecked(buf.len() == 4);
848 }
849
850 let quad = quad as u32;
851
852 // Note: this is equivalent to `quad / 100`, but contains no division instructions.
853 let high = (quad * const { (1 << 19) / 100 + 1 }) >> 19;
854 let low = quad - high * 100;
855 let high = high as usize;
856 let low = low as usize;
857
858 // SAFETY: `high` and `low` are below 100 because `quad` is below 10_000.
859 unsafe { core::hint::assert_unchecked(high < 100 && low < 100) }
860
861 buf[0..2].write_copy_of_slice(&DECIMAL_PAIRS[high * 2..high * 2 + 2]);
862 buf[2..4].write_copy_of_slice(&DECIMAL_PAIRS[low * 2..low * 2 + 2]);
863}
864
865/// Encodes the 16 least-significant decimals of n into `buf[OFFSET .. OFFSET +
866/// 16 ]`.
867///
868/// # Safety
869///
870/// `n` must be below 1e16, and `buf` must be at least `OFFSET + 16` bytes long.
871unsafe fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>], n: u64) {
872 // SAFETY: Every caller passes a remainder produced by division by 10^16,
873 // and every used `OFFSET` specialization reserves sixteen bytes in `buf`.
874 unsafe {
875 core::hint::assert_unchecked(n < 10_000_000_000_000_000);
876 core::hint::assert_unchecked(OFFSET + 16 <= buf.len());
877 }
878
879 // Peel four digits at a time from right to left (12345678 -> 1234 | 5678).
880 // Since 10_000 is constant, LLVM replaces each division with multiply or shift.
881 let mut remain = n;
882
883 for quad_index in (1..4).rev() {
884 let quad = remain % 1_00_00;
885 remain /= 1_00_00;
886
887 // SAFETY: `OFFSET + quad_index * 4` starts one of the four
888 // non-overlapping four-byte regions proven in bounds above.
889 unsafe {
890 write_quad(
891 buf.get_unchecked_mut(OFFSET + quad_index * 4..OFFSET + (quad_index + 1) * 4),
892 quad,
893 );
894 }
895 }
896
897 // SAFETY: OFFSET starts the first four-byte region proven in bounds above.
898 unsafe {
899 write_quad(buf.get_unchecked_mut(OFFSET..OFFSET + 4), remain);
900 }
901}
902
903/// Euclidean division plus remainder with constant 1E16 basically consumes 16
904/// decimals from n.
905///
906/// The integer division algorithm is based on the following paper:
907///
908/// T. Granlund and P. Montgomery, “Division by Invariant Integers Using Multiplication”
909/// in Proc. of the SIGPLAN94 Conference on Programming Language Design and
910/// Implementation, 1994, pp. 61–72
911///
912#[inline]
913fn div_rem_1e16(n: u128) -> (u128, u64) {
914 const D: u128 = 1_0000_0000_0000_0000;
915 // The check inlines well with the caller flow.
916 if n < D {
917 return (0, n as u64);
918 }
919
920 // These constant values are computed with the CHOOSE_MULTIPLIER procedure
921 // from the Granlund & Montgomery paper, using N=128, prec=128 and d=1E16.
922 const M_HIGH: u128 = 76624777043294442917917351357515459181;
923 const SH_POST: u8 = 51;
924
925 let quot = n.carrying_mul(M_HIGH, 0).1 >> SH_POST;
926 let rem = n - quot * D;
927 (quot, rem as u64)
928}