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