From d3bd82265d11b03f6d72aed871085e4de1c75411 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 17 Mar 2020 13:23:09 -0700 Subject: [PATCH 001/215] Select a single docs.rs build target --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 03fe09b..b91e437 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,6 @@ std = [] [badges] travis-ci = { repository = "dtolnay/itoa" } + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] From 641889d2ba4f6794e230b0139968c104e088d868 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 1 May 2020 21:02:30 -0700 Subject: [PATCH 002/215] Remove CI badge from Cargo.toml Support for badges has been deprecated by crates.io. --- Cargo.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b91e437..1bc51bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,5 @@ default = ["std"] i128 = [] std = [] -[badges] -travis-ci = { repository = "dtolnay/itoa" } - [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] From 9a46d47e2e7c6ba3cfc6eb81e426408322babe12 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 2 May 2020 23:33:01 -0700 Subject: [PATCH 003/215] Enable GitHub Actions --- .github/workflows/ci.yml | 45 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d157e90 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,45 @@ +name: test + +on: + push: + pull_request: + schedule: [cron: "40 1 * * *"] + +jobs: + test: + name: Rust ${{matrix.rust}} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + rust: [nightly, beta, stable, 1.26.0] + steps: + - uses: actions/checkout@v2 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{matrix.rust}} + - run: cargo build + - run: cargo build --features i128 + - run: cargo test --features i128 + - run: cargo test --features i128 --release + - run: cargo build --no-default-features --features i128 + - run: cargo test --tests --no-default-features --features i128 + - run: cargo test --tests --no-default-features --features i128 --release + - run: cargo bench --no-run --features i128 + if: matrix.rust == 'nightly' + + mintest: + name: Rust 1.20.0 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: dtolnay/rust-toolchain@1.20.0 + - run: cargo test + + msrv: + name: Rust 1.0.0 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: dtolnay/rust-toolchain@1.0.0 + - run: cargo build From a2c6d4bab3551408c13f3f11182d1ec7a0a3958e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 May 2020 11:29:48 -0700 Subject: [PATCH 004/215] Remove Travis configuration --- .github/workflows/ci.yml | 2 +- .travis.yml | 28 ---------------------------- 2 files changed, 1 insertion(+), 29 deletions(-) delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d157e90..ec51099 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: test +name: CI on: push: diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 34fd8de..0000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -sudo: false -language: rust - -matrix: - include: - - rust: stable - env: - - FEATURES="i128" - - rust: beta - env: - - FEATURES="i128" - - rust: nightly - env: - - FEATURES="i128" - - BUILD_BENCH="true" - - rust: 1.0.0 - script: cargo build - - rust: 1.20.0 - script: cargo test - -script: - - cargo build --features "$FEATURES" - - cargo test --features "$FEATURES" - - cargo test --features "$FEATURES" --release - - cargo build --no-default-features --features "$FEATURES" - - cargo test --tests --no-default-features --features "$FEATURES" - - cargo test --tests --no-default-features --features "$FEATURES" --release - - if [ "$BUILD_BENCH" == "true" ]; then cargo bench --no-run --features "$FEATURES"; fi From 5618b9dc4159cd839f2c5d493f09bfaa3d042793 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 May 2020 23:58:28 -0700 Subject: [PATCH 005/215] Update build status badge to GitHub Actions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d36f4fd..de54464 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ itoa ==== -[![Build Status](https://api.travis-ci.org/dtolnay/itoa.svg?branch=master)](https://travis-ci.org/dtolnay/itoa) +[![Build Status](https://img.shields.io/github/workflow/status/dtolnay/itoa/CI/master)](https://github.com/dtolnay/itoa/actions?query=branch%3Amaster) [![Latest Version](https://img.shields.io/crates/v/itoa.svg)](https://crates.io/crates/itoa) [![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/itoa) From f075e1bf716f898d6f570489eb66f1bc537e52d0 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 13 Jun 2020 22:36:21 -0700 Subject: [PATCH 006/215] New style of readme badges --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index de54464..cff3bb3 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ itoa ==== -[![Build Status](https://img.shields.io/github/workflow/status/dtolnay/itoa/CI/master)](https://github.com/dtolnay/itoa/actions?query=branch%3Amaster) -[![Latest Version](https://img.shields.io/crates/v/itoa.svg)](https://crates.io/crates/itoa) -[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/itoa) +[github](https://github.com/dtolnay/itoa) +[crates.io](https://crates.io/crates/itoa) +[docs.rs](https://docs.rs/itoa) +[build status](https://github.com/dtolnay/itoa/actions?query=branch%3Amaster) This crate provides fast functions for printing integer primitives to an [`io::Write`] or a [`fmt::Write`]. The implementation comes straight from From efc758b64603ba64d394089ee707c6eec1e3b5d9 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 13 Jun 2020 22:36:24 -0700 Subject: [PATCH 007/215] Add crosslink icons to top of rustdoc --- src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 1b0f1aa..822f66d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,11 @@ +//! [![github]](https://github.com/dtolnay/itoa) [![crates-io]](https://crates.io/crates/itoa) [![docs-rs]](https://docs.rs/itoa) +//! +//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github +//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust +//! [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 +//! +//!
+//! //! This crate provides fast functions for printing integer primitives to an //! [`io::Write`] or a [`fmt::Write`]. The implementation comes straight from //! [libcore] but avoids the performance penalty of going through From 63abae9b8257228320d293be9a531a66675a6754 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 14 Jun 2020 13:20:05 -0700 Subject: [PATCH 008/215] Add a sponsors link --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..7507077 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: dtolnay From 4911818fcf5105eb3d3b99b8e583271ef668146c Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 16 Jun 2020 11:30:45 -0700 Subject: [PATCH 009/215] Release 0.4.6 --- Cargo.toml | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1bc51bb..82a1934 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "itoa" -version = "0.4.5" # remember to update html_root_url +version = "0.4.6" # remember to update html_root_url authors = ["David Tolnay "] license = "MIT OR Apache-2.0" description = "Fast functions for printing integer primitives to an io::Write" diff --git a/src/lib.rs b/src/lib.rs index 822f66d..fe55012 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,7 +56,7 @@ //! } //! ``` -#![doc(html_root_url = "https://docs.rs/itoa/0.4.5")] +#![doc(html_root_url = "https://docs.rs/itoa/0.4.6")] #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] #![cfg_attr( From 8d64f674a03d171889949dcc52ad3780e55f9126 Mon Sep 17 00:00:00 2001 From: Samuel Marks <807580+SamuelMarks@users.noreply.github.com> Date: Mon, 29 Jun 2020 12:00:26 +1000 Subject: [PATCH 010/215] [*.rs] rustfmt --- benches/bench.rs | 2 +- src/lib.rs | 2 +- tests/test.rs | 7 ++----- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index c3b5500..a9ed517 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -68,7 +68,7 @@ macro_rules! benches { } } -benches!{ +benches! { bench_u64_0(0u64), bench_u64_half(::max_value() as u64), bench_u64_max(::max_value()), diff --git a/src/lib.rs b/src/lib.rs index fe55012..f7eedac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,7 +61,7 @@ #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] #![cfg_attr( feature = "cargo-clippy", - allow(const_static_lifetime, transmute_ptr_to_ptr), + allow(const_static_lifetime, transmute_ptr_to_ptr) )] #[cfg(feature = "i128")] diff --git a/tests/test.rs b/tests/test.rs index dd8d494..5355868 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,7 +1,4 @@ -#![cfg_attr( - feature = "cargo-clippy", - allow(cast_lossless, string_lit_as_bytes) -)] +#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless, string_lit_as_bytes))] #![allow(non_snake_case)] extern crate itoa; @@ -32,7 +29,7 @@ macro_rules! test { } } -test!{ +test! { test_u64_0(0u64, "0"), test_u64_half(::max_value() as u64, "4294967295"), test_u64_max(::max_value(), "18446744073709551615"), From 65c797190caab625fe73afa733e70f98e64cfdd7 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 7 Dec 2020 19:34:16 -0800 Subject: [PATCH 011/215] Point Cargo.toml metadata documentation link to docs.rs --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 82a1934..544af02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ authors = ["David Tolnay "] license = "MIT OR Apache-2.0" description = "Fast functions for printing integer primitives to an io::Write" repository = "https://github.com/dtolnay/itoa" -documentation = "https://github.com/dtolnay/itoa" +documentation = "https://docs.rs/itoa" categories = ["value-formatting"] readme = "README.md" exclude = ["performance.png"] From 08c79b5e2348a4b44cac8860612c9ee1f5518544 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 27 Dec 2020 12:59:05 -0800 Subject: [PATCH 012/215] Release 0.4.7 --- Cargo.toml | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 544af02..0192401 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "itoa" -version = "0.4.6" # remember to update html_root_url +version = "0.4.7" # remember to update html_root_url authors = ["David Tolnay "] license = "MIT OR Apache-2.0" description = "Fast functions for printing integer primitives to an io::Write" diff --git a/src/lib.rs b/src/lib.rs index f7eedac..d7bc81c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,7 +56,7 @@ //! } //! ``` -#![doc(html_root_url = "https://docs.rs/itoa/0.4.6")] +#![doc(html_root_url = "https://docs.rs/itoa/0.4.7")] #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] #![cfg_attr( From cc8ab5800c04df2b911056de35f2d76f7f96f7fc Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 29 Dec 2020 17:07:25 -0800 Subject: [PATCH 013/215] Run clippy linter in CI --- .github/workflows/ci.yml | 8 ++++++++ src/lib.rs | 5 +---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec51099..f231037 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,3 +43,11 @@ jobs: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@1.0.0 - run: cargo build + + clippy: + name: Clippy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: dtolnay/rust-toolchain@clippy + - run: cargo clippy -- -Dclippy::all diff --git a/src/lib.rs b/src/lib.rs index d7bc81c..6996c69 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,10 +59,7 @@ #![doc(html_root_url = "https://docs.rs/itoa/0.4.7")] #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] -#![cfg_attr( - feature = "cargo-clippy", - allow(const_static_lifetime, transmute_ptr_to_ptr) -)] +#![cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ptr))] #[cfg(feature = "i128")] mod udiv128; From 42353411072e2e21d791140d4c3ddfa46dc8d999 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 29 Dec 2020 17:07:33 -0800 Subject: [PATCH 014/215] Inform clippy of supported compiler version in clippy.toml --- .clippy.toml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .clippy.toml diff --git a/.clippy.toml b/.clippy.toml new file mode 100644 index 0000000..8e17d80 --- /dev/null +++ b/.clippy.toml @@ -0,0 +1 @@ +msrv = "1.0.0" From d00b37103f7db9dd26c28d666a0f7fbe30d83d4d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 29 Dec 2020 17:10:05 -0800 Subject: [PATCH 015/215] Opt in to pedantic clippy lints --- .github/workflows/ci.yml | 2 +- src/lib.rs | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f231037..6d87313 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,4 +50,4 @@ jobs: steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@clippy - - run: cargo clippy -- -Dclippy::all + - run: cargo clippy -- -Dclippy::pedantic diff --git a/src/lib.rs b/src/lib.rs index 6996c69..52a6522 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,7 +59,15 @@ #![doc(html_root_url = "https://docs.rs/itoa/0.4.7")] #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] -#![cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ptr))] +#![cfg_attr( + feature = "cargo-clippy", + allow( + expl_impl_clone_on_copy, + missing_errors_doc, + must_use_candidate, + transmute_ptr_to_ptr + ) +)] #[cfg(feature = "i128")] mod udiv128; From ac8183cdafe59ac25635ea3f4320cd2d34022f7f Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 4 Jan 2021 23:47:11 -0800 Subject: [PATCH 016/215] Fix catching clippy warnings as CI failures --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d87313..e0f8585 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,4 +50,4 @@ jobs: steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@clippy - - run: cargo clippy -- -Dclippy::pedantic + - run: cargo clippy -- -Dclippy::all -Dclippy::pedantic From 51f3f12113b67642794a55a33d255f811d57887f Mon Sep 17 00:00:00 2001 From: Kogia-sima Date: Thu, 28 Jan 2021 23:47:57 +0900 Subject: [PATCH 017/215] perf: Optimize udivmod_1e19 function --- src/udiv128.rs | 87 ++++++++++++++++++++------------------------------ 1 file changed, 35 insertions(+), 52 deletions(-) diff --git a/src/udiv128.rs b/src/udiv128.rs index adbdce2..ee2360e 100644 --- a/src/udiv128.rs +++ b/src/udiv128.rs @@ -1,61 +1,44 @@ -// The code in this file is based on Rust's compiler-builtins crate. The Rust -// compiler automatically links programs against this crate for target-specific -// runtime support. We have copied the implementation of `__udivmodti4()` which -// is an intrinsic implementing division with remainder for architectures -// without 128-bit integers. This implementation works around some poor codegen -// by LLVM (https://github.com/rust-lang/rust/issues/44545) and allows for -// inlining which does not happen with the intrinsic. -// -// The compiler-builtins crate carries the following license, which is available -// in full at: -// https://github.com/rust-lang-nursery/compiler-builtins/blob/master/LICENSE.TXT -// -// --- -// -// Copyright 2009-2016 compiler-builtins Developers -// -// The compiler-builtins crate is dual licensed under both the University of -// Illinois "BSD-Like" license and the MIT license. As a user of this code you -// may choose to use it under either license. As a contributor, you agree to -// allow your code to be used under both. - +/// Multiply unsigned 128 bit integers, return upper 128 bits of the result #[inline] -pub fn udivmod_1e19(n: u128) -> (u128, u64) { - let d = 10_000_000_000_000_000_000_u64; // 10^19 +fn u128_mulhi(x: u128, y: u128) -> u128 { + let x_lo = x as u64; + let x_hi = (x >> 64) as u64; + let y_lo = y as u64; + let y_hi = (y >> 64) as u64; - let high = (n >> 64) as u64; - if high == 0 { - let low = n as u64; - return ((low / d) as u128, low % d); - } + // handle possibility of overflow + let carry = (x_lo as u128 * y_lo as u128) >> 64; + let m = x_lo as u128 * y_hi as u128 + carry; + let high1 = m >> 64; - let sr = 65 - high.leading_zeros(); + let m_lo = m as u64; + let high2 = x_hi as u128 * y_lo as u128 + m_lo as u128 >> 64; - // 2 <= sr <= 65 - let mut q: u128 = n << (128 - sr); - let mut r: u128 = n >> sr; - let mut carry: u64 = 0; + x_hi as u128 * y_hi as u128 + high1 + high2 +} - // Don't use a range because they may generate references to memcpy in unoptimized code - // - // Loop invariants: r < d; carry is 0 or 1 - let mut i = 0; - while i < sr { - i += 1; +/// Divide `n` by 1e19 and return quotient and remainder +/// +/// Integer division algorithm is based on the following paper: +/// +/// T. Granlund and P. Montgomery, “Division by Invariant Integers Using Multiplication” +/// in Proc. of the SIGPLAN94 Conference on Programming Language Design and +/// Implementation, 1994, pp. 61–72 +/// +#[inline] +pub fn udivmod_1e19(n: u128) -> (u128, u64) { + let d = 10_000_000_000_000_000_000_u64; // 10^19 - // r:q = ((r:q) << 1) | carry - r = (r << 1) | (q >> 127); - q = (q << 1) | carry as u128; + let quot = if n < 1 << 83 { + ((n >> 19) as u64 / (d >> 19)) as u128 + } else { + let factor = 156927543384667019095894735580191660403_u128; + u128_mulhi(n, factor) >> 62 + }; - // carry = 0 - // if r >= d { - // r -= d; - // carry = 1; - // } - let s = (d as u128).wrapping_sub(r).wrapping_sub(1) as i128 >> 127; - carry = (s & 1) as u64; - r -= (d as u128) & s as u128; - } + let rem = (n - quot * d as u128) as u64; + debug_assert_eq!(quot, n / d as u128); + debug_assert_eq!(rem as u128, n % d as u128); - ((q << 1) | carry as u128, r as u64) + (quot, rem) } From 3a4047df0dac7e70a3498f76e920d05d16de72bf Mon Sep 17 00:00:00 2001 From: Kogia-sima Date: Fri, 29 Jan 2021 00:29:10 +0900 Subject: [PATCH 018/215] fix: Fix compilation error on 1.0.0 --- src/udiv128.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/udiv128.rs b/src/udiv128.rs index ee2360e..79ff166 100644 --- a/src/udiv128.rs +++ b/src/udiv128.rs @@ -32,7 +32,9 @@ pub fn udivmod_1e19(n: u128) -> (u128, u64) { let quot = if n < 1 << 83 { ((n >> 19) as u64 / (d >> 19)) as u128 } else { - let factor = 156927543384667019095894735580191660403_u128; + // avoid strange compilation error on old compiler + let factor = + (8507059173023461586_u64 as u128) << 64 | 10779635027931437427 as u128; u128_mulhi(n, factor) >> 62 }; From de247d6ac25d2e62d4cbd195f064ed4af35fd4eb Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 21 Aug 2021 22:22:57 -0700 Subject: [PATCH 019/215] Release 0.4.8 --- Cargo.toml | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0192401..2781d7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "itoa" -version = "0.4.7" # remember to update html_root_url +version = "0.4.8" # remember to update html_root_url authors = ["David Tolnay "] license = "MIT OR Apache-2.0" description = "Fast functions for printing integer primitives to an io::Write" diff --git a/src/lib.rs b/src/lib.rs index 52a6522..8d4582e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,7 +56,7 @@ //! } //! ``` -#![doc(html_root_url = "https://docs.rs/itoa/0.4.7")] +#![doc(html_root_url = "https://docs.rs/itoa/0.4.8")] #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] #![cfg_attr( From 462ada420fe968cdf5bacbad63237f119bb54584 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 18 Sep 2021 16:40:22 -0700 Subject: [PATCH 020/215] Skip clippy job on pull requests --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e0f8585..07122af 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,6 +47,7 @@ jobs: clippy: name: Clippy runs-on: ubuntu-latest + if: github.event_name != 'pull_request' steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@clippy From 8f58e3f64511eefb024b0cdfec5119269bf6f594 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 30 Sep 2021 01:27:18 -0400 Subject: [PATCH 021/215] Run clippy on test suite too --- .github/workflows/ci.yml | 2 +- tests/test.rs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 07122af..7b929f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,4 +51,4 @@ jobs: steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@clippy - - run: cargo clippy -- -Dclippy::all -Dclippy::pedantic + - run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic diff --git a/tests/test.rs b/tests/test.rs index 5355868..da33b5a 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,4 +1,7 @@ -#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless, string_lit_as_bytes))] +#![cfg_attr( + feature = "cargo-clippy", + allow(cast_lossless, string_lit_as_bytes, unseparated_literal_suffix) +)] #![allow(non_snake_case)] extern crate itoa; From dd3f590c41510ef84f3c16e9dc9e446c14493a01 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 30 Sep 2021 01:28:16 -0400 Subject: [PATCH 022/215] Format with rustfmt 2021-09-29 --- src/udiv128.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/udiv128.rs b/src/udiv128.rs index 617c1c1..8ecc496 100644 --- a/src/udiv128.rs +++ b/src/udiv128.rs @@ -32,8 +32,7 @@ pub fn udivmod_1e19(n: u128) -> (u128, u64) { let quot = if n < 1 << 83 { ((n >> 19) as u64 / (d >> 19)) as u128 } else { - let factor = - (8507059173023461586_u64 as u128) << 64 | 10779635027931437427 as u128; + let factor = (8507059173023461586_u64 as u128) << 64 | 10779635027931437427 as u128; u128_mulhi(n, factor) >> 62 }; From f12db11b6151aeede44eee4896a5e0ae65980b0d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 30 Sep 2021 01:29:43 -0400 Subject: [PATCH 023/215] Ignore renamed_and_removed_lints clippy warning We run our test suite as far back as rustc 1.20, which does not support the modern tool attribute syntax. warning: lint name `cast_lossless` is deprecated and may not have an effect in the future. --> tests/test.rs:3:11 | 3 | allow(cast_lossless, string_lit_as_bytes, unseparated_literal_suffix) | ^^^^^^^^^^^^^ help: change it to: `clippy::cast_lossless` | = note: `#[warn(renamed_and_removed_lints)]` on by default warning: lint name `string_lit_as_bytes` is deprecated and may not have an effect in the future. --> tests/test.rs:3:26 | 3 | allow(cast_lossless, string_lit_as_bytes, unseparated_literal_suffix) | ^^^^^^^^^^^^^^^^^^^ help: change it to: `clippy::string_lit_as_bytes` warning: lint name `unseparated_literal_suffix` is deprecated and may not have an effect in the future. --> tests/test.rs:3:47 | 3 | allow(cast_lossless, string_lit_as_bytes, unseparated_literal_suffix) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: change it to: `clippy::unseparated_literal_suffix` --- tests/test.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test.rs b/tests/test.rs index da33b5a..088065b 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,3 +1,4 @@ +#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] #![cfg_attr( feature = "cargo-clippy", allow(cast_lossless, string_lit_as_bytes, unseparated_literal_suffix) From 64d46a7b1d4223cdd7efe3cd4fa6b43c0e350c40 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 30 Sep 2021 01:31:19 -0400 Subject: [PATCH 024/215] Remove no longer triggered string_lit_as_bytes suppression --- tests/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test.rs b/tests/test.rs index 088065b..4931568 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,7 +1,7 @@ #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] #![cfg_attr( feature = "cargo-clippy", - allow(cast_lossless, string_lit_as_bytes, unseparated_literal_suffix) + allow(cast_lossless, unseparated_literal_suffix) )] #![allow(non_snake_case)] From 93e32f72f82d692a890d6f11b88b7fda635eceeb Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 2 Oct 2021 01:52:37 -0400 Subject: [PATCH 025/215] Declare minimum Rust version in Cargo metadata --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 2781d7c..f7a838c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "itoa" version = "0.4.8" # remember to update html_root_url authors = ["David Tolnay "] +rust-version = "1.0" license = "MIT OR Apache-2.0" description = "Fast functions for printing integer primitives to an io::Write" repository = "https://github.com/dtolnay/itoa" From d1d4554f26000c876d67ae2992c628927271c847 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 4 Oct 2021 23:49:30 -0400 Subject: [PATCH 026/215] Suppress broken semicolon_if_nothing_returned lint Gonna assume this is due to https://github.com/rust-lang/rust-clippy/issues/7768. error: consider adding a `;` to the last statement for consistent formatting --> src/lib.rs:271:1 | 271 | / impl_Integer!( 272 | | I8_MAX_LEN => i8, 273 | | U8_MAX_LEN => u8, 274 | | I16_MAX_LEN => i16, ... | 277 | | U32_MAX_LEN => u32 278 | | as u32); | |____________^ | = note: `-D clippy::semicolon-if-nothing-returned` implied by `-D clippy::pedantic` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned help: add a `;` here | 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, ... error: consider adding a `;` to the last statement for consistent formatting --> src/lib.rs:280:1 | 280 | impl_Integer!(I64_MAX_LEN => i64, U64_MAX_LEN => u64 as u64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `impl_Integer!(I64_MAX_LEN => i64, U64_MAX_LEN => u64 as u64);;` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned error: consider adding a `;` to the last statement for consistent formatting --> src/lib.rs:289:1 | 289 | impl_Integer!(I64_MAX_LEN => isize, U64_MAX_LEN => usize as u64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `impl_Integer!(I64_MAX_LEN => isize, U64_MAX_LEN => usize as u64);;` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 8d4582e..9ae9d0b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,6 +65,7 @@ expl_impl_clone_on_copy, missing_errors_doc, must_use_candidate, + semicolon_if_nothing_returned, // https://github.com/rust-lang/rust-clippy/issues/7768 transmute_ptr_to_ptr ) )] From 415ab8cf9aba08203ace17b761fb71b36ab9e574 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 10 Dec 2021 23:06:40 -0800 Subject: [PATCH 027/215] Add a miri test job in CI --- .github/workflows/ci.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7b929f6..81ca1d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,6 +44,16 @@ jobs: - uses: dtolnay/rust-toolchain@1.0.0 - run: cargo build + miri: + name: Miri + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: dtolnay/rust-toolchain@nightly + with: + components: miri + - run: cargo miri test + clippy: name: Clippy runs-on: ubuntu-latest From 96eef6ef6e9d0c9f69fea6710a2e8c993f554f2a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 00:04:28 -0800 Subject: [PATCH 028/215] Track raw pointers in miri CI run --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81ca1d2..c70d972 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,6 +53,8 @@ jobs: with: components: miri - run: cargo miri test + env: + MIRIFLAGS: "-Zmiri-tag-raw-pointers" clippy: name: Clippy From 341086a6ffde28985209e9dbf5b4b0d49fede725 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 00:14:08 -0800 Subject: [PATCH 029/215] Update to 2018 edition and rust 1.31+ --- .github/workflows/ci.yml | 18 +----------------- Cargo.toml | 3 ++- README.md | 2 +- 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c70d972..09d6846 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - rust: [nightly, beta, stable, 1.26.0] + rust: [nightly, beta, stable, 1.31.0] steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@master @@ -28,22 +28,6 @@ jobs: - run: cargo bench --no-run --features i128 if: matrix.rust == 'nightly' - mintest: - name: Rust 1.20.0 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: dtolnay/rust-toolchain@1.20.0 - - run: cargo test - - msrv: - name: Rust 1.0.0 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: dtolnay/rust-toolchain@1.0.0 - - run: cargo build - miri: name: Miri runs-on: ubuntu-latest diff --git a/Cargo.toml b/Cargo.toml index f7a838c..e927756 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "itoa" version = "0.4.8" # remember to update html_root_url authors = ["David Tolnay "] -rust-version = "1.0" +rust-version = "1.31" license = "MIT OR Apache-2.0" description = "Fast functions for printing integer primitives to an io::Write" repository = "https://github.com/dtolnay/itoa" @@ -10,6 +10,7 @@ documentation = "https://docs.rs/itoa" categories = ["value-formatting"] readme = "README.md" exclude = ["performance.png"] +edition = "2018" [features] default = ["std"] diff --git a/README.md b/README.md index cff3bb3..298983e 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ This crate provides fast functions for printing integer primitives to an See also [`dtoa`] for printing floating point primitives. -*Version requirement: rustc 1.0+* +*Version requirement: rustc 1.31+* [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html [`fmt::Write`]: https://doc.rust-lang.org/core/fmt/trait.Write.html From 36c5ae17b40b62d981c6805a4857332586f06b2a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 00:16:44 -0800 Subject: [PATCH 030/215] Convert clippy lint level attributes to tool attrs --- benches/bench.rs | 2 +- src/lib.rs | 16 ++++++---------- tests/test.rs | 6 +----- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index a9ed517..e9e87f0 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,6 +1,6 @@ -#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] #![feature(test)] #![allow(non_snake_case)] +#![allow(clippy::cast_lossless)] extern crate itoa; extern crate test; diff --git a/src/lib.rs b/src/lib.rs index 9ae9d0b..4f63e50 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,16 +58,12 @@ #![doc(html_root_url = "https://docs.rs/itoa/0.4.8")] #![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] -#![cfg_attr( - feature = "cargo-clippy", - allow( - expl_impl_clone_on_copy, - missing_errors_doc, - must_use_candidate, - semicolon_if_nothing_returned, // https://github.com/rust-lang/rust-clippy/issues/7768 - transmute_ptr_to_ptr - ) +#![allow( + clippy::expl_impl_clone_on_copy, + clippy::missing_errors_doc, + clippy::must_use_candidate, + clippy::semicolon_if_nothing_returned, // https://github.com/rust-lang/rust-clippy/issues/7768 + clippy::transmute_ptr_to_ptr )] #[cfg(feature = "i128")] diff --git a/tests/test.rs b/tests/test.rs index 4931568..e68fcfc 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,9 +1,5 @@ -#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] -#![cfg_attr( - feature = "cargo-clippy", - allow(cast_lossless, unseparated_literal_suffix) -)] #![allow(non_snake_case)] +#![allow(clippy::cast_lossless, clippy::unseparated_literal_suffix)] extern crate itoa; From 4d0a8c78c27e118202190634746275c360244de2 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 00:21:42 -0800 Subject: [PATCH 031/215] Raise clippy lints up to 1.31 compatibility --- .clippy.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.clippy.toml b/.clippy.toml index 8e17d80..3d30690 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1 +1 @@ -msrv = "1.0.0" +msrv = "1.31.0" From 035d16fda547373a9b8fd397020505e3b00524d3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 00:22:19 -0800 Subject: [PATCH 032/215] Resolve redundant_static_lifetimes clippy lint error: constants have by default a `'static` lifetime --> src/lib.rs:161:24 | 161 | const DEC_DIGITS_LUT: &'static [u8] = b"\ | -^^^^^^^----- help: consider removing `'static`: `&[u8]` | = note: `-D clippy::redundant-static-lifetimes` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 4f63e50..e1fee40 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -158,7 +158,7 @@ trait IntegerPrivate { fn write_to(self, buf: &mut B) -> &[u8]; } -const DEC_DIGITS_LUT: &'static [u8] = b"\ +const DEC_DIGITS_LUT: &[u8] = b"\ 0001020304050607080910111213141516171819\ 2021222324252627282930313233343536373839\ 4041424344454647484950515253545556575859\ From 3101467676ab5a303de7f9a52c86bc5185bd9a80 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 00:24:49 -0800 Subject: [PATCH 033/215] Replace deprecated mem::uninitialized with MaybeUninit --- .clippy.toml | 2 +- .github/workflows/ci.yml | 2 +- Cargo.toml | 2 +- README.md | 2 +- src/lib.rs | 33 +++++++++++++++++---------------- 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/.clippy.toml b/.clippy.toml index 3d30690..0a54853 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1 +1 @@ -msrv = "1.31.0" +msrv = "1.36.0" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09d6846..386b76a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - rust: [nightly, beta, stable, 1.31.0] + rust: [nightly, beta, stable, 1.36.0] steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@master diff --git a/Cargo.toml b/Cargo.toml index e927756..35c352f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "itoa" version = "0.4.8" # remember to update html_root_url authors = ["David Tolnay "] -rust-version = "1.31" +rust-version = "1.36" license = "MIT OR Apache-2.0" description = "Fast functions for printing integer primitives to an io::Write" repository = "https://github.com/dtolnay/itoa" diff --git a/README.md b/README.md index 298983e..6a3044b 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ This crate provides fast functions for printing integer primitives to an See also [`dtoa`] for printing floating point primitives. -*Version requirement: rustc 1.31+* +*Version requirement: rustc 1.36+* [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html [`fmt::Write`]: https://doc.rust-lang.org/core/fmt/trait.Write.html diff --git a/src/lib.rs b/src/lib.rs index e1fee40..b68b937 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,6 +75,8 @@ use std::{fmt, io, mem, ptr, slice, str}; #[cfg(not(feature = "std"))] use core::{fmt, mem, ptr, slice, str}; +use self::mem::MaybeUninit; + /// Write integer to an `io::Write`. #[cfg(feature = "std")] #[inline] @@ -105,7 +107,7 @@ pub fn fmt(mut wr: W, value: V) -> fmt::Result { /// ``` #[derive(Copy)] pub struct Buffer { - bytes: [u8; I128_MAX_LEN], + bytes: [MaybeUninit; I128_MAX_LEN], } impl Default for Buffer { @@ -126,11 +128,9 @@ impl Buffer { /// This is a cheap operation; you don't need to worry about reusing buffers /// for efficiency. #[inline] - #[allow(deprecated)] pub fn new() -> Buffer { - Buffer { - bytes: unsafe { mem::uninitialized() }, - } + let bytes = [MaybeUninit::::uninit(); I128_MAX_LEN]; + Buffer { bytes } } /// Print an integer into this buffer and return a reference to its string representation @@ -174,9 +174,10 @@ macro_rules! impl_IntegerCommon { fn write(self, buf: &mut Buffer) -> &str { unsafe { debug_assert!($max_len <= I128_MAX_LEN); - let buf = mem::transmute::<&mut [u8; I128_MAX_LEN], &mut [u8; $max_len]>( - &mut buf.bytes, - ); + let buf = mem::transmute::< + &mut [MaybeUninit; I128_MAX_LEN], + &mut [MaybeUninit; $max_len], + >(&mut buf.bytes); let bytes = self.write_to(buf); str::from_utf8_unchecked(bytes) } @@ -191,10 +192,10 @@ macro_rules! impl_Integer { ($($max_len:expr => $t:ident),* as $conv_fn:ident) => {$( impl_IntegerCommon!($max_len, $t); - impl IntegerPrivate<[u8; $max_len]> for $t { + impl IntegerPrivate<[MaybeUninit; $max_len]> for $t { #[allow(unused_comparisons)] #[inline] - fn write_to(self, buf: &mut [u8; $max_len]) -> &[u8] { + fn write_to(self, buf: &mut [MaybeUninit; $max_len]) -> &[u8] { let is_nonnegative = self >= 0; let mut n = if is_nonnegative { self as $conv_fn @@ -203,7 +204,7 @@ macro_rules! impl_Integer { (!(self as $conv_fn)).wrapping_add(1) }; let mut curr = buf.len() as isize; - let buf_ptr = buf.as_mut_ptr(); + let buf_ptr = buf.as_mut_ptr() as *mut u8; let lut_ptr = DEC_DIGITS_LUT.as_ptr(); unsafe { @@ -290,10 +291,10 @@ macro_rules! impl_Integer128 { ($($max_len:expr => $t:ident),*) => {$( impl_IntegerCommon!($max_len, $t); - impl IntegerPrivate<[u8; $max_len]> for $t { + impl IntegerPrivate<[MaybeUninit; $max_len]> for $t { #[allow(unused_comparisons)] #[inline] - fn write_to(self, buf: &mut [u8; $max_len]) -> &[u8] { + fn write_to(self, buf: &mut [MaybeUninit; $max_len]) -> &[u8] { let is_nonnegative = self >= 0; let n = if is_nonnegative { self as u128 @@ -302,12 +303,12 @@ macro_rules! impl_Integer128 { (!(self as u128)).wrapping_add(1) }; let mut curr = buf.len() as isize; - let buf_ptr = buf.as_mut_ptr(); + let buf_ptr = buf.as_mut_ptr() as *mut u8; unsafe { // Divide by 10^19 which is the highest power less than 2^64. let (n, rem) = udiv128::udivmod_1e19(n); - let buf1 = buf_ptr.offset(curr - U64_MAX_LEN as isize) as *mut [u8; U64_MAX_LEN]; + let buf1 = buf_ptr.offset(curr - U64_MAX_LEN as isize) as *mut [MaybeUninit; U64_MAX_LEN]; curr -= rem.write_to(&mut *buf1).len() as isize; if n != 0 { @@ -318,7 +319,7 @@ macro_rules! impl_Integer128 { // Divide by 10^19 again. let (n, rem) = udiv128::udivmod_1e19(n); - let buf2 = buf_ptr.offset(curr - U64_MAX_LEN as isize) as *mut [u8; U64_MAX_LEN]; + let buf2 = buf_ptr.offset(curr - U64_MAX_LEN as isize) as *mut [MaybeUninit; U64_MAX_LEN]; curr -= rem.write_to(&mut *buf2).len() as isize; if n != 0 { From 3091ce69da35e9c8a8ff29702ea3310af30684e4 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 00:50:44 -0800 Subject: [PATCH 034/215] Evaluate constant u128 factor --- src/udiv128.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/udiv128.rs b/src/udiv128.rs index 8ecc496..1c96d6f 100644 --- a/src/udiv128.rs +++ b/src/udiv128.rs @@ -32,8 +32,7 @@ pub fn udivmod_1e19(n: u128) -> (u128, u64) { let quot = if n < 1 << 83 { ((n >> 19) as u64 / (d >> 19)) as u128 } else { - let factor = (8507059173023461586_u64 as u128) << 64 | 10779635027931437427 as u128; - u128_mulhi(n, factor) >> 62 + u128_mulhi(n, 156927543384667019095894735580191660403) >> 62 }; let rem = (n - quot * d as u128) as u64; From fb7a827f32913b2d75d96cd895fe266e466f6769 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 00:51:31 -0800 Subject: [PATCH 035/215] Resolve precedence clippy lint error: operator precedence can trip the unwary --> src/udiv128.rs:15:17 | 15 | let high2 = x_hi as u128 * y_lo as u128 + m_lo as u128 >> 64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `(x_hi as u128 * y_lo as u128 + m_lo as u128) >> 64` | = note: `-D clippy::precedence` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#precedence --- src/udiv128.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/udiv128.rs b/src/udiv128.rs index 1c96d6f..df53eb5 100644 --- a/src/udiv128.rs +++ b/src/udiv128.rs @@ -12,7 +12,7 @@ fn u128_mulhi(x: u128, y: u128) -> u128 { let high1 = m >> 64; let m_lo = m as u64; - let high2 = x_hi as u128 * y_lo as u128 + m_lo as u128 >> 64; + let high2 = (x_hi as u128 * y_lo as u128 + m_lo as u128) >> 64; x_hi as u128 * y_hi as u128 + high1 + high2 } From 63d5944d90c35d90244ec635a06ca46a2ceda0d1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 00:45:50 -0800 Subject: [PATCH 036/215] Suppress remaining clippy lints in udiv128 --- src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index b68b937..6f01544 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,11 +59,14 @@ #![doc(html_root_url = "https://docs.rs/itoa/0.4.8")] #![cfg_attr(not(feature = "std"), no_std)] #![allow( + clippy::cast_lossless, + clippy::cast_possible_truncation, clippy::expl_impl_clone_on_copy, clippy::missing_errors_doc, clippy::must_use_candidate, clippy::semicolon_if_nothing_returned, // https://github.com/rust-lang/rust-clippy/issues/7768 - clippy::transmute_ptr_to_ptr + clippy::transmute_ptr_to_ptr, + clippy::unreadable_literal )] #[cfg(feature = "i128")] From e970e7117f03d41103ca677c3d15e583538090c9 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 00:41:24 -0800 Subject: [PATCH 037/215] Enable 128-bit impls unconditionally --- .github/workflows/ci.yml | 13 ++++++------- Cargo.toml | 1 - README.md | 3 +-- benches/bench.rs | 2 -- src/lib.rs | 4 ---- tests/test.rs | 3 --- 6 files changed, 7 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 386b76a..c8e329f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,13 +19,12 @@ jobs: with: toolchain: ${{matrix.rust}} - run: cargo build - - run: cargo build --features i128 - - run: cargo test --features i128 - - run: cargo test --features i128 --release - - run: cargo build --no-default-features --features i128 - - run: cargo test --tests --no-default-features --features i128 - - run: cargo test --tests --no-default-features --features i128 --release - - run: cargo bench --no-run --features i128 + - run: cargo test + - run: cargo test --release + - run: cargo build --no-default-features + - run: cargo test --tests --no-default-features + - run: cargo test --tests --no-default-features --release + - run: cargo bench --no-run if: matrix.rust == 'nightly' miri: diff --git a/Cargo.toml b/Cargo.toml index 35c352f..39409e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,6 @@ edition = "2018" [features] default = ["std"] -i128 = [] std = [] [package.metadata.docs.rs] diff --git a/README.md b/README.md index 6a3044b..37c8271 100644 --- a/README.md +++ b/README.md @@ -72,8 +72,7 @@ fn fmt(writer: W, value: V) -> fmt::Result; ``` where `itoa::Integer` is implemented for i8, u8, i16, u16, i32, u32, i64, u64, -i128, u128, isize and usize. 128-bit integer support requires rustc 1.26+ and -the `i128` feature of this crate enabled. +i128, u128, isize and usize. The `write` function is only available when the `std` feature is enabled (default is enabled). The return value gives the number of bytes written. diff --git a/benches/bench.rs b/benches/bench.rs index e9e87f0..31f5499 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -76,8 +76,6 @@ benches! { bench_i16_0(0i16), bench_i16_min(::min_value()), - #[cfg(feature = "i128")] bench_u128_0(0u128), - #[cfg(feature = "i128")] bench_u128_max(::max_value()) } diff --git a/src/lib.rs b/src/lib.rs index 6f01544..92feea6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,7 +69,6 @@ clippy::unreadable_literal )] -#[cfg(feature = "i128")] mod udiv128; #[cfg(feature = "std")] @@ -289,7 +288,6 @@ impl_Integer!(I32_MAX_LEN => isize, U32_MAX_LEN => usize as u32); #[cfg(target_pointer_width = "64")] impl_Integer!(I64_MAX_LEN => isize, U64_MAX_LEN => usize as u64); -#[cfg(all(feature = "i128"))] macro_rules! impl_Integer128 { ($($max_len:expr => $t:ident),*) => {$( impl_IntegerCommon!($max_len, $t); @@ -351,9 +349,7 @@ macro_rules! impl_Integer128 { )*}; } -#[cfg(all(feature = "i128"))] const U128_MAX_LEN: usize = 39; const I128_MAX_LEN: usize = 40; -#[cfg(all(feature = "i128"))] impl_Integer128!(I128_MAX_LEN => i128, U128_MAX_LEN => u128); diff --git a/tests/test.rs b/tests/test.rs index e68fcfc..a2c7ab0 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -38,10 +38,7 @@ test! { test_i16_0(0i16, "0"), test_i16_min(::min_value(), "-32768"), - #[cfg(feature = "i128")] test_u128_0(0u128, "0"), - #[cfg(feature = "i128")] test_u128_max(::max_value(), "340282366920938463463374607431768211455"), - #[cfg(feature = "i128")] test_i128_min(::min_value(), "-170141183460469231731687303715884105728") } From 865a5517ea3c40e8ad075b2ba6b8d99c3c6686b2 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 20:39:57 -0800 Subject: [PATCH 038/215] Remove 2015-style extern crate from test and benches --- benches/bench.rs | 5 ----- tests/test.rs | 2 -- 2 files changed, 7 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index 31f5499..277eff2 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -2,7 +2,6 @@ #![allow(non_snake_case)] #![allow(clippy::cast_lossless)] -extern crate itoa; extern crate test; macro_rules! benches { @@ -18,8 +17,6 @@ macro_rules! benches { $(#[$attr])* #[bench] fn $name(b: &mut Bencher) { - use itoa; - let mut buf = Vec::with_capacity(40); b.iter(|| { @@ -36,8 +33,6 @@ macro_rules! benches { $(#[$attr])* #[bench] fn $name(b: &mut Bencher) { - use itoa; - let mut buf = String::with_capacity(40); b.iter(|| { diff --git a/tests/test.rs b/tests/test.rs index a2c7ab0..9b9e852 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,8 +1,6 @@ #![allow(non_snake_case)] #![allow(clippy::cast_lossless, clippy::unseparated_literal_suffix)] -extern crate itoa; - macro_rules! test { ( $( From 1898210ac6b2930345802ecbeee694820ce2fb8d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 20:44:52 -0800 Subject: [PATCH 039/215] Eliminate itoa::write and itoa::fmt from tests --- tests/test.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/tests/test.rs b/tests/test.rs index 9b9e852..542c7d7 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -12,15 +12,8 @@ macro_rules! test { $(#[$attr])* #[test] fn $name() { - #[cfg(feature = "std")] - { - let mut buf = [b'\0'; 40]; - let len = itoa::write(&mut buf[..], $value).unwrap(); - assert_eq!(&buf[0..len], $expected.as_bytes()); - } - - let mut s = String::new(); - itoa::fmt(&mut s, $value).unwrap(); + let mut buffer = itoa::Buffer::new(); + let s = buffer.format($value); assert_eq!(s, $expected); } )* From 259ae8a794e132954c6d9a0f5d9eaff6f0fcca18 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 20:44:57 -0800 Subject: [PATCH 040/215] Eliminate itoa::write and itoa::fmt from benches --- benches/bench.rs | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index 277eff2..f6f082b 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -11,33 +11,17 @@ macro_rules! benches { $name:ident($value:expr) ),* ) => { - mod bench_itoa_write { + mod bench_itoa_format { use test::{Bencher, black_box}; $( $(#[$attr])* #[bench] fn $name(b: &mut Bencher) { - let mut buf = Vec::with_capacity(40); + let mut buffer = itoa::Buffer::new(); b.iter(|| { - buf.clear(); - itoa::write(&mut buf, black_box($value)).unwrap() - }); - } - )* - } - - mod bench_itoa_fmt { - use test::{Bencher, black_box}; - $( - $(#[$attr])* - #[bench] - fn $name(b: &mut Bencher) { - let mut buf = String::with_capacity(40); - - b.iter(|| { - buf.clear(); - itoa::fmt(&mut buf, black_box($value)).unwrap() + let printed = buffer.format(black_box($value)); + black_box(printed); }); } )* @@ -55,7 +39,8 @@ macro_rules! benches { b.iter(|| { buf.clear(); - write!(&mut buf, "{}", black_box($value)).unwrap() + write!(&mut buf, "{}", black_box($value)).unwrap(); + black_box(&buf); }); } )* From f42787cdc2537dd093a437816e53cdbbb2176a62 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 20:45:04 -0800 Subject: [PATCH 041/215] Eliminate itoa::write and itoa::fmt from readme --- README.md | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 37c8271..99c747d 100644 --- a/README.md +++ b/README.md @@ -34,32 +34,13 @@ itoa = "0.4"
-## Examples +## Example ```rust -use std::{fmt, io}; - -fn demo_itoa_write() -> io::Result<()> { - // Write to a vector or other io::Write. - let mut buf = Vec::new(); - itoa::write(&mut buf, 128u64)?; - println!("{:?}", buf); - - // Write to a stack buffer. - let mut bytes = [0u8; 20]; - let n = itoa::write(&mut bytes[..], 128u64)?; - println!("{:?}", &bytes[..n]); - - Ok(()) -} - -fn demo_itoa_fmt() -> fmt::Result { - // Write to a string. - let mut s = String::new(); - itoa::fmt(&mut s, 128u64)?; - println!("{}", s); - - Ok(()) +fn main() { + let mut buffer = itoa::Buffer::new(); + let printed = buffer.format(128u64); + assert_eq!(printed, "128"); } ``` From 2581c8cee7ac83aa52b872a3e20843d576c8cb9d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 20:48:02 -0800 Subject: [PATCH 042/215] Eliminate itoa::write and itoa::fmt from rustdoc --- src/lib.rs | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 92feea6..48b5f5f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,32 +27,13 @@ //! //!
//! -//! # Examples +//! # Example //! -//! ```edition2018 -//! use std::{fmt, io}; -//! -//! fn demo_itoa_write() -> io::Result<()> { -//! // Write to a vector or other io::Write. -//! let mut buf = Vec::new(); -//! itoa::write(&mut buf, 128u64)?; -//! println!("{:?}", buf); -//! -//! // Write to a stack buffer. -//! let mut bytes = [0u8; 20]; -//! let n = itoa::write(&mut bytes[..], 128u64)?; -//! println!("{:?}", &bytes[..n]); -//! -//! Ok(()) -//! } -//! -//! fn demo_itoa_fmt() -> fmt::Result { -//! // Write to a string. -//! let mut s = String::new(); -//! itoa::fmt(&mut s, 128u64)?; -//! println!("{}", s); -//! -//! Ok(()) +//! ``` +//! fn main() { +//! let mut buffer = itoa::Buffer::new(); +//! let printed = buffer.format(128u64); +//! assert_eq!(printed, "128"); //! } //! ``` @@ -147,7 +128,7 @@ mod private { pub trait Sealed {} } -/// An integer that can be formatted by `itoa::write` and `itoa::fmt`. +/// An integer that can be written into an [`itoa::Buffer`][Buffer]. /// /// This trait is sealed and cannot be implemented for types outside of itoa. pub trait Integer: private::Sealed { From 6b06fb04f7481961a9ba2a57d56a0ac9a8b9838f Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 21:02:31 -0800 Subject: [PATCH 043/215] Remove attr matcher from test and bench macro Formerly needed for conditional i128 support. --- benches/bench.rs | 9 +-------- tests/test.rs | 8 +------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index f6f082b..e32965c 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -5,16 +5,10 @@ extern crate test; macro_rules! benches { - ( - $( - $(#[$attr:meta])* - $name:ident($value:expr) - ),* - ) => { + ($($name:ident($value:expr)),*) => { mod bench_itoa_format { use test::{Bencher, black_box}; $( - $(#[$attr])* #[bench] fn $name(b: &mut Bencher) { let mut buffer = itoa::Buffer::new(); @@ -30,7 +24,6 @@ macro_rules! benches { mod bench_std_fmt { use test::{Bencher, black_box}; $( - $(#[$attr])* #[bench] fn $name(b: &mut Bencher) { use std::io::Write; diff --git a/tests/test.rs b/tests/test.rs index 542c7d7..1b33cbf 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -2,14 +2,8 @@ #![allow(clippy::cast_lossless, clippy::unseparated_literal_suffix)] macro_rules! test { - ( + ($($name:ident($value:expr, $expected:expr)),*) => { $( - $(#[$attr:meta])* - $name:ident($value:expr, $expected:expr) - ),* - ) => { - $( - $(#[$attr])* #[test] fn $name() { let mut buffer = itoa::Buffer::new(); From 42cb96a97513934e695de5229e7cffe00be9afe1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 21:03:51 -0800 Subject: [PATCH 044/215] Clean up test and bench macro syntax --- benches/bench.rs | 21 +++++++++++---------- tests/test.rs | 20 ++++++++++---------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index e32965c..acd2a0c 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -5,9 +5,10 @@ extern crate test; macro_rules! benches { - ($($name:ident($value:expr)),*) => { + ($($name:ident($value:expr))*) => { mod bench_itoa_format { use test::{Bencher, black_box}; + $( #[bench] fn $name(b: &mut Bencher) { @@ -22,12 +23,12 @@ macro_rules! benches { } mod bench_std_fmt { + use std::io::Write; use test::{Bencher, black_box}; + $( #[bench] fn $name(b: &mut Bencher) { - use std::io::Write; - let mut buf = Vec::with_capacity(40); b.iter(|| { @@ -42,13 +43,13 @@ macro_rules! benches { } benches! { - bench_u64_0(0u64), - bench_u64_half(::max_value() as u64), - bench_u64_max(::max_value()), + bench_u64_0(0u64) + bench_u64_half(u32::max_value() as u64) + bench_u64_max(u64::max_value()) - bench_i16_0(0i16), - bench_i16_min(::min_value()), + bench_i16_0(0i16) + bench_i16_min(i16::min_value()) - bench_u128_0(0u128), - bench_u128_max(::max_value()) + bench_u128_0(0u128) + bench_u128_max(u128::max_value()) } diff --git a/tests/test.rs b/tests/test.rs index 1b33cbf..43250ba 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -2,7 +2,7 @@ #![allow(clippy::cast_lossless, clippy::unseparated_literal_suffix)] macro_rules! test { - ($($name:ident($value:expr, $expected:expr)),*) => { + ($($name:ident($value:expr, $expected:expr))*) => { $( #[test] fn $name() { @@ -15,15 +15,15 @@ macro_rules! test { } test! { - test_u64_0(0u64, "0"), - test_u64_half(::max_value() as u64, "4294967295"), - test_u64_max(::max_value(), "18446744073709551615"), - test_i64_min(::min_value(), "-9223372036854775808"), + test_u64_0(0u64, "0") + test_u64_half(u32::max_value() as u64, "4294967295") + test_u64_max(u64::max_value(), "18446744073709551615") + test_i64_min(i64::min_value(), "-9223372036854775808") - test_i16_0(0i16, "0"), - test_i16_min(::min_value(), "-32768"), + test_i16_0(0i16, "0") + test_i16_min(i16::min_value(), "-32768") - test_u128_0(0u128, "0"), - test_u128_max(::max_value(), "340282366920938463463374607431768211455"), - test_i128_min(::min_value(), "-170141183460469231731687303715884105728") + test_u128_0(0u128, "0") + test_u128_max(u128::max_value(), "340282366920938463463374607431768211455") + test_i128_min(i128::min_value(), "-170141183460469231731687303715884105728") } From 9cf53f10832b202fa8f515352b4b1ebd7aa05e05 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 21:07:14 -0800 Subject: [PATCH 045/215] Delete fmt function --- src/lib.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 48b5f5f..052b88e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,10 +53,10 @@ mod udiv128; #[cfg(feature = "std")] -use std::{fmt, io, mem, ptr, slice, str}; +use std::{io, mem, ptr, slice, str}; #[cfg(not(feature = "std"))] -use core::{fmt, mem, ptr, slice, str}; +use core::{mem, ptr, slice, str}; use self::mem::MaybeUninit; @@ -72,13 +72,6 @@ pub fn write(mut wr: W, value: V) -> io::Result } } -/// Write integer to an `fmt::Write`. -#[inline] -pub fn fmt(mut wr: W, value: V) -> fmt::Result { - let mut buf = Buffer::new(); - wr.write_str(buf.format(value)) -} - /// A safe API for formatting integers to text. /// /// # Example From f90632b9db8b7326f5d0afd95c09aac872633da1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 21:07:41 -0800 Subject: [PATCH 046/215] Delete io write function --- src/lib.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 052b88e..d71a9be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,25 +53,13 @@ mod udiv128; #[cfg(feature = "std")] -use std::{io, mem, ptr, slice, str}; +use std::{mem, ptr, slice, str}; #[cfg(not(feature = "std"))] use core::{mem, ptr, slice, str}; use self::mem::MaybeUninit; -/// Write integer to an `io::Write`. -#[cfg(feature = "std")] -#[inline] -pub fn write(mut wr: W, value: V) -> io::Result { - let mut buf = Buffer::new(); - let s = buf.format(value); - match wr.write_all(s.as_bytes()) { - Ok(()) => Ok(s.len()), - Err(e) => Err(e), - } -} - /// A safe API for formatting integers to text. /// /// # Example From 58e20ae3f341afe8c85b43c03956cb6fc78ef930 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 21:08:32 -0800 Subject: [PATCH 047/215] Drop std feature --- Cargo.toml | 4 ---- src/lib.rs | 11 +++-------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 39409e5..5c48d0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,9 +12,5 @@ readme = "README.md" exclude = ["performance.png"] edition = "2018" -[features] -default = ["std"] -std = [] - [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/src/lib.rs b/src/lib.rs index d71a9be..fe87354 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,7 +38,7 @@ //! ``` #![doc(html_root_url = "https://docs.rs/itoa/0.4.8")] -#![cfg_attr(not(feature = "std"), no_std)] +#![no_std] #![allow( clippy::cast_lossless, clippy::cast_possible_truncation, @@ -52,13 +52,8 @@ mod udiv128; -#[cfg(feature = "std")] -use std::{mem, ptr, slice, str}; - -#[cfg(not(feature = "std"))] -use core::{mem, ptr, slice, str}; - -use self::mem::MaybeUninit; +use core::mem::{self, MaybeUninit}; +use core::{ptr, slice, str}; /// A safe API for formatting integers to text. /// From 1d447bdf15060d182deec88b851c22557de2ce3e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 21:08:50 -0800 Subject: [PATCH 048/215] Delete outdated documentation --- README.md | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/README.md b/README.md index 99c747d..77683d2 100644 --- a/README.md +++ b/README.md @@ -44,20 +44,6 @@ fn main() { } ``` -The function signatures are: - -```rust -fn write(writer: W, value: V) -> io::Result; - -fn fmt(writer: W, value: V) -> fmt::Result; -``` - -where `itoa::Integer` is implemented for i8, u8, i16, u16, i32, u32, i64, u64, -i128, u128, isize and usize. - -The `write` function is only available when the `std` feature is enabled -(default is enabled). The return value gives the number of bytes written. -
#### License From b618d972b20459437220674bb7a7e024747f3a8d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 21:17:45 -0800 Subject: [PATCH 049/215] Adjust documentation --- Cargo.toml | 2 +- README.md | 23 ++++++++++------------- src/lib.rs | 23 ++++++++--------------- 3 files changed, 19 insertions(+), 29 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5c48d0a..87ae67c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.4.8" # remember to update html_root_url authors = ["David Tolnay "] rust-version = "1.36" license = "MIT OR Apache-2.0" -description = "Fast functions for printing integer primitives to an io::Write" +description = "Fast integer primitive to string conversion" repository = "https://github.com/dtolnay/itoa" documentation = "https://docs.rs/itoa" categories = ["value-formatting"] diff --git a/README.md b/README.md index 77683d2..fa3d93e 100644 --- a/README.md +++ b/README.md @@ -6,19 +6,16 @@ itoa [docs.rs](https://docs.rs/itoa) [build status](https://github.com/dtolnay/itoa/actions?query=branch%3Amaster) -This crate provides fast functions for printing integer primitives to an -[`io::Write`] or a [`fmt::Write`]. The implementation comes straight from -[libcore] but avoids the performance penalty of going through -[`fmt::Formatter`]. +This crate provides a fast conversion of integer primitives to decimal strings. +The implementation comes straight from [libcore] but avoids the performance +penalty of going through [`core::fmt::Formatter`]. See also [`dtoa`] for printing floating point primitives. *Version requirement: rustc 1.36+* -[`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html -[`fmt::Write`]: https://doc.rust-lang.org/core/fmt/trait.Write.html [libcore]: https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L201-L254 -[`fmt::Formatter`]: https://doc.rust-lang.org/std/fmt/struct.Formatter.html +[`core::fmt::Formatter`]: https://doc.rust-lang.org/std/fmt/struct.Formatter.html [`dtoa`]: https://github.com/dtolnay/dtoa ```toml @@ -28,12 +25,6 @@ itoa = "0.4"
-## Performance (lower is better) - -![performance](https://raw.githubusercontent.com/dtolnay/itoa/master/performance.png) - -
- ## Example ```rust @@ -46,6 +37,12 @@ fn main() {
+## Performance (lower is better) + +![performance](https://raw.githubusercontent.com/dtolnay/itoa/master/performance.png) + +
+ #### License diff --git a/src/lib.rs b/src/lib.rs index fe87354..0cb7b67 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,27 +6,16 @@ //! //!
//! -//! This crate provides fast functions for printing integer primitives to an -//! [`io::Write`] or a [`fmt::Write`]. The implementation comes straight from -//! [libcore] but avoids the performance penalty of going through -//! [`fmt::Formatter`]. +//! This crate provides a fast conversion of integer primitives to decimal +//! strings. The implementation comes straight from [libcore] but avoids the +//! performance penalty of going through [`core::fmt::Formatter`]. //! //! See also [`dtoa`] for printing floating point primitives. //! -//! [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html -//! [`fmt::Write`]: https://doc.rust-lang.org/core/fmt/trait.Write.html //! [libcore]: https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L201-L254 -//! [`fmt::Formatter`]: https://doc.rust-lang.org/std/fmt/struct.Formatter.html +//! [`core::fmt::Formatter`]: https://doc.rust-lang.org/std/fmt/struct.Formatter.html //! [`dtoa`]: https://github.com/dtolnay/dtoa //! -//!
-//! -//! # Performance (lower is better) -//! -//! ![performance](https://raw.githubusercontent.com/dtolnay/itoa/master/performance.png) -//! -//!
-//! //! # Example //! //! ``` @@ -36,6 +25,10 @@ //! assert_eq!(printed, "128"); //! } //! ``` +//! +//! # Performance (lower is better) +//! +//! ![performance](https://raw.githubusercontent.com/dtolnay/itoa/master/performance.png) #![doc(html_root_url = "https://docs.rs/itoa/0.4.8")] #![no_std] From b85761ea04cdb180188e5d2c68782cd32e9b6f1a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 21:19:33 -0800 Subject: [PATCH 050/215] Link to ryu as successor to dtoa --- README.md | 4 ++-- src/lib.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fa3d93e..510cb82 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,13 @@ This crate provides a fast conversion of integer primitives to decimal strings. The implementation comes straight from [libcore] but avoids the performance penalty of going through [`core::fmt::Formatter`]. -See also [`dtoa`] for printing floating point primitives. +See also [`ryu`] for printing floating point primitives. *Version requirement: rustc 1.36+* [libcore]: https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L201-L254 [`core::fmt::Formatter`]: https://doc.rust-lang.org/std/fmt/struct.Formatter.html -[`dtoa`]: https://github.com/dtolnay/dtoa +[`ryu`]: https://github.com/dtolnay/ryu ```toml [dependencies] diff --git a/src/lib.rs b/src/lib.rs index 0cb7b67..6bede9a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,11 +10,11 @@ //! strings. The implementation comes straight from [libcore] but avoids the //! performance penalty of going through [`core::fmt::Formatter`]. //! -//! See also [`dtoa`] for printing floating point primitives. +//! See also [`ryu`] for printing floating point primitives. //! //! [libcore]: https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L201-L254 //! [`core::fmt::Formatter`]: https://doc.rust-lang.org/std/fmt/struct.Formatter.html -//! [`dtoa`]: https://github.com/dtolnay/dtoa +//! [`ryu`]: https://github.com/dtolnay/ryu //! //! # Example //! From 8c3a8a47dd17172d10fa71e67e44785e04773eb3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 11 Dec 2021 21:36:51 -0800 Subject: [PATCH 051/215] Add latex code for performance chart --- Cargo.toml | 2 +- chart/.gitignore | 7 ++++ chart/performance.tex | 79 ++++++++++++++++++++++++++++++++++++++++++ performance.png | Bin 74625 -> 78406 bytes 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 chart/.gitignore create mode 100644 chart/performance.tex diff --git a/Cargo.toml b/Cargo.toml index 87ae67c..b68fdc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/dtolnay/itoa" documentation = "https://docs.rs/itoa" categories = ["value-formatting"] readme = "README.md" -exclude = ["performance.png"] +exclude = ["performance.png", "chart/**"] edition = "2018" [package.metadata.docs.rs] diff --git a/chart/.gitignore b/chart/.gitignore new file mode 100644 index 0000000..27572bd --- /dev/null +++ b/chart/.gitignore @@ -0,0 +1,7 @@ +*.aux +*.fdb_latexmk +*.fls +*.log +*.pdf +*.png +*.svg diff --git a/chart/performance.tex b/chart/performance.tex new file mode 100644 index 0000000..3ad1ff9 --- /dev/null +++ b/chart/performance.tex @@ -0,0 +1,79 @@ +\documentclass{standalone} +\usepackage{pgfplots} +\usepackage{sansmath} +\pgfplotsset{compat=1.16} +\definecolor{itoa}{HTML}{3366FF} +\definecolor{std}{HTML}{949494} +\definecolor{bg}{HTML}{CFCFCF} +\begin{document} +\begin{tikzpicture} +\edef\entries{ + "$0${\enspace}as{\enspace}i16", + "$0${\enspace}as{\enspace}u64", + "$-32768${\enspace}as{\enspace}i16", + "$4294967295${\enspace}as{\enspace}u64", + "$18446744073709551615${\enspace}as{\enspace}u64", +} +\begin{axis}[ + width=5in, + height=3.5in, + ybar, + ymin=0, + bar width=18pt, + enlarge x limits={abs=31pt}, + ylabel={nanos for one call to write}, + legend style={ + anchor=north west, + at={(0.025,0.975)}, + legend columns=1, + draw=none, + fill=none, + }, + legend entries={ + itoa::Buffer::new().format(value)\\ + std::write!(\&mut buf, ``\{\}'', value)\\ + }, + legend cell align=left, + xtick={-0.5,0.5,1.5,2.5,3.5,4.5}, + xticklabels={}, + xtick pos=left, + visualization depends on={y \as \rawy}, + every node near coord/.append style={ + shift={(axis direction cs:0,-\rawy/2)}, + rotate=90, + anchor=center, + font=\sansmath\sffamily, + }, + axis background/.style={fill=bg}, + tick label style={font=\sansmath\sffamily}, + every axis label={font=\sansmath\sffamily}, + legend style={font=\sansmath\sffamily}, + label style={font=\sansmath\sffamily}, +] + \addplot[ + black, + fill=itoa, + area legend, + nodes near coords={}, + ] coordinates { + (0, 1) + (1, 1) + (2, 3) + (3, 5) + (4, 10) + }; + \addplot[ + black, + fill=std, + area legend, + nodes near coords=\pgfmathsetmacro{\input}{{\entries}[\coordindex]}\input, + ] coordinates { + (0, 16) + (1, 14) + (2, 20) + (3, 18) + (4, 24) + }; +\end{axis} +\end{tikzpicture} +\end{document} diff --git a/performance.png b/performance.png index 1e23b7123d6aa8bf373789ae5340c167bfe278b0..729ee6162898589927160517325e0341084365f0 100644 GIT binary patch literal 78406 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