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&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
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 [`ryu`] for printing floating point primitives.
14 //!
15 //! [libcore]: https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L201-L254
16 //! [`core::fmt::Formatter`]: https://doc.rust-lang.org/std/fmt/struct.Formatter.html
17 //! [`ryu`]: https://github.com/dtolnay/ryu
18 //!
19 //! # Example
20 //!
21 //! ```
22 //! fn main() {
23 //!     let mut buffer = itoa::Buffer::new();
24 //!     let printed = buffer.format(128u64);
25 //!     assert_eq!(printed, "128");
26 //! }
27 //! ```
28 //!
29 //! # Performance (lower is better)
30 //!
31 //! ![performance](https://raw.githubusercontent.com/dtolnay/itoa/master/performance.png)
32 
33 #![doc(html_root_url = "https://docs.rs/itoa/1.0.1")]
34 #![no_std]
35 #![allow(
36     clippy::cast_lossless,
37     clippy::cast_possible_truncation,
38     clippy::must_use_candidate,
39     clippy::unreadable_literal
40 )]
41 
42 mod udiv128;
43 
44 use core::mem::{self, MaybeUninit};
45 use core::{ptr, slice, str};
46 
47 /// A correctly sized stack allocation for the formatted integer to be written
48 /// into.
49 ///
50 /// # Example
51 ///
52 /// ```
53 /// let mut buffer = itoa::Buffer::new();
54 /// let printed = buffer.format(1234);
55 /// assert_eq!(printed, "1234");
56 /// ```
57 pub struct Buffer {
58     bytes: [MaybeUninit<u8>; I128_MAX_LEN],
59 }
LexizeInit(LexizeData * ld,TSConfigCacheEntry * cfg)60 
61 impl Default for Buffer {
62     #[inline]
63     fn default() -> Buffer {
64         Buffer::new()
65     }
66 }
67 
68 impl Clone for Buffer {
69     #[inline]
70     fn clone(&self) -> Self {
71         Buffer::new()
LPLAddTail(ListParsedLex * list,ParsedLex * newpl)72     }
73 }
74 
75 impl Buffer {
76     /// This is a cheap operation; you don't need to worry about reusing buffers
77     /// for efficiency.
78     #[inline]
79     pub fn new() -> Buffer {
80         let bytes = [MaybeUninit::<u8>::uninit(); I128_MAX_LEN];
81         Buffer { bytes }
82     }
83 
84     /// Print an integer into this buffer and return a reference to its string
85     /// representation within the buffer.
86     pub fn format<I: Integer>(&mut self, i: I) -> &str {
87         i.write(unsafe {
88             &mut *(&mut self.bytes as *mut [MaybeUninit<u8>; I128_MAX_LEN]
89                 as *mut <I as private::Sealed>::Buffer)
90         })
91     }
92 }
93 
94 /// An integer that can be written into an [`itoa::Buffer`][Buffer].
95 ///
96 /// This trait is sealed and cannot be implemented for types outside of itoa.
97 pub trait Integer: private::Sealed {}
98 
LexizeAddLemm(LexizeData * ld,int type,char * lemm,int lenlemm)99 // Seal to prevent downstream implementations of the Integer trait.
100 mod private {
101     pub trait Sealed: Copy {
102         type Buffer: 'static;
103         fn write(self, buf: &mut Self::Buffer) -> &str;
104     }
105 }
106 
107 const DEC_DIGITS_LUT: &[u8] = b"\
108       0001020304050607080910111213141516171819\
109       2021222324252627282930313233343536373839\
110       4041424344454647484950515253545556575859\
RemoveHead(LexizeData * ld)111       6061626364656667686970717273747576777879\
112       8081828384858687888990919293949596979899";
113 
114 // Adaptation of the original implementation at
115 // https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L188-L266
116 macro_rules! impl_Integer {
117     ($($max_len:expr => $t:ident),* as $conv_fn:ident) => {$(
118         impl Integer for $t {}
setCorrLex(LexizeData * ld,ParsedLex ** correspondLexem)119 
120         impl private::Sealed for $t {
121             type Buffer = [MaybeUninit<u8>; $max_len];
122 
123             #[allow(unused_comparisons)]
124             #[inline]
125             fn write(self, buf: &mut [MaybeUninit<u8>; $max_len]) -> &str {
126                 let is_nonnegative = self >= 0;
127                 let mut n = if is_nonnegative {
128                     self as $conv_fn
129                 } else {
130                     // convert the negative num to positive by summing 1 to it's 2 complement
131                     (!(self as $conv_fn)).wrapping_add(1)
132                 };
133                 let mut curr = buf.len() as isize;
134                 let buf_ptr = buf.as_mut_ptr() as *mut u8;
135                 let lut_ptr = DEC_DIGITS_LUT.as_ptr();
136 
137                 unsafe {
138                     // need at least 16 bits for the 4-characters-at-a-time to work.
139                     if mem::size_of::<$t>() >= 2 {
140                         // eagerly decode 4 characters at a time
141                         while n >= 10000 {
142                             let rem = (n % 10000) as isize;
143                             n /= 10000;
144 
145                             let d1 = (rem / 100) << 1;
146                             let d2 = (rem % 100) << 1;
147                             curr -= 4;
148                             ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
149                             ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
150                         }
151                     }
152 
153                     // if we reach here numbers are <= 9999, so at most 4 chars long
154                     let mut n = n as isize; // possibly reduce 64bit math
155 
156                     // decode 2 more chars, if > 2 chars
157                     if n >= 100 {
158                         let d1 = (n % 100) << 1;
159                         n /= 100;
160                         curr -= 2;
161                         ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
162                     }
163 
164                     // decode last 1 or 2 chars
165                     if n < 10 {
166                         curr -= 1;
167                         *buf_ptr.offset(curr) = (n as u8) + b'0';
168                     } else {
169                         let d1 = n << 1;
170                         curr -= 2;
171                         ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
172                     }
173 
174                     if !is_nonnegative {
175                         curr -= 1;
176                         *buf_ptr.offset(curr) = b'-';
177                     }
178                 }
179 
180                 let len = buf.len() - curr as usize;
181                 let bytes = unsafe { slice::from_raw_parts(buf_ptr.offset(curr), len) };
182                 unsafe { str::from_utf8_unchecked(bytes) }
183             }
184         }
185     )*};
186 }
187 
188 const I8_MAX_LEN: usize = 4;
189 const U8_MAX_LEN: usize = 3;
190 const I16_MAX_LEN: usize = 6;
191 const U16_MAX_LEN: usize = 5;
192 const I32_MAX_LEN: usize = 11;
193 const U32_MAX_LEN: usize = 10;
194 const I64_MAX_LEN: usize = 20;
195 const U64_MAX_LEN: usize = 20;
196 
197 impl_Integer!(
198     I8_MAX_LEN => i8,
199     U8_MAX_LEN => u8,
200     I16_MAX_LEN => i16,
201     U16_MAX_LEN => u16,
202     I32_MAX_LEN => i32,
203     U32_MAX_LEN => u32
204     as u32);
205 
206 impl_Integer!(I64_MAX_LEN => i64, U64_MAX_LEN => u64 as u64);
207 
208 #[cfg(target_pointer_width = "16")]
209 impl_Integer!(I16_MAX_LEN => isize, U16_MAX_LEN => usize as u16);
210 
211 #[cfg(target_pointer_width = "32")]
212 impl_Integer!(I32_MAX_LEN => isize, U32_MAX_LEN => usize as u32);
213 
214 #[cfg(target_pointer_width = "64")]
215 impl_Integer!(I64_MAX_LEN => isize, U64_MAX_LEN => usize as u64);
216 
217 macro_rules! impl_Integer128 {
218     ($($max_len:expr => $t:ident),*) => {$(
219         impl Integer for $t {}
220 
221         impl private::Sealed for $t {
222             type Buffer = [MaybeUninit<u8>; $max_len];
223 
224             #[allow(unused_comparisons)]
225             #[inline]
226             fn write(self, buf: &mut [MaybeUninit<u8>; $max_len]) -> &str {
227                 let is_nonnegative = self >= 0;
228                 let n = if is_nonnegative {
229                     self as u128
230                 } else {
231                     // convert the negative num to positive by summing 1 to it's 2 complement
232                     (!(self as u128)).wrapping_add(1)
233                 };
234                 let mut curr = buf.len() as isize;
235                 let buf_ptr = buf.as_mut_ptr() as *mut u8;
236 
237                 unsafe {
238                     // Divide by 10^19 which is the highest power less than 2^64.
239                     let (n, rem) = udiv128::udivmod_1e19(n);
240                     let buf1 = buf_ptr.offset(curr - U64_MAX_LEN as isize) as *mut [MaybeUninit<u8>; U64_MAX_LEN];
241                     curr -= rem.write(&mut *buf1).len() as isize;
242 
243                     if n != 0 {
244                         // Memset the base10 leading zeros of rem.
245                         let target = buf.len() as isize - 19;
246                         ptr::write_bytes(buf_ptr.offset(target), b'0', (curr - target) as usize);
247                         curr = target;
248 
249                         // Divide by 10^19 again.
250                         let (n, rem) = udiv128::udivmod_1e19(n);
251                         let buf2 = buf_ptr.offset(curr - U64_MAX_LEN as isize) as *mut [MaybeUninit<u8>; U64_MAX_LEN];
252                         curr -= rem.write(&mut *buf2).len() as isize;
253 
254                         if n != 0 {
255                             // Memset the leading zeros.
256                             let target = buf.len() as isize - 38;
257                             ptr::write_bytes(buf_ptr.offset(target), b'0', (curr - target) as usize);
258                             curr = target;
259 
260                             // There is at most one digit left
261                             // because u128::max / 10^19 / 10^19 is 3.
262                             curr -= 1;
263                             *buf_ptr.offset(curr) = (n as u8) + b'0';
264                         }
265                     }
266 
267                     if !is_nonnegative {
268                         curr -= 1;
269                         *buf_ptr.offset(curr) = b'-';
270                     }
271 
272                     let len = buf.len() - curr as usize;
273                     let bytes = slice::from_raw_parts(buf_ptr.offset(curr), len);
274                     str::from_utf8_unchecked(bytes)
275                 }
276             }
277         }
278     )*};
279 }
280 
281 const U128_MAX_LEN: usize = 39;
282 const I128_MAX_LEN: usize = 40;
283 
284 impl_Integer128!(I128_MAX_LEN => i128, U128_MAX_LEN => u128);
285