1//! Formatting utilities for numbers.
2//!
3//! These functions are low-level, but are designed to be _extremely_ fast for their designed use
4//! cases. They have strict requirements, and may not return the most ergonomic types to avoid
5//! unnecessary allocations and copying.
67use core::mem::MaybeUninit;
8use core::ops::Deref;
9use core::{ptr, slice};
1011#[cfg(feature = "formatting")]
12use deranged::ru64;
13use deranged::{ru8, ru16, ru32};
1415static SINGLE_DIGITS: [u8; 10] = *b"0123456789";
1617static ZERO_PADDED_PAIRS: [u8; 200] = *b"0001020304050607080910111213141516171819\
18 2021222324252627282930313233343536373839\
19 4041424344454647484950515253545556575859\
20 6061626364656667686970717273747576777879\
21 8081828384858687888990919293949596979899";
2223#[cfg(feature = "formatting")]
24static SPACE_PADDED_PAIRS: [u8; 200] = *b" 0 1 2 3 4 5 6 7 8 910111213141516171819\
25 2021222324252627282930313233343536373839\
26 4041424344454647484950515253545556575859\
27 6061626364656667686970717273747576777879\
28 8081828384858687888990919293949596979899";
2930/// A string type with a maximum length known at compile time, stored on the stack.
31///
32/// Note that while the _maximum_ length is known at compile time, the string may be shorter. This
33/// information is stored inline.
34#[derive(#[automatically_derived]
impl<const MAX_LEN : usize> ::core::clone::Clone for StackStr<MAX_LEN> {
#[inline]
fn clone(&self) -> StackStr<MAX_LEN> {
let _: ::core::clone::AssertParamIsClone<[MaybeUninit<u8>; MAX_LEN]>;
let _: ::core::clone::AssertParamIsClone<usize>;
*self
}
}Clone, #[automatically_derived]
impl<const MAX_LEN : usize> ::core::marker::Copy for StackStr<MAX_LEN> { }Copy)]
35pub(crate) struct StackStr<const MAX_LEN: usize> {
36 buf: [MaybeUninit<u8>; MAX_LEN],
37 len: usize,
38}
3940impl<const MAX_LEN: usize> StackStr<MAX_LEN> {
41/// # Safety:
42 ///
43 /// - `buf` must be initialized for at least `len` bytes.
44 /// - The first `len` bytes of `buf` must be valid UTF-8.
45#[inline]
46pub(crate) const unsafe fn new(buf: [MaybeUninit<u8>; MAX_LEN], len: usize) -> Self {
47if true {
if !(len <= MAX_LEN) {
::core::panicking::panic("assertion failed: len <= MAX_LEN")
};
};debug_assert!(len <= MAX_LEN);
48Self { buf, len }
49 }
50}
5152impl<const MAX_LEN: usize> Dereffor StackStr<MAX_LEN> {
53type Target = str;
5455#[inline]
56fn deref(&self) -> &Self::Target {
57// Safety: This type can only be constructed when the caller asserts that the buffer is
58 // valid UTF-8 for the first `len` bytes.
59unsafe { str_from_raw_parts(self.buf.as_ptr().cast(), self.len) }
60 }
61}
6263/// A string type with a maximum length known at compile time, stored on the stack.
64///
65/// Note that while the _maximum_ length is known at compile time, the string may be shorter. This
66/// information is stored inline.
67#[derive(#[automatically_derived]
impl<const MAX_LEN : usize> ::core::clone::Clone for StackTrailingStr<MAX_LEN>
{
#[inline]
fn clone(&self) -> StackTrailingStr<MAX_LEN> {
let _: ::core::clone::AssertParamIsClone<[MaybeUninit<u8>; MAX_LEN]>;
let _: ::core::clone::AssertParamIsClone<usize>;
*self
}
}Clone, #[automatically_derived]
impl<const MAX_LEN : usize> ::core::marker::Copy for StackTrailingStr<MAX_LEN>
{
}Copy)]
68pub(crate) struct StackTrailingStr<const MAX_LEN: usize> {
69 buf: [MaybeUninit<u8>; MAX_LEN],
70 start_index: usize,
71}
7273impl<const MAX_LEN: usize> StackTrailingStr<MAX_LEN> {
74/// # Safety:
75 ///
76 /// - The last `MAX_LEN - start_index` bytes of `buf` must be initialized and valid UTF-8.
77#[inline]
78pub(crate) const unsafe fn new(buf: [MaybeUninit<u8>; MAX_LEN], start_index: usize) -> Self {
79if true {
if !(start_index <= MAX_LEN) {
::core::panicking::panic("assertion failed: start_index <= MAX_LEN")
};
};debug_assert!(start_index <= MAX_LEN);
80Self { buf, start_index }
81 }
8283/// Return the length of `self` in bytes.
84#[inline]
85pub(crate) const fn len(&self) -> usize {
86let len = MAX_LEN - self.start_index;
87// Safety: `self.start_index` is an unsigned integer, so `len` cannot be larger than
88 // `MAX_LEN` with the arithmetic above.
89unsafe { core::hint::assert_unchecked(len <= MAX_LEN) };
90len91 }
92}
9394impl<const MAX_LEN: usize> Dereffor StackTrailingStr<MAX_LEN> {
95type Target = str;
9697#[inline]
98fn deref(&self) -> &Self::Target {
99// Safety: This type can only be constructed when the caller asserts that the buffer is
100 // valid UTF-8 for the last `len` bytes.
101unsafe {
102str_from_raw_parts(
103self.buf.as_ptr().add(self.start_index).cast(),
104MAX_LEN - self.start_index,
105 )
106 }
107 }
108}
109110/// Write a two digit integer to `buf` at `offset` and `offset + 1`.
111///
112/// # Safety
113///
114/// `buf` must be at least `offset + 2` bytes long.
115#[inline]
116const unsafe fn write_two_digits(buf: &mut [MaybeUninit<u8>], offset: usize, value: ru8<0, 99>) {
117// Safety: `buf` is at least `offset + 2` bytes long.
118unsafe {
119 ptr::copy_nonoverlapping(
120two_digits_zero_padded(value).as_ptr().cast(),
121buf.as_mut_ptr().add(offset),
1222,
123 );
124 }
125}
126127/// Write a single digit integer to `buf` at `offset`.
128///
129/// # Safety
130///
131/// `buf` must be at least `offset` bytes long.
132#[inline]
133const unsafe fn write_one_digit(buf: &mut [MaybeUninit<u8>], offset: usize, value: ru8<0, 9>) {
134// Safety: `buf` is at least `offset` bytes long.
135unsafe {
136 ptr::copy_nonoverlapping(
137single_digit(value).as_ptr().cast(),
138buf.as_mut_ptr().add(offset),
1391,
140 );
141 }
142}
143144/// # Safety
145///
146/// - `ptr` must be non-null and point to `len` initialized bytes of UTF-8 data.
147/// - `ptr` is valid for (and not mutated during) lifetime `'a`.
148#[inline]
149pub(crate) const unsafe fn str_from_raw_parts<'a>(ptr: *const u8, len: usize) -> &'a str {
150// Safety: The caller must ensure that `ptr` is valid for `len` bytes and that the bytes are
151 // valid UTF-8. The caller must also ensure that the lifetime `'a` is valid for the returned
152 // string.
153unsafe { str::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) }
154}
155156#[inline]
157const fn div_100(n: ru16<0, 9_999>) -> [ru8<0, 99>; 2] {
158const EXP: u32 = 19; // 19 is faster or equal to 12 even for 3 digits.
159const SIG: u32 = (1 << EXP) / 100 + 1;
160161let n = n.get();
162163let high = (nas u32 * SIG) >> EXP; // value / 100
164let low = nas u32 - high * 100;
165166// Safety: `high` is guaranteed to be less than 100 and `low` is guaranteed to be less than 100
167 // due to the arithmetic above.
168unsafe {
169 [
170ru8::new_unchecked(highas u8),
171ru8::new_unchecked(lowas u8),
172 ]
173 }
174}
175176/// Obtain a string containing a single ASCII digit representing `n`.
177#[inline]
178pub(crate) const fn single_digit(n: ru8<0, 9>) -> &'static str {
179// Safety: We're staying within the bounds of the array. The array contains only ASCII
180 // characters, so it's valid UTF-8.
181unsafe { str_from_raw_parts(SINGLE_DIGITS.as_ptr().add(n.get() as usize), 1) }
182}
183184/// Obtain a string of one or two ASCII digits representing `n`. No leading zeros or spaces are
185/// included.
186#[inline]
187pub(crate) const fn one_to_two_digits_no_padding(n: ru8<0, 99>) -> &'static str {
188let n = n.get();
189let is_single_digit = n < 10;
190// Safety: We're staying within the bounds of the array. The array contains only ASCII
191 // characters, so it's valid UTF-8.
192unsafe {
193str_from_raw_parts(
194ZERO_PADDED_PAIRS195 .as_ptr()
196 .add((nas usize) * 2 + is_single_digitas usize),
1972 - is_single_digitas usize,
198 )
199 }
200}
201202/// Obtain a string of two ASCII digits representing `n`. This includes a leading zero if `n` is
203/// less than 10.
204#[inline]
205pub(crate) const fn two_digits_zero_padded(n: ru8<0, 99>) -> &'static str {
206// Safety: We're staying within the bounds of the array. The array contains only ASCII
207 // characters, so it's valid UTF-8.
208unsafe { str_from_raw_parts(ZERO_PADDED_PAIRS.as_ptr().add((n.get() as usize) * 2), 2) }
209}
210211/// Obtain a string of two ASCII digits representing `n`. This includes a leading space if `n` is
212/// less than 10.
213#[inline]
214#[cfg(feature = "formatting")]
215pub(crate) const fn two_digits_space_padded(n: ru8<0, 99>) -> &'static str {
216// Safety: We're staying within the bounds of the array. The array contains only ASCII
217 // characters, so it's valid UTF-8.
218unsafe { str_from_raw_parts(SPACE_PADDED_PAIRS.as_ptr().add((n.get() as usize) * 2), 2) }
219}
220221/// Obtain two strings of ASCII digits representing `n`. The first string is most significant. No
222/// leading zeros or spaces are included.
223#[inline]
224#[cfg(feature = "formatting")]
225pub(crate) fn one_to_three_digits_no_padding(n: ru16<0, 999>) -> [&'static str; 2] {
226if let Some(n) = n.narrow::<0, 99>() {
227crate::hint::cold_path();
228 ["", one_to_two_digits_no_padding(n.into())]
229 } else {
230three_digits_zero_padded(n)
231 }
232}
233234/// Obtain two strings of ASCII digits representing `n`. The first string is the most significant.
235/// Leading zeros are included if the number has fewer than 3 digits.
236#[inline]
237#[cfg(feature = "formatting")]
238pub(crate) const fn three_digits_zero_padded(n: ru16<0, 999>) -> [&'static str; 2] {
239let [high, low] = div_100(n.expand());
240 [
241// Safety: `high` is guaranteed to be less than 10 due to the range of the input.
242single_digit(unsafe { high.narrow_unchecked() }),
243two_digits_zero_padded(low),
244 ]
245}
246247/// Obtain two strings of ASCII digits representing `n`. The first string is the most significant.
248/// Leading spaces are included if the number has fewer than 3 digits.
249#[inline]
250#[cfg(feature = "formatting")]
251pub(crate) const fn three_digits_space_padded(n: ru16<0, 999>) -> [&'static str; 2] {
252let [high, low] = div_100(n.expand());
253254if let Some(high) = high.narrow::<1, 9>() {
255 [single_digit(high.expand()), two_digits_zero_padded(low)]
256 } else {
257 [" ", two_digits_space_padded(low)]
258 }
259}
260261/// Obtain two strings of ASCII digits representing `n`. The first string is the most significant.
262/// No leading zeros or spaces are included.
263#[inline]
264#[cfg(feature = "formatting")]
265pub(crate) fn one_to_four_digits_no_padding(n: ru16<0, 9_999>) -> [&'static str; 2] {
266if let Some(n) = n.narrow::<0, 999>() {
267crate::hint::cold_path();
268one_to_three_digits_no_padding(n)
269 } else {
270four_digits_zero_padded(n)
271 }
272}
273274/// Obtain two strings of two ASCII digits each representing `n`. The first string is the most
275/// significant. Leading zeros are included if the number has fewer than 4 digits.
276#[inline]
277pub(crate) const fn four_digits_zero_padded(n: ru16<0, 9_999>) -> [&'static str; 2] {
278let [high, low] = div_100(n);
279 [two_digits_zero_padded(high), two_digits_zero_padded(low)]
280}
281282/// Obtain two strings of two ASCII digits each representing `n`. The first string is the most
283/// significant. Leading spaces are included if the number has fewer than 4 digits.
284#[inline]
285#[cfg(feature = "formatting")]
286pub(crate) const fn four_digits_space_padded(n: ru16<0, 9_999>) -> [&'static str; 2] {
287let [high, low] = div_100(n);
288289if high.get() == 0 {
290 [" ", two_digits_space_padded(low)]
291 } else {
292 [two_digits_space_padded(high), two_digits_zero_padded(low)]
293 }
294}
295296/// Obtain three strings which together represent `n`. The first string is the most significant.
297/// Leading zeros are included if the number has fewer than 4 digits. The first string will be empty
298/// if `n` is less than 10,000.
299#[inline]
300pub(crate) const fn four_to_six_digits(n: ru32<0, 999_999>) -> [&'static str; 3] {
301let n = n.get();
302303let (first_two, remaining) = (n / 10_000, n % 10_000);
304305let size = 2 - (first_two < 10) as usize - (first_two == 0) as usize;
306let offset = first_twoas usize * 2 + 2 - size;
307308// Safety: `offset` is within the bounds of the array. The array contains only ASCII characters,
309 // so it's valid UTF-8.
310let first_two = unsafe { str_from_raw_parts(ZERO_PADDED_PAIRS.as_ptr().add(offset), size) };
311// Safety: `remaining` is guaranteed to be less than 10,000 due to the modulus above.
312let [second_two, last_two] =
313four_digits_zero_padded(unsafe { ru16::new_unchecked(remainingas u16) });
314 [first_two, second_two, last_two]
315}
316317/// Obtain three strings which together represent `n`. The first string is the most significant.
318/// Leading zeros are included if the number has fewer than 5 digits. The first string will be empty
319/// if `n` is less than 10,000.
320#[inline]
321#[cfg(feature = "formatting")]
322pub(crate) const fn five_digits_zero_padded(n: ru32<0, 99_999>) -> [&'static str; 3] {
323let n = n.get();
324325let (first_one, remaining) = (n / 10_000, n % 10_000);
326327// Safety: `first_one` is guaranteed to be less than 10 due to the division above.
328let first_one = single_digit(unsafe { ru8::new_unchecked(first_oneas u8) });
329// Safety: `remaining` is guaranteed to be less than 10,000 due to the modulus above.
330let [second_two, last_two] =
331four_digits_zero_padded(unsafe { ru16::new_unchecked(remainingas u16) });
332 [first_one, second_two, last_two]
333}
334335/// Obtain three strings which together represent `n`. The first string is the most significant.
336/// Leading zeroes are included if the number has fewer than 6 digits.
337#[inline]
338#[cfg(feature = "formatting")]
339pub(crate) const fn six_digits_zero_padded(n: ru32<0, 999_999>) -> [&'static str; 3] {
340let n = n.get();
341342let (first_two, remaining) = (n / 10_000, n % 10_000);
343344// Safety: `first_two` is guaranteed to be less than 100 due to the division above.
345let first_two = two_digits_zero_padded(unsafe { ru8::new_unchecked(first_twoas u8) });
346// Safety: `remaining` is guaranteed to be less than 10,000 due to the modulus above.
347let [second_two, last_two] =
348four_digits_zero_padded(unsafe { ru16::new_unchecked(remainingas u16) });
349 [first_two, second_two, last_two]
350}
351352/// Obtain five strings which together represent `n`, which is a number of nanoseconds.
353///
354/// This value is intended to be used after a decimal point to represent a fractional second. The
355/// first string will always contain exactly one digit; the remaining four will contain two digits
356/// each.
357#[inline]
358pub(crate) const fn subsecond_from_nanos(n: ru32<0, 999_999_999>) -> [&'static str; 5] {
359let n = n.get();
360let (digits_1_thru_5, digits_6_thru_9) = (n / 10_000, n % 10_000);
361let (digit_1, digits_2_thru_5) = (digits_1_thru_5 / 10_000, digits_1_thru_5 % 10_000);
362363// Safety: The type of `n` ensures that `n` is less than 1,000,000,000. Combined with the
364 // arithmetic above, this guarantees that all values are in the required ranges.
365unsafe {
366let digit_1 = single_digit(ru8::new_unchecked(digit_1as u8));
367let [digits_2_and_3, digits_4_and_5] =
368four_digits_zero_padded(ru16::new_unchecked(digits_2_thru_5as u16));
369let [digits_6_and_7, digits_8_and_9] =
370four_digits_zero_padded(ru16::new_unchecked(digits_6_thru_9as u16));
371372 [
373digit_1,
374digits_2_and_3,
375digits_4_and_5,
376digits_6_and_7,
377digits_8_and_9,
378 ]
379 }
380}
381382/// Obtain a string of 1 to 9 ASCII digits representing `n`, which is a number of nanoseconds.
383///
384/// This value is intended to be used after a decimal point to represent a fractional second.
385/// Trailing zeros are truncated, but at least one digit is always present.
386#[inline]
387pub(crate) const fn truncated_subsecond_from_nanos(n: ru32<0, 999_999_999>) -> StackStr<9> {
388#[repr(C, align(8))]
389#[derive(#[automatically_derived]
impl ::core::clone::Clone for Digits {
#[inline]
fn clone(&self) -> Digits {
let _: ::core::clone::AssertParamIsClone<MaybeUninit<[u8; 7]>>;
let _: ::core::clone::AssertParamIsClone<u8>;
let _: ::core::clone::AssertParamIsClone<[u8; 8]>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Digits { }Copy)]
390struct Digits {
391 _padding: MaybeUninit<[u8; 7]>,
392 digit_1: u8,
393 digits_2_thru_9: [u8; 8],
394 }
395396let [
397 digit_1,
398 digits_2_and_3,
399 digits_4_and_5,
400 digits_6_and_7,
401 digits_8_and_9,
402 ] = subsecond_from_nanos(n);
403404// Ensure that digits 2 thru 9 are stored as a single array that is 8-aligned. This allows the
405 // conversion to a `u64` to be zero cost, resulting in a nontrivial performance improvement.
406let buf = Digits {
407 _padding: MaybeUninit::uninit(),
408 digit_1: digit_1.as_bytes()[0],
409 digits_2_thru_9: [
410digits_2_and_3.as_bytes()[0],
411digits_2_and_3.as_bytes()[1],
412digits_4_and_5.as_bytes()[0],
413digits_4_and_5.as_bytes()[1],
414digits_6_and_7.as_bytes()[0],
415digits_6_and_7.as_bytes()[1],
416digits_8_and_9.as_bytes()[0],
417digits_8_and_9.as_bytes()[1],
418 ],
419 };
420421// By converting the bytes into a single integer, we can effectively perform an equality check
422 // against b'0' for all bytes at once. This is actually faster than using portable SIMD (even
423 // with `-Ctarget-cpu=native`).
424let bitmask = u64::from_le_bytes(buf.digits_2_thru_9) ^ u64::from_le_bytes([b'0'; 8]);
425let digits_to_truncate = bitmask.leading_zeros() / 8;
426let len = 9 - digits_to_truncateas usize;
427428// Safety: All bytes are initialized and valid UTF-8, and `len` represents the number of bytes
429 // we wish to display (that is between 1 and 9 inclusive). `Digits` is `#[repr(C)]`, so the
430 // layout is guaranteed.
431unsafe {
432StackStr::new(
433*(&raw const buf)
434 .byte_add(const { builtin # offset_of(Digits, digit_1) }core::mem::offset_of!(Digits, digit_1))
435 .cast(),
436len,
437 )
438 }
439}
440441/// Format a `u64` into a string with no padding.
442#[inline]
443pub(crate) const fn u64_pad_none(value: u64) -> StackTrailingStr<20> {
444let mut bytes = [MaybeUninit::uninit(); 20];
445446let mut offset = 20;
447let mut remain = value;
448449while remain > 999 {
450 offset -= 4;
451let quad = remain % 1_00_00;
452 remain /= 1_00_00;
453// Safety: `quad` is guaranteed to be less than 10,000 due to the modulus above.
454let [pair1, pair2] = div_100(unsafe { ru16::new_unchecked(quad as u16) });
455// Safety: `buf` is at least `offset + 4` bytes long.
456unsafe {
457 write_two_digits(&mut bytes, offset, pair1);
458 write_two_digits(&mut bytes, offset + 2, pair2);
459 }
460 }
461462if remain > 9 {
463offset -= 2;
464465// Safety: `remain` is guaranteed to be less than 10,000 due to the loop above.
466let [last, pair] = div_100(unsafe { ru16::new_unchecked(remainas u16) });
467remain = last.get() as u64;
468// Safety: `buf` is at least `offset + 2` bytes long.
469unsafe { write_two_digits(&mut bytes, offset, pair) };
470 }
471472if remain != 0 || value == 0 {
473offset -= 1;
474475let last = remainas u8 & 15;
476// Safety: `offset` is known to be in bounds, and the value is known to be less than 10 due
477 // to the conditionals and bitwise AND above.
478unsafe { write_one_digit(&mut bytes, offset, ru8::new_unchecked(last)) };
479 }
480481// Safety: All bytes starting at `offset` are initialized and valid UTF-8.
482unsafe { StackTrailingStr::new(bytes, offset) }
483}
484485/// Format a `u128` into a string with no padding.
486#[inline]
487#[cfg(feature = "formatting")]
488pub(crate) const fn u128_pad_none(value: u128) -> StackTrailingStr<39> {
489let mut bytes = [MaybeUninit::uninit(); 39];
490491// Take the 16 least-significant decimals.
492let (quot_1e16, mod_1e16) = div_rem_1e16(value);
493let (mut remain, mut offset) = if quot_1e16 == 0 {
494 (mod_1e16.get(), 39)
495 } else {
496// Write digits at buf[23..39].
497 // Safety: `bytes` is 39 bytes long, so writing at offset 23 for 16 bytes is sound.
498unsafe { enc_16lsd::<23>(&mut bytes, mod_1e16) };
499500// Take another 16 decimals.
501let (quot2, mod2) = div_rem_1e16(quot_1e16);
502if quot2 == 0 {
503 (mod2.get(), 23)
504 } else {
505// Write digits at buf[7..23].
506 // Safety: `bytes` is 39 bytes long, so writing at offset 7 for 16 bytes is sound.
507unsafe { enc_16lsd::<7>(&mut bytes, mod2) };
508// Safety: `quot2`` has at most 7 decimals remaining after two 1e16 divisions.
509(quot2as u64, 7)
510 }
511 };
512513// Format per four digits from the lookup table.
514while remain > 999 {
515 offset -= 4;
516517// pull two pairs
518let quad = remain % 1_00_00;
519 remain /= 1_00_00;
520// Safety: `quad` is guaranteed to be less than 10,000 due to the modulus above.
521let [pair1, pair2] = div_100(unsafe { ru16::new_unchecked(quad as u16) });
522// Safety: `buf` is at least `offset + 4` bytes long.
523unsafe {
524 write_two_digits(&mut bytes, offset, pair1);
525 write_two_digits(&mut bytes, offset + 2, pair2);
526 }
527 }
528529// Format per two digits from the lookup table.
530if remain > 9 {
531offset -= 2;
532533// Safety: `remain` is guaranteed to be less than 10,000 due to the loop above.
534let [last, pair] = div_100(unsafe { ru16::new_unchecked(remainas u16) });
535remain = last.get() as u64;
536// Safety: `buf` is at least `offset + 2` bytes long.
537unsafe { write_two_digits(&mut bytes, offset, pair) };
538 }
539540// Format the last remaining digit, if any.
541if remain != 0 || value == 0 {
542offset -= 1;
543544// Either the compiler sees that remain < 10, or it prevents a boundary check up next.
545let last = remainas u8 & 15;
546// Safety: `offset` is known to be in bounds, and the value is known to be less than 10 due
547 // to the conditionals and bitwise AND above.
548unsafe { write_one_digit(&mut bytes, offset, ru8::new_unchecked(last)) };
549 }
550551// Safety: All bytes starting at `offset` are initialized and valid UTF-8.
552unsafe { StackTrailingStr::new(bytes, offset) }
553}
554555/// Encodes the 16 least-significant decimals of n into `buf[OFFSET..OFFSET + 16]`.
556///
557/// # Safety
558///
559/// - `buf` must be at least `OFFSET + 16` bytes long.
560#[cfg(feature = "formatting")]
561const unsafe fn enc_16lsd<const OFFSET: usize>(
562 buf: &mut [MaybeUninit<u8>],
563 n: ru64<0, 9999_9999_9999_9999>,
564) {
565// Consume the least-significant decimals from a working copy.
566let mut remain = n.get();
567568let mut quad_index = 3;
569while quad_index >= 1 {
570let quad = remain % 1_00_00;
571 remain /= 1_00_00;
572// Safety: `quad` is guaranteed to be less than 10,000 due to the modulus above.
573let [pair1, pair2] = div_100(unsafe { ru16::new_unchecked(quad as u16) });
574// Safety: `buf` is at least `quad_index * 4 + OFFSET + 4` bytes long.
575unsafe {
576 write_two_digits(buf, quad_index * 4 + OFFSET, pair1);
577 write_two_digits(buf, quad_index * 4 + OFFSET + 2, pair2);
578 }
579 quad_index -= 1;
580 }
581582// Safety: `remain` is guaranteed to be less than 10,000 due the range of `n` and the arithmetic
583 // in the loop above.
584let [pair1, pair2] = div_100(unsafe { ru16::new_unchecked(remainas u16) });
585// Safety: `buf` is at least `OFFSET + 4` bytes long.
586unsafe {
587write_two_digits(buf, OFFSET, pair1);
588write_two_digits(buf, OFFSET + 2, pair2);
589 }
590}
591592// Euclidean division plus remainder with constant 1e16 basically consumes 16
593// decimals from n.
594#[cfg(feature = "formatting")]
595const fn div_rem_1e16(n: u128) -> (u128, ru64<0, 9999_9999_9999_9999>) {
596const D: u128 = 1_0000_0000_0000_0000;
597if n < D {
598// Safety: We just checked that `n` is in range.
599return (0, unsafe { ru64::new_unchecked(nas u64) });
600 }
601602const M_HIGH: u128 = 76_624_777_043_294_442_917_917_351_357_515_459_181;
603const SH_POST: u8 = 51;
604605// n.widening_mul(M_HIGH).1 >> SH_POST
606let quot = mulhi(n, M_HIGH) >> SH_POST;
607let rem = n - quot * D;
608// Safety: The arithmetic above ensures that `rem` is in range.
609(quot, unsafe { ru64::new_unchecked(remas u64) })
610}
611612/// Multiply unsigned 128 bit integers, return upper 128 bits of the result
613#[inline]
614#[cfg(feature = "formatting")]
615const fn mulhi(x: u128, y: u128) -> u128 {
616let x_lo = xas u64;
617let x_hi = (x >> 64) as u64;
618let y_lo = yas u64;
619let y_hi = (y >> 64) as u64;
620621// handle possibility of overflow
622let carry = (x_loas u128 * y_loas u128) >> 64;
623let m = x_loas u128 * y_hias u128 + carry;
624let high1 = m >> 64;
625626let m_lo = mas u64;
627let high2 = (x_hias u128 * y_loas u128 + m_loas u128) >> 64;
628629x_hias u128 * y_hias u128 + high1 + high2630}