From a4d77e31641439de3c9c6081a8b905db9362c27d Mon Sep 17 00:00:00 2001 From: chiri Date: Sun, 30 Aug 2026 16:58:40 +0300 Subject: [PATCH] a bit optimize four-digit chunks in integer formatting https://github.com/rust-lang/rust/pull/159130 --- src/lib.rs | 88 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 74cd9b4..69d01c6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -347,7 +347,9 @@ impl Unsigned for u128 { (mod_1e16, u128::MAX_STR_LEN) } else { // Write digits at buf[23..39]. - enc_16lsd::<{ u128::MAX_STR_LEN - 16 }>(buf, mod_1e16); + // + // SAFETY: `mod_1e16 < 1e16` (remainder), and `U128_MAX_DEC_N - 16 + 16 == buf.len()`. + unsafe { enc_16lsd::<{ u128::MAX_STR_LEN - 16 }>(buf, mod_1e16) }; // Take another 16 decimals. let (quot2, mod2) = div_rem_1e16(quot_1e16); @@ -355,7 +357,9 @@ impl Unsigned for u128 { (mod2, u128::MAX_STR_LEN - 16) } else { // Write digits at buf[7..23]. - enc_16lsd::<{ u128::MAX_STR_LEN - 32 }>(buf, mod2); + // + // SAFETY: `mod2 < 1e16` (remainder), and `U128_MAX_DEC_N - 32 + 16 <= buf.len()`. + unsafe { enc_16lsd::<{ u128::MAX_STR_LEN - 32 }>(buf, mod2) }; // Quot2 has at most 7 decimals remaining after two 1e16 divisions. (quot2 as u64, u128::MAX_STR_LEN - 32) } @@ -369,11 +373,10 @@ impl Unsigned for u128 { let quad = remain % 1_00_00; remain /= 1_00_00; let (pair1, pair2) = divmod100(quad as u32); + // SAFETY: quad is a remainder modulo 10_000. The offset checks + // above reserve exactly four bytes in buf. unsafe { - buf[offset + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0)); - buf[offset + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1)); - buf[offset + 2].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0)); - buf[offset + 3].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1)); + write_quad(buf.get_unchecked_mut(offset..offset + 4), quad); } } @@ -403,37 +406,70 @@ impl Unsigned for u128 { } } -// Encodes the 16 least-significant decimals of n into `buf[OFFSET..OFFSET + 16]`. +// Writes `quad` as exactly four digits (for example: `42` becomes `"0042"`). +// +// # Safety +// +// `quad` must be below 10_000 and `buf` must contain exactly four bytes. #[cfg_attr(feature = "no-panic", no_panic)] -fn enc_16lsd(buf: &mut [MaybeUninit], n: u64) { - // Consume the least-significant decimals from a working copy. +#[inline(always)] +unsafe fn write_quad(buf: &mut [MaybeUninit], quad: u64) { + // SAFETY: These are this function's caller-provided invariants. + unsafe { + core::hint::assert_unchecked(quad < 10_000); + core::hint::assert_unchecked(buf.len() == 4); + } + + let quad = quad as u32; + + // Note: this is equivalent to `quad / 100`, but contains no division instructions. + let high = (quad * const { (1 << 19) / 100 + 1 }) >> 19; + let low = quad - high * 100; + let high = high as usize; + let low = low as usize; + + // SAFETY: `high` and `low` are below 100 because `quad` is below 10_000. + unsafe { core::hint::assert_unchecked(high < 100 && low < 100) } + + buf[0..2].write_copy_of_slice(&DECIMAL_PAIRS[high * 2..high * 2 + 2]); + buf[2..4].write_copy_of_slice(&DECIMAL_PAIRS[low * 2..low * 2 + 2]); +} + +// Encodes the 16 least-significant decimals of n into `buf[OFFSET .. OFFSET + 16 ]`. +// +// # Safety +// +// `n` must be below 1e16, and `buf` must be at least `OFFSET + 16` bytes long. +#[cfg_attr(feature = "no-panic", no_panic)] +unsafe fn enc_16lsd(buf: &mut [MaybeUninit], n: u64) { + // SAFETY: Every caller passes a remainder produced by division by 10^16, + // and every used `OFFSET` specialization reserves sixteen bytes in `buf`. + unsafe { + core::hint::assert_unchecked(n < 10_000_000_000_000_000); + core::hint::assert_unchecked(OFFSET + 16 <= buf.len()); + } + + // Peel four digits at a time from right to left (12345678 -> 1234 | 5678). + // Since 10_000 is constant, LLVM replaces each division with multiply or shift. let mut remain = n; - // Format per four digits from the lookup table. for quad_index in (1..4).rev() { - // pull two pairs let quad = remain % 1_00_00; remain /= 1_00_00; - let (pair1, pair2) = divmod100(quad as u32); + + // SAFETY: `OFFSET + quad_index * 4` starts one of the four + // non-overlapping four-byte regions proven in bounds above. unsafe { - buf[quad_index * 4 + OFFSET + 0] - .write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0)); - buf[quad_index * 4 + OFFSET + 1] - .write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1)); - buf[quad_index * 4 + OFFSET + 2] - .write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0)); - buf[quad_index * 4 + OFFSET + 3] - .write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1)); + write_quad( + buf.get_unchecked_mut(OFFSET + quad_index * 4..OFFSET + (quad_index + 1) * 4), + quad, + ); } } - // final two pairs - let (pair1, pair2) = divmod100(remain as u32); + // SAFETY: OFFSET starts the first four-byte region proven in bounds above. unsafe { - buf[OFFSET + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0)); - buf[OFFSET + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1)); - buf[OFFSET + 2].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0)); - buf[OFFSET + 3].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1)); + write_quad(buf.get_unchecked_mut(OFFSET..OFFSET + 4), remain); } }