Skip to content

Commit

Permalink
Destructured code for reusability
Browse files Browse the repository at this point in the history
  • Loading branch information
madhav-madhusoodanan committed Mar 11, 2025
1 parent 040cedb commit 766cc48
Showing 1 changed file with 146 additions and 181 deletions.
327 changes: 146 additions & 181 deletions library/core/src/num/int_format.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use crate::mem::MaybeUninit;
use crate::slice;

/// A minimal buffer implementation containing elements of type
/// `MaybeUninit<u8>`.
#[unstable(feature = "int_format_into", issue = "138215")]
#[derive(Debug)]
pub struct NumBuffer<const BUF_SIZE: usize> {
/// A statically allocated array of elements of type
/// `MaybeUninit::<u8>`.
/// An array of elements of type `MaybeUninit<u8>`.
///
/// An alternative to `contents.len()` is `BUF_SIZE`.
pub contents: [MaybeUninit<u8>; BUF_SIZE],
Expand All @@ -21,11 +21,134 @@ impl<const BUF_SIZE: usize> NumBuffer<BUF_SIZE> {
}
}

macro_rules! int_impl_format_into {
($($T:ident)*) => {
const DEC_DIGITS_LUT: &[u8; 200] = b"\
0001020304050607080910111213141516171819\
2021222324252627282930313233343536373839\
4041424344454647484950515253545556575859\
6061626364656667686970717273747576777879\
8081828384858687888990919293949596979899";

const NEGATIVE_SIGN: &[u8; 1] = b"-";

#[inline]
fn raw_write_sign_into<const BUF_SIZE: usize>(
buf: &mut NumBuffer<BUF_SIZE>,
start_offset: usize,
) -> usize {
let mut offset = start_offset;

// SAFETY: All of the decimals (with the sign) fit in buf, since it now is size-checked
// and the if condition ensures (at least) that the sign can be added.
unsafe { core::hint::assert_unchecked(offset >= 1) }

// SAFETY: The offset counts down from its initial value BUF_SIZE
// without underflow due to the previous precondition.
unsafe { core::hint::assert_unchecked(offset <= BUF_SIZE) }

// Setting sign for the negative number
offset -= 1;
buf.contents[offset].write(NEGATIVE_SIGN[0]);

offset
}

#[inline]
fn raw_extract_as_str<const BUF_SIZE: usize>(buf: &NumBuffer<BUF_SIZE>, offset: usize) -> &str {
// SAFETY: All contents of `buf` since `offset` is set.
let written = unsafe { buf.contents.get_unchecked(offset..) };

// SAFETY: Writes use ASCII from the lookup table
// (and `NEGATIVE_SIGN` in case of negative numbers) exclusively.
let as_str = unsafe {
str::from_utf8_unchecked(slice::from_raw_parts(
MaybeUninit::slice_as_ptr(written),
written.len(),
))
};

as_str
}

macro_rules! raw_write_digits_into {
($T:ty, $BUF_SIZE:expr) => {
|target_var: $T, buf: &mut NumBuffer<{ $BUF_SIZE }>, start_offset: usize| -> usize {
let mut offset = start_offset;

// Consume the least-significant decimals from a working copy.
let mut remain: $T = target_var;

// Format per four digits from the lookup table.
// Four digits need a 16-bit $unsigned or wider.
while size_of::<$T>() > 1
&& remain
> 999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)")
{
// SAFETY: All of the decimals fit in buf, since it now is size-checked
// and the while condition ensures at least 4 more decimals.
unsafe { core::hint::assert_unchecked(offset >= 4) }
// SAFETY: The offset counts down from its initial value $BUF_SIZE
// without underflow due to the previous precondition.
unsafe { core::hint::assert_unchecked(offset <= $BUF_SIZE) }
offset -= 4;

// pull two pairs
let scale: $T = 1_00_00
.try_into()
.expect("branch is not hit for types that cannot fit 1E4 (u8)");

let quad = remain % scale;
remain /= scale;
let pair1 = (quad / 100) as usize;
let pair2 = (quad % 100) as usize;
buf.contents[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
buf.contents[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
buf.contents[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
buf.contents[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, since it now is size-checked
// and the while condition ensures at least 2 more decimals.
unsafe { core::hint::assert_unchecked(offset >= 2) }
// SAFETY: The offset counts down from its initial value $BUF_SIZE
// without underflow due to the previous precondition.
unsafe { core::hint::assert_unchecked(offset <= $BUF_SIZE) }
offset -= 2;

let pair = (remain % 100) as usize;
remain /= 100;
buf.contents[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]);
buf.contents[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]);
}

// Format the last remaining digit, if any.
if remain != 0 || target_var == 0 {
// SAFETY: All of the decimals fit in buf, since it now is size-checked
// and the if condition ensures (at least) 1 more decimals.
unsafe { core::hint::assert_unchecked(offset >= 1) }
// SAFETY: The offset counts down from its initial value $BUF_SIZE
// without underflow due to the previous precondition.
unsafe { core::hint::assert_unchecked(offset <= $BUF_SIZE) }
offset -= 1;

// Either the compiler sees that remain < 10, or it prevents
// a boundary check up next.
let last = (remain & 15) as usize;
buf.contents[offset].write(DEC_DIGITS_LUT[last * 2 + 1]);
// not used: remain = 0;
}

offset
}
};
}

macro_rules! macro_impl_format_into {
(signed; $($SignedT:ty, $UnsignedT:ty)*) => {
$(
#[unstable(feature = "int_format_into", issue = "138215")]
impl $T {
impl $SignedT {
/// Allows users to write an integer (in signed decimal format) into a variable `buf` of
/// type [`NumBuffer`] that is passed by the caller by mutable reference.
///
Expand All @@ -37,26 +160,21 @@ macro_rules! int_impl_format_into {
/// #![feature(int_format_into)]
///
/// use core::num::NumBuffer;
#[doc = concat!("let n = -32", stringify!($T), ";")]
#[doc = concat!("let n = -32", stringify!($SignedT), ";")]
/// let mut buf = NumBuffer::<3>::new();
///
/// assert_eq!(n.format_into(&mut buf), "-32");
/// ```
///
pub fn format_into<const BUF_SIZE: usize>(self, buf: &mut crate::num::NumBuffer<BUF_SIZE>) -> &str {
// 2 digit decimal look up table
const DEC_DIGITS_LUT: &[u8; 200] = b"\
0001020304050607080910111213141516171819\
2021222324252627282930313233343536373839\
4041424344454647484950515253545556575859\
6061626364656667686970717273747576777879\
8081828384858687888990919293949596979899";

const NEGATIVE_SIGN: &[u8; 1] = b"-";

// counting space for negative sign too, if `self` is negative
let sign_offset = if self < 0 {1} else {0};
let decimal_string_size: usize = self.ilog(10) as usize + 1 + sign_offset;
let decimal_string_size: usize = if self < 0 {
self.unsigned_abs().ilog(10) as usize + 1 + 1
} else if self == 0 {
1
} else {
self.ilog(10) as usize + 1
};

// `buf` must have minimum size to store the decimal string version.
// BUF_SIZE is the size of the buffer.
Expand All @@ -66,102 +184,23 @@ macro_rules! int_impl_format_into {

// Count the number of bytes in `buf` that are not initialized.
let mut offset = BUF_SIZE;
// Consume the least-significant decimals from a working copy.
let mut remain = self;

// Format per four digits from the lookup table.
// Four digits need a 16-bit $unsigned or wider.
while size_of::<Self>() > 1 && remain > 999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)") {
// SAFETY: All of the decimals fit in buf, since it now is size-checked
// and the while condition ensures at least 4 more decimals.
unsafe { core::hint::assert_unchecked(offset >= 4) }
// SAFETY: The offset counts down from its initial value BUF_SIZE
// without underflow due to the previous precondition.
unsafe { core::hint::assert_unchecked(offset <= BUF_SIZE) }
offset -= 4;

// pull two pairs
let scale: Self = 1_00_00.try_into().expect("branch is not hit for types that cannot fit 1E4 (u8)");
let quad = remain % scale;
remain /= scale;
let pair1 = (quad / 100) as usize;
let pair2 = (quad % 100) as usize;
buf.contents[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
buf.contents[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
buf.contents[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
buf.contents[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, since it now is size-checked
// and the while condition ensures at least 2 more decimals.
unsafe { core::hint::assert_unchecked(offset >= 2) }
// SAFETY: The offset counts down from its initial value BUF_SIZE
// without underflow due to the previous precondition.
unsafe { core::hint::assert_unchecked(offset <= BUF_SIZE) }
offset -= 2;

let pair = (remain % 100) as usize;
remain /= 100;
buf.contents[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]);
buf.contents[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]);
}

// Format the last remaining digit, if any.
if remain != 0 || self == 0 {
// SAFETY: All of the decimals fit in buf, since it now is size-checked
// and the if condition ensures (at least) 1 more decimals.
unsafe { core::hint::assert_unchecked(offset >= 1) }
// SAFETY: The offset counts down from its initial value BUF_SIZE
// without underflow due to the previous precondition.
unsafe { core::hint::assert_unchecked(offset <= BUF_SIZE) }
offset -= 1;

// Either the compiler sees that remain < 10, or it prevents
// a boundary check up next.
let last = (remain & 15) as usize;
buf.contents[offset].write(DEC_DIGITS_LUT[last * 2 + 1]);
// not used: remain = 0;
}
offset = raw_write_digits_into!($UnsignedT, BUF_SIZE)(self.unsigned_abs(), buf, offset);

if self < 0 {
// SAFETY: All of the decimals (with the sign) fit in buf, since it now is size-checked
// and the if condition ensures (at least) that the sign can be added.
unsafe { core::hint::assert_unchecked(offset >= 1) }

// SAFETY: The offset counts down from its initial value BUF_SIZE
// without underflow due to the previous precondition.
unsafe { core::hint::assert_unchecked(offset <= BUF_SIZE) }

// Setting sign for the negative number
offset -= 1;
buf.contents[offset].write(NEGATIVE_SIGN[0]);
offset = raw_write_sign_into(buf, offset);
}

// SAFETY: All buf content since offset is set.
let written = unsafe { buf.contents.get_unchecked(offset..) };

// SAFETY: Writes use ASCII from the lookup table
// (and `NEGATIVE_SIGN` in case of negative numbers) exclusively.
let as_str = unsafe {
str::from_utf8_unchecked(crate::slice::from_raw_parts(
crate::mem::MaybeUninit::slice_as_ptr(written),
written.len(),
))
};
as_str
raw_extract_as_str(buf, offset)
}
}
)*
};
}

macro_rules! uint_impl_format_into {
($($T:ident)*) => {
(unsigned; $($UnsignedT:ty)*) => {
$(
#[unstable(feature = "int_format_into", issue = "138215")]
impl $T {
impl $UnsignedT {
/// Allows users to write an integer (in signed decimal format) into a variable `buf` of
/// type [`NumBuffer`] that is passed by the caller by mutable reference.
///
Expand All @@ -180,16 +219,8 @@ macro_rules! uint_impl_format_into {
/// ```
///
pub fn format_into<const BUF_SIZE: usize>(self, buf: &mut crate::num::NumBuffer<BUF_SIZE>) -> &str {
// 2 digit decimal look up table
const DEC_DIGITS_LUT: &[u8; 200] = b"\
0001020304050607080910111213141516171819\
2021222324252627282930313233343536373839\
4041424344454647484950515253545556575859\
6061626364656667686970717273747576777879\
8081828384858687888990919293949596979899";

// counting space for negative sign too, if `self` is negative
let decimal_string_size: usize = self.ilog(10) as usize + 1;
let decimal_string_size: usize = if self == 0 { 1 } else { self.ilog(10) as usize + 1 };

// `buf` must have minimum size to store the decimal string version.
// BUF_SIZE is the size of the buffer.
Expand All @@ -199,81 +230,15 @@ macro_rules! uint_impl_format_into {

// Count the number of bytes in `buf` that are not initialized.
let mut offset = BUF_SIZE;
// Consume the least-significant decimals from a working copy.
let mut remain = self;

// Format per four digits from the lookup table.
// Four digits need a 16-bit $unsigned or wider.
while size_of::<Self>() > 1 && remain > 999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)") {
// SAFETY: All of the decimals fit in buf, since it now is size-checked
// and the while condition ensures at least 4 more decimals.
unsafe { core::hint::assert_unchecked(offset >= 4) }
// SAFETY: The offset counts down from its initial value BUF_SIZE
// without underflow due to the previous precondition.
unsafe { core::hint::assert_unchecked(offset <= BUF_SIZE) }
offset -= 4;

// pull two pairs
let scale: Self = 1_00_00.try_into().expect("branch is not hit for types that cannot fit 1E4 (u8)");
let quad = remain % scale;
remain /= scale;
let pair1 = (quad / 100) as usize;
let pair2 = (quad % 100) as usize;
buf.contents[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
buf.contents[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
buf.contents[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
buf.contents[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, since it now is size-checked
// and the while condition ensures at least 2 more decimals.
unsafe { core::hint::assert_unchecked(offset >= 2) }
// SAFETY: The offset counts down from its initial value BUF_SIZE
// without underflow due to the previous precondition.
unsafe { core::hint::assert_unchecked(offset <= BUF_SIZE) }
offset -= 2;

let pair = (remain % 100) as usize;
remain /= 100;
buf.contents[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]);
buf.contents[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]);
}

// Format the last remaining digit, if any.
if remain != 0 || self == 0 {
// SAFETY: All of the decimals fit in buf, since it now is size-checked
// and the if condition ensures (at least) 1 more decimals.
unsafe { core::hint::assert_unchecked(offset >= 1) }
// SAFETY: The offset counts down from its initial value BUF_SIZE
// without underflow due to the previous precondition.
unsafe { core::hint::assert_unchecked(offset <= BUF_SIZE) }
offset -= 1;

// Either the compiler sees that remain < 10, or it prevents
// a boundary check up next.
let last = (remain & 15) as usize;
buf.contents[offset].write(DEC_DIGITS_LUT[last * 2 + 1]);
// not used: remain = 0;
}
offset = raw_write_digits_into!(Self, BUF_SIZE)(self, buf, offset);

// SAFETY: All buf content since offset is set.
let written = unsafe { buf.contents.get_unchecked(offset..) };

// SAFETY: Writes use ASCII from the lookup table exclusively.
let as_str = unsafe {
str::from_utf8_unchecked(crate::slice::from_raw_parts(
crate::mem::MaybeUninit::slice_as_ptr(written),
written.len(),
))
};
as_str
raw_extract_as_str(buf, offset)
}
}
)*
};
}

int_impl_format_into! { i8 i16 i32 i64 i128 isize }
uint_impl_format_into! { u8 u16 u32 u64 u128 usize }
macro_impl_format_into! { unsigned; u8 u16 u32 u64 u128 usize }
macro_impl_format_into! { signed; (i8, u8) (i16, u16) (i32, u32) (i64, u64) (i128, u128) (isize, usize) }

0 comments on commit 766cc48

Please sign in to comment.