• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 fast functions for printing integer primitives to an
10 //! [`io::Write`] or a [`fmt::Write`]. The implementation comes straight from
11 //! [libcore] but avoids the performance penalty of going through
12 //! [`fmt::Formatter`].
13 //!
14 //! See also [`dtoa`] for printing floating point primitives.
15 //!
16 //! [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
17 //! [`fmt::Write`]: https://doc.rust-lang.org/core/fmt/trait.Write.html
18 //! [libcore]: https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L201-L254
19 //! [`fmt::Formatter`]: https://doc.rust-lang.org/std/fmt/struct.Formatter.html
20 //! [`dtoa`]: https://github.com/dtolnay/dtoa
21 //!
22 //! <br>
23 //!
24 //! # Performance (lower is better)
25 //!
26 //! ![performance](https://raw.githubusercontent.com/dtolnay/itoa/master/performance.png)
27 //!
28 //! <br>
29 //!
30 //! # Examples
31 //!
32 //! ```edition2018
33 //! use std::{fmt, io};
34 //!
35 //! fn demo_itoa_write() -> io::Result<()> {
36 //!     // Write to a vector or other io::Write.
37 //!     let mut buf = Vec::new();
38 //!     itoa::write(&mut buf, 128u64)?;
39 //!     println!("{:?}", buf);
40 //!
41 //!     // Write to a stack buffer.
42 //!     let mut bytes = [0u8; 20];
43 //!     let n = itoa::write(&mut bytes[..], 128u64)?;
44 //!     println!("{:?}", &bytes[..n]);
45 //!
46 //!     Ok(())
47 //! }
48 //!
49 //! fn demo_itoa_fmt() -> fmt::Result {
50 //!     // Write to a string.
51 //!     let mut s = String::new();
52 //!     itoa::fmt(&mut s, 128u64)?;
53 //!     println!("{}", s);
54 //!
55 //!     Ok(())
56 //! }
57 //! ```
58 
59 #![doc(html_root_url = "https://docs.rs/itoa/0.4.8")]
60 #![cfg_attr(not(feature = "std"), no_std)]
61 #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
62 #![cfg_attr(
63     feature = "cargo-clippy",
64     allow(
65         expl_impl_clone_on_copy,
66         missing_errors_doc,
67         must_use_candidate,
68         transmute_ptr_to_ptr
69     )
70 )]
71 
72 #[cfg(feature = "i128")]
73 mod udiv128;
74 
75 #[cfg(feature = "std")]
76 use std::{fmt, io, mem, ptr, slice, str};
77 
78 #[cfg(not(feature = "std"))]
79 use core::{fmt, mem, ptr, slice, str};
80 
81 /// Write integer to an `io::Write`.
82 #[cfg(feature = "std")]
83 #[inline]
write<W: io::Write, V: Integer>(mut wr: W, value: V) -> io::Result<usize>84 pub fn write<W: io::Write, V: Integer>(mut wr: W, value: V) -> io::Result<usize> {
85     let mut buf = Buffer::new();
86     let s = buf.format(value);
87     match wr.write_all(s.as_bytes()) {
88         Ok(()) => Ok(s.len()),
89         Err(e) => Err(e),
90     }
91 }
92 
93 /// Write integer to an `fmt::Write`.
94 #[inline]
fmt<W: fmt::Write, V: Integer>(mut wr: W, value: V) -> fmt::Result95 pub fn fmt<W: fmt::Write, V: Integer>(mut wr: W, value: V) -> fmt::Result {
96     let mut buf = Buffer::new();
97     wr.write_str(buf.format(value))
98 }
99 
100 /// A safe API for formatting integers to text.
101 ///
102 /// # Example
103 ///
104 /// ```
105 /// let mut buffer = itoa::Buffer::new();
106 /// let printed = buffer.format(1234);
107 /// assert_eq!(printed, "1234");
108 /// ```
109 #[derive(Copy)]
110 pub struct Buffer {
111     bytes: [u8; I128_MAX_LEN],
112 }
113 
114 impl Default for Buffer {
115     #[inline]
default() -> Buffer116     fn default() -> Buffer {
117         Buffer::new()
118     }
119 }
120 
121 impl Clone for Buffer {
122     #[inline]
clone(&self) -> Self123     fn clone(&self) -> Self {
124         Buffer::new()
125     }
126 }
127 
128 impl Buffer {
129     /// This is a cheap operation; you don't need to worry about reusing buffers
130     /// for efficiency.
131     #[inline]
132     #[allow(deprecated)]
new() -> Buffer133     pub fn new() -> Buffer {
134         Buffer {
135             bytes: unsafe { mem::uninitialized() },
136         }
137     }
138 
139     /// Print an integer into this buffer and return a reference to its string representation
140     /// within the buffer.
format<I: Integer>(&mut self, i: I) -> &str141     pub fn format<I: Integer>(&mut self, i: I) -> &str {
142         i.write(self)
143     }
144 }
145 
146 // Seal to prevent downstream implementations of the Integer trait.
147 mod private {
148     pub trait Sealed {}
149 }
150 
151 /// An integer that can be formatted by `itoa::write` and `itoa::fmt`.
152 ///
153 /// This trait is sealed and cannot be implemented for types outside of itoa.
154 pub trait Integer: private::Sealed {
155     // Not public API.
156     #[doc(hidden)]
write(self, buf: &mut Buffer) -> &str157     fn write(self, buf: &mut Buffer) -> &str;
158 }
159 
160 trait IntegerPrivate<B> {
write_to(self, buf: &mut B) -> &[u8]161     fn write_to(self, buf: &mut B) -> &[u8];
162 }
163 
164 const DEC_DIGITS_LUT: &'static [u8] = b"\
165       0001020304050607080910111213141516171819\
166       2021222324252627282930313233343536373839\
167       4041424344454647484950515253545556575859\
168       6061626364656667686970717273747576777879\
169       8081828384858687888990919293949596979899";
170 
171 // Adaptation of the original implementation at
172 // https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L188-L266
173 macro_rules! impl_IntegerCommon {
174     ($max_len:expr, $t:ident) => {
175         impl Integer for $t {
176             #[inline]
177             fn write(self, buf: &mut Buffer) -> &str {
178                 unsafe {
179                     debug_assert!($max_len <= I128_MAX_LEN);
180                     let buf = mem::transmute::<&mut [u8; I128_MAX_LEN], &mut [u8; $max_len]>(
181                         &mut buf.bytes,
182                     );
183                     let bytes = self.write_to(buf);
184                     str::from_utf8_unchecked(bytes)
185                 }
186             }
187         }
188 
189         impl private::Sealed for $t {}
190     };
191 }
192 
193 macro_rules! impl_Integer {
194     ($($max_len:expr => $t:ident),* as $conv_fn:ident) => {$(
195         impl_IntegerCommon!($max_len, $t);
196 
197         impl IntegerPrivate<[u8; $max_len]> for $t {
198             #[allow(unused_comparisons)]
199             #[inline]
200             fn write_to(self, buf: &mut [u8; $max_len]) -> &[u8] {
201                 let is_nonnegative = self >= 0;
202                 let mut n = if is_nonnegative {
203                     self as $conv_fn
204                 } else {
205                     // convert the negative num to positive by summing 1 to it's 2 complement
206                     (!(self as $conv_fn)).wrapping_add(1)
207                 };
208                 let mut curr = buf.len() as isize;
209                 let buf_ptr = buf.as_mut_ptr();
210                 let lut_ptr = DEC_DIGITS_LUT.as_ptr();
211 
212                 unsafe {
213                     // need at least 16 bits for the 4-characters-at-a-time to work.
214                     if mem::size_of::<$t>() >= 2 {
215                         // eagerly decode 4 characters at a time
216                         while n >= 10000 {
217                             let rem = (n % 10000) as isize;
218                             n /= 10000;
219 
220                             let d1 = (rem / 100) << 1;
221                             let d2 = (rem % 100) << 1;
222                             curr -= 4;
223                             ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
224                             ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
225                         }
226                     }
227 
228                     // if we reach here numbers are <= 9999, so at most 4 chars long
229                     let mut n = n as isize; // possibly reduce 64bit math
230 
231                     // decode 2 more chars, if > 2 chars
232                     if n >= 100 {
233                         let d1 = (n % 100) << 1;
234                         n /= 100;
235                         curr -= 2;
236                         ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
237                     }
238 
239                     // decode last 1 or 2 chars
240                     if n < 10 {
241                         curr -= 1;
242                         *buf_ptr.offset(curr) = (n as u8) + b'0';
243                     } else {
244                         let d1 = n << 1;
245                         curr -= 2;
246                         ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
247                     }
248 
249                     if !is_nonnegative {
250                         curr -= 1;
251                         *buf_ptr.offset(curr) = b'-';
252                     }
253                 }
254 
255                 let len = buf.len() - curr as usize;
256                 unsafe { slice::from_raw_parts(buf_ptr.offset(curr), len) }
257             }
258         }
259     )*};
260 }
261 
262 const I8_MAX_LEN: usize = 4;
263 const U8_MAX_LEN: usize = 3;
264 const I16_MAX_LEN: usize = 6;
265 const U16_MAX_LEN: usize = 5;
266 const I32_MAX_LEN: usize = 11;
267 const U32_MAX_LEN: usize = 10;
268 const I64_MAX_LEN: usize = 20;
269 const U64_MAX_LEN: usize = 20;
270 
271 impl_Integer!(
272     I8_MAX_LEN => i8,
273     U8_MAX_LEN => u8,
274     I16_MAX_LEN => i16,
275     U16_MAX_LEN => u16,
276     I32_MAX_LEN => i32,
277     U32_MAX_LEN => u32
278     as u32);
279 
280 impl_Integer!(I64_MAX_LEN => i64, U64_MAX_LEN => u64 as u64);
281 
282 #[cfg(target_pointer_width = "16")]
283 impl_Integer!(I16_MAX_LEN => isize, U16_MAX_LEN => usize as u16);
284 
285 #[cfg(target_pointer_width = "32")]
286 impl_Integer!(I32_MAX_LEN => isize, U32_MAX_LEN => usize as u32);
287 
288 #[cfg(target_pointer_width = "64")]
289 impl_Integer!(I64_MAX_LEN => isize, U64_MAX_LEN => usize as u64);
290 
291 #[cfg(all(feature = "i128"))]
292 macro_rules! impl_Integer128 {
293     ($($max_len:expr => $t:ident),*) => {$(
294         impl_IntegerCommon!($max_len, $t);
295 
296         impl IntegerPrivate<[u8; $max_len]> for $t {
297             #[allow(unused_comparisons)]
298             #[inline]
299             fn write_to(self, buf: &mut [u8; $max_len]) -> &[u8] {
300                 let is_nonnegative = self >= 0;
301                 let n = if is_nonnegative {
302                     self as u128
303                 } else {
304                     // convert the negative num to positive by summing 1 to it's 2 complement
305                     (!(self as u128)).wrapping_add(1)
306                 };
307                 let mut curr = buf.len() as isize;
308                 let buf_ptr = buf.as_mut_ptr();
309 
310                 unsafe {
311                     // Divide by 10^19 which is the highest power less than 2^64.
312                     let (n, rem) = udiv128::udivmod_1e19(n);
313                     let buf1 = buf_ptr.offset(curr - U64_MAX_LEN as isize) as *mut [u8; U64_MAX_LEN];
314                     curr -= rem.write_to(&mut *buf1).len() as isize;
315 
316                     if n != 0 {
317                         // Memset the base10 leading zeros of rem.
318                         let target = buf.len() as isize - 19;
319                         ptr::write_bytes(buf_ptr.offset(target), b'0', (curr - target) as usize);
320                         curr = target;
321 
322                         // Divide by 10^19 again.
323                         let (n, rem) = udiv128::udivmod_1e19(n);
324                         let buf2 = buf_ptr.offset(curr - U64_MAX_LEN as isize) as *mut [u8; U64_MAX_LEN];
325                         curr -= rem.write_to(&mut *buf2).len() as isize;
326 
327                         if n != 0 {
328                             // Memset the leading zeros.
329                             let target = buf.len() as isize - 38;
330                             ptr::write_bytes(buf_ptr.offset(target), b'0', (curr - target) as usize);
331                             curr = target;
332 
333                             // There is at most one digit left
334                             // because u128::max / 10^19 / 10^19 is 3.
335                             curr -= 1;
336                             *buf_ptr.offset(curr) = (n as u8) + b'0';
337                         }
338                     }
339 
340                     if !is_nonnegative {
341                         curr -= 1;
342                         *buf_ptr.offset(curr) = b'-';
343                     }
344 
345                     let len = buf.len() - curr as usize;
346                     slice::from_raw_parts(buf_ptr.offset(curr), len)
347                 }
348             }
349         }
350     )*};
351 }
352 
353 #[cfg(all(feature = "i128"))]
354 const U128_MAX_LEN: usize = 39;
355 const I128_MAX_LEN: usize = 40;
356 
357 #[cfg(all(feature = "i128"))]
358 impl_Integer128!(I128_MAX_LEN => i128, U128_MAX_LEN => u128);
359