1#![doc(html_root_url = "https://docs.rs/itoa/1.0.18")]
41#![no_std]
42#![allow(
43 clippy::cast_lossless,
44 clippy::cast_possible_truncation,
45 clippy::cast_sign_loss,
46 clippy::expl_impl_clone_on_copy,
47 clippy::identity_op,
48 clippy::items_after_statements,
49 clippy::must_use_candidate,
50 clippy::needless_doctest_main,
51 clippy::unreadable_literal
52)]
53
54mod u128_ext;
55
56use core::hint;
57use core::mem::{self, MaybeUninit};
58use core::str;
59#[cfg(feature = "no-panic")]
60use no_panic::no_panic;
61
62pub struct Buffer {
73 bytes: [MaybeUninit<u8>; i128::MAX_STR_LEN],
74}
75
76impl Default for Buffer {
77 #[inline]
78 fn default() -> Buffer {
79 Buffer::new()
80 }
81}
82
83impl Copy for Buffer {}
84
85#[allow(clippy::non_canonical_clone_impl)]
86impl Clone for Buffer {
87 #[inline]
88 fn clone(&self) -> Self {
89 Buffer::new()
90 }
91}
92
93impl Buffer {
94 #[inline]
97 #[cfg_attr(feature = "no-panic", no_panic)]
98 pub fn new() -> Buffer {
99 let bytes = [MaybeUninit::<u8>::uninit(); i128::MAX_STR_LEN];
100 Buffer { bytes }
101 }
102
103 #[cfg_attr(feature = "no-panic", no_panic)]
106 pub fn format<I: Integer>(&mut self, i: I) -> &str {
107 let buf_ptr = self.bytes.as_mut_ptr().cast::<I::Buffer>();
108 let string = i.write(unsafe { &mut *buf_ptr });
109 if string.len() > I::MAX_STR_LEN {
110 unsafe { hint::unreachable_unchecked() };
111 }
112 string
113 }
114}
115
116pub trait Integer: private::Sealed {
120 const MAX_STR_LEN: usize;
123}
124
125mod private {
127 #[doc(hidden)]
128 pub trait Sealed: Copy {
129 #[doc(hidden)]
130 type Buffer: 'static;
131 fn write(self, buf: &mut Self::Buffer) -> &str;
132 }
133}
134
135macro_rules! impl_Integer {
136 ($Signed:ident, $Unsigned:ident) => {
137 const _: () = {
138 assert!($Signed::MIN < 0, "need signed");
139 assert!($Unsigned::MIN == 0, "need unsigned");
140 assert!($Signed::BITS == $Unsigned::BITS, "need counterparts");
141 };
142
143 impl Integer for $Unsigned {
144 const MAX_STR_LEN: usize = $Unsigned::MAX.ilog10() as usize + 1;
145 }
146
147 impl private::Sealed for $Unsigned {
148 type Buffer = [MaybeUninit<u8>; Self::MAX_STR_LEN];
149
150 #[inline]
151 #[cfg_attr(feature = "no-panic", no_panic)]
152 fn write(self, buf: &mut Self::Buffer) -> &str {
153 let offset = Unsigned::fmt(self, buf);
154 unsafe { slice_buffer_to_str(buf, offset) }
156 }
157 }
158
159 impl Integer for $Signed {
160 const MAX_STR_LEN: usize = $Signed::MAX.ilog10() as usize + 2;
161 }
162
163 impl private::Sealed for $Signed {
164 type Buffer = [MaybeUninit<u8>; Self::MAX_STR_LEN];
165
166 #[inline]
167 #[cfg_attr(feature = "no-panic", no_panic)]
168 fn write(self, buf: &mut Self::Buffer) -> &str {
169 let mut offset = Self::MAX_STR_LEN - $Unsigned::MAX_STR_LEN;
170 offset += Unsigned::fmt(
171 self.unsigned_abs(),
172 (&mut buf[offset..]).try_into().unwrap(),
173 );
174 if self < 0 {
175 offset -= 1;
176 buf[offset].write(b'-');
177 }
178 unsafe { slice_buffer_to_str(buf, offset) }
180 }
181 }
182 };
183}
184
185const _: () =
{
if !(i8::MIN < 0) {
{ ::core::panicking::panic_fmt(format_args!("need signed")); }
};
if !(u8::MIN == 0) {
{ ::core::panicking::panic_fmt(format_args!("need unsigned")); }
};
if !(i8::BITS == u8::BITS) {
{
::core::panicking::panic_fmt(format_args!("need counterparts"));
}
};
};
impl Integer for u8 {
const MAX_STR_LEN: usize = u8::MAX.ilog10() as usize + 1;
}
impl private::Sealed for u8 {
type Buffer = [MaybeUninit<u8>; Self::MAX_STR_LEN];
#[inline]
fn write(self, buf: &mut Self::Buffer) -> &str {
let offset = Unsigned::fmt(self, buf);
unsafe { slice_buffer_to_str(buf, offset) }
}
}
impl Integer for i8 {
const MAX_STR_LEN: usize = i8::MAX.ilog10() as usize + 2;
}
impl private::Sealed for i8 {
type Buffer = [MaybeUninit<u8>; Self::MAX_STR_LEN];
#[inline]
fn write(self, buf: &mut Self::Buffer) -> &str {
let mut offset = Self::MAX_STR_LEN - u8::MAX_STR_LEN;
offset +=
Unsigned::fmt(self.unsigned_abs(),
(&mut buf[offset..]).try_into().unwrap());
if self < 0 { offset -= 1; buf[offset].write(b'-'); }
unsafe { slice_buffer_to_str(buf, offset) }
}
}impl_Integer!(i8, u8);
186const _: () =
{
if !(i16::MIN < 0) {
{ ::core::panicking::panic_fmt(format_args!("need signed")); }
};
if !(u16::MIN == 0) {
{ ::core::panicking::panic_fmt(format_args!("need unsigned")); }
};
if !(i16::BITS == u16::BITS) {
{
::core::panicking::panic_fmt(format_args!("need counterparts"));
}
};
};
impl Integer for u16 {
const MAX_STR_LEN: usize = u16::MAX.ilog10() as usize + 1;
}
impl private::Sealed for u16 {
type Buffer = [MaybeUninit<u8>; Self::MAX_STR_LEN];
#[inline]
fn write(self, buf: &mut Self::Buffer) -> &str {
let offset = Unsigned::fmt(self, buf);
unsafe { slice_buffer_to_str(buf, offset) }
}
}
impl Integer for i16 {
const MAX_STR_LEN: usize = i16::MAX.ilog10() as usize + 2;
}
impl private::Sealed for i16 {
type Buffer = [MaybeUninit<u8>; Self::MAX_STR_LEN];
#[inline]
fn write(self, buf: &mut Self::Buffer) -> &str {
let mut offset = Self::MAX_STR_LEN - u16::MAX_STR_LEN;
offset +=
Unsigned::fmt(self.unsigned_abs(),
(&mut buf[offset..]).try_into().unwrap());
if self < 0 { offset -= 1; buf[offset].write(b'-'); }
unsafe { slice_buffer_to_str(buf, offset) }
}
}impl_Integer!(i16, u16);
187const _: () =
{
if !(i32::MIN < 0) {
{ ::core::panicking::panic_fmt(format_args!("need signed")); }
};
if !(u32::MIN == 0) {
{ ::core::panicking::panic_fmt(format_args!("need unsigned")); }
};
if !(i32::BITS == u32::BITS) {
{
::core::panicking::panic_fmt(format_args!("need counterparts"));
}
};
};
impl Integer for u32 {
const MAX_STR_LEN: usize = u32::MAX.ilog10() as usize + 1;
}
impl private::Sealed for u32 {
type Buffer = [MaybeUninit<u8>; Self::MAX_STR_LEN];
#[inline]
fn write(self, buf: &mut Self::Buffer) -> &str {
let offset = Unsigned::fmt(self, buf);
unsafe { slice_buffer_to_str(buf, offset) }
}
}
impl Integer for i32 {
const MAX_STR_LEN: usize = i32::MAX.ilog10() as usize + 2;
}
impl private::Sealed for i32 {
type Buffer = [MaybeUninit<u8>; Self::MAX_STR_LEN];
#[inline]
fn write(self, buf: &mut Self::Buffer) -> &str {
let mut offset = Self::MAX_STR_LEN - u32::MAX_STR_LEN;
offset +=
Unsigned::fmt(self.unsigned_abs(),
(&mut buf[offset..]).try_into().unwrap());
if self < 0 { offset -= 1; buf[offset].write(b'-'); }
unsafe { slice_buffer_to_str(buf, offset) }
}
}impl_Integer!(i32, u32);
188const _: () =
{
if !(i64::MIN < 0) {
{ ::core::panicking::panic_fmt(format_args!("need signed")); }
};
if !(u64::MIN == 0) {
{ ::core::panicking::panic_fmt(format_args!("need unsigned")); }
};
if !(i64::BITS == u64::BITS) {
{
::core::panicking::panic_fmt(format_args!("need counterparts"));
}
};
};
impl Integer for u64 {
const MAX_STR_LEN: usize = u64::MAX.ilog10() as usize + 1;
}
impl private::Sealed for u64 {
type Buffer = [MaybeUninit<u8>; Self::MAX_STR_LEN];
#[inline]
fn write(self, buf: &mut Self::Buffer) -> &str {
let offset = Unsigned::fmt(self, buf);
unsafe { slice_buffer_to_str(buf, offset) }
}
}
impl Integer for i64 {
const MAX_STR_LEN: usize = i64::MAX.ilog10() as usize + 2;
}
impl private::Sealed for i64 {
type Buffer = [MaybeUninit<u8>; Self::MAX_STR_LEN];
#[inline]
fn write(self, buf: &mut Self::Buffer) -> &str {
let mut offset = Self::MAX_STR_LEN - u64::MAX_STR_LEN;
offset +=
Unsigned::fmt(self.unsigned_abs(),
(&mut buf[offset..]).try_into().unwrap());
if self < 0 { offset -= 1; buf[offset].write(b'-'); }
unsafe { slice_buffer_to_str(buf, offset) }
}
}impl_Integer!(i64, u64);
189const _: () =
{
if !(i128::MIN < 0) {
{ ::core::panicking::panic_fmt(format_args!("need signed")); }
};
if !(u128::MIN == 0) {
{ ::core::panicking::panic_fmt(format_args!("need unsigned")); }
};
if !(i128::BITS == u128::BITS) {
{
::core::panicking::panic_fmt(format_args!("need counterparts"));
}
};
};
impl Integer for u128 {
const MAX_STR_LEN: usize = u128::MAX.ilog10() as usize + 1;
}
impl private::Sealed for u128 {
type Buffer = [MaybeUninit<u8>; Self::MAX_STR_LEN];
#[inline]
fn write(self, buf: &mut Self::Buffer) -> &str {
let offset = Unsigned::fmt(self, buf);
unsafe { slice_buffer_to_str(buf, offset) }
}
}
impl Integer for i128 {
const MAX_STR_LEN: usize = i128::MAX.ilog10() as usize + 2;
}
impl private::Sealed for i128 {
type Buffer = [MaybeUninit<u8>; Self::MAX_STR_LEN];
#[inline]
fn write(self, buf: &mut Self::Buffer) -> &str {
let mut offset = Self::MAX_STR_LEN - u128::MAX_STR_LEN;
offset +=
Unsigned::fmt(self.unsigned_abs(),
(&mut buf[offset..]).try_into().unwrap());
if self < 0 { offset -= 1; buf[offset].write(b'-'); }
unsafe { slice_buffer_to_str(buf, offset) }
}
}impl_Integer!(i128, u128);
190
191macro_rules! impl_Integer_size {
192 ($t:ty as $primitive:ident #[cfg(target_pointer_width = $width:literal)]) => {
193 #[cfg(target_pointer_width = $width)]
194 impl Integer for $t {
195 const MAX_STR_LEN: usize = <$primitive as Integer>::MAX_STR_LEN;
196 }
197
198 #[cfg(target_pointer_width = $width)]
199 impl private::Sealed for $t {
200 type Buffer = <$primitive as private::Sealed>::Buffer;
201
202 #[inline]
203 #[cfg_attr(feature = "no-panic", no_panic)]
204 fn write(self, buf: &mut Self::Buffer) -> &str {
205 (self as $primitive).write(buf)
206 }
207 }
208 };
209}
210
211impl_Integer_size!(isize as i16 #[cfg(target_pointer_width = "16")]);
212impl_Integer_size!(usize as u16 #[cfg(target_pointer_width = "16")]);
213impl_Integer_size!(isize as i32 #[cfg(target_pointer_width = "32")]);
214impl_Integer_size!(usize as u32 #[cfg(target_pointer_width = "32")]);
215impl Integer for isize {
const MAX_STR_LEN: usize = <i64 as Integer>::MAX_STR_LEN;
}
impl private::Sealed for isize {
type Buffer = <i64 as private::Sealed>::Buffer;
#[inline]
fn write(self, buf: &mut Self::Buffer) -> &str {
(self as i64).write(buf)
}
}impl_Integer_size!(isize as i64 #[cfg(target_pointer_width = "64")]);
216impl Integer for usize {
const MAX_STR_LEN: usize = <u64 as Integer>::MAX_STR_LEN;
}
impl private::Sealed for usize {
type Buffer = <u64 as private::Sealed>::Buffer;
#[inline]
fn write(self, buf: &mut Self::Buffer) -> &str {
(self as u64).write(buf)
}
}impl_Integer_size!(usize as u64 #[cfg(target_pointer_width = "64")]);
217
218#[repr(C, align(2))]
219struct DecimalPairs([u8; 200]);
220
221static DECIMAL_PAIRS: DecimalPairs = DecimalPairs(
223 *b"0001020304050607080910111213141516171819\
224 2021222324252627282930313233343536373839\
225 4041424344454647484950515253545556575859\
226 6061626364656667686970717273747576777879\
227 8081828384858687888990919293949596979899",
228);
229
230fn divmod100(value: u32) -> (u32, u32) {
232 if true {
if !(value < 10_000) {
::core::panicking::panic("assertion failed: value < 10_000")
};
};debug_assert!(value < 10_000);
233 const EXP: u32 = 19; const SIG: u32 = (1 << EXP) / 100 + 1;
235 let div = (value * SIG) >> EXP; (div, value - div * 100)
237}
238
239#[cfg_attr(feature = "no-panic", no_panic)]
247unsafe fn slice_buffer_to_str(buf: &[MaybeUninit<u8>], offset: usize) -> &str {
248 let written = unsafe { buf.get_unchecked(offset..) };
250 unsafe { str::from_utf8_unchecked(&*(written as *const [MaybeUninit<u8>] as *const [u8])) }
253}
254
255trait Unsigned: Integer {
256 fn fmt(self, buf: &mut Self::Buffer) -> usize;
257}
258
259macro_rules! impl_Unsigned {
260 ($Unsigned:ident) => {
261 impl Unsigned for $Unsigned {
262 #[cfg_attr(feature = "no-panic", no_panic)]
263 fn fmt(self, buf: &mut Self::Buffer) -> usize {
264 let mut offset = buf.len();
266 let mut remain = self;
268
269 while mem::size_of::<Self>() > 1
272 && remain
273 > 999
274 .try_into()
275 .expect("branch is not hit for types that cannot fit 999 (u8)")
276 {
277 offset -= 4;
278
279 let scale: Self = 1_00_00
281 .try_into()
282 .expect("branch is not hit for types that cannot fit 1E4 (u8)");
283 let quad = remain % scale;
284 remain /= scale;
285 let (pair1, pair2) = divmod100(quad as u32);
286 unsafe {
287 buf[offset + 0]
288 .write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0));
289 buf[offset + 1]
290 .write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1));
291 buf[offset + 2]
292 .write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0));
293 buf[offset + 3]
294 .write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1));
295 }
296 }
297
298 if remain > 9 {
300 offset -= 2;
301
302 let (last, pair) = divmod100(remain as u32);
303 remain = last as Self;
304 unsafe {
305 buf[offset + 0]
306 .write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 0));
307 buf[offset + 1]
308 .write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 1));
309 }
310 }
311
312 if remain != 0 || self == 0 {
314 offset -= 1;
315
316 let last = remain as u8 & 15;
319 buf[offset].write(b'0' + last);
320 }
322
323 offset
324 }
325 }
326 };
327}
328
329impl Unsigned for u8 {
fn fmt(self, buf: &mut Self::Buffer) -> usize {
let mut offset = buf.len();
let mut remain = self;
while mem::size_of::<Self>() > 1 &&
remain >
999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)")
{
offset -= 4;
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, pair2) = divmod100(quad as u32);
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));
}
}
if remain > 9 {
offset -= 2;
let (last, pair) = divmod100(remain as u32);
remain = last as Self;
unsafe {
buf[offset +
0].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 +
0));
buf[offset +
1].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 +
1));
}
}
if remain != 0 || self == 0 {
offset -= 1;
let last = remain as u8 & 15;
buf[offset].write(b'0' + last);
}
offset
}
}impl_Unsigned!(u8);
330impl Unsigned for u16 {
fn fmt(self, buf: &mut Self::Buffer) -> usize {
let mut offset = buf.len();
let mut remain = self;
while mem::size_of::<Self>() > 1 &&
remain >
999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)")
{
offset -= 4;
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, pair2) = divmod100(quad as u32);
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));
}
}
if remain > 9 {
offset -= 2;
let (last, pair) = divmod100(remain as u32);
remain = last as Self;
unsafe {
buf[offset +
0].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 +
0));
buf[offset +
1].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 +
1));
}
}
if remain != 0 || self == 0 {
offset -= 1;
let last = remain as u8 & 15;
buf[offset].write(b'0' + last);
}
offset
}
}impl_Unsigned!(u16);
331impl Unsigned for u32 {
fn fmt(self, buf: &mut Self::Buffer) -> usize {
let mut offset = buf.len();
let mut remain = self;
while mem::size_of::<Self>() > 1 &&
remain >
999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)")
{
offset -= 4;
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, pair2) = divmod100(quad as u32);
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));
}
}
if remain > 9 {
offset -= 2;
let (last, pair) = divmod100(remain as u32);
remain = last as Self;
unsafe {
buf[offset +
0].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 +
0));
buf[offset +
1].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 +
1));
}
}
if remain != 0 || self == 0 {
offset -= 1;
let last = remain as u8 & 15;
buf[offset].write(b'0' + last);
}
offset
}
}impl_Unsigned!(u32);
332impl Unsigned for u64 {
fn fmt(self, buf: &mut Self::Buffer) -> usize {
let mut offset = buf.len();
let mut remain = self;
while mem::size_of::<Self>() > 1 &&
remain >
999.try_into().expect("branch is not hit for types that cannot fit 999 (u8)")
{
offset -= 4;
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, pair2) = divmod100(quad as u32);
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));
}
}
if remain > 9 {
offset -= 2;
let (last, pair) = divmod100(remain as u32);
remain = last as Self;
unsafe {
buf[offset +
0].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 +
0));
buf[offset +
1].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 +
1));
}
}
if remain != 0 || self == 0 {
offset -= 1;
let last = remain as u8 & 15;
buf[offset].write(b'0' + last);
}
offset
}
}impl_Unsigned!(u64);
333
334impl Unsigned for u128 {
335 #[cfg_attr(feature = "no-panic", no_panic)]
336 fn fmt(self, buf: &mut Self::Buffer) -> usize {
337 if self == 0 {
340 let offset = buf.len() - 1;
341 buf[offset].write(b'0');
342 return offset;
343 }
344 let (quot_1e16, mod_1e16) = div_rem_1e16(self);
346 let (mut remain, mut offset) = if quot_1e16 == 0 {
347 (mod_1e16, u128::MAX_STR_LEN)
348 } else {
349 enc_16lsd::<{ u128::MAX_STR_LEN - 16 }>(buf, mod_1e16);
351
352 let (quot2, mod2) = div_rem_1e16(quot_1e16);
354 if quot2 == 0 {
355 (mod2, u128::MAX_STR_LEN - 16)
356 } else {
357 enc_16lsd::<{ u128::MAX_STR_LEN - 32 }>(buf, mod2);
359 (quot2 as u64, u128::MAX_STR_LEN - 32)
361 }
362 };
363
364 while remain > 999 {
366 offset -= 4;
367
368 let quad = remain % 1_00_00;
370 remain /= 1_00_00;
371 let (pair1, pair2) = divmod100(quad as u32);
372 unsafe {
373 buf[offset + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0));
374 buf[offset + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1));
375 buf[offset + 2].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0));
376 buf[offset + 3].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1));
377 }
378 }
379
380 if remain > 9 {
382 offset -= 2;
383
384 let (last, pair) = divmod100(remain as u32);
385 remain = last as u64;
386 unsafe {
387 buf[offset + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 0));
388 buf[offset + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 1));
389 }
390 }
391
392 if remain != 0 {
394 offset -= 1;
395
396 let last = remain as u8 & 15;
399 buf[offset].write(b'0' + last);
400 }
402 offset
403 }
404}
405
406#[cfg_attr(feature = "no-panic", no_panic)]
408fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>], n: u64) {
409 let mut remain = n;
411
412 for quad_index in (1..4).rev() {
414 let quad = remain % 1_00_00;
416 remain /= 1_00_00;
417 let (pair1, pair2) = divmod100(quad as u32);
418 unsafe {
419 buf[quad_index * 4 + OFFSET + 0]
420 .write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0));
421 buf[quad_index * 4 + OFFSET + 1]
422 .write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1));
423 buf[quad_index * 4 + OFFSET + 2]
424 .write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0));
425 buf[quad_index * 4 + OFFSET + 3]
426 .write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1));
427 }
428 }
429
430 let (pair1, pair2) = divmod100(remain as u32);
432 unsafe {
433 buf[OFFSET + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0));
434 buf[OFFSET + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1));
435 buf[OFFSET + 2].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0));
436 buf[OFFSET + 3].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1));
437 }
438}
439
440#[cfg_attr(feature = "no-panic", no_panic)]
450fn div_rem_1e16(n: u128) -> (u128, u64) {
451 const D: u128 = 1_0000_0000_0000_0000;
452 if n < D {
454 return (0, n as u64);
455 }
456
457 const M_HIGH: u128 = 76624777043294442917917351357515459181;
460 const SH_POST: u8 = 51;
461
462 let quot = u128_ext::mulhi(n, M_HIGH) >> SH_POST;
464 let rem = n - quot * D;
465 (quot, rem as u64)
466}