core/fmt/num.rs
1//! Integer and floating-point number formatting
2
3use crate::fmt::NumBuffer;
4use crate::mem::MaybeUninit;
5use crate::num::fmt as numfmt;
6use crate::{fmt, ptr, slice, 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// 2 digit decimal look up table
100static DEC_DIGITS_LUT: &[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::BITS <= $T::BITS, "need lossless conversion");
127 assert!($Unsigned::BITS <= $T::BITS, "need lossless conversion");
128 };
129
130 #[stable(feature = "rust1", since = "1.0.0")]
131 impl fmt::Display for $Unsigned {
132 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133 #[cfg(not(feature = "optimize_for_size"))]
134 {
135 const MAX_DEC_N: usize = $Unsigned::MAX.ilog10() as usize + 1;
136 // Buffer decimals for self with right alignment.
137 let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
138
139 // SAFETY: `buf` is always big enough to contain all the digits.
140 unsafe { f.pad_integral(true, "", self._fmt(&mut buf)) }
141 }
142 #[cfg(feature = "optimize_for_size")]
143 {
144 // Lossless conversion (with as) is asserted at the top of
145 // this macro.
146 ${concat($fmt_fn, _small)}(*self as $T, true, f)
147 }
148 }
149 }
150
151 #[stable(feature = "rust1", since = "1.0.0")]
152 impl fmt::Display for $Signed {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 #[cfg(not(feature = "optimize_for_size"))]
155 {
156 const MAX_DEC_N: usize = $Unsigned::MAX.ilog10() as usize + 1;
157 // Buffer decimals for self with right alignment.
158 let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
159
160 // SAFETY: `buf` is always big enough to contain all the digits.
161 unsafe { f.pad_integral(*self >= 0, "", self.unsigned_abs()._fmt(&mut buf)) }
162 }
163 #[cfg(feature = "optimize_for_size")]
164 {
165 // Lossless conversion (with as) is asserted at the top of
166 // this macro.
167 return ${concat($fmt_fn, _small)}(self.unsigned_abs() as $T, *self >= 0, f);
168 }
169 }
170 }
171
172 #[cfg(not(feature = "optimize_for_size"))]
173 impl $Unsigned {
174 #[doc(hidden)]
175 #[unstable(
176 feature = "fmt_internals",
177 reason = "specialized method meant to only be used by `SpecToString` implementation",
178 issue = "none"
179 )]
180 pub unsafe fn _fmt<'a>(self, buf: &'a mut [MaybeUninit::<u8>]) -> &'a str {
181 // SAFETY: `buf` will always be big enough to contain all digits.
182 let offset = unsafe { self._fmt_inner(buf) };
183 // SAFETY: Starting from `offset`, all elements of the slice have been set.
184 unsafe { slice_buffer_to_str(buf, offset) }
185 }
186
187 unsafe fn _fmt_inner(self, buf: &mut [MaybeUninit::<u8>]) -> usize {
188 // Count the number of bytes in buf that are not initialized.
189 let mut offset = buf.len();
190 // Consume the least-significant decimals from a working copy.
191 let mut remain = self;
192
193 // Format per four digits from the lookup table.
194 // Four digits need a 16-bit $Unsigned or wider.
195 while size_of::<Self>() > 1 && remain > 999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)") {
196 // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
197 // and the while condition ensures at least 4 more decimals.
198 unsafe { core::hint::assert_unchecked(offset >= 4) }
199 // SAFETY: The offset counts down from its initial buf.len()
200 // without underflow due to the previous precondition.
201 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
202 offset -= 4;
203
204 // pull two pairs
205 let scale: Self = 1_00_00.try_into().expect("branch is not hit for types that cannot fit 1E4 (u8)");
206 let quad = remain % scale;
207 remain /= scale;
208 let pair1 = (quad / 100) as usize;
209 let pair2 = (quad % 100) as usize;
210 buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
211 buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
212 buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
213 buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
214 }
215
216 // Format per two digits from the lookup table.
217 if remain > 9 {
218 // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
219 // and the if condition ensures at least 2 more decimals.
220 unsafe { core::hint::assert_unchecked(offset >= 2) }
221 // SAFETY: The offset counts down from its initial buf.len()
222 // without underflow due to the previous precondition.
223 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
224 offset -= 2;
225
226 let pair = (remain % 100) as usize;
227 remain /= 100;
228 buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]);
229 buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]);
230 }
231
232 // Format the last remaining digit, if any.
233 if remain != 0 || self == 0 {
234 // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
235 // and the if condition ensures (at least) 1 more decimals.
236 unsafe { core::hint::assert_unchecked(offset >= 1) }
237 // SAFETY: The offset counts down from its initial buf.len()
238 // without underflow due to the previous precondition.
239 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
240 offset -= 1;
241
242 // Either the compiler sees that remain < 10, or it prevents
243 // a boundary check up next.
244 let last = (remain & 15) as usize;
245 buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]);
246 // not used: remain = 0;
247 }
248
249 offset
250 }
251 }
252
253 impl $Signed {
254 /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
255 /// type [`NumBuffer`] that is passed by the caller by mutable reference.
256 ///
257 /// # Examples
258 ///
259 /// ```
260 /// #![feature(int_format_into)]
261 /// use core::fmt::NumBuffer;
262 ///
263 #[doc = concat!("let n = 0", stringify!($Signed), ";")]
264 /// let mut buf = NumBuffer::new();
265 /// assert_eq!(n.format_into(&mut buf), "0");
266 ///
267 #[doc = concat!("let n1 = 32", stringify!($Signed), ";")]
268 /// assert_eq!(n1.format_into(&mut buf), "32");
269 ///
270 #[doc = concat!("let n2 = ", stringify!($Signed::MAX), ";")]
271 #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Signed::MAX), ".to_string());")]
272 /// ```
273 #[unstable(feature = "int_format_into", issue = "138215")]
274 pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
275 let mut offset;
276
277 #[cfg(not(feature = "optimize_for_size"))]
278 // SAFETY: `buf` will always be big enough to contain all digits.
279 unsafe {
280 offset = self.unsigned_abs()._fmt_inner(&mut buf.buf);
281 }
282 #[cfg(feature = "optimize_for_size")]
283 {
284 // Lossless conversion (with as) is asserted at the top of
285 // this macro.
286 offset = ${concat($fmt_fn, _in_buf_small)}(self.unsigned_abs() as $T, &mut buf.buf);
287 }
288 // Only difference between signed and unsigned are these 4 lines.
289 if self < 0 {
290 offset -= 1;
291 buf.buf[offset].write(b'-');
292 }
293 // SAFETY: Starting from `offset`, all elements of the slice have been set.
294 unsafe { slice_buffer_to_str(&buf.buf, offset) }
295 }
296 }
297
298 impl $Unsigned {
299 /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
300 /// type [`NumBuffer`] that is passed by the caller by mutable reference.
301 ///
302 /// # Examples
303 ///
304 /// ```
305 /// #![feature(int_format_into)]
306 /// use core::fmt::NumBuffer;
307 ///
308 #[doc = concat!("let n = 0", stringify!($Unsigned), ";")]
309 /// let mut buf = NumBuffer::new();
310 /// assert_eq!(n.format_into(&mut buf), "0");
311 ///
312 #[doc = concat!("let n1 = 32", stringify!($Unsigned), ";")]
313 /// assert_eq!(n1.format_into(&mut buf), "32");
314 ///
315 #[doc = concat!("let n2 = ", stringify!($Unsigned::MAX), ";")]
316 #[doc = concat!("assert_eq!(n2.format_into(&mut buf), ", stringify!($Unsigned::MAX), ".to_string());")]
317 /// ```
318 #[unstable(feature = "int_format_into", issue = "138215")]
319 pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
320 let offset;
321
322 #[cfg(not(feature = "optimize_for_size"))]
323 // SAFETY: `buf` will always be big enough to contain all digits.
324 unsafe {
325 offset = self._fmt_inner(&mut buf.buf);
326 }
327 #[cfg(feature = "optimize_for_size")]
328 {
329 // Lossless conversion (with as) is asserted at the top of
330 // this macro.
331 offset = ${concat($fmt_fn, _in_buf_small)}(self as $T, &mut buf.buf);
332 }
333 // SAFETY: Starting from `offset`, all elements of the slice have been set.
334 unsafe { slice_buffer_to_str(&buf.buf, offset) }
335 }
336 }
337
338
339 )*
340
341 #[cfg(feature = "optimize_for_size")]
342 fn ${concat($fmt_fn, _in_buf_small)}(mut n: $T, buf: &mut [MaybeUninit::<u8>]) -> usize {
343 let mut curr = buf.len();
344
345 // SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning
346 // `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at
347 // each step this is kept the same as `n` is divided. Since `n` is always
348 // non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]`
349 // is safe to access.
350 loop {
351 curr -= 1;
352 buf[curr].write((n % 10) as u8 + b'0');
353 n /= 10;
354
355 if n == 0 {
356 break;
357 }
358 }
359 curr
360 }
361
362 #[cfg(feature = "optimize_for_size")]
363 fn ${concat($fmt_fn, _small)}(n: $T, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364 const MAX_DEC_N: usize = $T::MAX.ilog(10) as usize + 1;
365 let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
366
367 let offset = ${concat($fmt_fn, _in_buf_small)}(n, &mut buf);
368 // SAFETY: Starting from `offset`, all elements of the slice have been set.
369 let buf_slice = unsafe { slice_buffer_to_str(&buf, offset) };
370 f.pad_integral(is_nonnegative, "", buf_slice)
371 }
372 };
373}
374
375macro_rules! impl_Exp {
376 ($($Signed:ident, $Unsigned:ident),* ; as $T:ident into $fmt_fn:ident) => {
377 fn $fmt_fn(
378 mut n: $T,
379 is_nonnegative: bool,
380 upper: bool,
381 f: &mut fmt::Formatter<'_>
382 ) -> fmt::Result {
383 let (mut n, mut exponent, trailing_zeros, added_precision) = {
384 let mut exponent = 0;
385 // count and remove trailing decimal zeroes
386 while n % 10 == 0 && n >= 10 {
387 n /= 10;
388 exponent += 1;
389 }
390 let (added_precision, subtracted_precision) = match f.precision() {
391 Some(fmt_prec) => {
392 // number of decimal digits minus 1
393 let mut tmp = n;
394 let mut prec = 0;
395 while tmp >= 10 {
396 tmp /= 10;
397 prec += 1;
398 }
399 (fmt_prec.saturating_sub(prec), prec.saturating_sub(fmt_prec))
400 }
401 None => (0, 0)
402 };
403 for _ in 1..subtracted_precision {
404 n /= 10;
405 exponent += 1;
406 }
407 if subtracted_precision != 0 {
408 let rem = n % 10;
409 n /= 10;
410 exponent += 1;
411 // round up last digit, round to even on a tie
412 if rem > 5 || (rem == 5 && (n % 2 != 0 || subtracted_precision > 1 )) {
413 n += 1;
414 // if the digit is rounded to the next power
415 // instead adjust the exponent
416 if n.ilog10() > (n - 1).ilog10() {
417 n /= 10;
418 exponent += 1;
419 }
420 }
421 }
422 (n, exponent, exponent, added_precision)
423 };
424
425 // Since `curr` always decreases by the number of digits copied, this means
426 // that `curr >= 0`.
427 let mut buf = [MaybeUninit::<u8>::uninit(); 40];
428 let mut curr = buf.len(); //index for buf
429 let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
430 let lut_ptr = DEC_DIGITS_LUT.as_ptr();
431
432 // decode 2 chars at a time
433 while n >= 100 {
434 let d1 = ((n % 100) as usize) << 1;
435 curr -= 2;
436 // SAFETY: `d1 <= 198`, so we can copy from `lut_ptr[d1..d1 + 2]` since
437 // `DEC_DIGITS_LUT` has a length of 200.
438 unsafe {
439 ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
440 }
441 n /= 100;
442 exponent += 2;
443 }
444 // n is <= 99, so at most 2 chars long
445 let mut n = n as isize; // possibly reduce 64bit math
446 // decode second-to-last character
447 if n >= 10 {
448 curr -= 1;
449 // SAFETY: Safe since `40 > curr >= 0` (see comment)
450 unsafe {
451 *buf_ptr.add(curr) = (n as u8 % 10_u8) + b'0';
452 }
453 n /= 10;
454 exponent += 1;
455 }
456 // add decimal point iff >1 mantissa digit will be printed
457 if exponent != trailing_zeros || added_precision != 0 {
458 curr -= 1;
459 // SAFETY: Safe since `40 > curr >= 0`
460 unsafe {
461 *buf_ptr.add(curr) = b'.';
462 }
463 }
464
465 // SAFETY: Safe since `40 > curr >= 0`
466 let buf_slice = unsafe {
467 // decode last character
468 curr -= 1;
469 *buf_ptr.add(curr) = (n as u8) + b'0';
470
471 let len = buf.len() - curr as usize;
472 slice::from_raw_parts(buf_ptr.add(curr), len)
473 };
474
475 // stores 'e' (or 'E') and the up to 2-digit exponent
476 let mut exp_buf = [MaybeUninit::<u8>::uninit(); 3];
477 let exp_ptr = MaybeUninit::slice_as_mut_ptr(&mut exp_buf);
478 // SAFETY: In either case, `exp_buf` is written within bounds and `exp_ptr[..len]`
479 // is contained within `exp_buf` since `len <= 3`.
480 let exp_slice = unsafe {
481 *exp_ptr.add(0) = if upper { b'E' } else { b'e' };
482 let len = if exponent < 10 {
483 *exp_ptr.add(1) = (exponent as u8) + b'0';
484 2
485 } else {
486 let off = exponent << 1;
487 ptr::copy_nonoverlapping(lut_ptr.add(off), exp_ptr.add(1), 2);
488 3
489 };
490 slice::from_raw_parts(exp_ptr, len)
491 };
492
493 let parts = &[
494 numfmt::Part::Copy(buf_slice),
495 numfmt::Part::Zero(added_precision),
496 numfmt::Part::Copy(exp_slice),
497 ];
498 let sign = if !is_nonnegative {
499 "-"
500 } else if f.sign_plus() {
501 "+"
502 } else {
503 ""
504 };
505 let formatted = numfmt::Formatted { sign, parts };
506 // SAFETY: `buf_slice` and `exp_slice` contain only ASCII characters.
507 unsafe { f.pad_formatted_parts(&formatted) }
508 }
509
510 $(
511 #[stable(feature = "integer_exp_format", since = "1.42.0")]
512 impl fmt::LowerExp for $Signed {
513 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
514 let is_nonnegative = *self >= 0;
515 let n = if is_nonnegative {
516 *self as $T
517 } else {
518 self.unsigned_abs() as $T
519 };
520 $fmt_fn(n, is_nonnegative, false, f)
521 }
522 }
523 #[stable(feature = "integer_exp_format", since = "1.42.0")]
524 impl fmt::LowerExp for $Unsigned {
525 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
526 $fmt_fn(*self as $T, true, false, f)
527 }
528 })*
529
530 $(
531 #[stable(feature = "integer_exp_format", since = "1.42.0")]
532 impl fmt::UpperExp for $Signed {
533 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
534 let is_nonnegative = *self >= 0;
535 let n = if is_nonnegative {
536 *self as $T
537 } else {
538 self.unsigned_abs() as $T
539 };
540 $fmt_fn(n, is_nonnegative, true, f)
541 }
542 }
543 #[stable(feature = "integer_exp_format", since = "1.42.0")]
544 impl fmt::UpperExp for $Unsigned {
545 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
546 $fmt_fn(*self as $T, true, true, f)
547 }
548 })*
549 };
550}
551
552impl_Debug! {
553 i8 i16 i32 i64 i128 isize
554 u8 u16 u32 u64 u128 usize
555}
556
557// Include wasm32 in here since it doesn't reflect the native pointer size, and
558// often cares strongly about getting a smaller code size.
559#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))]
560mod imp {
561 use super::*;
562 impl_Display!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize; as u64 into display_u64);
563 impl_Exp!(i8, u8, i16, u16, i32, u32, i64, u64, isize, usize; as u64 into exp_u64);
564}
565
566#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
567mod imp {
568 use super::*;
569 impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize; as u32 into display_u32);
570 impl_Display!(i64, u64; as u64 into display_u64);
571
572 impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize; as u32 into exp_u32);
573 impl_Exp!(i64, u64; as u64 into exp_u64);
574}
575impl_Exp!(i128, u128; as u128 into exp_u128);
576
577const U128_MAX_DEC_N: usize = u128::MAX.ilog10() as usize + 1;
578
579#[stable(feature = "rust1", since = "1.0.0")]
580impl fmt::Display for u128 {
581 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
582 let mut buf = [MaybeUninit::<u8>::uninit(); U128_MAX_DEC_N];
583
584 // SAFETY: `buf` is always big enough to contain all the digits.
585 unsafe { f.pad_integral(true, "", self._fmt(&mut buf)) }
586 }
587}
588
589#[stable(feature = "rust1", since = "1.0.0")]
590impl fmt::Display for i128 {
591 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
592 // This is not a typo, we use the maximum number of digits of `u128`, hence why we use
593 // `U128_MAX_DEC_N`.
594 let mut buf = [MaybeUninit::<u8>::uninit(); U128_MAX_DEC_N];
595
596 let is_nonnegative = *self >= 0;
597 // SAFETY: `buf` is always big enough to contain all the digits.
598 unsafe { f.pad_integral(is_nonnegative, "", self.unsigned_abs()._fmt(&mut buf)) }
599 }
600}
601
602impl u128 {
603 /// Format optimized for u128. Computation of 128 bits is limited by processing
604 /// in batches of 16 decimals at a time.
605 #[doc(hidden)]
606 #[unstable(
607 feature = "fmt_internals",
608 reason = "specialized method meant to only be used by `SpecToString` implementation",
609 issue = "none"
610 )]
611 pub unsafe fn _fmt<'a>(self, buf: &'a mut [MaybeUninit<u8>]) -> &'a str {
612 // SAFETY: `buf` will always be big enough to contain all digits.
613 let offset = unsafe { self._fmt_inner(buf) };
614 // SAFETY: Starting from `offset`, all elements of the slice have been set.
615 unsafe { slice_buffer_to_str(buf, offset) }
616 }
617
618 unsafe fn _fmt_inner(self, buf: &mut [MaybeUninit<u8>]) -> usize {
619 // Optimize common-case zero, which would also need special treatment due to
620 // its "leading" zero.
621 if self == 0 {
622 let offset = buf.len() - 1;
623 buf[offset].write(b'0');
624 return offset;
625 }
626 // Take the 16 least-significant decimals.
627 let (quot_1e16, mod_1e16) = div_rem_1e16(self);
628 let (mut remain, mut offset) = if quot_1e16 == 0 {
629 (mod_1e16, U128_MAX_DEC_N)
630 } else {
631 // Write digits at buf[23..39].
632 enc_16lsd::<{ U128_MAX_DEC_N - 16 }>(buf, mod_1e16);
633
634 // Take another 16 decimals.
635 let (quot2, mod2) = div_rem_1e16(quot_1e16);
636 if quot2 == 0 {
637 (mod2, U128_MAX_DEC_N - 16)
638 } else {
639 // Write digits at buf[7..23].
640 enc_16lsd::<{ U128_MAX_DEC_N - 32 }>(buf, mod2);
641 // Quot2 has at most 7 decimals remaining after two 1e16 divisions.
642 (quot2 as u64, U128_MAX_DEC_N - 32)
643 }
644 };
645
646 // Format per four digits from the lookup table.
647 while remain > 999 {
648 // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N
649 // and the while condition ensures at least 4 more decimals.
650 unsafe { core::hint::assert_unchecked(offset >= 4) }
651 // SAFETY: The offset counts down from its initial buf.len()
652 // without underflow due to the previous precondition.
653 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
654 offset -= 4;
655
656 // pull two pairs
657 let quad = remain % 1_00_00;
658 remain /= 1_00_00;
659 let pair1 = (quad / 100) as usize;
660 let pair2 = (quad % 100) as usize;
661 buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
662 buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
663 buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
664 buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
665 }
666
667 // Format per two digits from the lookup table.
668 if remain > 9 {
669 // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N
670 // and the if condition ensures at least 2 more decimals.
671 unsafe { core::hint::assert_unchecked(offset >= 2) }
672 // SAFETY: The offset counts down from its initial buf.len()
673 // without underflow due to the previous precondition.
674 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
675 offset -= 2;
676
677 let pair = (remain % 100) as usize;
678 remain /= 100;
679 buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]);
680 buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]);
681 }
682
683 // Format the last remaining digit, if any.
684 if remain != 0 {
685 // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N
686 // and the if condition ensures (at least) 1 more decimals.
687 unsafe { core::hint::assert_unchecked(offset >= 1) }
688 // SAFETY: The offset counts down from its initial buf.len()
689 // without underflow due to the previous precondition.
690 unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
691 offset -= 1;
692
693 // Either the compiler sees that remain < 10, or it prevents
694 // a boundary check up next.
695 let last = (remain & 15) as usize;
696 buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]);
697 // not used: remain = 0;
698 }
699 offset
700 }
701
702 /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
703 /// type [`NumBuffer`] that is passed by the caller by mutable reference.
704 ///
705 /// # Examples
706 ///
707 /// ```
708 /// #![feature(int_format_into)]
709 /// use core::fmt::NumBuffer;
710 ///
711 /// let n = 0u128;
712 /// let mut buf = NumBuffer::new();
713 /// assert_eq!(n.format_into(&mut buf), "0");
714 ///
715 /// let n1 = 32u128;
716 /// let mut buf1 = NumBuffer::new();
717 /// assert_eq!(n1.format_into(&mut buf1), "32");
718 ///
719 /// let n2 = u128::MAX;
720 /// let mut buf2 = NumBuffer::new();
721 /// assert_eq!(n2.format_into(&mut buf2), u128::MAX.to_string());
722 /// ```
723 #[unstable(feature = "int_format_into", issue = "138215")]
724 pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
725 let diff = buf.capacity() - U128_MAX_DEC_N;
726 // FIXME: Once const generics are better, use `NumberBufferTrait::BUF_SIZE` as generic const
727 // for `fmt_u128_inner`.
728 //
729 // In the meantime, we have to use a slice starting at index 1 and add 1 to the returned
730 // offset to ensure the number is correctly generated at the end of the buffer.
731 // SAFETY: `diff` will always be between 0 and its initial value.
732 unsafe { self._fmt(buf.buf.get_unchecked_mut(diff..)) }
733 }
734}
735
736impl i128 {
737 /// Allows users to write an integer (in signed decimal format) into a variable `buf` of
738 /// type [`NumBuffer`] that is passed by the caller by mutable reference.
739 ///
740 /// # Examples
741 ///
742 /// ```
743 /// #![feature(int_format_into)]
744 /// use core::fmt::NumBuffer;
745 ///
746 /// let n = 0i128;
747 /// let mut buf = NumBuffer::new();
748 /// assert_eq!(n.format_into(&mut buf), "0");
749 ///
750 /// let n1 = i128::MIN;
751 /// assert_eq!(n1.format_into(&mut buf), i128::MIN.to_string());
752 ///
753 /// let n2 = i128::MAX;
754 /// assert_eq!(n2.format_into(&mut buf), i128::MAX.to_string());
755 /// ```
756 #[unstable(feature = "int_format_into", issue = "138215")]
757 pub fn format_into(self, buf: &mut NumBuffer<Self>) -> &str {
758 let diff = buf.capacity() - U128_MAX_DEC_N;
759 // FIXME: Once const generics are better, use `NumberBufferTrait::BUF_SIZE` as generic const
760 // for `fmt_u128_inner`.
761 //
762 // In the meantime, we have to use a slice starting at index 1 and add 1 to the returned
763 // offset to ensure the number is correctly generated at the end of the buffer.
764 let mut offset =
765 // SAFETY: `buf` will always be big enough to contain all digits.
766 unsafe { self.unsigned_abs()._fmt_inner(buf.buf.get_unchecked_mut(diff..)) };
767 // We put back the offset at the right position.
768 offset += diff;
769 // Only difference between signed and unsigned are these 4 lines.
770 if self < 0 {
771 offset -= 1;
772 // SAFETY: `buf` will always be big enough to contain all digits plus the minus sign.
773 unsafe {
774 buf.buf.get_unchecked_mut(offset).write(b'-');
775 }
776 }
777 // SAFETY: Starting from `offset`, all elements of the slice have been set.
778 unsafe { slice_buffer_to_str(&buf.buf, offset) }
779 }
780}
781
782/// Encodes the 16 least-significant decimals of n into `buf[OFFSET .. OFFSET +
783/// 16 ]`.
784fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>], n: u64) {
785 // Consume the least-significant decimals from a working copy.
786 let mut remain = n;
787
788 // Format per four digits from the lookup table.
789 for quad_index in (0..4).rev() {
790 // pull two pairs
791 let quad = remain % 1_00_00;
792 remain /= 1_00_00;
793 let pair1 = (quad / 100) as usize;
794 let pair2 = (quad % 100) as usize;
795 buf[quad_index * 4 + OFFSET + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
796 buf[quad_index * 4 + OFFSET + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
797 buf[quad_index * 4 + OFFSET + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
798 buf[quad_index * 4 + OFFSET + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
799 }
800}
801
802/// Euclidean division plus remainder with constant 1E16 basically consumes 16
803/// decimals from n.
804///
805/// The integer division algorithm is based on the following paper:
806///
807/// T. Granlund and P. Montgomery, “Division by Invariant Integers Using Multiplication”
808/// in Proc. of the SIGPLAN94 Conference on Programming Language Design and
809/// Implementation, 1994, pp. 61–72
810///
811#[inline]
812fn div_rem_1e16(n: u128) -> (u128, u64) {
813 const D: u128 = 1_0000_0000_0000_0000;
814 // The check inlines well with the caller flow.
815 if n < D {
816 return (0, n as u64);
817 }
818
819 // These constant values are computed with the CHOOSE_MULTIPLIER procedure
820 // from the Granlund & Montgomery paper, using N=128, prec=128 and d=1E16.
821 const M_HIGH: u128 = 76624777043294442917917351357515459181;
822 const SH_POST: u8 = 51;
823
824 let quot = n.widening_mul(M_HIGH).1 >> SH_POST;
825 let rem = n - quot * D;
826 (quot, rem as u64)
827}