/rust/registry/src/index.crates.io-1949cf8c6b5b557f/itoa-1.0.17/src/lib.rs
Line | Count | Source |
1 | | //! [![github]](https://github.com/dtolnay/itoa) [![crates-io]](https://crates.io/crates/itoa) [![docs-rs]](https://docs.rs/itoa) |
2 | | //! |
3 | | //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github |
4 | | //! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust |
5 | | //! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs |
6 | | //! |
7 | | //! <br> |
8 | | //! |
9 | | //! This crate provides a fast conversion of integer primitives to decimal |
10 | | //! strings. The implementation comes straight from [libcore] but avoids the |
11 | | //! performance penalty of going through [`core::fmt::Formatter`]. |
12 | | //! |
13 | | //! See also [`zmij`] for printing floating point primitives. |
14 | | //! |
15 | | //! [libcore]: https://github.com/rust-lang/rust/blob/1.92.0/library/core/src/fmt/num.rs#L190-L253 |
16 | | //! [`zmij`]: https://github.com/dtolnay/zmij |
17 | | //! |
18 | | //! # Example |
19 | | //! |
20 | | //! ``` |
21 | | //! fn main() { |
22 | | //! let mut buffer = itoa::Buffer::new(); |
23 | | //! let printed = buffer.format(128u64); |
24 | | //! assert_eq!(printed, "128"); |
25 | | //! } |
26 | | //! ``` |
27 | | //! |
28 | | //! # Performance |
29 | | //! |
30 | | //! The [itoa-benchmark] compares this library and other Rust integer formatting |
31 | | //! implementations across a range of integer sizes. The vertical axis in this |
32 | | //! chart shows nanoseconds taken by a single execution of |
33 | | //! `itoa::Buffer::new().format(value)` so a lower result indicates a faster |
34 | | //! library. |
35 | | //! |
36 | | //! [itoa-benchmark]: https://github.com/dtolnay/itoa-benchmark |
37 | | //! |
38 | | //!  |
39 | | |
40 | | #![doc(html_root_url = "https://docs.rs/itoa/1.0.17")] |
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 | | |
54 | | mod u128_ext; |
55 | | |
56 | | use core::hint; |
57 | | use core::mem::{self, MaybeUninit}; |
58 | | use core::ptr; |
59 | | use core::str; |
60 | | #[cfg(feature = "no-panic")] |
61 | | use no_panic::no_panic; |
62 | | |
63 | | /// A correctly sized stack allocation for the formatted integer to be written |
64 | | /// into. |
65 | | /// |
66 | | /// # Example |
67 | | /// |
68 | | /// ``` |
69 | | /// let mut buffer = itoa::Buffer::new(); |
70 | | /// let printed = buffer.format(1234); |
71 | | /// assert_eq!(printed, "1234"); |
72 | | /// ``` |
73 | | pub struct Buffer { |
74 | | bytes: [MaybeUninit<u8>; i128::MAX_STR_LEN], |
75 | | } |
76 | | |
77 | | impl Default for Buffer { |
78 | | #[inline] |
79 | 0 | fn default() -> Buffer { |
80 | 0 | Buffer::new() |
81 | 0 | } |
82 | | } |
83 | | |
84 | | impl Copy for Buffer {} |
85 | | |
86 | | #[allow(clippy::non_canonical_clone_impl)] |
87 | | impl Clone for Buffer { |
88 | | #[inline] |
89 | 0 | fn clone(&self) -> Self { |
90 | 0 | Buffer::new() |
91 | 0 | } |
92 | | } |
93 | | |
94 | | impl Buffer { |
95 | | /// This is a cheap operation; you don't need to worry about reusing buffers |
96 | | /// for efficiency. |
97 | | #[inline] |
98 | | #[cfg_attr(feature = "no-panic", no_panic)] |
99 | 0 | pub fn new() -> Buffer { |
100 | 0 | let bytes = [MaybeUninit::<u8>::uninit(); i128::MAX_STR_LEN]; |
101 | 0 | Buffer { bytes } |
102 | 0 | } Unexecuted instantiation: <itoa::Buffer>::new Unexecuted instantiation: <itoa::Buffer>::new |
103 | | |
104 | | /// Print an integer into this buffer and return a reference to its string |
105 | | /// representation within the buffer. |
106 | | #[cfg_attr(feature = "no-panic", no_panic)] |
107 | 0 | pub fn format<I: Integer>(&mut self, i: I) -> &str { |
108 | 0 | let string = i.write(unsafe { |
109 | 0 | &mut *ptr::addr_of_mut!(self.bytes).cast::<<I as private::Sealed>::Buffer>() |
110 | | }); |
111 | 0 | if string.len() > I::MAX_STR_LEN { |
112 | 0 | unsafe { hint::unreachable_unchecked() }; |
113 | 0 | } |
114 | 0 | string |
115 | 0 | } Unexecuted instantiation: <itoa::Buffer>::format::<i8> Unexecuted instantiation: <itoa::Buffer>::format::<u8> Unexecuted instantiation: <itoa::Buffer>::format::<i32> Unexecuted instantiation: <itoa::Buffer>::format::<u32> Unexecuted instantiation: <itoa::Buffer>::format::<i128> Unexecuted instantiation: <itoa::Buffer>::format::<u128> Unexecuted instantiation: <itoa::Buffer>::format::<i16> Unexecuted instantiation: <itoa::Buffer>::format::<u16> Unexecuted instantiation: <itoa::Buffer>::format::<i64> Unexecuted instantiation: <itoa::Buffer>::format::<u64> Unexecuted instantiation: <itoa::Buffer>::format::<_> |
116 | | } |
117 | | |
118 | | /// An integer that can be written into an [`itoa::Buffer`][Buffer]. |
119 | | /// |
120 | | /// This trait is sealed and cannot be implemented for types outside of itoa. |
121 | | pub trait Integer: private::Sealed { |
122 | | /// The maximum length of string that formatting an integer of this type can |
123 | | /// produce on the current target platform. |
124 | | const MAX_STR_LEN: usize; |
125 | | } |
126 | | |
127 | | // Seal to prevent downstream implementations of the Integer trait. |
128 | | mod private { |
129 | | #[doc(hidden)] |
130 | | pub trait Sealed: Copy { |
131 | | #[doc(hidden)] |
132 | | type Buffer: 'static; |
133 | | fn write(self, buf: &mut Self::Buffer) -> &str; |
134 | | } |
135 | | } |
136 | | |
137 | | macro_rules! impl_Integer { |
138 | | ($Signed:ident, $Unsigned:ident) => { |
139 | | const _: () = { |
140 | | assert!($Signed::MIN < 0, "need signed"); |
141 | | assert!($Unsigned::MIN == 0, "need unsigned"); |
142 | | assert!($Signed::BITS == $Unsigned::BITS, "need counterparts"); |
143 | | }; |
144 | | |
145 | | impl Integer for $Unsigned { |
146 | | const MAX_STR_LEN: usize = $Unsigned::MAX.ilog10() as usize + 1; |
147 | | } |
148 | | |
149 | | impl private::Sealed for $Unsigned { |
150 | | type Buffer = [MaybeUninit<u8>; Self::MAX_STR_LEN]; |
151 | | |
152 | | #[inline] |
153 | | #[cfg_attr(feature = "no-panic", no_panic)] |
154 | 0 | fn write(self, buf: &mut Self::Buffer) -> &str { |
155 | 0 | let offset = Unsigned::fmt(self, buf); |
156 | | // SAFETY: Starting from `offset`, all elements of the slice have been set. |
157 | 0 | unsafe { slice_buffer_to_str(buf, offset) } |
158 | 0 | } Unexecuted instantiation: <u8 as itoa::private::Sealed>::write Unexecuted instantiation: <u16 as itoa::private::Sealed>::write Unexecuted instantiation: <u32 as itoa::private::Sealed>::write Unexecuted instantiation: <u64 as itoa::private::Sealed>::write Unexecuted instantiation: <u128 as itoa::private::Sealed>::write Unexecuted instantiation: <u8 as itoa::private::Sealed>::write Unexecuted instantiation: <u16 as itoa::private::Sealed>::write Unexecuted instantiation: <u32 as itoa::private::Sealed>::write Unexecuted instantiation: <u64 as itoa::private::Sealed>::write Unexecuted instantiation: <u128 as itoa::private::Sealed>::write |
159 | | } |
160 | | |
161 | | impl Integer for $Signed { |
162 | | const MAX_STR_LEN: usize = $Signed::MAX.ilog10() as usize + 2; |
163 | | } |
164 | | |
165 | | impl private::Sealed for $Signed { |
166 | | type Buffer = [MaybeUninit<u8>; Self::MAX_STR_LEN]; |
167 | | |
168 | | #[inline] |
169 | | #[cfg_attr(feature = "no-panic", no_panic)] |
170 | 0 | fn write(self, buf: &mut Self::Buffer) -> &str { |
171 | 0 | let mut offset = Self::MAX_STR_LEN - $Unsigned::MAX_STR_LEN; |
172 | 0 | offset += Unsigned::fmt( |
173 | 0 | self.unsigned_abs(), |
174 | 0 | (&mut buf[offset..]).try_into().unwrap(), |
175 | 0 | ); |
176 | 0 | if self < 0 { |
177 | 0 | offset -= 1; |
178 | 0 | buf[offset].write(b'-'); |
179 | 0 | } |
180 | | // SAFETY: Starting from `offset`, all elements of the slice have been set. |
181 | 0 | unsafe { slice_buffer_to_str(buf, offset) } |
182 | 0 | } Unexecuted instantiation: <i8 as itoa::private::Sealed>::write Unexecuted instantiation: <i16 as itoa::private::Sealed>::write Unexecuted instantiation: <i32 as itoa::private::Sealed>::write Unexecuted instantiation: <i64 as itoa::private::Sealed>::write Unexecuted instantiation: <i128 as itoa::private::Sealed>::write Unexecuted instantiation: <i8 as itoa::private::Sealed>::write Unexecuted instantiation: <i16 as itoa::private::Sealed>::write Unexecuted instantiation: <i32 as itoa::private::Sealed>::write Unexecuted instantiation: <i64 as itoa::private::Sealed>::write Unexecuted instantiation: <i128 as itoa::private::Sealed>::write |
183 | | } |
184 | | }; |
185 | | } |
186 | | |
187 | | impl_Integer!(i8, u8); |
188 | | impl_Integer!(i16, u16); |
189 | | impl_Integer!(i32, u32); |
190 | | impl_Integer!(i64, u64); |
191 | | impl_Integer!(i128, u128); |
192 | | |
193 | | macro_rules! impl_Integer_size { |
194 | | ($t:ty as $primitive:ident #[cfg(target_pointer_width = $width:literal)]) => { |
195 | | #[cfg(target_pointer_width = $width)] |
196 | | impl Integer for $t { |
197 | | const MAX_STR_LEN: usize = <$primitive as Integer>::MAX_STR_LEN; |
198 | | } |
199 | | |
200 | | #[cfg(target_pointer_width = $width)] |
201 | | impl private::Sealed for $t { |
202 | | type Buffer = <$primitive as private::Sealed>::Buffer; |
203 | | |
204 | | #[inline] |
205 | | #[cfg_attr(feature = "no-panic", no_panic)] |
206 | 0 | fn write(self, buf: &mut Self::Buffer) -> &str { |
207 | 0 | (self as $primitive).write(buf) |
208 | 0 | } Unexecuted instantiation: <isize as itoa::private::Sealed>::write Unexecuted instantiation: <usize as itoa::private::Sealed>::write |
209 | | } |
210 | | }; |
211 | | } |
212 | | |
213 | | impl_Integer_size!(isize as i16 #[cfg(target_pointer_width = "16")]); |
214 | | impl_Integer_size!(usize as u16 #[cfg(target_pointer_width = "16")]); |
215 | | impl_Integer_size!(isize as i32 #[cfg(target_pointer_width = "32")]); |
216 | | impl_Integer_size!(usize as u32 #[cfg(target_pointer_width = "32")]); |
217 | | impl_Integer_size!(isize as i64 #[cfg(target_pointer_width = "64")]); |
218 | | impl_Integer_size!(usize as u64 #[cfg(target_pointer_width = "64")]); |
219 | | |
220 | | #[repr(C, align(2))] |
221 | | struct DecimalPairs([u8; 200]); |
222 | | |
223 | | // The string of all two-digit numbers in range 00..99 is used as a lookup table. |
224 | | static DECIMAL_PAIRS: DecimalPairs = DecimalPairs( |
225 | | *b"0001020304050607080910111213141516171819\ |
226 | | 2021222324252627282930313233343536373839\ |
227 | | 4041424344454647484950515253545556575859\ |
228 | | 6061626364656667686970717273747576777879\ |
229 | | 8081828384858687888990919293949596979899", |
230 | | ); |
231 | | |
232 | | // Returns {value / 100, value % 100} correct for values of up to 4 digits. |
233 | 0 | fn divmod100(value: u32) -> (u32, u32) { |
234 | 0 | debug_assert!(value < 10_000); |
235 | | const EXP: u32 = 19; // 19 is faster or equal to 12 even for 3 digits. |
236 | | const SIG: u32 = (1 << EXP) / 100 + 1; |
237 | 0 | let div = (value * SIG) >> EXP; // value / 100 |
238 | 0 | (div, value - div * 100) |
239 | 0 | } |
240 | | |
241 | | /// This function converts a slice of ascii characters into a `&str` starting |
242 | | /// from `offset`. |
243 | | /// |
244 | | /// # Safety |
245 | | /// |
246 | | /// `buf` content starting from `offset` index MUST BE initialized and MUST BE |
247 | | /// ascii characters. |
248 | | #[cfg_attr(feature = "no-panic", no_panic)] |
249 | 0 | unsafe fn slice_buffer_to_str(buf: &[MaybeUninit<u8>], offset: usize) -> &str { |
250 | | // SAFETY: `offset` is always included between 0 and `buf`'s length. |
251 | 0 | let written = unsafe { buf.get_unchecked(offset..) }; |
252 | | // SAFETY: (`assume_init_ref`) All buf content since offset is set. |
253 | | // SAFETY: (`from_utf8_unchecked`) Writes use ASCII from the lookup table exclusively. |
254 | 0 | unsafe { str::from_utf8_unchecked(&*(written as *const [MaybeUninit<u8>] as *const [u8])) } |
255 | 0 | } |
256 | | |
257 | | trait Unsigned: Integer { |
258 | | fn fmt(self, buf: &mut Self::Buffer) -> usize; |
259 | | } |
260 | | |
261 | | macro_rules! impl_Unsigned { |
262 | | ($Unsigned:ident) => { |
263 | | impl Unsigned for $Unsigned { |
264 | | #[cfg_attr(feature = "no-panic", no_panic)] |
265 | 0 | fn fmt(self, buf: &mut Self::Buffer) -> usize { |
266 | | // Count the number of bytes in buf that are not initialized. |
267 | 0 | let mut offset = buf.len(); |
268 | | // Consume the least-significant decimals from a working copy. |
269 | 0 | let mut remain = self; |
270 | | |
271 | | // Format per four digits from the lookup table. |
272 | | // Four digits need a 16-bit $Unsigned or wider. |
273 | 0 | while mem::size_of::<Self>() > 1 |
274 | 0 | && remain |
275 | 0 | > 999 |
276 | 0 | .try_into() |
277 | 0 | .expect("branch is not hit for types that cannot fit 999 (u8)") |
278 | | { |
279 | 0 | offset -= 4; |
280 | | |
281 | | // pull two pairs |
282 | 0 | let scale: Self = 1_00_00 |
283 | 0 | .try_into() |
284 | 0 | .expect("branch is not hit for types that cannot fit 1E4 (u8)"); |
285 | 0 | let quad = remain % scale; |
286 | 0 | remain /= scale; |
287 | 0 | let (pair1, pair2) = divmod100(quad as u32); |
288 | 0 | unsafe { |
289 | 0 | buf[offset + 0] |
290 | 0 | .write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0)); |
291 | 0 | buf[offset + 1] |
292 | 0 | .write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1)); |
293 | 0 | buf[offset + 2] |
294 | 0 | .write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0)); |
295 | 0 | buf[offset + 3] |
296 | 0 | .write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1)); |
297 | 0 | } |
298 | | } |
299 | | |
300 | | // Format per two digits from the lookup table. |
301 | 0 | if remain > 9 { |
302 | 0 | offset -= 2; |
303 | | |
304 | 0 | let (last, pair) = divmod100(remain as u32); |
305 | 0 | remain = last as Self; |
306 | 0 | unsafe { |
307 | 0 | buf[offset + 0] |
308 | 0 | .write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 0)); |
309 | 0 | buf[offset + 1] |
310 | 0 | .write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 1)); |
311 | 0 | } |
312 | 0 | } |
313 | | |
314 | | // Format the last remaining digit, if any. |
315 | 0 | if remain != 0 || self == 0 { |
316 | 0 | offset -= 1; |
317 | 0 |
|
318 | 0 | // Either the compiler sees that remain < 10, or it prevents |
319 | 0 | // a boundary check up next. |
320 | 0 | let last = remain as u8 & 15; |
321 | 0 | buf[offset].write(b'0' + last); |
322 | 0 | // not used: remain = 0; |
323 | 0 | } |
324 | | |
325 | 0 | offset |
326 | 0 | } Unexecuted instantiation: <u8 as itoa::Unsigned>::fmt Unexecuted instantiation: <u16 as itoa::Unsigned>::fmt Unexecuted instantiation: <u32 as itoa::Unsigned>::fmt Unexecuted instantiation: <u64 as itoa::Unsigned>::fmt |
327 | | } |
328 | | }; |
329 | | } |
330 | | |
331 | | impl_Unsigned!(u8); |
332 | | impl_Unsigned!(u16); |
333 | | impl_Unsigned!(u32); |
334 | | impl_Unsigned!(u64); |
335 | | |
336 | | impl Unsigned for u128 { |
337 | | #[cfg_attr(feature = "no-panic", no_panic)] |
338 | 0 | fn fmt(self, buf: &mut Self::Buffer) -> usize { |
339 | | // Optimize common-case zero, which would also need special treatment due to |
340 | | // its "leading" zero. |
341 | 0 | if self == 0 { |
342 | 0 | let offset = buf.len() - 1; |
343 | 0 | buf[offset].write(b'0'); |
344 | 0 | return offset; |
345 | 0 | } |
346 | | // Take the 16 least-significant decimals. |
347 | 0 | let (quot_1e16, mod_1e16) = div_rem_1e16(self); |
348 | 0 | let (mut remain, mut offset) = if quot_1e16 == 0 { |
349 | 0 | (mod_1e16, u128::MAX_STR_LEN) |
350 | | } else { |
351 | | // Write digits at buf[23..39]. |
352 | 0 | enc_16lsd::<{ u128::MAX_STR_LEN - 16 }>(buf, mod_1e16); |
353 | | |
354 | | // Take another 16 decimals. |
355 | 0 | let (quot2, mod2) = div_rem_1e16(quot_1e16); |
356 | 0 | if quot2 == 0 { |
357 | 0 | (mod2, u128::MAX_STR_LEN - 16) |
358 | | } else { |
359 | | // Write digits at buf[7..23]. |
360 | 0 | enc_16lsd::<{ u128::MAX_STR_LEN - 32 }>(buf, mod2); |
361 | | // Quot2 has at most 7 decimals remaining after two 1e16 divisions. |
362 | 0 | (quot2 as u64, u128::MAX_STR_LEN - 32) |
363 | | } |
364 | | }; |
365 | | |
366 | | // Format per four digits from the lookup table. |
367 | 0 | while remain > 999 { |
368 | 0 | offset -= 4; |
369 | | |
370 | | // pull two pairs |
371 | 0 | let quad = remain % 1_00_00; |
372 | 0 | remain /= 1_00_00; |
373 | 0 | let (pair1, pair2) = divmod100(quad as u32); |
374 | 0 | unsafe { |
375 | 0 | buf[offset + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0)); |
376 | 0 | buf[offset + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1)); |
377 | 0 | buf[offset + 2].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0)); |
378 | 0 | buf[offset + 3].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1)); |
379 | 0 | } |
380 | | } |
381 | | |
382 | | // Format per two digits from the lookup table. |
383 | 0 | if remain > 9 { |
384 | 0 | offset -= 2; |
385 | | |
386 | 0 | let (last, pair) = divmod100(remain as u32); |
387 | 0 | remain = last as u64; |
388 | 0 | unsafe { |
389 | 0 | buf[offset + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 0)); |
390 | 0 | buf[offset + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 1)); |
391 | 0 | } |
392 | 0 | } |
393 | | |
394 | | // Format the last remaining digit, if any. |
395 | 0 | if remain != 0 { |
396 | 0 | offset -= 1; |
397 | 0 |
|
398 | 0 | // Either the compiler sees that remain < 10, or it prevents |
399 | 0 | // a boundary check up next. |
400 | 0 | let last = remain as u8 & 15; |
401 | 0 | buf[offset].write(b'0' + last); |
402 | 0 | // not used: remain = 0; |
403 | 0 | } |
404 | 0 | offset |
405 | 0 | } |
406 | | } |
407 | | |
408 | | // Encodes the 16 least-significant decimals of n into `buf[OFFSET..OFFSET + 16]`. |
409 | | #[cfg_attr(feature = "no-panic", no_panic)] |
410 | 0 | fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>], n: u64) { |
411 | | // Consume the least-significant decimals from a working copy. |
412 | 0 | let mut remain = n; |
413 | | |
414 | | // Format per four digits from the lookup table. |
415 | 0 | for quad_index in (0..4).rev() { |
416 | | // pull two pairs |
417 | 0 | let quad = remain % 1_00_00; |
418 | 0 | remain /= 1_00_00; |
419 | 0 | let (pair1, pair2) = divmod100(quad as u32); |
420 | 0 | unsafe { |
421 | 0 | buf[quad_index * 4 + OFFSET + 0] |
422 | 0 | .write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0)); |
423 | 0 | buf[quad_index * 4 + OFFSET + 1] |
424 | 0 | .write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1)); |
425 | 0 | buf[quad_index * 4 + OFFSET + 2] |
426 | 0 | .write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0)); |
427 | 0 | buf[quad_index * 4 + OFFSET + 3] |
428 | 0 | .write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1)); |
429 | 0 | } |
430 | | } |
431 | 0 | } Unexecuted instantiation: itoa::enc_16lsd::<23> Unexecuted instantiation: itoa::enc_16lsd::<7> |
432 | | |
433 | | // Euclidean division plus remainder with constant 1E16 basically consumes 16 |
434 | | // decimals from n. |
435 | | // |
436 | | // The integer division algorithm is based on the following paper: |
437 | | // |
438 | | // T. Granlund and P. Montgomery, “Division by Invariant Integers Using Multiplication” |
439 | | // in Proc. of the SIGPLAN94 Conference on Programming Language Design and |
440 | | // Implementation, 1994, pp. 61–72 |
441 | | // |
442 | | #[cfg_attr(feature = "no-panic", no_panic)] |
443 | 0 | fn div_rem_1e16(n: u128) -> (u128, u64) { |
444 | | const D: u128 = 1_0000_0000_0000_0000; |
445 | | // The check inlines well with the caller flow. |
446 | 0 | if n < D { |
447 | 0 | return (0, n as u64); |
448 | 0 | } |
449 | | |
450 | | // These constant values are computed with the CHOOSE_MULTIPLIER procedure |
451 | | // from the Granlund & Montgomery paper, using N=128, prec=128 and d=1E16. |
452 | | const M_HIGH: u128 = 76624777043294442917917351357515459181; |
453 | | const SH_POST: u8 = 51; |
454 | | |
455 | | // n.widening_mul(M_HIGH).1 >> SH_POST |
456 | 0 | let quot = u128_ext::mulhi(n, M_HIGH) >> SH_POST; |
457 | 0 | let rem = n - quot * D; |
458 | 0 | (quot, rem as u64) |
459 | 0 | } |