Skip to content

Commit 8d5614a

Browse files
committed
compiler hint the implied assertions in fmt::Display of integers
1 parent cf278f7 commit 8d5614a

File tree

1 file changed

+34
-28
lines changed

1 file changed

+34
-28
lines changed

library/core/src/fmt/num.rs

+34-28
Original file line numberDiff line numberDiff line change
@@ -234,70 +234,76 @@ macro_rules! impl_Display {
234234
#[cfg(not(feature = "optimize_for_size"))]
235235
impl $unsigned {
236236
fn _fmt(self, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237-
// Buffer decimals for $unsigned type with fixed positions. Thus
238-
// the least significant digit is located at the last buf byte.
239237
const MAX_DEC_N: usize = $unsigned::MAX.ilog(10) as usize + 1;
238+
// Buffer decimals for $unsigned with right alignment.
240239
let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
241-
// Leading zero count & write index in buf.
240+
// Count the number of bytes in buf that are not initialized.
242241
let mut offset = buf.len();
243-
// Consume decimals from working copy until none left.
242+
// Consume the least-significant decimals from a working copy.
244243
let mut remain = self;
245244

246245
// Format per four digits from the lookup table.
247246
// Four digits need a 16-bit $unsigned or wider.
248247
#[allow(overflowing_literals)]
249248
#[allow(unused_comparisons)]
250-
while offset >= 4 && remain > 999 {
251-
// SAFETY: Offset from the initial buf.len() gets deducted
252-
// with underflow checks exclusively.
249+
while remain > 999 {
250+
// SAFETY: All of the decimals fit in buf due to MAX_DEC_N.
251+
unsafe { core::hint::assert_unchecked(offset >= 4) }
252+
// SAFETY: The offset counts down from its initial buf.len()
253+
// without underflow due to the previous assertion.
253254
unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
254255
offset -= 4;
255256

256257
let quad = remain % 100_00;
257258
remain /= 100_00;
258-
let i1 = (quad / 100) as usize;
259-
let i2 = (quad % 100) as usize;
260-
buf[offset + 0].write(DEC_DIGITS_LUT[i1 * 2 + 0]);
261-
buf[offset + 1].write(DEC_DIGITS_LUT[i1 * 2 + 1]);
262-
buf[offset + 2].write(DEC_DIGITS_LUT[i2 * 2 + 0]);
263-
buf[offset + 3].write(DEC_DIGITS_LUT[i2 * 2 + 1]);
259+
let pair1 = (quad / 100) as usize;
260+
let pair2 = (quad % 100) as usize;
261+
buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
262+
buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
263+
buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
264+
buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
264265
}
265266

266267
// Format per two digits from the lookup table.
267-
if offset >= 2 && remain > 9 {
268-
// SAFETY: Offset from the initial buf.len() gets deducted
269-
// with underflow checks exclusively.
268+
if remain > 9 {
269+
// SAFETY: All of the decimals fit in buf due to MAX_DEC_N.
270+
unsafe { core::hint::assert_unchecked(offset >= 2) }
271+
// SAFETY: The offset counts down from its initial buf.len()
272+
// without underflow due to the previous assertion.
270273
unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
271274
offset -= 2;
272275

273-
let i = (remain % 100) as usize;
276+
let pair = (remain % 100) as usize;
274277
remain /= 100;
275-
buf[offset + 0].write(DEC_DIGITS_LUT[i * 2 + 0]);
276-
buf[offset + 1].write(DEC_DIGITS_LUT[i * 2 + 1]);
278+
buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]);
279+
buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]);
277280
}
278281

279282
// Format the last remaining digit, if any.
280-
if offset != 0 && remain != 0 || self == 0 {
281-
// SAFETY: Offset from the initial buf.len() gets deducted
282-
// with underflow checks exclusively.
283+
if remain != 0 || self == 0 {
284+
// SAFETY: All of the decimals fit in buf due to MAX_DEC_N.
285+
unsafe { core::hint::assert_unchecked(offset >= 1) }
286+
// SAFETY: The offset counts down from its initial buf.len()
287+
// without underflow due to the previous assertion.
283288
unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
284289
offset -= 1;
285290

286291
// Either the compiler sees that remain < 10, or it prevents
287292
// a boundary check up next.
288-
let i = (remain & 15) as usize;
293+
let last = (remain & 15) as usize;
294+
buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]);
289295
// not used: remain = 0;
290-
buf[offset].write(DEC_DIGITS_LUT[i * 2 + 1]);
291296
}
292297

298+
// SAFETY: Offset has been used as a write index.
299+
unsafe { core::hint::assert_unchecked(offset < buf.len()) }
300+
let written = &buf[offset..];
293301
// SAFETY: All buf content since offset is set with bytes form
294302
// the lookup table, which consists of valid ASCII exclusively.
295-
let decimals = unsafe {
296-
let written = &buf[offset..];
303+
f.pad_integral(is_nonnegative, "", unsafe {
297304
let as_init = MaybeUninit::slice_assume_init_ref(written);
298305
str::from_utf8_unchecked(as_init)
299-
};
300-
f.pad_integral(is_nonnegative, "", decimals)
306+
})
301307
}
302308
})*
303309

0 commit comments

Comments
 (0)