Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Algol68
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C with Coccinelle
C++ with Coccinelle
C++ (Circle)
CIRCT
Clean
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
GLSL
Go
Haskell
HLSL
Hook
Hylo
IL
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Mojo
Nim
Numba
Nix
Objective-C
Objective-C++
OCaml
Odin
OpenCL C
Pascal
Pony
PTX
Python
Racket
Raku
Ruby
Rust
Sail
Snowball
Scala
Slang
Solidity
Spice
SPIR-V
Swift
LLVM TableGen
Toit
TypeScript Native
V
Vala
Visual Basic
Vyper
WASM
Zig
Javascript
GIMPLE
Ygen
sway
rust source #2
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
mrustc (master)
rustc 1.0.0
rustc 1.1.0
rustc 1.10.0
rustc 1.11.0
rustc 1.12.0
rustc 1.13.0
rustc 1.14.0
rustc 1.15.1
rustc 1.16.0
rustc 1.17.0
rustc 1.18.0
rustc 1.19.0
rustc 1.2.0
rustc 1.20.0
rustc 1.21.0
rustc 1.22.0
rustc 1.23.0
rustc 1.24.0
rustc 1.25.0
rustc 1.26.0
rustc 1.27.0
rustc 1.27.1
rustc 1.28.0
rustc 1.29.0
rustc 1.3.0
rustc 1.30.0
rustc 1.31.0
rustc 1.32.0
rustc 1.33.0
rustc 1.34.0
rustc 1.35.0
rustc 1.36.0
rustc 1.37.0
rustc 1.38.0
rustc 1.39.0
rustc 1.4.0
rustc 1.40.0
rustc 1.41.0
rustc 1.42.0
rustc 1.43.0
rustc 1.44.0
rustc 1.45.0
rustc 1.45.2
rustc 1.46.0
rustc 1.47.0
rustc 1.48.0
rustc 1.49.0
rustc 1.5.0
rustc 1.50.0
rustc 1.51.0
rustc 1.52.0
rustc 1.53.0
rustc 1.54.0
rustc 1.55.0
rustc 1.56.0
rustc 1.57.0
rustc 1.58.0
rustc 1.59.0
rustc 1.6.0
rustc 1.60.0
rustc 1.61.0
rustc 1.62.0
rustc 1.63.0
rustc 1.64.0
rustc 1.65.0
rustc 1.66.0
rustc 1.67.0
rustc 1.68.0
rustc 1.69.0
rustc 1.7.0
rustc 1.70.0
rustc 1.71.0
rustc 1.72.0
rustc 1.73.0
rustc 1.74.0
rustc 1.75.0
rustc 1.76.0
rustc 1.77.0
rustc 1.78.0
rustc 1.79.0
rustc 1.8.0
rustc 1.80.0
rustc 1.81.0
rustc 1.82.0
rustc 1.83.0
rustc 1.84.0
rustc 1.85.0
rustc 1.86.0
rustc 1.87.0
rustc 1.9.0
rustc beta
rustc nightly
rustc-cg-gcc (master)
x86-64 GCCRS (GCC master)
x86-64 GCCRS (GCCRS master)
x86-64 GCCRS 14.1 (GCC assertions)
x86-64 GCCRS 14.1 (GCC)
x86-64 GCCRS 14.2 (GCC assertions)
x86-64 GCCRS 14.2 (GCC)
x86-64 GCCRS 14.3 (GCC assertions)
x86-64 GCCRS 14.3 (GCC)
x86-64 GCCRS 15.1 (GCC assertions)
x86-64 GCCRS 15.1 (GCC)
Options
Source code
#![feature(maybe_uninit_slice)] use core::fmt; use core::ptr; use core::slice; use core::str; use core::mem::MaybeUninit; static DEC_DIGITS_LUT: &[u8; 200] = b"\ 0001020304050607080910111213141516171819\ 2021222324252627282930313233343536373839\ 4041424344454647484950515253545556575859\ 6061626364656667686970717273747576777879\ 8081828384858687888990919293949596979899"; macro_rules! impl_fmt { ($name:ident, $unsigned:ty) => { #[no_mangle] #[inline(never)] fn $name(mut this: $unsigned, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { const SIZE: usize = <$unsigned>::MAX.ilog(10) as usize + 1; let mut buf = [MaybeUninit::<u8>::uninit(); SIZE]; let mut curr = SIZE; let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); let lut_ptr = DEC_DIGITS_LUT.as_ptr(); // SAFETY: Since `d1` and `d2` are always less than or equal to `198`, we // can copy from `lut_ptr[d1..d1 + 1]` and `lut_ptr[d2..d2 + 1]`. To show // that it's OK to copy into `buf_ptr`, notice that at the beginning // `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at // each step this is kept the same as `n` is divided. Since `n` is always // non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]` // is safe to access. unsafe { // need at least 16 bits for the 4-characters-at-a-time to work. #[allow(overflowing_literals)] #[allow(unused_comparisons)] // This block will be removed for smaller types at compile time and in the worst // case, it will prevent to have the `10000` literal to overflow for `i8` and `u8`. if core::mem::size_of::<$unsigned>() >= 2 { // eagerly decode 4 characters at a time while this >= 10000 { let rem = (this % 10000) as usize; this /= 10000; let d1 = (rem / 100) << 1; let d2 = (rem % 100) << 1; curr -= 4; // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since // otherwise `curr < 0`. But then `n` was originally at least `10000^10` // which is `10^40 > 2^128 > n`. ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(curr), 2); ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(curr + 2), 2); } } // if we reach here numbers are <= 9999, so at most 4 chars long let mut n = this as usize; // possibly reduce 64bit math // decode 2 more chars, if > 2 chars if n >= 100 { let d1 = (n % 100) << 1; n /= 100; curr -= 2; ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2); } // if we reach here numbers are <= 100, so at most 2 chars long // The biggest it can be is 99, and 99 << 1 == 198, so a `u8` is enough. // decode last 1 or 2 chars if n < 10 { curr -= 1; *buf_ptr.add(curr) = (n as u8) + b'0'; } else { let d1 = n << 1; curr -= 2; ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2); } } // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid // UTF-8 since `DEC_DIGITS_LUT` is let buf_slice = unsafe { str::from_utf8_unchecked( slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr)) }; f.pad_integral(is_nonnegative, "", buf_slice) } } } impl_fmt!(fmt_u8_master, u8); impl_fmt!(fmt_u16_master, u16); impl_fmt!(fmt_u32_master, u32); impl_fmt!(fmt_u64_master, u64); impl_fmt!(fmt_u128_master, u128);
rust source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
mrustc (master)
rustc 1.0.0
rustc 1.1.0
rustc 1.10.0
rustc 1.11.0
rustc 1.12.0
rustc 1.13.0
rustc 1.14.0
rustc 1.15.1
rustc 1.16.0
rustc 1.17.0
rustc 1.18.0
rustc 1.19.0
rustc 1.2.0
rustc 1.20.0
rustc 1.21.0
rustc 1.22.0
rustc 1.23.0
rustc 1.24.0
rustc 1.25.0
rustc 1.26.0
rustc 1.27.0
rustc 1.27.1
rustc 1.28.0
rustc 1.29.0
rustc 1.3.0
rustc 1.30.0
rustc 1.31.0
rustc 1.32.0
rustc 1.33.0
rustc 1.34.0
rustc 1.35.0
rustc 1.36.0
rustc 1.37.0
rustc 1.38.0
rustc 1.39.0
rustc 1.4.0
rustc 1.40.0
rustc 1.41.0
rustc 1.42.0
rustc 1.43.0
rustc 1.44.0
rustc 1.45.0
rustc 1.45.2
rustc 1.46.0
rustc 1.47.0
rustc 1.48.0
rustc 1.49.0
rustc 1.5.0
rustc 1.50.0
rustc 1.51.0
rustc 1.52.0
rustc 1.53.0
rustc 1.54.0
rustc 1.55.0
rustc 1.56.0
rustc 1.57.0
rustc 1.58.0
rustc 1.59.0
rustc 1.6.0
rustc 1.60.0
rustc 1.61.0
rustc 1.62.0
rustc 1.63.0
rustc 1.64.0
rustc 1.65.0
rustc 1.66.0
rustc 1.67.0
rustc 1.68.0
rustc 1.69.0
rustc 1.7.0
rustc 1.70.0
rustc 1.71.0
rustc 1.72.0
rustc 1.73.0
rustc 1.74.0
rustc 1.75.0
rustc 1.76.0
rustc 1.77.0
rustc 1.78.0
rustc 1.79.0
rustc 1.8.0
rustc 1.80.0
rustc 1.81.0
rustc 1.82.0
rustc 1.83.0
rustc 1.84.0
rustc 1.85.0
rustc 1.86.0
rustc 1.87.0
rustc 1.9.0
rustc beta
rustc nightly
rustc-cg-gcc (master)
x86-64 GCCRS (GCC master)
x86-64 GCCRS (GCCRS master)
x86-64 GCCRS 14.1 (GCC assertions)
x86-64 GCCRS 14.1 (GCC)
x86-64 GCCRS 14.2 (GCC assertions)
x86-64 GCCRS 14.2 (GCC)
x86-64 GCCRS 14.3 (GCC assertions)
x86-64 GCCRS 14.3 (GCC)
x86-64 GCCRS 15.1 (GCC assertions)
x86-64 GCCRS 15.1 (GCC)
Options
Source code
#![feature(maybe_uninit_slice)] use core::fmt; use core::str; use core::mem::MaybeUninit; static DEC_DIGITS_LUT: &[u8; 200] = b"\ 0001020304050607080910111213141516171819\ 2021222324252627282930313233343536373839\ 4041424344454647484950515253545556575859\ 6061626364656667686970717273747576777879\ 8081828384858687888990919293949596979899"; macro_rules! impl_fmt { ($name:ident, $unsigned:ty) => { #[no_mangle] #[inline(never)] pub fn $name(this: $unsigned, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { const MAX_DEC_N: usize = <$unsigned>::MAX.ilog(10) as usize + 1; // Buffer decimals for $unsigned with right alignment. let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N]; // Count the number of bytes in buf that are not initialized. let mut offset = buf.len(); // Consume the least-significant decimals from a working copy. let mut remain = this; // Format per four digits from the lookup table. // Four digits need a 16-bit $unsigned or wider. #[allow(overflowing_literals)] #[allow(unused_comparisons)] while remain > 999 { // SAFETY: All of the decimals fit in buf due to MAX_DEC_N. unsafe { core::hint::assert_unchecked(offset >= 4) } // SAFETY: The offset counts down from its initial buf.len() // without underflow due to the previous assertion. unsafe { core::hint::assert_unchecked(offset <= buf.len()) } offset -= 4; let quad = remain % 100_00; remain /= 100_00; let pair1 = (quad / 100) as usize; let pair2 = (quad % 100) as usize; buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]); buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]); buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]); buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]); } // Format per two digits from the lookup table. if remain > 9 { // SAFETY: All of the decimals fit in buf due to MAX_DEC_N. unsafe { core::hint::assert_unchecked(offset >= 2) } // SAFETY: The offset counts down from its initial buf.len() // without underflow due to the previous assertion. unsafe { core::hint::assert_unchecked(offset <= buf.len()) } offset -= 2; let pair = (remain % 100) as usize; remain /= 100; buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]); buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]); } // Format the last remaining digit, if any. if remain != 0 || this == 0 { // SAFETY: All of the decimals fit in buf due to MAX_DEC_N. unsafe { core::hint::assert_unchecked(offset >= 1) } // SAFETY: The offset counts down from its initial buf.len() // without underflow due to the previous assertion. unsafe { core::hint::assert_unchecked(offset <= buf.len()) } offset -= 1; // Either the compiler sees that remain < 10, or it prevents // a boundary check up next. let last = (remain & 15) as usize; buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]); // not used: remain = 0; } // SAFETY: Offset has been used as a write index. unsafe { core::hint::assert_unchecked(offset < buf.len()) } let written = &buf[offset..]; // SAFETY: All buf content since offset is set with bytes form // the lookup table, which consists of valid ASCII exclusively. f.pad_integral(is_nonnegative, "", unsafe { let as_init = MaybeUninit::slice_assume_init_ref(written); str::from_utf8_unchecked(as_init) }) } } } impl_fmt!(fmt_u8_pr, u8); impl_fmt!(fmt_u16_pr, u16); impl_fmt!(fmt_u32_pr, u32); impl_fmt!(fmt_u64_pr, u64); impl_fmt!(fmt_u128_pr, u128);
Become a Patron
Sponsor on GitHub
Donate via PayPal
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
CE on Bluesky
About the author
Statistics
Changelog
Version tree