1 //! Integer and floating-point number formatting
2
3 use crate::fmt;
4 use crate::mem::MaybeUninit;
5 use crate::num::fmt as numfmt;
6 use crate::ops::{Div, Rem, Sub};
7 use crate::ptr;
8 use crate::slice;
9 use crate::str;
10
11 #[doc(hidden)]
12 trait DisplayInt:
13 PartialEq + PartialOrd + Div<Output = Self> + Rem<Output = Self> + Sub<Output = Self> + Copy
14 {
zero() -> Self15 fn zero() -> Self;
from_u8(u: u8) -> Self16 fn from_u8(u: u8) -> Self;
to_u8(&self) -> u817 fn to_u8(&self) -> u8;
to_u16(&self) -> u1618 fn to_u16(&self) -> u16;
to_u32(&self) -> u3219 fn to_u32(&self) -> u32;
to_u64(&self) -> u6420 fn to_u64(&self) -> u64;
to_u128(&self) -> u12821 fn to_u128(&self) -> u128;
22 }
23
24 macro_rules! impl_int {
25 ($($t:ident)*) => (
26 $(impl DisplayInt for $t {
27 fn zero() -> Self { 0 }
28 fn from_u8(u: u8) -> Self { u as Self }
29 fn to_u8(&self) -> u8 { *self as u8 }
30 fn to_u16(&self) -> u16 { *self as u16 }
31 fn to_u32(&self) -> u32 { *self as u32 }
32 fn to_u64(&self) -> u64 { *self as u64 }
33 fn to_u128(&self) -> u128 { *self as u128 }
34 })*
35 )
36 }
37 macro_rules! impl_uint {
38 ($($t:ident)*) => (
39 $(impl DisplayInt for $t {
40 fn zero() -> Self { 0 }
41 fn from_u8(u: u8) -> Self { u as Self }
42 fn to_u8(&self) -> u8 { *self as u8 }
43 fn to_u16(&self) -> u16 { *self as u16 }
44 fn to_u32(&self) -> u32 { *self as u32 }
45 fn to_u64(&self) -> u64 { *self as u64 }
46 fn to_u128(&self) -> u128 { *self as u128 }
47 })*
48 )
49 }
50
51 impl_int! { i8 i16 i32 i64 i128 isize }
52 impl_uint! { u8 u16 u32 u64 u128 usize }
53
54 /// A type that represents a specific radix
55 ///
56 /// # Safety
57 ///
58 /// `digit` must return an ASCII character.
59 #[doc(hidden)]
60 unsafe trait GenericRadix: Sized {
61 /// The number of digits.
62 const BASE: u8;
63
64 /// A radix-specific prefix string.
65 const PREFIX: &'static str;
66
67 /// Converts an integer to corresponding radix digit.
digit(x: u8) -> u868 fn digit(x: u8) -> u8;
69
70 /// Format an integer using the radix using a formatter.
fmt_int<T: DisplayInt>(&self, mut x: T, f: &mut fmt::Formatter<'_>) -> fmt::Result71 fn fmt_int<T: DisplayInt>(&self, mut x: T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 // The radix can be as low as 2, so we need a buffer of at least 128
73 // characters for a base 2 number.
74 let zero = T::zero();
75 let is_nonnegative = x >= zero;
76 let mut buf = [MaybeUninit::<u8>::uninit(); 128];
77 let mut curr = buf.len();
78 let base = T::from_u8(Self::BASE);
79 if is_nonnegative {
80 // Accumulate each digit of the number from the least significant
81 // to the most significant figure.
82 for byte in buf.iter_mut().rev() {
83 let n = x % base; // Get the current place value.
84 x = x / base; // Deaccumulate the number.
85 byte.write(Self::digit(n.to_u8())); // Store the digit in the buffer.
86 curr -= 1;
87 if x == zero {
88 // No more digits left to accumulate.
89 break;
90 };
91 }
92 } else {
93 // Do the same as above, but accounting for two's complement.
94 for byte in buf.iter_mut().rev() {
95 let n = zero - (x % base); // Get the current place value.
96 x = x / base; // Deaccumulate the number.
97 byte.write(Self::digit(n.to_u8())); // Store the digit in the buffer.
98 curr -= 1;
99 if x == zero {
100 // No more digits left to accumulate.
101 break;
102 };
103 }
104 }
105 let buf = &buf[curr..];
106 // SAFETY: The only chars in `buf` are created by `Self::digit` which are assumed to be
107 // valid UTF-8
108 let buf = unsafe {
109 str::from_utf8_unchecked(slice::from_raw_parts(
110 MaybeUninit::slice_as_ptr(buf),
111 buf.len(),
112 ))
113 };
114 f.pad_integral(is_nonnegative, Self::PREFIX, buf)
115 }
116 }
117
118 /// A binary (base 2) radix
119 #[derive(Clone, PartialEq)]
120 struct Binary;
121
122 /// An octal (base 8) radix
123 #[derive(Clone, PartialEq)]
124 struct Octal;
125
126 /// A hexadecimal (base 16) radix, formatted with lower-case characters
127 #[derive(Clone, PartialEq)]
128 struct LowerHex;
129
130 /// A hexadecimal (base 16) radix, formatted with upper-case characters
131 #[derive(Clone, PartialEq)]
132 struct UpperHex;
133
134 macro_rules! radix {
135 ($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => {
136 unsafe impl GenericRadix for $T {
137 const BASE: u8 = $base;
138 const PREFIX: &'static str = $prefix;
139 fn digit(x: u8) -> u8 {
140 match x {
141 $($x => $conv,)+
142 x => panic!("number not in the range 0..={}: {}", Self::BASE - 1, x),
143 }
144 }
145 }
146 }
147 }
148
149 radix! { Binary, 2, "0b", x @ 0 ..= 1 => b'0' + x }
150 radix! { Octal, 8, "0o", x @ 0 ..= 7 => b'0' + x }
151 radix! { LowerHex, 16, "0x", x @ 0 ..= 9 => b'0' + x, x @ 10 ..= 15 => b'a' + (x - 10) }
152 radix! { UpperHex, 16, "0x", x @ 0 ..= 9 => b'0' + x, x @ 10 ..= 15 => b'A' + (x - 10) }
153
154 macro_rules! int_base {
155 (fmt::$Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
156 #[stable(feature = "rust1", since = "1.0.0")]
157 impl fmt::$Trait for $T {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 $Radix.fmt_int(*self as $U, f)
160 }
161 }
162 };
163 }
164
165 macro_rules! integer {
166 ($Int:ident, $Uint:ident) => {
167 int_base! { fmt::Binary for $Int as $Uint -> Binary }
168 int_base! { fmt::Octal for $Int as $Uint -> Octal }
169 int_base! { fmt::LowerHex for $Int as $Uint -> LowerHex }
170 int_base! { fmt::UpperHex for $Int as $Uint -> UpperHex }
171
172 int_base! { fmt::Binary for $Uint as $Uint -> Binary }
173 int_base! { fmt::Octal for $Uint as $Uint -> Octal }
174 int_base! { fmt::LowerHex for $Uint as $Uint -> LowerHex }
175 int_base! { fmt::UpperHex for $Uint as $Uint -> UpperHex }
176 };
177 }
178 integer! { isize, usize }
179 integer! { i8, u8 }
180 integer! { i16, u16 }
181 integer! { i32, u32 }
182 integer! { i64, u64 }
183 integer! { i128, u128 }
184 macro_rules! debug {
185 ($($T:ident)*) => {$(
186 #[stable(feature = "rust1", since = "1.0.0")]
187 impl fmt::Debug for $T {
188 #[inline]
189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190 if f.debug_lower_hex() {
191 fmt::LowerHex::fmt(self, f)
192 } else if f.debug_upper_hex() {
193 fmt::UpperHex::fmt(self, f)
194 } else {
195 fmt::Display::fmt(self, f)
196 }
197 }
198 }
199 )*};
200 }
201 debug! {
202 i8 i16 i32 i64 i128 isize
203 u8 u16 u32 u64 u128 usize
204 }
205
206 // 2 digit decimal look up table
207 static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\
208 2021222324252627282930313233343536373839\
209 4041424344454647484950515253545556575859\
210 6061626364656667686970717273747576777879\
211 8081828384858687888990919293949596979899";
212
213 macro_rules! impl_Display {
214 ($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => {
215 fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 // 2^128 is about 3*10^38, so 39 gives an extra byte of space
217 let mut buf = [MaybeUninit::<u8>::uninit(); 39];
218 let mut curr = buf.len();
219 let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
220 let lut_ptr = DEC_DIGITS_LUT.as_ptr();
221
222 // SAFETY: Since `d1` and `d2` are always less than or equal to `198`, we
223 // can copy from `lut_ptr[d1..d1 + 1]` and `lut_ptr[d2..d2 + 1]`. To show
224 // that it's OK to copy into `buf_ptr`, notice that at the beginning
225 // `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at
226 // each step this is kept the same as `n` is divided. Since `n` is always
227 // non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]`
228 // is safe to access.
229 unsafe {
230 // need at least 16 bits for the 4-characters-at-a-time to work.
231 assert!(crate::mem::size_of::<$u>() >= 2);
232
233 // eagerly decode 4 characters at a time
234 while n >= 10000 {
235 let rem = (n % 10000) as usize;
236 n /= 10000;
237
238 let d1 = (rem / 100) << 1;
239 let d2 = (rem % 100) << 1;
240 curr -= 4;
241
242 // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since
243 // otherwise `curr < 0`. But then `n` was originally at least `10000^10`
244 // which is `10^40 > 2^128 > n`.
245 ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
246 ptr::copy_nonoverlapping(lut_ptr.add(d2), buf_ptr.add(curr + 2), 2);
247 }
248
249 // if we reach here numbers are <= 9999, so at most 4 chars long
250 let mut n = n as usize; // possibly reduce 64bit math
251
252 // decode 2 more chars, if > 2 chars
253 if n >= 100 {
254 let d1 = (n % 100) << 1;
255 n /= 100;
256 curr -= 2;
257 ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
258 }
259
260 // decode last 1 or 2 chars
261 if n < 10 {
262 curr -= 1;
263 *buf_ptr.add(curr) = (n as u8) + b'0';
264 } else {
265 let d1 = n << 1;
266 curr -= 2;
267 ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
268 }
269 }
270
271 // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid
272 // UTF-8 since `DEC_DIGITS_LUT` is
273 let buf_slice = unsafe {
274 str::from_utf8_unchecked(
275 slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr))
276 };
277 f.pad_integral(is_nonnegative, "", buf_slice)
278 }
279
280 $(#[stable(feature = "rust1", since = "1.0.0")]
281 impl fmt::Display for $t {
282 #[allow(unused_comparisons)]
283 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
284 let is_nonnegative = *self >= 0;
285 let n = if is_nonnegative {
286 self.$conv_fn()
287 } else {
288 // convert the negative num to positive by summing 1 to it's 2 complement
289 (!self.$conv_fn()).wrapping_add(1)
290 };
291 $name(n, is_nonnegative, f)
292 }
293 })*
294 };
295 }
296
297 macro_rules! impl_Exp {
298 ($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => {
299 fn $name(
300 mut n: $u,
301 is_nonnegative: bool,
302 upper: bool,
303 f: &mut fmt::Formatter<'_>
304 ) -> fmt::Result {
305 let (mut n, mut exponent, trailing_zeros, added_precision) = {
306 let mut exponent = 0;
307 // count and remove trailing decimal zeroes
308 while n % 10 == 0 && n >= 10 {
309 n /= 10;
310 exponent += 1;
311 }
312
313 let (added_precision, subtracted_precision) = match f.precision() {
314 Some(fmt_prec) => {
315 // number of decimal digits minus 1
316 let mut tmp = n;
317 let mut prec = 0;
318 while tmp >= 10 {
319 tmp /= 10;
320 prec += 1;
321 }
322 (fmt_prec.saturating_sub(prec), prec.saturating_sub(fmt_prec))
323 }
324 None => (0, 0)
325 };
326 for _ in 1..subtracted_precision {
327 n /= 10;
328 exponent += 1;
329 }
330 if subtracted_precision != 0 {
331 let rem = n % 10;
332 n /= 10;
333 exponent += 1;
334 // round up last digit
335 if rem >= 5 {
336 n += 1;
337 }
338 }
339 (n, exponent, exponent, added_precision)
340 };
341
342 // 39 digits (worst case u128) + . = 40
343 // Since `curr` always decreases by the number of digits copied, this means
344 // that `curr >= 0`.
345 let mut buf = [MaybeUninit::<u8>::uninit(); 40];
346 let mut curr = buf.len(); //index for buf
347 let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
348 let lut_ptr = DEC_DIGITS_LUT.as_ptr();
349
350 // decode 2 chars at a time
351 while n >= 100 {
352 let d1 = ((n % 100) as usize) << 1;
353 curr -= 2;
354 // SAFETY: `d1 <= 198`, so we can copy from `lut_ptr[d1..d1 + 2]` since
355 // `DEC_DIGITS_LUT` has a length of 200.
356 unsafe {
357 ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
358 }
359 n /= 100;
360 exponent += 2;
361 }
362 // n is <= 99, so at most 2 chars long
363 let mut n = n as isize; // possibly reduce 64bit math
364 // decode second-to-last character
365 if n >= 10 {
366 curr -= 1;
367 // SAFETY: Safe since `40 > curr >= 0` (see comment)
368 unsafe {
369 *buf_ptr.add(curr) = (n as u8 % 10_u8) + b'0';
370 }
371 n /= 10;
372 exponent += 1;
373 }
374 // add decimal point iff >1 mantissa digit will be printed
375 if exponent != trailing_zeros || added_precision != 0 {
376 curr -= 1;
377 // SAFETY: Safe since `40 > curr >= 0`
378 unsafe {
379 *buf_ptr.add(curr) = b'.';
380 }
381 }
382
383 // SAFETY: Safe since `40 > curr >= 0`
384 let buf_slice = unsafe {
385 // decode last character
386 curr -= 1;
387 *buf_ptr.add(curr) = (n as u8) + b'0';
388
389 let len = buf.len() - curr as usize;
390 slice::from_raw_parts(buf_ptr.add(curr), len)
391 };
392
393 // stores 'e' (or 'E') and the up to 2-digit exponent
394 let mut exp_buf = [MaybeUninit::<u8>::uninit(); 3];
395 let exp_ptr = MaybeUninit::slice_as_mut_ptr(&mut exp_buf);
396 // SAFETY: In either case, `exp_buf` is written within bounds and `exp_ptr[..len]`
397 // is contained within `exp_buf` since `len <= 3`.
398 let exp_slice = unsafe {
399 *exp_ptr.add(0) = if upper { b'E' } else { b'e' };
400 let len = if exponent < 10 {
401 *exp_ptr.add(1) = (exponent as u8) + b'0';
402 2
403 } else {
404 let off = exponent << 1;
405 ptr::copy_nonoverlapping(lut_ptr.add(off), exp_ptr.add(1), 2);
406 3
407 };
408 slice::from_raw_parts(exp_ptr, len)
409 };
410
411 let parts = &[
412 numfmt::Part::Copy(buf_slice),
413 numfmt::Part::Zero(added_precision),
414 numfmt::Part::Copy(exp_slice),
415 ];
416 let sign = if !is_nonnegative {
417 "-"
418 } else if f.sign_plus() {
419 "+"
420 } else {
421 ""
422 };
423 let formatted = numfmt::Formatted { sign, parts };
424 // SAFETY: `buf_slice` and `exp_slice` contain only ASCII characters.
425 unsafe { f.pad_formatted_parts(&formatted) }
426 }
427
428 $(
429 #[stable(feature = "integer_exp_format", since = "1.42.0")]
430 impl fmt::LowerExp for $t {
431 #[allow(unused_comparisons)]
432 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
433 let is_nonnegative = *self >= 0;
434 let n = if is_nonnegative {
435 self.$conv_fn()
436 } else {
437 // convert the negative num to positive by summing 1 to it's 2 complement
438 (!self.$conv_fn()).wrapping_add(1)
439 };
440 $name(n, is_nonnegative, false, f)
441 }
442 })*
443 $(
444 #[stable(feature = "integer_exp_format", since = "1.42.0")]
445 impl fmt::UpperExp for $t {
446 #[allow(unused_comparisons)]
447 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
448 let is_nonnegative = *self >= 0;
449 let n = if is_nonnegative {
450 self.$conv_fn()
451 } else {
452 // convert the negative num to positive by summing 1 to it's 2 complement
453 (!self.$conv_fn()).wrapping_add(1)
454 };
455 $name(n, is_nonnegative, true, f)
456 }
457 })*
458 };
459 }
460
461 // Include wasm32 in here since it doesn't reflect the native pointer size, and
462 // often cares strongly about getting a smaller code size.
463 #[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))]
464 mod imp {
465 use super::*;
466 impl_Display!(
467 i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
468 as u64 via to_u64 named fmt_u64
469 );
470 impl_Exp!(
471 i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
472 as u64 via to_u64 named exp_u64
473 );
474 }
475
476 #[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
477 mod imp {
478 use super::*;
479 impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named fmt_u32);
480 impl_Display!(i64, u64 as u64 via to_u64 named fmt_u64);
481 impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32);
482 impl_Exp!(i64, u64 as u64 via to_u64 named exp_u64);
483 }
484 impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128);
485
486 /// Helper function for writing a u64 into `buf` going from last to first, with `curr`.
parse_u64_into<const N: usize>(mut n: u64, buf: &mut [MaybeUninit<u8>; N], curr: &mut usize)487 fn parse_u64_into<const N: usize>(mut n: u64, buf: &mut [MaybeUninit<u8>; N], curr: &mut usize) {
488 let buf_ptr = MaybeUninit::slice_as_mut_ptr(buf);
489 let lut_ptr = DEC_DIGITS_LUT.as_ptr();
490 assert!(*curr > 19);
491
492 // SAFETY:
493 // Writes at most 19 characters into the buffer. Guaranteed that any ptr into LUT is at most
494 // 198, so will never OOB. There is a check above that there are at least 19 characters
495 // remaining.
496 unsafe {
497 if n >= 1e16 as u64 {
498 let to_parse = n % 1e16 as u64;
499 n /= 1e16 as u64;
500
501 // Some of these are nops but it looks more elegant this way.
502 let d1 = ((to_parse / 1e14 as u64) % 100) << 1;
503 let d2 = ((to_parse / 1e12 as u64) % 100) << 1;
504 let d3 = ((to_parse / 1e10 as u64) % 100) << 1;
505 let d4 = ((to_parse / 1e8 as u64) % 100) << 1;
506 let d5 = ((to_parse / 1e6 as u64) % 100) << 1;
507 let d6 = ((to_parse / 1e4 as u64) % 100) << 1;
508 let d7 = ((to_parse / 1e2 as u64) % 100) << 1;
509 let d8 = ((to_parse / 1e0 as u64) % 100) << 1;
510
511 *curr -= 16;
512
513 ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr + 0), 2);
514 ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(*curr + 2), 2);
515 ptr::copy_nonoverlapping(lut_ptr.add(d3 as usize), buf_ptr.add(*curr + 4), 2);
516 ptr::copy_nonoverlapping(lut_ptr.add(d4 as usize), buf_ptr.add(*curr + 6), 2);
517 ptr::copy_nonoverlapping(lut_ptr.add(d5 as usize), buf_ptr.add(*curr + 8), 2);
518 ptr::copy_nonoverlapping(lut_ptr.add(d6 as usize), buf_ptr.add(*curr + 10), 2);
519 ptr::copy_nonoverlapping(lut_ptr.add(d7 as usize), buf_ptr.add(*curr + 12), 2);
520 ptr::copy_nonoverlapping(lut_ptr.add(d8 as usize), buf_ptr.add(*curr + 14), 2);
521 }
522 if n >= 1e8 as u64 {
523 let to_parse = n % 1e8 as u64;
524 n /= 1e8 as u64;
525
526 // Some of these are nops but it looks more elegant this way.
527 let d1 = ((to_parse / 1e6 as u64) % 100) << 1;
528 let d2 = ((to_parse / 1e4 as u64) % 100) << 1;
529 let d3 = ((to_parse / 1e2 as u64) % 100) << 1;
530 let d4 = ((to_parse / 1e0 as u64) % 100) << 1;
531 *curr -= 8;
532
533 ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr + 0), 2);
534 ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(*curr + 2), 2);
535 ptr::copy_nonoverlapping(lut_ptr.add(d3 as usize), buf_ptr.add(*curr + 4), 2);
536 ptr::copy_nonoverlapping(lut_ptr.add(d4 as usize), buf_ptr.add(*curr + 6), 2);
537 }
538 // `n` < 1e8 < (1 << 32)
539 let mut n = n as u32;
540 if n >= 1e4 as u32 {
541 let to_parse = n % 1e4 as u32;
542 n /= 1e4 as u32;
543
544 let d1 = (to_parse / 100) << 1;
545 let d2 = (to_parse % 100) << 1;
546 *curr -= 4;
547
548 ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr + 0), 2);
549 ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(*curr + 2), 2);
550 }
551
552 // `n` < 1e4 < (1 << 16)
553 let mut n = n as u16;
554 if n >= 100 {
555 let d1 = (n % 100) << 1;
556 n /= 100;
557 *curr -= 2;
558 ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr), 2);
559 }
560
561 // decode last 1 or 2 chars
562 if n < 10 {
563 *curr -= 1;
564 *buf_ptr.add(*curr) = (n as u8) + b'0';
565 } else {
566 let d1 = n << 1;
567 *curr -= 2;
568 ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr), 2);
569 }
570 }
571 }
572
573 #[stable(feature = "rust1", since = "1.0.0")]
574 impl fmt::Display for u128 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result575 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
576 fmt_u128(*self, true, f)
577 }
578 }
579
580 #[stable(feature = "rust1", since = "1.0.0")]
581 impl fmt::Display for i128 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result582 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
583 let is_nonnegative = *self >= 0;
584 let n = if is_nonnegative {
585 self.to_u128()
586 } else {
587 // convert the negative num to positive by summing 1 to it's 2 complement
588 (!self.to_u128()).wrapping_add(1)
589 };
590 fmt_u128(n, is_nonnegative, f)
591 }
592 }
593
594 /// Specialized optimization for u128. Instead of taking two items at a time, it splits
595 /// into at most 2 u64s, and then chunks by 10e16, 10e8, 10e4, 10e2, and then 10e1.
596 /// It also has to handle 1 last item, as 10^40 > 2^128 > 10^39, whereas
597 /// 10^20 > 2^64 > 10^19.
fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result598 fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
599 // 2^128 is about 3*10^38, so 39 gives an extra byte of space
600 let mut buf = [MaybeUninit::<u8>::uninit(); 39];
601 let mut curr = buf.len();
602
603 let (n, rem) = udiv_1e19(n);
604 parse_u64_into(rem, &mut buf, &mut curr);
605
606 if n != 0 {
607 // 0 pad up to point
608 let target = buf.len() - 19;
609 // SAFETY: Guaranteed that we wrote at most 19 bytes, and there must be space
610 // remaining since it has length 39
611 unsafe {
612 ptr::write_bytes(
613 MaybeUninit::slice_as_mut_ptr(&mut buf).add(target),
614 b'0',
615 curr - target,
616 );
617 }
618 curr = target;
619
620 let (n, rem) = udiv_1e19(n);
621 parse_u64_into(rem, &mut buf, &mut curr);
622 // Should this following branch be annotated with unlikely?
623 if n != 0 {
624 let target = buf.len() - 38;
625 // The raw `buf_ptr` pointer is only valid until `buf` is used the next time,
626 // buf `buf` is not used in this scope so we are good.
627 let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
628 // SAFETY: At this point we wrote at most 38 bytes, pad up to that point,
629 // There can only be at most 1 digit remaining.
630 unsafe {
631 ptr::write_bytes(buf_ptr.add(target), b'0', curr - target);
632 curr = target - 1;
633 *buf_ptr.add(curr) = (n as u8) + b'0';
634 }
635 }
636 }
637
638 // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid
639 // UTF-8 since `DEC_DIGITS_LUT` is
640 let buf_slice = unsafe {
641 str::from_utf8_unchecked(slice::from_raw_parts(
642 MaybeUninit::slice_as_mut_ptr(&mut buf).add(curr),
643 buf.len() - curr,
644 ))
645 };
646 f.pad_integral(is_nonnegative, "", buf_slice)
647 }
648
649 /// Partition of `n` into n > 1e19 and rem <= 1e19
650 ///
651 /// Integer division algorithm is based on the following paper:
652 ///
653 /// T. Granlund and P. Montgomery, “Division by Invariant Integers Using Multiplication”
654 /// in Proc. of the SIGPLAN94 Conference on Programming Language Design and
655 /// Implementation, 1994, pp. 61–72
656 ///
udiv_1e19(n: u128) -> (u128, u64)657 fn udiv_1e19(n: u128) -> (u128, u64) {
658 const DIV: u64 = 1e19 as u64;
659 const FACTOR: u128 = 156927543384667019095894735580191660403;
660
661 let quot = if n < 1 << 83 {
662 ((n >> 19) as u64 / (DIV >> 19)) as u128
663 } else {
664 u128_mulhi(n, FACTOR) >> 62
665 };
666
667 let rem = (n - quot * DIV as u128) as u64;
668 (quot, rem)
669 }
670
671 /// Multiply unsigned 128 bit integers, return upper 128 bits of the result
672 #[inline]
u128_mulhi(x: u128, y: u128) -> u128673 fn u128_mulhi(x: u128, y: u128) -> u128 {
674 let x_lo = x as u64;
675 let x_hi = (x >> 64) as u64;
676 let y_lo = y as u64;
677 let y_hi = (y >> 64) as u64;
678
679 // handle possibility of overflow
680 let carry = (x_lo as u128 * y_lo as u128) >> 64;
681 let m = x_lo as u128 * y_hi as u128 + carry;
682 let high1 = m >> 64;
683
684 let m_lo = m as u64;
685 let high2 = (x_hi as u128 * y_lo as u128 + m_lo as u128) >> 64;
686
687 x_hi as u128 * y_hi as u128 + high1 + high2
688 }
689