dragonbox_ecma-0.1.12/.cargo_vcs_info.json0000644000000001361046102023000141070ustar { "git": { "sha1": "1eb76896e620708bc8b659284f115b6cc1c3a8a6" }, "path_in_vcs": "" }dragonbox_ecma-0.1.12/.github/FUNDING.yml000064400000000000000000000000371046102023000160320ustar 00000000000000github: [magic-akari, dtolnay] dragonbox_ecma-0.1.12/.github/workflows/ci.yml000064400000000000000000000056751046102023000174050ustar 00000000000000name: CI on: push: pull_request: workflow_dispatch: schedule: [cron: "40 1 * * *"] permissions: contents: read env: RUSTFLAGS: -Dwarnings jobs: pre_ci: uses: dtolnay/.github/.github/workflows/pre_ci.yml@master test: name: Rust ${{matrix.rust}} needs: pre_ci if: needs.pre_ci.outputs.continue runs-on: ubuntu-latest strategy: fail-fast: false matrix: rust: [nightly, beta, stable, 1.86.0] timeout-minutes: 45 steps: - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{matrix.rust}} - name: Enable type layout randomization run: echo RUSTFLAGS=${RUSTFLAGS}\ -Zrandomize-layout >> $GITHUB_ENV if: matrix.rust == 'nightly' - run: cargo test --release - run: cargo test - uses: actions/upload-artifact@v6 if: matrix.rust == 'nightly' && always() with: name: Cargo.lock path: Cargo.lock continue-on-error: true msrv: name: Rust 1.79.0 needs: pre_ci if: needs.pre_ci.outputs.continue runs-on: ubuntu-latest timeout-minutes: 45 steps: - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@1.79.0 - run: cargo build doc: name: Documentation needs: pre_ci if: needs.pre_ci.outputs.continue runs-on: ubuntu-latest timeout-minutes: 45 env: RUSTDOCFLAGS: -Dwarnings steps: - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@nightly - uses: dtolnay/install@cargo-docs-rs - run: cargo docs-rs miri: name: Miri (${{matrix.name}}) needs: pre_ci if: needs.pre_ci.outputs.continue runs-on: ubuntu-latest strategy: fail-fast: false matrix: include: - name: 64-bit little endian target: x86_64-unknown-linux-gnu - name: 64-bit big endian target: powerpc64-unknown-linux-gnu - name: 32-bit little endian target: i686-unknown-linux-gnu - name: 32-bit big endian target: mips-unknown-linux-gnu timeout-minutes: 45 steps: - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@miri - run: cargo miri setup - run: cargo miri test --target ${{matrix.target}} env: MIRIFLAGS: -Zmiri-strict-provenance clippy: name: Clippy runs-on: ubuntu-latest if: github.event_name != 'pull_request' timeout-minutes: 45 steps: - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@clippy - run: cargo clippy --tests --benches -- -Dclippy::all -Dclippy::pedantic outdated: name: Outdated runs-on: ubuntu-latest if: github.event_name != 'pull_request' timeout-minutes: 45 steps: - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable - uses: dtolnay/install@cargo-outdated - run: cargo outdated --workspace --exit-code 1 dragonbox_ecma-0.1.12/.github/workflows/release.yml000064400000000000000000000010631046102023000204150ustar 00000000000000name: Publish to crates.io on: push: tags: ["v*"] # Triggers when pushing tags starting with 'v' jobs: publish: runs-on: ubuntu-latest environment: release # Optional: for enhanced security permissions: id-token: write # Required for OIDC token exchange steps: - uses: actions/checkout@v6 - uses: rust-lang/crates-io-auth-action@v1 id: auth - run: cargo publish env: CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} dragonbox_ecma-0.1.12/.gitignore000064400000000000000000000000251046102023000146420ustar 00000000000000/Cargo.lock /target/ dragonbox_ecma-0.1.12/Cargo.lock0000644000000451331046102023000120700ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] [[package]] name = "alloca" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4" dependencies = [ "cc", ] [[package]] name = "anes" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstyle" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anyhow" version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "cast" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" version = "1.2.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" dependencies = [ "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chacha20" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" dependencies = [ "cfg-if", "cpufeatures", "rand_core", ] [[package]] name = "ciborium" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", "serde", ] [[package]] name = "ciborium-io" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", "half", ] [[package]] name = "clap" version = "4.5.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6899ea499e3fb9305a65d5ebf6e3d2248c5fab291f300ad0a704fbe142eae31a" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" version = "4.5.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b12c8b680195a62a8364d16b8447b01b6c2c8f9aaf68bee653be34d4245e238" dependencies = [ "anstyle", "clap_lex", ] [[package]] name = "clap_lex" version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" [[package]] name = "cpufeatures" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" dependencies = [ "libc", ] [[package]] name = "criterion" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "950046b2aa2492f9a536f5f4f9a3de7b9e2476e575e05bd6c333371add4d98f3" dependencies = [ "alloca", "anes", "cast", "ciborium", "clap", "criterion-plot", "itertools", "num-traits", "oorandom", "page_size", "regex", "serde", "serde_json", "tinytemplate", "walkdir", ] [[package]] name = "criterion-plot" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29ea" dependencies = [ "cast", "itertools", ] [[package]] name = "crunchy" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "dragonbox_ecma" version = "0.1.12" dependencies = [ "criterion", "rand", ] [[package]] name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "find-msvc-tools" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "foldhash" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "getrandom" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" dependencies = [ "cfg-if", "libc", "r-efi", "rand_core", "wasip2", "wasip3", ] [[package]] name = "half" version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", "zerocopy", ] [[package]] name = "hashbrown" version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "foldhash", ] [[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "id-arena" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" [[package]] name = "indexmap" version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown 0.16.1", "serde", "serde_core", ] [[package]] name = "itertools" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "leb128fmt" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" version = "0.2.181" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5" [[package]] name = "log" version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "memchr" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "oorandom" version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "page_size" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" dependencies = [ "libc", "winapi", ] [[package]] name = "prettyplease" version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", "syn", ] [[package]] name = "proc-macro2" version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" dependencies = [ "chacha20", "getrandom", "rand_core", ] [[package]] name = "rand_core" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" [[package]] name = "regex" version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] [[package]] name = "semver" version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", ] [[package]] name = "serde_core" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", "serde", "serde_core", "zmij", ] [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "syn" version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "tinytemplate" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ "serde", "serde_json", ] [[package]] name = "unicode-ident" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" [[package]] name = "unicode-xid" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasip2" version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ "wit-bindgen", ] [[package]] name = "wasip3" version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-encoder" version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" dependencies = [ "leb128fmt", "wasmparser", ] [[package]] name = "wasm-metadata" version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ "anyhow", "indexmap", "wasm-encoder", "wasmparser", ] [[package]] name = "wasmparser" version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ "bitflags", "hashbrown 0.15.5", "indexmap", "semver", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ "windows-sys", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ "windows-link", ] [[package]] name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" dependencies = [ "wit-bindgen-rust-macro", ] [[package]] name = "wit-bindgen-core" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" dependencies = [ "anyhow", "heck", "wit-parser", ] [[package]] name = "wit-bindgen-rust" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ "anyhow", "heck", "indexmap", "prettyplease", "syn", "wasm-metadata", "wit-bindgen-core", "wit-component", ] [[package]] name = "wit-bindgen-rust-macro" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" dependencies = [ "anyhow", "prettyplease", "proc-macro2", "quote", "syn", "wit-bindgen-core", "wit-bindgen-rust", ] [[package]] name = "wit-component" version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", "bitflags", "indexmap", "log", "serde", "serde_derive", "serde_json", "wasm-encoder", "wasm-metadata", "wasmparser", "wit-parser", ] [[package]] name = "wit-parser" version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ "anyhow", "id-arena", "indexmap", "log", "semver", "serde", "serde_derive", "serde_json", "unicode-xid", "wasmparser", ] [[package]] name = "zerocopy" version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "zmij" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4de98dfa5d5b7fef4ee834d0073d560c9ca7b6c46a71d058c48db7960f8cfaf7" dragonbox_ecma-0.1.12/Cargo.toml0000644000000037701046102023000121140ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.79" name = "dragonbox_ecma" version = "0.1.12" authors = [ "David Tolnay ", "magic-akari ", ] build = "build.rs" exclude = [ "performance.png", "chart/**", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Fast floating point to string conversion conforming to ECMAScript specification" documentation = "https://docs.rs/dragonbox_ecma" readme = "README.md" keywords = ["float"] categories = [ "value-formatting", "no-std", "no-std::no-alloc", ] license = "Apache-2.0 WITH LLVM-exception OR BSL-1.0" repository = "https://github.com/magic-akari/dragonbox" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] rustdoc-args = [ "--generate-link-to-definition", "--generate-macro-expansion", "--extern-html-root-url=core=https://doc.rust-lang.org", "--extern-html-root-url=alloc=https://doc.rust-lang.org", "--extern-html-root-url=std=https://doc.rust-lang.org", ] [features] default = ["ecma"] ecma = [] original_dragonbox = [] [lib] name = "dragonbox_ecma" path = "src/lib.rs" [[test]] name = "binary64_test" path = "tests/binary64_test.rs" required-features = ["original_dragonbox"] [[test]] name = "binary64_test_ecma" path = "tests/binary64_test_ecma.rs" [[bench]] name = "bench" path = "benches/bench.rs" harness = false [dev-dependencies.rand] version = "0.10" [target."cfg(not(miri))".dev-dependencies.criterion] version = "0.8" default-features = false dragonbox_ecma-0.1.12/Cargo.toml.orig000064400000000000000000000025221046102023000155450ustar 00000000000000[package] name = "dragonbox_ecma" version = "0.1.12" authors = [ "David Tolnay ", "magic-akari ", ] categories = ["value-formatting", "no-std", "no-std::no-alloc"] description = "Fast floating point to string conversion conforming to ECMAScript specification" documentation = "https://docs.rs/dragonbox_ecma" edition = "2021" exclude = ["performance.png", "chart/**"] keywords = ["float"] license = "Apache-2.0 WITH LLVM-exception OR BSL-1.0" repository = "https://github.com/magic-akari/dragonbox" rust-version = "1.79" [dev-dependencies] rand = "0.10" [features] default = ["ecma"] ecma = [] original_dragonbox = [] [target.'cfg(not(miri))'.dev-dependencies] criterion = { version = "0.8", default-features = false } [[bench]] name = "bench" harness = false [[test]] name = "binary64_test" path = "tests/binary64_test.rs" default-features = false required-features = ["original_dragonbox"] [[test]] name = "binary64_test_ecma" path = "tests/binary64_test_ecma.rs" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] rustdoc-args = [ "--generate-link-to-definition", "--generate-macro-expansion", "--extern-html-root-url=core=https://doc.rust-lang.org", "--extern-html-root-url=alloc=https://doc.rust-lang.org", "--extern-html-root-url=std=https://doc.rust-lang.org", ] dragonbox_ecma-0.1.12/LICENSE-Apache2-LLVM000064400000000000000000000254741046102023000157070ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS --- LLVM Exceptions to the Apache 2.0 License ---- As an exception, if, as a result of your compiling your source code, portions of this Software are embedded into an Object form of such source code, you may redistribute such embedded portions in such Object form without complying with the conditions of Sections 4(a), 4(b) and 4(d) of the License. In addition, if you combine or link compiled forms of this Software with software that is licensed under the GPLv2 ("Combined Software") and if a court of competent jurisdiction determines that the patent provision (Section 3), the indemnity provision (Section 9) or other Section of the License conflicts with the conditions of the GPLv2, you may retroactively and prospectively choose to deem waived or otherwise exclude such Section(s) of the License, but only in their entirety and only with respect to the Combined Software. dragonbox_ecma-0.1.12/LICENSE-Boost000064400000000000000000000024721046102023000147530ustar 00000000000000Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. dragonbox_ecma-0.1.12/README.md000064400000000000000000000040511046102023000141340ustar 00000000000000# Dragonbox ECMA [github](https://github.com/magic-akari/dragonbox) [crates.io](https://crates.io/crates/dragonbox_ecma) [docs.rs](https://docs.rs/dragonbox_ecma) [build status](https://github.com/magic-akari/dragonbox/actions?query=branch%3Aecma) Dragonbox ECMA is a fork of the [Dragonbox][dragonbox-crate] crate adjusted to comply with the ECMAScript [number-to-string][number-to-string] algorithm. [dragonbox-crate]: https://crates.io/crates/dragonbox [number-to-string]: https://tc39.es/ecma262/#sec-numeric-types-number-tostring --- This crate contains a basic port of to Rust for benchmarking purposes. Please see the upstream repo for an explanation of the approach and comparison to the Ryū algorithm.
## Example ```rust fn main() { let mut buffer = dragonbox_ecma::Buffer::new(); let printed = buffer.format(1.234); assert_eq!(printed, "1.234"); } ```
## Performance (lower is better) ![performance](https://raw.githubusercontent.com/dtolnay/dragonbox/master/performance.png)
#### License Licensed under either of Apache License, Version 2.0 with LLVM Exceptions or Boost Software License Version 1.0 at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. dragonbox_ecma-0.1.12/benches/bench.rs000064400000000000000000000021241046102023000157100ustar 00000000000000use criterion::{criterion_group, criterion_main, Criterion}; use std::f64; use std::hint; use std::io::Write; use dragonbox_ecma as dragonbox; fn do_bench(c: &mut Criterion, group_name: &str, float: f64) { let mut group = c.benchmark_group(group_name); group.bench_function("dragonbox", |b| { let mut buf = dragonbox::Buffer::new(); b.iter(move || { let float = hint::black_box(float); let formatted = buf.format_finite(float); hint::black_box(formatted); }); }); group.bench_function("std::fmt", |b| { let mut buf = Vec::with_capacity(20); b.iter(|| { buf.clear(); let float = hint::black_box(float); write!(&mut buf, "{float}").unwrap(); hint::black_box(buf.as_slice()); }); }); group.finish(); } fn bench(c: &mut Criterion) { do_bench(c, "f64[0]", 0f64); do_bench(c, "f64[short]", 0.1234f64); do_bench(c, "f64[e]", f64::consts::E); do_bench(c, "f64[max]", f64::MAX); } criterion_group!(benches, bench); criterion_main!(benches); dragonbox_ecma-0.1.12/build.rs000064400000000000000000000020141046102023000143170ustar 00000000000000use std::env; use std::ffi::OsString; use std::process::{self, Command}; use std::str; fn main() { println!("cargo:rerun-if-changed=build.rs"); let rustc = rustc_minor_version().unwrap_or(u32::MAX); if rustc >= 80 { println!("cargo:rustc-check-cfg=cfg(dragonbox_dead_code_workaround)"); } if rustc < 89 { // https://github.com/rust-lang/rust/pull/142208 println!("cargo:rustc-cfg=dragonbox_dead_code_workaround"); } } fn rustc_minor_version() -> Option { let rustc = cargo_env_var("RUSTC"); let output = Command::new(rustc).arg("--version").output().ok()?; let version = str::from_utf8(&output.stdout).ok()?; let mut pieces = version.split('.'); if pieces.next() != Some("rustc 1") { return None; } pieces.next()?.parse().ok() } fn cargo_env_var(key: &str) -> OsString { env::var_os(key).unwrap_or_else(|| { eprintln!("Environment variable ${key} is not set during execution of build script"); process::exit(1); }) } dragonbox_ecma-0.1.12/src/buffer.rs000064400000000000000000000071111046102023000152630ustar 00000000000000use crate::to_chars; use crate::{Buffer, Float}; use core::mem::MaybeUninit; use core::slice; use core::str; impl Buffer { /// This is a cheap operation; you don't need to worry about reusing buffers /// for efficiency. #[inline] pub fn new() -> Self { let bytes = [MaybeUninit::::uninit(); to_chars::MAX_OUTPUT_STRING_LENGTH]; Buffer { bytes } } /// Print a floating point number into this buffer and return a reference to /// its string representation within the buffer. /// /// # Special cases /// /// This function formats NaN as the string "NaN", positive infinity as /// "inf", and negative infinity as "-inf" to match std::fmt. /// /// If your input is known to be finite, you may get better performance by /// calling the `format_finite` method instead of `format` to avoid the /// checks for special cases. pub fn format(&mut self, f: F) -> &str { if f.is_nonfinite() { f.format_nonfinite() } else { self.format_finite(f) } } /// Print a floating point number into this buffer and return a reference to /// its string representation within the buffer. /// /// # Special cases /// /// This function **does not** check for NaN or infinity. If the input /// number is not a finite float, the printed representation will be some /// correctly formatted but unspecified numerical value. /// /// Please check [`is_finite`] yourself before calling this function, or /// check [`is_nan`] and [`is_infinite`] and handle those cases yourself. /// /// [`is_finite`]: f64::is_finite /// [`is_nan`]: f64::is_nan /// [`is_infinite`]: f64::is_infinite #[inline] pub fn format_finite(&mut self, f: F) -> &str { unsafe { let n = f.write_to_dragonbox_buffer(self.bytes.as_mut_ptr().cast::()); debug_assert!(n <= self.bytes.len()); let slice = slice::from_raw_parts(self.bytes.as_ptr().cast::(), n); str::from_utf8_unchecked(slice) } } } impl Copy for Buffer {} #[allow(clippy::non_canonical_clone_impl)] impl Clone for Buffer { #[inline] fn clone(&self) -> Self { Buffer::new() } } impl Default for Buffer { #[inline] fn default() -> Self { Buffer::new() } } impl Float for f64 {} const NAN: &str = "NaN"; #[cfg(not(feature = "ecma"))] const INFINITY: &str = "inf"; #[cfg(feature = "ecma")] const INFINITY: &str = "Infinity"; #[cfg(not(feature = "ecma"))] const NEG_INFINITY: &str = "-inf"; #[cfg(feature = "ecma")] const NEG_INFINITY: &str = "-Infinity"; pub trait Sealed: Copy { fn is_nonfinite(self) -> bool; fn format_nonfinite(self) -> &'static str; unsafe fn write_to_dragonbox_buffer(self, result: *mut u8) -> usize; } impl Sealed for f64 { #[inline] fn is_nonfinite(self) -> bool { const EXP_MASK: u64 = 0x7ff0000000000000; let bits = self.to_bits(); bits & EXP_MASK == EXP_MASK } #[cold] fn format_nonfinite(self) -> &'static str { const MANTISSA_MASK: u64 = 0x000fffffffffffff; const SIGN_MASK: u64 = 0x8000000000000000; let bits = self.to_bits(); if bits & MANTISSA_MASK != 0 { NAN } else if bits & SIGN_MASK != 0 { NEG_INFINITY } else { INFINITY } } #[inline] unsafe fn write_to_dragonbox_buffer(self, buffer: *mut u8) -> usize { let end = crate::to_chars::to_chars(self, buffer); end.offset_from(buffer) as usize } } dragonbox_ecma-0.1.12/src/cache.rs000064400000000000000000000642171046102023000150670ustar 00000000000000// Translated from C++ to Rust. The original C++ code can be found at // https://github.com/jk-jeon/dragonbox and carries the following license: // // Copyright 2020-2025 Junekey Jeon // // The contents of this file may be used under the terms of // the Apache License v2.0 with LLVM Exceptions. // // (See accompanying file LICENSE-Apache or copy at // https://llvm.org/foundation/relicensing/LICENSE.txt) // // Alternatively, the contents of this file may be used under the terms of // the Boost Software License, Version 1.0. // (See accompanying file LICENSE-Boost or copy at // https://www.boost.org/LICENSE_1_0.txt) // // Unless required by applicable law or agreed to in writing, this software // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. pub(crate) type EntryType = u128; pub(crate) const MIN_K: i32 = -292; pub(crate) const MAX_K: i32 = 326; pub(crate) unsafe fn get(k: i32) -> EntryType { debug_assert!((MIN_K..=MAX_K).contains(&k)); *CACHE.get_unchecked((k - MIN_K) as usize) } pub(crate) trait EntryTypeExt { fn high(&self) -> u64; fn low(&self) -> u64; } impl EntryTypeExt for EntryType { fn high(&self) -> u64 { (self >> 64) as u64 } fn low(&self) -> u64 { *self as u64 } } static CACHE: [EntryType; (MAX_K - MIN_K + 1) as usize] = [ 0xff77b1fcbebcdc4f_25e8e89c13bb0f7b, 0x9faacf3df73609b1_77b191618c54e9ad, 0xc795830d75038c1d_d59df5b9ef6a2418, 0xf97ae3d0d2446f25_4b0573286b44ad1e, 0x9becce62836ac577_4ee367f9430aec33, 0xc2e801fb244576d5_229c41f793cda740, 0xf3a20279ed56d48a_6b43527578c11110, 0x9845418c345644d6_830a13896b78aaaa, 0xbe5691ef416bd60c_23cc986bc656d554, 0xedec366b11c6cb8f_2cbfbe86b7ec8aa9, 0x94b3a202eb1c3f39_7bf7d71432f3d6aa, 0xb9e08a83a5e34f07_daf5ccd93fb0cc54, 0xe858ad248f5c22c9_d1b3400f8f9cff69, 0x91376c36d99995be_23100809b9c21fa2, 0xb58547448ffffb2d_abd40a0c2832a78b, 0xe2e69915b3fff9f9_16c90c8f323f516d, 0x8dd01fad907ffc3b_ae3da7d97f6792e4, 0xb1442798f49ffb4a_99cd11cfdf41779d, 0xdd95317f31c7fa1d_40405643d711d584, 0x8a7d3eef7f1cfc52_482835ea666b2573, 0xad1c8eab5ee43b66_da3243650005eed0, 0xd863b256369d4a40_90bed43e40076a83, 0x873e4f75e2224e68_5a7744a6e804a292, 0xa90de3535aaae202_711515d0a205cb37, 0xd3515c2831559a83_0d5a5b44ca873e04, 0x8412d9991ed58091_e858790afe9486c3, 0xa5178fff668ae0b6_626e974dbe39a873, 0xce5d73ff402d98e3_fb0a3d212dc81290, 0x80fa687f881c7f8e_7ce66634bc9d0b9a, 0xa139029f6a239f72_1c1fffc1ebc44e81, 0xc987434744ac874e_a327ffb266b56221, 0xfbe9141915d7a922_4bf1ff9f0062baa9, 0x9d71ac8fada6c9b5_6f773fc3603db4aa, 0xc4ce17b399107c22_cb550fb4384d21d4, 0xf6019da07f549b2b_7e2a53a146606a49, 0x99c102844f94e0fb_2eda7444cbfc426e, 0xc0314325637a1939_fa911155fefb5309, 0xf03d93eebc589f88_793555ab7eba27cb, 0x96267c7535b763b5_4bc1558b2f3458df, 0xbbb01b9283253ca2_9eb1aaedfb016f17, 0xea9c227723ee8bcb_465e15a979c1cadd, 0x92a1958a7675175f_0bfacd89ec191eca, 0xb749faed14125d36_cef980ec671f667c, 0xe51c79a85916f484_82b7e12780e7401b, 0x8f31cc0937ae58d2_d1b2ecb8b0908811, 0xb2fe3f0b8599ef07_861fa7e6dcb4aa16, 0xdfbdcece67006ac9_67a791e093e1d49b, 0x8bd6a141006042bd_e0c8bb2c5c6d24e1, 0xaecc49914078536d_58fae9f773886e19, 0xda7f5bf590966848_af39a475506a899f, 0x888f99797a5e012d_6d8406c952429604, 0xaab37fd7d8f58178_c8e5087ba6d33b84, 0xd5605fcdcf32e1d6_fb1e4a9a90880a65, 0x855c3be0a17fcd26_5cf2eea09a550680, 0xa6b34ad8c9dfc06f_f42faa48c0ea481f, 0xd0601d8efc57b08b_f13b94daf124da27, 0x823c12795db6ce57_76c53d08d6b70859, 0xa2cb1717b52481ed_54768c4b0c64ca6f, 0xcb7ddcdda26da268_a9942f5dcf7dfd0a, 0xfe5d54150b090b02_d3f93b35435d7c4d, 0x9efa548d26e5a6e1_c47bc5014a1a6db0, 0xc6b8e9b0709f109a_359ab6419ca1091c, 0xf867241c8cc6d4c0_c30163d203c94b63, 0x9b407691d7fc44f8_79e0de63425dcf1e, 0xc21094364dfb5636_985915fc12f542e5, 0xf294b943e17a2bc4_3e6f5b7b17b2939e, 0x979cf3ca6cec5b5a_a705992ceecf9c43, 0xbd8430bd08277231_50c6ff782a838354, 0xece53cec4a314ebd_a4f8bf5635246429, 0x940f4613ae5ed136_871b7795e136be9a, 0xb913179899f68584_28e2557b59846e40, 0xe757dd7ec07426e5_331aeada2fe589d0, 0x9096ea6f3848984f_3ff0d2c85def7622, 0xb4bca50b065abe63_0fed077a756b53aa, 0xe1ebce4dc7f16dfb_d3e8495912c62895, 0x8d3360f09cf6e4bd_64712dd7abbbd95d, 0xb080392cc4349dec_bd8d794d96aacfb4, 0xdca04777f541c567_ecf0d7a0fc5583a1, 0x89e42caaf9491b60_f41686c49db57245, 0xac5d37d5b79b6239_311c2875c522ced6, 0xd77485cb25823ac7_7d633293366b828c, 0x86a8d39ef77164bc_ae5dff9c02033198, 0xa8530886b54dbdeb_d9f57f830283fdfd, 0xd267caa862a12d66_d072df63c324fd7c, 0x8380dea93da4bc60_4247cb9e59f71e6e, 0xa46116538d0deb78_52d9be85f074e609, 0xcd795be870516656_67902e276c921f8c, 0x806bd9714632dff6_00ba1cd8a3db53b7, 0xa086cfcd97bf97f3_80e8a40eccd228a5, 0xc8a883c0fdaf7df0_6122cd128006b2ce, 0xfad2a4b13d1b5d6c_796b805720085f82, 0x9cc3a6eec6311a63_cbe3303674053bb1, 0xc3f490aa77bd60fc_bedbfc4411068a9d, 0xf4f1b4d515acb93b_ee92fb5515482d45, 0x991711052d8bf3c5_751bdd152d4d1c4b, 0xbf5cd54678eef0b6_d262d45a78a0635e, 0xef340a98172aace4_86fb897116c87c35, 0x9580869f0e7aac0e_d45d35e6ae3d4da1, 0xbae0a846d2195712_8974836059cca10a, 0xe998d258869facd7_2bd1a438703fc94c, 0x91ff83775423cc06_7b6306a34627ddd0, 0xb67f6455292cbf08_1a3bc84c17b1d543, 0xe41f3d6a7377eeca_20caba5f1d9e4a94, 0x8e938662882af53e_547eb47b7282ee9d, 0xb23867fb2a35b28d_e99e619a4f23aa44, 0xdec681f9f4c31f31_6405fa00e2ec94d5, 0x8b3c113c38f9f37e_de83bc408dd3dd05, 0xae0b158b4738705e_9624ab50b148d446, 0xd98ddaee19068c76_3badd624dd9b0958, 0x87f8a8d4cfa417c9_e54ca5d70a80e5d7, 0xa9f6d30a038d1dbc_5e9fcf4ccd211f4d, 0xd47487cc8470652b_7647c32000696720, 0x84c8d4dfd2c63f3b_29ecd9f40041e074, 0xa5fb0a17c777cf09_f468107100525891, 0xcf79cc9db955c2cc_7182148d4066eeb5, 0x81ac1fe293d599bf_c6f14cd848405531, 0xa21727db38cb002f_b8ada00e5a506a7d, 0xca9cf1d206fdc03b_a6d90811f0e4851d, 0xfd442e4688bd304a_908f4a166d1da664, 0x9e4a9cec15763e2e_9a598e4e043287ff, 0xc5dd44271ad3cdba_40eff1e1853f29fe, 0xf7549530e188c128_d12bee59e68ef47d, 0x9a94dd3e8cf578b9_82bb74f8301958cf, 0xc13a148e3032d6e7_e36a52363c1faf02, 0xf18899b1bc3f8ca1_dc44e6c3cb279ac2, 0x96f5600f15a7b7e5_29ab103a5ef8c0ba, 0xbcb2b812db11a5de_7415d448f6b6f0e8, 0xebdf661791d60f56_111b495b3464ad22, 0x936b9fcebb25c995_cab10dd900beec35, 0xb84687c269ef3bfb_3d5d514f40eea743, 0xe65829b3046b0afa_0cb4a5a3112a5113, 0x8ff71a0fe2c2e6dc_47f0e785eaba72ac, 0xb3f4e093db73a093_59ed216765690f57, 0xe0f218b8d25088b8_306869c13ec3532d, 0x8c974f7383725573_1e414218c73a13fc, 0xafbd2350644eeacf_e5d1929ef90898fb, 0xdbac6c247d62a583_df45f746b74abf3a, 0x894bc396ce5da772_6b8bba8c328eb784, 0xab9eb47c81f5114f_066ea92f3f326565, 0xd686619ba27255a2_c80a537b0efefebe, 0x8613fd0145877585_bd06742ce95f5f37, 0xa798fc4196e952e7_2c48113823b73705, 0xd17f3b51fca3a7a0_f75a15862ca504c6, 0x82ef85133de648c4_9a984d73dbe722fc, 0xa3ab66580d5fdaf5_c13e60d0d2e0ebbb, 0xcc963fee10b7d1b3_318df905079926a9, 0xffbbcfe994e5c61f_fdf17746497f7053, 0x9fd561f1fd0f9bd3_feb6ea8bedefa634, 0xc7caba6e7c5382c8_fe64a52ee96b8fc1, 0xf9bd690a1b68637b_3dfdce7aa3c673b1, 0x9c1661a651213e2d_06bea10ca65c084f, 0xc31bfa0fe5698db8_486e494fcff30a63, 0xf3e2f893dec3f126_5a89dba3c3efccfb, 0x986ddb5c6b3a76b7_f89629465a75e01d, 0xbe89523386091465_f6bbb397f1135824, 0xee2ba6c0678b597f_746aa07ded582e2d, 0x94db483840b717ef_a8c2a44eb4571cdd, 0xba121a4650e4ddeb_92f34d62616ce414, 0xe896a0d7e51e1566_77b020baf9c81d18, 0x915e2486ef32cd60_0ace1474dc1d122f, 0xb5b5ada8aaff80b8_0d819992132456bb, 0xe3231912d5bf60e6_10e1fff697ed6c6a, 0x8df5efabc5979c8f_ca8d3ffa1ef463c2, 0xb1736b96b6fd83b3_bd308ff8a6b17cb3, 0xddd0467c64bce4a0_ac7cb3f6d05ddbdf, 0x8aa22c0dbef60ee4_6bcdf07a423aa96c, 0xad4ab7112eb3929d_86c16c98d2c953c7, 0xd89d64d57a607744_e871c7bf077ba8b8, 0x87625f056c7c4a8b_11471cd764ad4973, 0xa93af6c6c79b5d2d_d598e40d3dd89bd0, 0xd389b47879823479_4aff1d108d4ec2c4, 0x843610cb4bf160cb_cedf722a585139bb, 0xa54394fe1eedb8fe_c2974eb4ee658829, 0xce947a3da6a9273e_733d226229feea33, 0x811ccc668829b887_0806357d5a3f5260, 0xa163ff802a3426a8_ca07c2dcb0cf26f8, 0xc9bcff6034c13052_fc89b393dd02f0b6, 0xfc2c3f3841f17c67_bbac2078d443ace3, 0x9d9ba7832936edc0_d54b944b84aa4c0e, 0xc5029163f384a931_0a9e795e65d4df12, 0xf64335bcf065d37d_4d4617b5ff4a16d6, 0x99ea0196163fa42e_504bced1bf8e4e46, 0xc06481fb9bcf8d39_e45ec2862f71e1d7, 0xf07da27a82c37088_5d767327bb4e5a4d, 0x964e858c91ba2655_3a6a07f8d510f870, 0xbbe226efb628afea_890489f70a55368c, 0xeadab0aba3b2dbe5_2b45ac74ccea842f, 0x92c8ae6b464fc96f_3b0b8bc90012929e, 0xb77ada0617e3bbcb_09ce6ebb40173745, 0xe55990879ddcaabd_cc420a6a101d0516, 0x8f57fa54c2a9eab6_9fa946824a12232e, 0xb32df8e9f3546564_47939822dc96abfa, 0xdff9772470297ebd_59787e2b93bc56f8, 0x8bfbea76c619ef36_57eb4edb3c55b65b, 0xaefae51477a06b03_ede622920b6b23f2, 0xdab99e59958885c4_e95fab368e45ecee, 0x88b402f7fd75539b_11dbcb0218ebb415, 0xaae103b5fcd2a881_d652bdc29f26a11a, 0xd59944a37c0752a2_4be76d3346f04960, 0x857fcae62d8493a5_6f70a4400c562ddc, 0xa6dfbd9fb8e5b88e_cb4ccd500f6bb953, 0xd097ad07a71f26b2_7e2000a41346a7a8, 0x825ecc24c873782f_8ed400668c0c28c9, 0xa2f67f2dfa90563b_728900802f0f32fb, 0xcbb41ef979346bca_4f2b40a03ad2ffba, 0xfea126b7d78186bc_e2f610c84987bfa9, 0x9f24b832e6b0f436_0dd9ca7d2df4d7ca, 0xc6ede63fa05d3143_91503d1c79720dbc, 0xf8a95fcf88747d94_75a44c6397ce912b, 0x9b69dbe1b548ce7c_c986afbe3ee11abb, 0xc24452da229b021b_fbe85badce996169, 0xf2d56790ab41c2a2_fae27299423fb9c4, 0x97c560ba6b0919a5_dccd879fc967d41b, 0xbdb6b8e905cb600f_5400e987bbc1c921, 0xed246723473e3813_290123e9aab23b69, 0x9436c0760c86e30b_f9a0b6720aaf6522, 0xb94470938fa89bce_f808e40e8d5b3e6a, 0xe7958cb87392c2c2_b60b1d1230b20e05, 0x90bd77f3483bb9b9_b1c6f22b5e6f48c3, 0xb4ecd5f01a4aa828_1e38aeb6360b1af4, 0xe2280b6c20dd5232_25c6da63c38de1b1, 0x8d590723948a535f_579c487e5a38ad0f, 0xb0af48ec79ace837_2d835a9df0c6d852, 0xdcdb1b2798182244_f8e431456cf88e66, 0x8a08f0f8bf0f156b_1b8e9ecb641b5900, 0xac8b2d36eed2dac5_e272467e3d222f40, 0xd7adf884aa879177_5b0ed81dcc6abb10, 0x86ccbb52ea94baea_98e947129fc2b4ea, 0xa87fea27a539e9a5_3f2398d747b36225, 0xd29fe4b18e88640e_8eec7f0d19a03aae, 0x83a3eeeef9153e89_1953cf68300424ad, 0xa48ceaaab75a8e2b_5fa8c3423c052dd8, 0xcdb02555653131b6_3792f412cb06794e, 0x808e17555f3ebf11_e2bbd88bbee40bd1, 0xa0b19d2ab70e6ed6_5b6aceaeae9d0ec5, 0xc8de047564d20a8b_f245825a5a445276, 0xfb158592be068d2e_eed6e2f0f0d56713, 0x9ced737bb6c4183d_55464dd69685606c, 0xc428d05aa4751e4c_aa97e14c3c26b887, 0xf53304714d9265df_d53dd99f4b3066a9, 0x993fe2c6d07b7fab_e546a8038efe402a, 0xbf8fdb78849a5f96_de98520472bdd034, 0xef73d256a5c0f77c_963e66858f6d4441, 0x95a8637627989aad_dde7001379a44aa9, 0xbb127c53b17ec159_5560c018580d5d53, 0xe9d71b689dde71af_aab8f01e6e10b4a7, 0x9226712162ab070d_cab3961304ca70e9, 0xb6b00d69bb55c8d1_3d607b97c5fd0d23, 0xe45c10c42a2b3b05_8cb89a7db77c506b, 0x8eb98a7a9a5b04e3_77f3608e92adb243, 0xb267ed1940f1c61c_55f038b237591ed4, 0xdf01e85f912e37a3_6b6c46dec52f6689, 0x8b61313bbabce2c6_2323ac4b3b3da016, 0xae397d8aa96c1b77_abec975e0a0d081b, 0xd9c7dced53c72255_96e7bd358c904a22, 0x881cea14545c7575_7e50d64177da2e55, 0xaa242499697392d2_dde50bd1d5d0b9ea, 0xd4ad2dbfc3d07787_955e4ec64b44e865, 0x84ec3c97da624ab4_bd5af13bef0b113f, 0xa6274bbdd0fadd61_ecb1ad8aeacdd58f, 0xcfb11ead453994ba_67de18eda5814af3, 0x81ceb32c4b43fcf4_80eacf948770ced8, 0xa2425ff75e14fc31_a1258379a94d028e, 0xcad2f7f5359a3b3e_096ee45813a04331, 0xfd87b5f28300ca0d_8bca9d6e188853fd, 0x9e74d1b791e07e48_775ea264cf55347e, 0xc612062576589dda_95364afe032a819e, 0xf79687aed3eec551_3a83ddbd83f52205, 0x9abe14cd44753b52_c4926a9672793543, 0xc16d9a0095928a27_75b7053c0f178294, 0xf1c90080baf72cb1_5324c68b12dd6339, 0x971da05074da7bee_d3f6fc16ebca5e04, 0xbce5086492111aea_88f4bb1ca6bcf585, 0xec1e4a7db69561a5_2b31e9e3d06c32e6, 0x9392ee8e921d5d07_3aff322e62439fd0, 0xb877aa3236a4b449_09befeb9fad487c3, 0xe69594bec44de15b_4c2ebe687989a9b4, 0x901d7cf73ab0acd9_0f9d37014bf60a11, 0xb424dc35095cd80f_538484c19ef38c95, 0xe12e13424bb40e13_2865a5f206b06fba, 0x8cbccc096f5088cb_f93f87b7442e45d4, 0xafebff0bcb24aafe_f78f69a51539d749, 0xdbe6fecebdedd5be_b573440e5a884d1c, 0x89705f4136b4a597_31680a88f8953031, 0xabcc77118461cefc_fdc20d2b36ba7c3e, 0xd6bf94d5e57a42bc_3d32907604691b4d, 0x8637bd05af6c69b5_a63f9a49c2c1b110, 0xa7c5ac471b478423_0fcf80dc33721d54, 0xd1b71758e219652b_d3c36113404ea4a9, 0x83126e978d4fdf3b_645a1cac083126ea, 0xa3d70a3d70a3d70a_3d70a3d70a3d70a4, 0xcccccccccccccccc_cccccccccccccccd, 0x8000000000000000_0000000000000000, 0xa000000000000000_0000000000000000, 0xc800000000000000_0000000000000000, 0xfa00000000000000_0000000000000000, 0x9c40000000000000_0000000000000000, 0xc350000000000000_0000000000000000, 0xf424000000000000_0000000000000000, 0x9896800000000000_0000000000000000, 0xbebc200000000000_0000000000000000, 0xee6b280000000000_0000000000000000, 0x9502f90000000000_0000000000000000, 0xba43b74000000000_0000000000000000, 0xe8d4a51000000000_0000000000000000, 0x9184e72a00000000_0000000000000000, 0xb5e620f480000000_0000000000000000, 0xe35fa931a0000000_0000000000000000, 0x8e1bc9bf04000000_0000000000000000, 0xb1a2bc2ec5000000_0000000000000000, 0xde0b6b3a76400000_0000000000000000, 0x8ac7230489e80000_0000000000000000, 0xad78ebc5ac620000_0000000000000000, 0xd8d726b7177a8000_0000000000000000, 0x878678326eac9000_0000000000000000, 0xa968163f0a57b400_0000000000000000, 0xd3c21bcecceda100_0000000000000000, 0x84595161401484a0_0000000000000000, 0xa56fa5b99019a5c8_0000000000000000, 0xcecb8f27f4200f3a_0000000000000000, 0x813f3978f8940984_4000000000000000, 0xa18f07d736b90be5_5000000000000000, 0xc9f2c9cd04674ede_a400000000000000, 0xfc6f7c4045812296_4d00000000000000, 0x9dc5ada82b70b59d_f020000000000000, 0xc5371912364ce305_6c28000000000000, 0xf684df56c3e01bc6_c732000000000000, 0x9a130b963a6c115c_3c7f400000000000, 0xc097ce7bc90715b3_4b9f100000000000, 0xf0bdc21abb48db20_1e86d40000000000, 0x96769950b50d88f4_1314448000000000, 0xbc143fa4e250eb31_17d955a000000000, 0xeb194f8e1ae525fd_5dcfab0800000000, 0x92efd1b8d0cf37be_5aa1cae500000000, 0xb7abc627050305ad_f14a3d9e40000000, 0xe596b7b0c643c719_6d9ccd05d0000000, 0x8f7e32ce7bea5c6f_e4820023a2000000, 0xb35dbf821ae4f38b_dda2802c8a800000, 0xe0352f62a19e306e_d50b2037ad200000, 0x8c213d9da502de45_4526f422cc340000, 0xaf298d050e4395d6_9670b12b7f410000, 0xdaf3f04651d47b4c_3c0cdd765f114000, 0x88d8762bf324cd0f_a5880a69fb6ac800, 0xab0e93b6efee0053_8eea0d047a457a00, 0xd5d238a4abe98068_72a4904598d6d880, 0x85a36366eb71f041_47a6da2b7f864750, 0xa70c3c40a64e6c51_999090b65f67d924, 0xd0cf4b50cfe20765_fff4b4e3f741cf6d, 0x82818f1281ed449f_bff8f10e7a8921a5, 0xa321f2d7226895c7_aff72d52192b6a0e, 0xcbea6f8ceb02bb39_9bf4f8a69f764491, 0xfee50b7025c36a08_02f236d04753d5b5, 0x9f4f2726179a2245_01d762422c946591, 0xc722f0ef9d80aad6_424d3ad2b7b97ef6, 0xf8ebad2b84e0d58b_d2e0898765a7deb3, 0x9b934c3b330c8577_63cc55f49f88eb30, 0xc2781f49ffcfa6d5_3cbf6b71c76b25fc, 0xf316271c7fc3908a_8bef464e3945ef7b, 0x97edd871cfda3a56_97758bf0e3cbb5ad, 0xbde94e8e43d0c8ec_3d52eeed1cbea318, 0xed63a231d4c4fb27_4ca7aaa863ee4bde, 0x945e455f24fb1cf8_8fe8caa93e74ef6b, 0xb975d6b6ee39e436_b3e2fd538e122b45, 0xe7d34c64a9c85d44_60dbbca87196b617, 0x90e40fbeea1d3a4a_bc8955e946fe31ce, 0xb51d13aea4a488dd_6babab6398bdbe42, 0xe264589a4dcdab14_c696963c7eed2dd2, 0x8d7eb76070a08aec_fc1e1de5cf543ca3, 0xb0de65388cc8ada8_3b25a55f43294bcc, 0xdd15fe86affad912_49ef0eb713f39ebf, 0x8a2dbf142dfcc7ab_6e3569326c784338, 0xacb92ed9397bf996_49c2c37f07965405, 0xd7e77a8f87daf7fb_dc33745ec97be907, 0x86f0ac99b4e8dafd_69a028bb3ded71a4, 0xa8acd7c0222311bc_c40832ea0d68ce0d, 0xd2d80db02aabd62b_f50a3fa490c30191, 0x83c7088e1aab65db_792667c6da79e0fb, 0xa4b8cab1a1563f52_577001b891185939, 0xcde6fd5e09abcf26_ed4c0226b55e6f87, 0x80b05e5ac60b6178_544f8158315b05b5, 0xa0dc75f1778e39d6_696361ae3db1c722, 0xc913936dd571c84c_03bc3a19cd1e38ea, 0xfb5878494ace3a5f_04ab48a04065c724, 0x9d174b2dcec0e47b_62eb0d64283f9c77, 0xc45d1df942711d9a_3ba5d0bd324f8395, 0xf5746577930d6500_ca8f44ec7ee3647a, 0x9968bf6abbe85f20_7e998b13cf4e1ecc, 0xbfc2ef456ae276e8_9e3fedd8c321a67f, 0xefb3ab16c59b14a2_c5cfe94ef3ea101f, 0x95d04aee3b80ece5_bba1f1d158724a13, 0xbb445da9ca61281f_2a8a6e45ae8edc98, 0xea1575143cf97226_f52d09d71a3293be, 0x924d692ca61be758_593c2626705f9c57, 0xb6e0c377cfa2e12e_6f8b2fb00c77836d, 0xe498f455c38b997a_0b6dfb9c0f956448, 0x8edf98b59a373fec_4724bd4189bd5ead, 0xb2977ee300c50fe7_58edec91ec2cb658, 0xdf3d5e9bc0f653e1_2f2967b66737e3ee, 0x8b865b215899f46c_bd79e0d20082ee75, 0xae67f1e9aec07187_ecd8590680a3aa12, 0xda01ee641a708de9_e80e6f4820cc9496, 0x884134fe908658b2_3109058d147fdcde, 0xaa51823e34a7eede_bd4b46f0599fd416, 0xd4e5e2cdc1d1ea96_6c9e18ac7007c91b, 0x850fadc09923329e_03e2cf6bc604ddb1, 0xa6539930bf6bff45_84db8346b786151d, 0xcfe87f7cef46ff16_e612641865679a64, 0x81f14fae158c5f6e_4fcb7e8f3f60c07f, 0xa26da3999aef7749_e3be5e330f38f09e, 0xcb090c8001ab551c_5cadf5bfd3072cc6, 0xfdcb4fa002162a63_73d9732fc7c8f7f7, 0x9e9f11c4014dda7e_2867e7fddcdd9afb, 0xc646d63501a1511d_b281e1fd541501b9, 0xf7d88bc24209a565_1f225a7ca91a4227, 0x9ae757596946075f_3375788de9b06959, 0xc1a12d2fc3978937_0052d6b1641c83af, 0xf209787bb47d6b84_c0678c5dbd23a49b, 0x9745eb4d50ce6332_f840b7ba963646e1, 0xbd176620a501fbff_b650e5a93bc3d899, 0xec5d3fa8ce427aff_a3e51f138ab4cebf, 0x93ba47c980e98cdf_c66f336c36b10138, 0xb8a8d9bbe123f017_b80b0047445d4185, 0xe6d3102ad96cec1d_a60dc059157491e6, 0x9043ea1ac7e41392_87c89837ad68db30, 0xb454e4a179dd1877_29babe4598c311fc, 0xe16a1dc9d8545e94_f4296dd6fef3d67b, 0x8ce2529e2734bb1d_1899e4a65f58660d, 0xb01ae745b101e9e4_5ec05dcff72e7f90, 0xdc21a1171d42645d_76707543f4fa1f74, 0x899504ae72497eba_6a06494a791c53a9, 0xabfa45da0edbde69_0487db9d17636893, 0xd6f8d7509292d603_45a9d2845d3c42b7, 0x865b86925b9bc5c2_0b8a2392ba45a9b3, 0xa7f26836f282b732_8e6cac7768d7141f, 0xd1ef0244af2364ff_3207d795430cd927, 0x8335616aed761f1f_7f44e6bd49e807b9, 0xa402b9c5a8d3a6e7_5f16206c9c6209a7, 0xcd036837130890a1_36dba887c37a8c10, 0x802221226be55a64_c2494954da2c978a, 0xa02aa96b06deb0fd_f2db9baa10b7bd6d, 0xc83553c5c8965d3d_6f92829494e5acc8, 0xfa42a8b73abbf48c_cb772339ba1f17fa, 0x9c69a97284b578d7_ff2a760414536efc, 0xc38413cf25e2d70d_fef5138519684abb, 0xf46518c2ef5b8cd1_7eb258665fc25d6a, 0x98bf2f79d5993802_ef2f773ffbd97a62, 0xbeeefb584aff8603_aafb550ffacfd8fb, 0xeeaaba2e5dbf6784_95ba2a53f983cf39, 0x952ab45cfa97a0b2_dd945a747bf26184, 0xba756174393d88df_94f971119aeef9e5, 0xe912b9d1478ceb17_7a37cd5601aab85e, 0x91abb422ccb812ee_ac62e055c10ab33b, 0xb616a12b7fe617aa_577b986b314d600a, 0xe39c49765fdf9d94_ed5a7e85fda0b80c, 0x8e41ade9fbebc27d_14588f13be847308, 0xb1d219647ae6b31c_596eb2d8ae258fc9, 0xde469fbd99a05fe3_6fca5f8ed9aef3bc, 0x8aec23d680043bee_25de7bb9480d5855, 0xada72ccc20054ae9_af561aa79a10ae6b, 0xd910f7ff28069da4_1b2ba1518094da05, 0x87aa9aff79042286_90fb44d2f05d0843, 0xa99541bf57452b28_353a1607ac744a54, 0xd3fa922f2d1675f2_42889b8997915ce9, 0x847c9b5d7c2e09b7_69956135febada12, 0xa59bc234db398c25_43fab9837e699096, 0xcf02b2c21207ef2e_94f967e45e03f4bc, 0x8161afb94b44f57d_1d1be0eebac278f6, 0xa1ba1ba79e1632dc_6462d92a69731733, 0xca28a291859bbf93_7d7b8f7503cfdcff, 0xfcb2cb35e702af78_5cda735244c3d43f, 0x9defbf01b061adab_3a0888136afa64a8, 0xc56baec21c7a1916_088aaa1845b8fdd1, 0xf6c69a72a3989f5b_8aad549e57273d46, 0x9a3c2087a63f6399_36ac54e2f678864c, 0xc0cb28a98fcf3c7f_84576a1bb416a7de, 0xf0fdf2d3f3c30b9f_656d44a2a11c51d6, 0x969eb7c47859e743_9f644ae5a4b1b326, 0xbc4665b596706114_873d5d9f0dde1fef, 0xeb57ff22fc0c7959_a90cb506d155a7eb, 0x9316ff75dd87cbd8_09a7f12442d588f3, 0xb7dcbf5354e9bece_0c11ed6d538aeb30, 0xe5d3ef282a242e81_8f1668c8a86da5fb, 0x8fa475791a569d10_f96e017d694487bd, 0xb38d92d760ec4455_37c981dcc395a9ad, 0xe070f78d3927556a_85bbe253f47b1418, 0x8c469ab843b89562_93956d7478ccec8f, 0xaf58416654a6babb_387ac8d1970027b3, 0xdb2e51bfe9d0696a_06997b05fcc0319f, 0x88fcf317f22241e2_441fece3bdf81f04, 0xab3c2fddeeaad25a_d527e81cad7626c4, 0xd60b3bd56a5586f1_8a71e223d8d3b075, 0x85c7056562757456_f6872d5667844e4a, 0xa738c6bebb12d16c_b428f8ac016561dc, 0xd106f86e69d785c7_e13336d701beba53, 0x82a45b450226b39c_ecc0024661173474, 0xa34d721642b06084_27f002d7f95d0191, 0xcc20ce9bd35c78a5_31ec038df7b441f5, 0xff290242c83396ce_7e67047175a15272, 0x9f79a169bd203e41_0f0062c6e984d387, 0xc75809c42c684dd1_52c07b78a3e60869, 0xf92e0c3537826145_a7709a56ccdf8a83, 0x9bbcc7a142b17ccb_88a66076400bb692, 0xc2abf989935ddbfe_6acff893d00ea436, 0xf356f7ebf83552fe_0583f6b8c4124d44, 0x98165af37b2153de_c3727a337a8b704b, 0xbe1bf1b059e9a8d6_744f18c0592e4c5d, 0xeda2ee1c7064130c_1162def06f79df74, 0x9485d4d1c63e8be7_8addcb5645ac2ba9, 0xb9a74a0637ce2ee1_6d953e2bd7173693, 0xe8111c87c5c1ba99_c8fa8db6ccdd0438, 0x910ab1d4db9914a0_1d9c9892400a22a3, 0xb54d5e4a127f59c8_2503beb6d00cab4c, 0xe2a0b5dc971f303a_2e44ae64840fd61e, 0x8da471a9de737e24_5ceaecfed289e5d3, 0xb10d8e1456105dad_7425a83e872c5f48, 0xdd50f1996b947518_d12f124e28f7771a, 0x8a5296ffe33cc92f_82bd6b70d99aaa70, 0xace73cbfdc0bfb7b_636cc64d1001550c, 0xd8210befd30efa5a_3c47f7e05401aa4f, 0x8714a775e3e95c78_65acfaec34810a72, 0xa8d9d1535ce3b396_7f1839a741a14d0e, 0xd31045a8341ca07c_1ede48111209a051, 0x83ea2b892091e44d_934aed0aab460433, 0xa4e4b66b68b65d60_f81da84d56178540, 0xce1de40642e3f4b9_36251260ab9d668f, 0x80d2ae83e9ce78f3_c1d72b7c6b42601a, 0xa1075a24e4421730_b24cf65b8612f820, 0xc94930ae1d529cfc_dee033f26797b628, 0xfb9b7cd9a4a7443c_169840ef017da3b2, 0x9d412e0806e88aa5_8e1f289560ee864f, 0xc491798a08a2ad4e_f1a6f2bab92a27e3, 0xf5b5d7ec8acb58a2_ae10af696774b1dc, 0x9991a6f3d6bf1765_acca6da1e0a8ef2a, 0xbff610b0cc6edd3f_17fd090a58d32af4, 0xeff394dcff8a948e_ddfc4b4cef07f5b1, 0x95f83d0a1fb69cd9_4abdaf101564f98f, 0xbb764c4ca7a4440f_9d6d1ad41abe37f2, 0xea53df5fd18d5513_84c86189216dc5ee, 0x92746b9be2f8552c_32fd3cf5b4e49bb5, 0xb7118682dbb66a77_3fbc8c33221dc2a2, 0xe4d5e82392a40515_0fabaf3feaa5334b, 0x8f05b1163ba6832d_29cb4d87f2a7400f, 0xb2c71d5bca9023f8_743e20e9ef511013, 0xdf78e4b2bd342cf6_914da9246b255417, 0x8bab8eefb6409c1a_1ad089b6c2f7548f, 0xae9672aba3d0c320_a184ac2473b529b2, 0xda3c0f568cc4f3e8_c9e5d72d90a2741f, 0x8865899617fb1871_7e2fa67c7a658893, 0xaa7eebfb9df9de8d_ddbb901b98feeab8, 0xd51ea6fa85785631_552a74227f3ea566, 0x8533285c936b35de_d53a88958f872760, 0xa67ff273b8460356_8a892abaf368f138, 0xd01fef10a657842c_2d2b7569b0432d86, 0x8213f56a67f6b29b_9c3b29620e29fc74, 0xa298f2c501f45f42_8349f3ba91b47b90, 0xcb3f2f7642717713_241c70a936219a74, 0xfe0efb53d30dd4d7_ed238cd383aa0111, 0x9ec95d1463e8a506_f4363804324a40ab, 0xc67bb4597ce2ce48_b143c6053edcd0d6, 0xf81aa16fdc1b81da_dd94b7868e94050b, 0x9b10a4e5e9913128_ca7cf2b4191c8327, 0xc1d4ce1f63f57d72_fd1c2f611f63a3f1, 0xf24a01a73cf2dccf_bc633b39673c8ced, 0x976e41088617ca01_d5be0503e085d814, 0xbd49d14aa79dbc82_4b2d8644d8a74e19, 0xec9c459d51852ba2_ddf8e7d60ed1219f, 0x93e1ab8252f33b45_cabb90e5c942b504, 0xb8da1662e7b00a17_3d6a751f3b936244, 0xe7109bfba19c0c9d_0cc512670a783ad5, 0x906a617d450187e2_27fb2b80668b24c6, 0xb484f9dc9641e9da_b1f9f660802dedf7, 0xe1a63853bbd26451_5e7873f8a0396974, 0x8d07e33455637eb2_db0b487b6423e1e9, 0xb049dc016abc5e5f_91ce1a9a3d2cda63, 0xdc5c5301c56b75f7_7641a140cc7810fc, 0x89b9b3e11b6329ba_a9e904c87fcb0a9e, 0xac2820d9623bf429_546345fa9fbdcd45, 0xd732290fbacaf133_a97c177947ad4096, 0x867f59a9d4bed6c0_49ed8eabcccc485e, 0xa81f301449ee8c70_5c68f256bfff5a75, 0xd226fc195c6a2f8c_73832eec6fff3112, 0x83585d8fd9c25db7_c831fd53c5ff7eac, 0xa42e74f3d032f525_ba3e7ca8b77f5e56, 0xcd3a1230c43fb26f_28ce1bd2e55f35ec, 0x80444b5e7aa7cf85_7980d163cf5b81b4, 0xa0555e361951c366_d7e105bcc3326220, 0xc86ab5c39fa63440_8dd9472bf3fefaa8, 0xfa856334878fc150_b14f98f6f0feb952, 0x9c935e00d4b9d8d2_6ed1bf9a569f33d4, 0xc3b8358109e84f07_0a862f80ec4700c9, 0xf4a642e14c6262c8_cd27bb612758c0fb, 0x98e7e9cccfbd7dbd_8038d51cb897789d, 0xbf21e44003acdd2c_e0470a63e6bd56c4, 0xeeea5d5004981478_1858ccfce06cac75, 0x95527a5202df0ccb_0f37801e0c43ebc9, 0xbaa718e68396cffd_d30560258f54e6bb, 0xe950df20247c83fd_47c6b82ef32a206a, 0x91d28b7416cdd27e_4cdc331d57fa5442, 0xb6472e511c81471d_e0133fe4adf8e953, 0xe3d8f9e563a198e5_58180fddd97723a7, 0x8e679c2f5e44ff8f_570f09eaa7ea7649, 0xb201833b35d63f73_2cd2cc6551e513db, 0xde81e40a034bcf4f_f8077f7ea65e58d2, 0x8b112e86420f6191_fb04afaf27faf783, 0xadd57a27d29339f6_79c5db9af1f9b564, 0xd94ad8b1c7380874_18375281ae7822bd, 0x87cec76f1c830548_8f2293910d0b15b6, 0xa9c2794ae3a3c69a_b2eb3875504ddb23, 0xd433179d9c8cb841_5fa60692a46151ec, 0x849feec281d7f328_dbc7c41ba6bcd334, 0xa5c7ea73224deff3_12b9b522906c0801, 0xcf39e50feae16bef_d768226b34870a01, 0x81842f29f2cce375_e6a1158300d46641, 0xa1e53af46f801c53_60495ae3c1097fd1, 0xca5e89b18b602368_385bb19cb14bdfc5, 0xfcf62c1dee382c42_46729e03dd9ed7b6, 0x9e19db92b4e31ba9_6c07a2c26a8346d2, 0xc5a05277621be293_c7098b7305241886, 0xf70867153aa2db38_b8cbee4fc66d1ea8, ]; dragonbox_ecma-0.1.12/src/div.rs000064400000000000000000000044041046102023000145760ustar 00000000000000// Translated from C++ to Rust. The original C++ code can be found at // https://github.com/jk-jeon/dragonbox and carries the following license: // // Copyright 2020-2025 Junekey Jeon // // The contents of this file may be used under the terms of // the Apache License v2.0 with LLVM Exceptions. // // (See accompanying file LICENSE-Apache or copy at // https://llvm.org/foundation/relicensing/LICENSE.txt) // // Alternatively, the contents of this file may be used under the terms of // the Boost Software License, Version 1.0. // (See accompanying file LICENSE-Boost or copy at // https://www.boost.org/LICENSE_1_0.txt) // // Unless required by applicable law or agreed to in writing, this software // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. use crate::wuint; // Replace n by floor(n / 10^N). // Returns true if and only if n is divisible by 10^N. // Precondition: n <= 10^(N+1) pub(crate) fn check_divisibility_and_divide_by_pow10(n: &mut u32) -> bool { const N: u32 = 2; debug_assert!(*n <= crate::compute_power32::<{ N + 1 }>(10)); struct Info; impl Info { const MAGIC_NUMBER: u32 = 656; const SHIFT_AMOUNT: i32 = 16; } let prod = *n * Info::MAGIC_NUMBER; const MASK: u32 = (1 << Info::SHIFT_AMOUNT) - 1; let result = (prod & MASK) < Info::MAGIC_NUMBER; *n = prod >> Info::SHIFT_AMOUNT; result } // Compute floor(n / 10^N) for small N. // Precondition: n <= n_max pub(crate) fn divide_by_pow10(n: u64) -> u64 { // Specialize for 64-bit division by 10. // Without the bound on n_max (which compilers these days never leverage), // the minimum needed amount of shift is larger than 64. if N == 1 && N_MAX <= 4611686018427387908 { return wuint::umul128_upper64(n, 1844674407370955162); } // Specialize for 64-bit division by 1000. // Without the bound on n_max (which compilers these days never leverage), // the smallest magic number for this computation does not fit into 64-bits. if N == 3 && N_MAX <= 15534100272597517998 { return wuint::umul128_upper64(n, 4722366482869645214) >> 8; } let divisor = const { crate::compute_power64::(10) }; n / divisor } dragonbox_ecma-0.1.12/src/lib.rs000064400000000000000000000474171046102023000145750ustar 00000000000000// Translated from C++ to Rust. The original C++ code can be found at // https://github.com/jk-jeon/dragonbox and carries the following license: // // Copyright 2020-2025 Junekey Jeon // // The contents of this file may be used under the terms of // the Apache License v2.0 with LLVM Exceptions. // // (See accompanying file LICENSE-Apache or copy at // https://llvm.org/foundation/relicensing/LICENSE.txt) // // Alternatively, the contents of this file may be used under the terms of // the Boost Software License, Version 1.0. // (See accompanying file LICENSE-Boost or copy at // https://www.boost.org/LICENSE_1_0.txt) // // Unless required by applicable law or agreed to in writing, this software // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. //! [![github]](https://github.com/magic-akari/dragonbox) [![crates-io]](https://crates.io/crates/dragonbox_ecma) [![docs-rs]](https://docs.rs/dragonbox_ecma) //! //! [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&logo=docs.rs //! //!
//! //! This crate contains a basic port of //! to Rust for benchmarking purposes. //! //! Please see the upstream repo for an explanation of the approach and //! comparison to the Ryū algorithm. //! //! # Example //! //! ``` //! fn main() { //! let mut buffer = dragonbox_ecma::Buffer::new(); //! let printed = buffer.format(1.234); //! assert_eq!(printed, "1.234"); //! } //! ``` //! //! ## Performance (lower is better) //! //! ![performance](https://raw.githubusercontent.com/dtolnay/dragonbox/master/performance.png) #![no_std] #![doc(html_root_url = "https://docs.rs/dragonbox/0.1.12")] #![allow(unsafe_op_in_unsafe_fn, unused_parens)] #![cfg_attr(dragonbox_dead_code_workaround, allow(dead_code))] #![allow( clippy::assertions_on_constants, clippy::bool_to_int_with_if, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_sign_loss, clippy::comparison_chain, clippy::doc_markdown, clippy::eq_op, clippy::expl_impl_clone_on_copy, clippy::if_not_else, clippy::items_after_statements, clippy::must_use_candidate, clippy::needless_bitwise_bool, clippy::needless_doctest_main, clippy::never_loop, clippy::similar_names, clippy::too_many_lines, clippy::unreadable_literal, clippy::verbose_bit_mask )] mod buffer; mod cache; mod div; mod log; mod policy; #[cfg_attr(feature = "ecma", path = "to_chars_ecma.rs")] mod to_chars; mod wuint; use crate::buffer::Sealed; use crate::cache::EntryTypeExt as _; use core::mem::MaybeUninit; /// Buffer correctly sized to hold the text representation of any floating point /// value. /// /// ## Example /// /// ``` /// let mut buffer = dragonbox_ecma::Buffer::new(); /// let printed = buffer.format_finite(1.234); /// assert_eq!(printed, "1.234"); /// ``` pub struct Buffer { bytes: [MaybeUninit; to_chars::MAX_OUTPUT_STRING_LENGTH], } /// A floating point number that can be written into a /// [`dragonbox_ecma::Buffer`][Buffer]. /// /// This trait is sealed and cannot be implemented for types outside of the /// `dragonbox` crate. pub trait Float: Sealed {} // IEEE754-binary64 const TOTAL_BITS: usize = 64; const SIGNIFICAND_BITS: usize = 52; const EXPONENT_BITS: usize = 11; const MIN_EXPONENT: i32 = -1022; const MAX_EXPONENT: i32 = 1023; const EXPONENT_BIAS: i32 = -1023; #[allow(dead_code)] const DECIMAL_SIGNIFICAND_DIGITS: usize = 17; #[allow(dead_code)] const DECIMAL_EXPONENT_DIGITS: usize = 3; // Defines an unsigned integer type that is large enough // to carry a variable of type f64. // Most of the operations will be done on this integer type. type CarrierUint = u64; // Number of bits in the above unsigned integer type. const CARRIER_BITS: usize = 64; // Specifies the signed integer type to hold the exponent of Float. type ExponentInt = i32; // Extract exponent bits from a bit pattern. The result must be aligned to the // LSB so that there is no additional zero paddings on the right. This function // does not do bias adjustment. const fn extract_exponent_bits(u: CarrierUint) -> ExponentInt { (u >> SIGNIFICAND_BITS) as ExponentInt & (((1 as ExponentInt) << EXPONENT_BITS) - 1) } // Remove the exponent bits and extract significand bits together with the sign // bit. const fn remove_exponent_bits(u: CarrierUint) -> CarrierUint { u & !(((1 << EXPONENT_BITS) - 1) << SIGNIFICAND_BITS) } // Shift the obtained signed significand bits to the left by 1 to remove the // sign bit. const fn remove_sign_bit_and_shift(u: CarrierUint) -> CarrierUint { (u << 1) & ((((1 << (TOTAL_BITS - 1)) - 1) << 1) | 1) } const fn is_nonzero(u: CarrierUint) -> bool { (u & ((1 << (SIGNIFICAND_BITS + EXPONENT_BITS)) - 1)) != 0 } const fn is_positive(u: CarrierUint) -> bool { u < (1 << (SIGNIFICAND_BITS + EXPONENT_BITS)) } const fn is_negative(u: CarrierUint) -> bool { !is_positive(u) } const fn has_even_significand_bits(s: CarrierUint) -> bool { s % 2 == 0 } const fn compute_power32(a: u32) -> u32 { let mut p = 1; let mut i = 0; while i < K { p *= a; i += 1; } p } const fn compute_power64(a: u64) -> u64 { let mut p = 1; let mut i = 0; while i < K { p *= a; i += 1; } p } const fn count_factors(mut n: usize) -> u32 { const { assert!(A > 1); } let mut c = 0; while n % A == 0 { n /= A; c += 1; } c } struct Decimal { significand: u64, exponent: i32, } const KAPPA: u32 = (log::floor_log10_pow2::< { log::FLOOR_LOG10_POW2_MIN_EXPONENT }, { log::FLOOR_LOG10_POW2_MAX_EXPONENT }, >(CARRIER_BITS as i32 - SIGNIFICAND_BITS as i32 - 2) - 1) as u32; const _: () = assert!( CARRIER_BITS as i32 >= SIGNIFICAND_BITS as i32 + 2 + log::floor_log2_pow10::< { log::FLOOR_LOG2_POW10_MIN_EXPONENT }, { log::FLOOR_LOG2_POW10_MAX_EXPONENT }, >(KAPPA as i32 + 1), ); const fn min(x: i32, y: i32) -> i32 { if x < y { x } else { y } } const fn max(x: i32, y: i32) -> i32 { if x > y { x } else { y } } const MIN_K: i32 = min( -log::floor_log10_pow2_minus_log10_4_over_3::< { log::FLOOR_LOG10_POW2_MINUS_LOG10_4_OVER_3_MIN_EXPONENT }, { log::FLOOR_LOG10_POW2_MINUS_LOG10_4_OVER_3_MAX_EXPONENT }, >(MAX_EXPONENT - SIGNIFICAND_BITS as i32), -log::floor_log10_pow2::< { log::FLOOR_LOG10_POW2_MIN_EXPONENT }, { log::FLOOR_LOG10_POW2_MAX_EXPONENT }, >(MAX_EXPONENT - SIGNIFICAND_BITS as i32) + KAPPA as i32, ); const _: () = assert!(MIN_K >= cache::MIN_K); // We do invoke shorter_interval_case for exponent == min_exponent case, so we // should not add 1 here. const MAX_K: i32 = max( -log::floor_log10_pow2_minus_log10_4_over_3::< { log::FLOOR_LOG10_POW2_MINUS_LOG10_4_OVER_3_MIN_EXPONENT }, { log::FLOOR_LOG10_POW2_MINUS_LOG10_4_OVER_3_MAX_EXPONENT }, >(MIN_EXPONENT - SIGNIFICAND_BITS as i32 /* + 1*/), -log::floor_log10_pow2::< { log::FLOOR_LOG10_POW2_MIN_EXPONENT }, { log::FLOOR_LOG10_POW2_MAX_EXPONENT }, >(MIN_EXPONENT - SIGNIFICAND_BITS as i32) + KAPPA as i32, ); const _: () = assert!(MAX_K <= cache::MAX_K); struct ComputeMulResult { integer_part: CarrierUint, is_integer: bool, } fn compute_mul(u: CarrierUint, cache: &cache::EntryType) -> ComputeMulResult { let r = wuint::umul192_upper128(u, *cache); ComputeMulResult { integer_part: r.high(), is_integer: r.low() == 0, } } fn compute_delta(cache: &cache::EntryType, beta: i32) -> u32 { (cache.high() >> ((CARRIER_BITS - 1) as i32 - beta)) as u32 } struct ComputeMulParityResult { parity: bool, is_integer: bool, } fn compute_mul_parity( two_f: CarrierUint, cache: &cache::EntryType, beta: i32, ) -> ComputeMulParityResult { debug_assert!(beta >= 1); debug_assert!(beta < 64); let r = wuint::umul192_lower128(two_f, *cache); ComputeMulParityResult { parity: ((r.high() >> (64 - beta)) & 1) != 0, is_integer: ((r.high() << beta) | (r.low() >> (64 - beta))) == 0, } } fn compute_left_endpoint_for_shorter_interval_case( cache: &cache::EntryType, beta: i32, ) -> CarrierUint { (cache.high() - (cache.high() >> (SIGNIFICAND_BITS + 2))) >> ((CARRIER_BITS - SIGNIFICAND_BITS - 1) as i32 - beta) } fn compute_right_endpoint_for_shorter_interval_case( cache: &cache::EntryType, beta: i32, ) -> CarrierUint { (cache.high() + (cache.high() >> (SIGNIFICAND_BITS + 1))) >> ((CARRIER_BITS - SIGNIFICAND_BITS - 1) as i32 - beta) } fn compute_round_up_for_shorter_interval_case(cache: &cache::EntryType, beta: i32) -> CarrierUint { (cache.high() >> ((CARRIER_BITS - SIGNIFICAND_BITS - 2) as i32 - beta)).div_ceil(2) } const fn floor_log2(mut n: u64) -> i32 { let mut count = -1; while n != 0 { count += 1; n >>= 1; } count } fn is_left_endpoint_integer_shorter_interval(exponent: i32) -> bool { const CASE_SHORTER_INTERVAL_LEFT_ENDPOINT_LOWER_THRESHOLD: i32 = 2; const CASE_SHORTER_INTERVAL_LEFT_ENDPOINT_UPPER_THRESHOLD: i32 = 2 + floor_log2( compute_power64::< { count_factors::<5>((((1 as CarrierUint) << (SIGNIFICAND_BITS + 2)) - 1) as usize) + 1 }, >(10) / 3, ); (CASE_SHORTER_INTERVAL_LEFT_ENDPOINT_LOWER_THRESHOLD ..=CASE_SHORTER_INTERVAL_LEFT_ENDPOINT_UPPER_THRESHOLD) .contains(&exponent) } // The main algorithm assumes the input is a normal/subnormal finite number. fn compute_nearest(signed_significand_bits: CarrierUint, exponent_bits: ExponentInt) -> Decimal { let mut two_fc = remove_sign_bit_and_shift(signed_significand_bits); let mut binary_exponent = exponent_bits; // Is the input a normal number? if binary_exponent != 0 { binary_exponent += EXPONENT_BIAS - SIGNIFICAND_BITS as i32; // Shorter interval case; proceed like Schubfach. One might think this // condition is wrong, since when exponent_bits == 1 and two_fc == 0, // the interval is actually regular. However, it turns out that this // seemingly wrong condition is actually fine, because the end result is // anyway the same. // // [binary32] // (fc-1/2) * 2^e = 1.175'494'28... * 10^-38 // (fc-1/4) * 2^e = 1.175'494'31... * 10^-38 // fc * 2^e = 1.175'494'35... * 10^-38 // (fc+1/2) * 2^e = 1.175'494'42... * 10^-38 // // Hence, shorter_interval_case will return 1.175'494'4 * 10^-38. // 1.175'494'3 * 10^-38 is also a correct shortest representation that // will be rejected if we assume shorter interval, but 1.175'494'4 * // 10^-38 is closer to the true value so it doesn't matter. // // [binary64] // (fc-1/2) * 2^e = 2.225'073'858'507'201'13... * 10^-308 // (fc-1/4) * 2^e = 2.225'073'858'507'201'25... * 10^-308 // fc * 2^e = 2.225'073'858'507'201'38... * 10^-308 // (fc+1/2) * 2^e = 2.225'073'858'507'201'63... * 10^-308 // // Hence, shorter_interval_case will return 2.225'073'858'507'201'4 * 10^-308. // This is indeed of the shortest length, and it is the unique one // closest to the true value among valid representations of the same // length. // Shorter interval case. if two_fc == 0 { // Compute k and beta. let minus_k = log::floor_log10_pow2_minus_log10_4_over_3::< { MIN_EXPONENT - SIGNIFICAND_BITS as i32 }, { MAX_EXPONENT - SIGNIFICAND_BITS as i32 }, >(binary_exponent); let beta = binary_exponent + log::floor_log2_pow10::(-minus_k); // Compute xi and zi. let cache = unsafe { cache::get(-minus_k) }; let mut xi = compute_left_endpoint_for_shorter_interval_case(&cache, beta); let zi = compute_right_endpoint_for_shorter_interval_case(&cache, beta); // If the left endpoint is not an integer, increase it. if !is_left_endpoint_integer_shorter_interval(binary_exponent) { xi += 1; } // Try bigger divisor. // zi is at most floor((f_c + 1/2) * 2^e * 10^k0). // Substituting f_c = 2^p and k0 = -floor(log10(3 * 2^(e-2))), we get // zi <= floor((2^(p+1) + 1) * 20/3) <= ceil((2^(p+1) + 1)/3) * 20. // This computation does not overflow for any of the formats I care about. let mut decimal_significand = div::divide_by_pow10::< 1, { ((((1 << (SIGNIFICAND_BITS + 1)) + 1) / 3) + 1) * 20 }, >(zi); // If succeed, remove trailing zeros if necessary and return. if decimal_significand * 10 >= xi { return Decimal { significand: decimal_significand, exponent: minus_k + 1, }; } // Otherwise, compute the round-up of y. decimal_significand = compute_round_up_for_shorter_interval_case(&cache, beta); // When tie occurs, choose one of them according to the rule. const SHORTER_INTERVAL_TIE_LOWER_THRESHOLD: i32 = -log::floor_log5_pow2_minus_log5_3(SIGNIFICAND_BITS as i32 + 4) - 2 - SIGNIFICAND_BITS as i32; const SHORTER_INTERVAL_TIE_UPPER_THRESHOLD: i32 = -log::floor_log5_pow2(SIGNIFICAND_BITS as i32 + 2) - 2 - SIGNIFICAND_BITS as i32; if policy::prefer_round_down(decimal_significand) && binary_exponent >= SHORTER_INTERVAL_TIE_LOWER_THRESHOLD && binary_exponent <= SHORTER_INTERVAL_TIE_UPPER_THRESHOLD { decimal_significand -= 1; } else if decimal_significand < xi { decimal_significand += 1; } return Decimal { significand: decimal_significand, exponent: minus_k, }; } two_fc |= 1 << (SIGNIFICAND_BITS + 1); } // Is the input a subnormal number? else { binary_exponent = MIN_EXPONENT - SIGNIFICAND_BITS as i32; } ////////////////////////////////////////////////////////////////////// // Step 1: Schubfach multiplier calculation. ////////////////////////////////////////////////////////////////////// let has_even_significand_bits = has_even_significand_bits(signed_significand_bits); // Compute k and beta. let minus_k = log::floor_log10_pow2::< { MIN_EXPONENT - SIGNIFICAND_BITS as i32 }, { MAX_EXPONENT - SIGNIFICAND_BITS as i32 }, >(binary_exponent) - KAPPA as i32; let cache = unsafe { cache::get(-minus_k) }; let beta = binary_exponent + log::floor_log2_pow10::(-minus_k); // Compute zi and deltai. // 10^kappa <= deltai < 10^(kappa + 1) let deltai = compute_delta(&cache, beta); // For the case of binary32, the result of integer check is not correct for // 29711844 * 2^-82 // = 6.1442653300000000008655037797566933477355632930994033813476... * 10^-18 // and 29711844 * 2^-81 // = 1.2288530660000000001731007559513386695471126586198806762695... * 10^-17, // and they are the unique counterexamples. However, since 29711844 is even, // this does not cause any problem for the endpoints calculations; it can // only cause a problem when we need to perform integer check for the // center. Fortunately, with these inputs, that branch is never executed, so // we are fine. let z_result = compute_mul((two_fc | 1) << beta, &cache); ////////////////////////////////////////////////////////////////////// // Step 2: Try larger divisor; remove trailing zeros if necessary. ////////////////////////////////////////////////////////////////////// const BIG_DIVISOR: u32 = compute_power32::<{ KAPPA + 1 }>(10); const SMALL_DIVISOR: u32 = compute_power32::(10); // Using an upper bound on zi, we might be able to optimize the division // better than the compiler; we are computing zi / big_divisor here. let mut decimal_significand = div::divide_by_pow10::< { KAPPA + 1 }, { (1 << (SIGNIFICAND_BITS + 1)) * BIG_DIVISOR as u64 - 1 }, >(z_result.integer_part); let mut r = (z_result.integer_part - u64::from(BIG_DIVISOR) * decimal_significand) as u32; loop { if r < deltai { // Exclude the right endpoint if necessary. if (r | u32::from(!z_result.is_integer) | u32::from(has_even_significand_bits)) == 0 { decimal_significand -= 1; r = BIG_DIVISOR; break; } } else if r > deltai { break; } else { // r == deltai; compare fractional parts. let x_result = compute_mul_parity(two_fc - 1, &cache, beta); if !(x_result.parity | (x_result.is_integer & has_even_significand_bits)) { break; } } return Decimal { significand: decimal_significand, exponent: minus_k + KAPPA as i32 + 1, }; } ////////////////////////////////////////////////////////////////////// // Step 3: Find the significand with the smaller divisor. ////////////////////////////////////////////////////////////////////// decimal_significand *= 10; // delta is equal to 10^(kappa + elog10(2) - floor(elog10(2))), so dist // cannot be larger than r. let mut dist = r - (deltai / 2) + (SMALL_DIVISOR / 2); let approx_y_parity = ((dist ^ (SMALL_DIVISOR / 2)) & 1) != 0; // Is dist divisible by 10^kappa? let divisible_by_small_divisor = div::check_divisibility_and_divide_by_pow10(&mut dist); // Add dist / 10^kappa to the significand. decimal_significand += CarrierUint::from(dist); if divisible_by_small_divisor { // Check z^(f) >= epsilon^(f). // We have either yi == zi - epsiloni or yi == (zi - epsiloni) - 1, // where yi == zi - epsiloni if and only if z^(f) >= epsilon^(f). // Since there are only 2 possibilities, we only need to care about the parity. // Also, zi and r should have the same parity since the divisor // is an even number. let y_result = compute_mul_parity(two_fc, &cache, beta); if y_result.parity != approx_y_parity { decimal_significand -= 1; } else { // If z^(f) >= epsilon^(f), we might have a tie // when z^(f) == epsilon^(f), or equivalently, when y is an integer. // For tie-to-up case, we can just choose the upper one. if policy::prefer_round_down(decimal_significand) & y_result.is_integer { decimal_significand -= 1; } } } Decimal { significand: decimal_significand, exponent: minus_k + KAPPA as i32, } } #[cfg(not(feature = "ecma"))] fn to_decimal(x: f64) -> Decimal { let br = x.to_bits(); let exponent_bits = extract_exponent_bits(br); let s = remove_exponent_bits(br); compute_nearest(s, exponent_bits) } #[cfg(feature = "ecma")] fn to_decimal(x: f64) -> Decimal { let br = x.to_bits(); let exponent_bits = extract_exponent_bits(br); let s = remove_exponent_bits(br); let mut decimal = compute_nearest(s, exponent_bits); policy::remove_trailing_zeros(&mut decimal.significand, &mut decimal.exponent); decimal } dragonbox_ecma-0.1.12/src/log.rs000064400000000000000000000176671046102023000146140ustar 00000000000000// Translated from C++ to Rust. The original C++ code can be found at // https://github.com/jk-jeon/dragonbox and carries the following license: // // Copyright 2020-2025 Junekey Jeon // // The contents of this file may be used under the terms of // the Apache License v2.0 with LLVM Exceptions. // // (See accompanying file LICENSE-Apache or copy at // https://llvm.org/foundation/relicensing/LICENSE.txt) // // Alternatively, the contents of this file may be used under the terms of // the Boost Software License, Version 1.0. // (See accompanying file LICENSE-Boost or copy at // https://www.boost.org/LICENSE_1_0.txt) // // Unless required by applicable law or agreed to in writing, this software // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. //////////////////////////////////////////////////////////////////////////////////////// // Utilities for fast/constexpr log computation. //////////////////////////////////////////////////////////////////////////////////////// const _: () = assert!( (-1 >> 1) == -1, "right-shift for signed integers must be arithmetic", ); // Implementations of various log computations using binary approximations. On // less powerful platforms, using smaller integer types and magic numbers for // these computations significantly improve codegen, so depending on the range // of input we try to choose the smallest possible magic numbers that result in // the best codegen. To generically achieve that goal, we list multiple sets of // magic numbers with associated ranges of inputs, called "tiers", so that we // choose the smallest tier whose associated range covers the requested range of // input. trait TierInfo { const TIER: usize; const MULTIPLY: u32; const SUBTRACT: u32; const SHIFT: u32; const MIN_EXPONENT: i32; const MAX_EXPONENT: i32; type Next: TierInfo; } // Check if the given tier covers the requested range. Info is // supposed to hold the magic numbers needed for the computation and the // supported range of input (i.e. the range of input where the computation with // the given magic numbers must be valid). const fn is_in_range() -> bool { MIN_EXPONENT >= Info::MIN_EXPONENT && MAX_EXPONENT <= Info::MAX_EXPONENT } // Generic implementation of log computations. const fn compute(e: i32) -> i32 { if is_in_range::() { // Specialization for the case when the given tier covers the requested // range of input. In this case, do the computation with the given magic // numbers. debug_assert!(MIN_EXPONENT <= e && e <= MAX_EXPONENT); (e * Info::MULTIPLY as i32 - Info::SUBTRACT as i32) >> Info::SHIFT } else { // Specialization for the case when the given tier does not cover the // requested range of input. In this case, delegate the computation to // the next tier. If the next tier does not exist, then the compilation // must fail. debug_assert!(Info::TIER < Info::Next::TIER); compute::(e) } } pub(crate) const FLOOR_LOG10_POW2_MIN_EXPONENT: i32 = -2620; pub(crate) const FLOOR_LOG10_POW2_MAX_EXPONENT: i32 = 2620; pub(crate) const fn floor_log10_pow2( e: i32, ) -> i32 { enum Info0 {} impl TierInfo for Info0 { const TIER: usize = 0; const MULTIPLY: u32 = 77; const SUBTRACT: u32 = 0; const SHIFT: u32 = 8; const MIN_EXPONENT: i32 = -102; const MAX_EXPONENT: i32 = 102; type Next = Info1; } enum Info1 {} impl TierInfo for Info1 { const TIER: usize = 1; // 24-bits are enough in fact. const MULTIPLY: u32 = 1233; const SUBTRACT: u32 = 0; const SHIFT: u32 = 12; // Formula itself holds on [-680,680]; [-425,425] is to ensure that // the output is within [-127,127]. const MIN_EXPONENT: i32 = -425; const MAX_EXPONENT: i32 = 425; type Next = Info2; } enum Info2 {} impl TierInfo for Info2 { const TIER: usize = 2; const MULTIPLY: u32 = 315653; const SUBTRACT: u32 = 0; const SHIFT: u32 = 20; const MIN_EXPONENT: i32 = -2620; const MAX_EXPONENT: i32 = 2620; type Next = Self; } compute::(e) } pub(crate) const FLOOR_LOG2_POW10_MIN_EXPONENT: i32 = -1233; pub(crate) const FLOOR_LOG2_POW10_MAX_EXPONENT: i32 = 1233; pub(crate) const fn floor_log2_pow10( e: i32, ) -> i32 { enum Info0 {} impl TierInfo for Info0 { const TIER: usize = 0; const MULTIPLY: u32 = 53; const SUBTRACT: u32 = 0; const SHIFT: u32 = 4; const MIN_EXPONENT: i32 = -15; const MAX_EXPONENT: i32 = 18; type Next = Info1; } enum Info1 {} impl TierInfo for Info1 { const TIER: usize = 1; // 24-bits are enough in fact. const MULTIPLY: u32 = 1701; const SUBTRACT: u32 = 0; const SHIFT: u32 = 9; const MIN_EXPONENT: i32 = -58; const MAX_EXPONENT: i32 = 58; type Next = Info2; } enum Info2 {} impl TierInfo for Info2 { const TIER: usize = 2; const MULTIPLY: u32 = 1741647; const SUBTRACT: u32 = 0; const SHIFT: u32 = 19; // Formula itself holds on [-4003,4003]; [-1233,1233] is to ensure // no overflow. const MIN_EXPONENT: i32 = -1233; const MAX_EXPONENT: i32 = 1233; type Next = Self; } compute::(e) } pub(crate) const FLOOR_LOG10_POW2_MINUS_LOG10_4_OVER_3_MIN_EXPONENT: i32 = -2985; pub(crate) const FLOOR_LOG10_POW2_MINUS_LOG10_4_OVER_3_MAX_EXPONENT: i32 = 2936; pub(crate) const fn floor_log10_pow2_minus_log10_4_over_3< const MIN_EXPONENT: i32, const MAX_EXPONENT: i32, >( e: i32, ) -> i32 { enum Info0 {} impl TierInfo for Info0 { const TIER: usize = 0; const MULTIPLY: u32 = 77; const SUBTRACT: u32 = 31; const SHIFT: u32 = 8; const MIN_EXPONENT: i32 = -75; const MAX_EXPONENT: i32 = 129; type Next = Info1; } enum Info1 {} impl TierInfo for Info1 { const TIER: usize = 1; // 24-bits are enough in fact. const MULTIPLY: u32 = 19728; const SUBTRACT: u32 = 8241; const SHIFT: u32 = 16; // Formula itself holds on [-849,315]; [-424,315] is to ensure that // the output is within [-127,127]. const MIN_EXPONENT: i32 = -424; const MAX_EXPONENT: i32 = 315; type Next = Info2; } enum Info2 {} impl TierInfo for Info2 { const TIER: usize = 2; const MULTIPLY: u32 = 631305; const SUBTRACT: u32 = 261663; const SHIFT: u32 = 21; const MIN_EXPONENT: i32 = -2985; const MAX_EXPONENT: i32 = 2936; type Next = Self; } compute::(e) } pub(crate) const fn floor_log5_pow2(e: i32) -> i32 { enum Info0 {} impl TierInfo for Info0 { const TIER: usize = 0; const MULTIPLY: u32 = 225799; const SUBTRACT: u32 = 0; const SHIFT: u32 = 19; const MIN_EXPONENT: i32 = -1831; const MAX_EXPONENT: i32 = 1831; type Next = Self; } compute::(e) } pub(crate) const fn floor_log5_pow2_minus_log5_3(e: i32) -> i32 { enum Info0 {} impl TierInfo for Info0 { const TIER: usize = 0; const MULTIPLY: u32 = 451597; const SUBTRACT: u32 = 715764; const SHIFT: u32 = 20; const MIN_EXPONENT: i32 = -3543; const MAX_EXPONENT: i32 = 2427; type Next = Self; } compute::(e) } dragonbox_ecma-0.1.12/src/policy.rs000064400000000000000000000042011046102023000153060ustar 00000000000000// Translated from C++ to Rust. The original C++ code can be found at // https://github.com/jk-jeon/dragonbox and carries the following license: // // Copyright 2020-2025 Junekey Jeon // // The contents of this file may be used under the terms of // the Apache License v2.0 with LLVM Exceptions. // // (See accompanying file LICENSE-Apache or copy at // https://llvm.org/foundation/relicensing/LICENSE.txt) // // Alternatively, the contents of this file may be used under the terms of // the Boost Software License, Version 1.0. // (See accompanying file LICENSE-Boost or copy at // https://www.boost.org/LICENSE_1_0.txt) // // Unless required by applicable law or agreed to in writing, this software // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. use crate::CarrierUint; pub(crate) fn prefer_round_down(significand: CarrierUint) -> bool { significand % 2 != 0 } // Remove trailing zeros from decimal significand. // Adapted from upstream's remove_trailing_zeros_traits for binary64. // See: https://github.com/jk-jeon/rtz_benchmark // The idea of branchless search is by reddit users r/pigeon768 and r/TheoreticalDumbass. pub(crate) fn remove_trailing_zeros(significand: &mut CarrierUint, exponent: &mut i32) { let mut r = rotr64(significand.wrapping_mul(28999941890838049), 8); let mut b = r < 184467440738; let mut s = i32::from(b); *significand = if b { r } else { *significand }; r = rotr64(significand.wrapping_mul(182622766329724561), 4); b = r < 1844674407370956; s = s * 2 + i32::from(b); *significand = if b { r } else { *significand }; r = rotr64(significand.wrapping_mul(10330176681277348905), 2); b = r < 184467440737095517; s = s * 2 + i32::from(b); *significand = if b { r } else { *significand }; r = rotr64(significand.wrapping_mul(14757395258967641293), 1); b = r < 1844674407370955162; s = s * 2 + i32::from(b); *significand = if b { r } else { *significand }; *exponent += s; } const fn rotr64(n: CarrierUint, r: u32) -> CarrierUint { let r = r & 63; (n >> r) | (n << ((64 - r) & 63)) } dragonbox_ecma-0.1.12/src/to_chars.rs000064400000000000000000000514651046102023000156270ustar 00000000000000// Translated from C++ to Rust. The original C++ code can be found at // https://github.com/jk-jeon/dragonbox and carries the following license: // // Copyright 2020-2025 Junekey Jeon // // The contents of this file may be used under the terms of // the Apache License v2.0 with LLVM Exceptions. // // (See accompanying file LICENSE-Apache or copy at // https://llvm.org/foundation/relicensing/LICENSE.txt) // // Alternatively, the contents of this file may be used under the terms of // the Boost Software License, Version 1.0. // (See accompanying file LICENSE-Boost or copy at // https://www.boost.org/LICENSE_1_0.txt) // // Unless required by applicable law or agreed to in writing, this software // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. use core::ptr; // sign(1) + significand + decimal_point(1) + exp_marker(1) + exp_sign(1) + exp pub(crate) const MAX_OUTPUT_STRING_LENGTH: usize = 1 + crate::DECIMAL_SIGNIFICAND_DIGITS + 1 + 1 + 1 + crate::DECIMAL_EXPONENT_DIGITS; pub(crate) unsafe fn to_chars(x: f64, mut buffer: *mut u8) -> *mut u8 { let br = x.to_bits(); let s = crate::remove_exponent_bits(br); if crate::is_negative(s) { *buffer = b'-'; buffer = buffer.add(1); } if crate::is_nonzero(br) { let result = crate::to_decimal(x); to_chars_detail(result.significand, result.exponent, buffer) } else { *buffer = b'0'; *buffer.add(1) = b'E'; *buffer.add(2) = b'0'; buffer.add(3) } } type BytePair = [u8; 2]; #[rustfmt::skip] static RADIX_100_TABLE: [BytePair; 100] = [ [b'0', b'0'], [b'0', b'1'], [b'0', b'2'], [b'0', b'3'], [b'0', b'4'], [b'0', b'5'], [b'0', b'6'], [b'0', b'7'], [b'0', b'8'], [b'0', b'9'], [b'1', b'0'], [b'1', b'1'], [b'1', b'2'], [b'1', b'3'], [b'1', b'4'], [b'1', b'5'], [b'1', b'6'], [b'1', b'7'], [b'1', b'8'], [b'1', b'9'], [b'2', b'0'], [b'2', b'1'], [b'2', b'2'], [b'2', b'3'], [b'2', b'4'], [b'2', b'5'], [b'2', b'6'], [b'2', b'7'], [b'2', b'8'], [b'2', b'9'], [b'3', b'0'], [b'3', b'1'], [b'3', b'2'], [b'3', b'3'], [b'3', b'4'], [b'3', b'5'], [b'3', b'6'], [b'3', b'7'], [b'3', b'8'], [b'3', b'9'], [b'4', b'0'], [b'4', b'1'], [b'4', b'2'], [b'4', b'3'], [b'4', b'4'], [b'4', b'5'], [b'4', b'6'], [b'4', b'7'], [b'4', b'8'], [b'4', b'9'], [b'5', b'0'], [b'5', b'1'], [b'5', b'2'], [b'5', b'3'], [b'5', b'4'], [b'5', b'5'], [b'5', b'6'], [b'5', b'7'], [b'5', b'8'], [b'5', b'9'], [b'6', b'0'], [b'6', b'1'], [b'6', b'2'], [b'6', b'3'], [b'6', b'4'], [b'6', b'5'], [b'6', b'6'], [b'6', b'7'], [b'6', b'8'], [b'6', b'9'], [b'7', b'0'], [b'7', b'1'], [b'7', b'2'], [b'7', b'3'], [b'7', b'4'], [b'7', b'5'], [b'7', b'6'], [b'7', b'7'], [b'7', b'8'], [b'7', b'9'], [b'8', b'0'], [b'8', b'1'], [b'8', b'2'], [b'8', b'3'], [b'8', b'4'], [b'8', b'5'], [b'8', b'6'], [b'8', b'7'], [b'8', b'8'], [b'8', b'9'], [b'9', b'0'], [b'9', b'1'], [b'9', b'2'], [b'9', b'3'], [b'9', b'4'], [b'9', b'5'], [b'9', b'6'], [b'9', b'7'], [b'9', b'8'], [b'9', b'9'], ]; #[rustfmt::skip] static RADIX_100_HEAD_TABLE: [BytePair; 100] = [ [b'0', b'.'], [b'1', b'.'], [b'2', b'.'], [b'3', b'.'], [b'4', b'.'], [b'5', b'.'], [b'6', b'.'], [b'7', b'.'], [b'8', b'.'], [b'9', b'.'], [b'1', b'.'], [b'1', b'.'], [b'1', b'.'], [b'1', b'.'], [b'1', b'.'], [b'1', b'.'], [b'1', b'.'], [b'1', b'.'], [b'1', b'.'], [b'1', b'.'], [b'2', b'.'], [b'2', b'.'], [b'2', b'.'], [b'2', b'.'], [b'2', b'.'], [b'2', b'.'], [b'2', b'.'], [b'2', b'.'], [b'2', b'.'], [b'2', b'.'], [b'3', b'.'], [b'3', b'.'], [b'3', b'.'], [b'3', b'.'], [b'3', b'.'], [b'3', b'.'], [b'3', b'.'], [b'3', b'.'], [b'3', b'.'], [b'3', b'.'], [b'4', b'.'], [b'4', b'.'], [b'4', b'.'], [b'4', b'.'], [b'4', b'.'], [b'4', b'.'], [b'4', b'.'], [b'4', b'.'], [b'4', b'.'], [b'4', b'.'], [b'5', b'.'], [b'5', b'.'], [b'5', b'.'], [b'5', b'.'], [b'5', b'.'], [b'5', b'.'], [b'5', b'.'], [b'5', b'.'], [b'5', b'.'], [b'5', b'.'], [b'6', b'.'], [b'6', b'.'], [b'6', b'.'], [b'6', b'.'], [b'6', b'.'], [b'6', b'.'], [b'6', b'.'], [b'6', b'.'], [b'6', b'.'], [b'6', b'.'], [b'7', b'.'], [b'7', b'.'], [b'7', b'.'], [b'7', b'.'], [b'7', b'.'], [b'7', b'.'], [b'7', b'.'], [b'7', b'.'], [b'7', b'.'], [b'7', b'.'], [b'8', b'.'], [b'8', b'.'], [b'8', b'.'], [b'8', b'.'], [b'8', b'.'], [b'8', b'.'], [b'8', b'.'], [b'8', b'.'], [b'8', b'.'], [b'8', b'.'], [b'9', b'.'], [b'9', b'.'], [b'9', b'.'], [b'9', b'.'], [b'9', b'.'], [b'9', b'.'], [b'9', b'.'], [b'9', b'.'], [b'9', b'.'], [b'9', b'.'], ]; unsafe fn print_1_digit(n: u32, buffer: *mut u8) { const { assert!((b'0' & 0xf) == 0); } *buffer = b'0' | n as u8; } unsafe fn print_2_digits(n: u32, buffer: *mut u8) { let bp = *RADIX_100_TABLE.get_unchecked(n as usize); *buffer.cast::() = bp; } unsafe fn print_head_chars(n: u32, buffer: *mut u8) { let bp = *RADIX_100_HEAD_TABLE.get_unchecked(n as usize); *buffer.cast::() = bp; } // These digit generation routines are inspired by James Anhalt's itoa // algorithm: https://github.com/jeaiii/itoa // The main idea is for given n, find y such that floor(10^k * y / 2^32) = n // holds, where k is an appropriate integer depending on the length of n. For // example, if n = 1234567, we set k = 6. In this case, we have // floor(y / 2^32) = 1, // floor(10^2 * ((10^0 * y) mod 2^32) / 2^32) = 23, // floor(10^2 * ((10^2 * y) mod 2^32) / 2^32) = 45, and // floor(10^2 * ((10^4 * y) mod 2^32) / 2^32) = 67. // See https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/ for more explanation. unsafe fn print_9_digits(s32: u32, exponent: &mut i32, buffer: &mut *mut u8) { // -- IEEE-754 binary32 // Since we do not cut trailing zeros in advance, s32 must be of 6~9 digits // unless the original input was subnormal. In particular, when it is of 9 // digits it shouldn't have any trailing zeros. // -- IEEE-754 binary64 // In this case, s32 must be of 7~9 digits unless the input is subnormal, // and it shouldn't have any trailing zeros if it is of 9 digits. if s32 >= 1_0000_0000 { // 9 digits. // 1441151882 = ceil(2^57 / 1_0000_0000) + 1 let mut prod = u64::from(s32) * 1441151882; prod >>= 25; print_head_chars((prod >> 32) as u32, *buffer); prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(2)); prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(4)); prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(6)); prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(8)); *exponent += 8; *buffer = buffer.add(10); } else if s32 >= 100_0000 { // 7 or 8 digits. // 281474978 = ceil(2^48 / 100_0000) + 1 let mut prod = u64::from(s32) * 281474978; prod >>= 16; let head_digits = (prod >> 32) as u32; // If s32 is of 8 digits, increase the exponent by 7. // Otherwise, increase it by 6. *exponent += 6 + i32::from(head_digits >= 10); // Write the first digit and the decimal point. print_head_chars(head_digits, *buffer); // This third character may be overwritten later but we don't care. *buffer.add(2) = RADIX_100_TABLE.get_unchecked(head_digits as usize)[1]; // Remaining 6 digits are all zero? if prod as u32 <= ((1u64 << 32) / 100_0000) as u32 { // The number of characters actually need to be written is: // 1, if only the first digit is nonzero, which means that either s32 is of 7 // digits or it is of 8 digits but the second digit is zero, or // 3, otherwise. // Note that buffer[2] is never '0' if s32 is of 7 digits, because the input is // never zero. *buffer = buffer .add(1 + (usize::from(head_digits >= 10) & usize::from(*buffer.add(2) > b'0')) * 2); } else { // At least one of the remaining 6 digits are nonzero. // After this adjustment, now the first destination becomes buffer + 2. *buffer = buffer.add(usize::from(head_digits >= 10)); // Obtain the next two digits. prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(2)); // Remaining 4 digits are all zero? if prod as u32 <= ((1u64 << 32) / 1_0000) as u32 { *buffer = buffer.add(3 + usize::from(*buffer.add(3) > b'0')); } else { // At least one of the remaining 4 digits are nonzero. // Obtain the next two digits. prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(4)); // Remaining 2 digits are all zero? if prod as u32 <= ((1u64 << 32) / 100) as u32 { *buffer = buffer.add(5 + usize::from(*buffer.add(5) > b'0')); } else { // Obtain the last two digits. prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(6)); *buffer = buffer.add(7 + usize::from(*buffer.add(7) > b'0')); } } } } else if s32 >= 1_0000 { // 5 or 6 digits. // 429497 = ceil(2^32 / 1_0000) let mut prod = u64::from(s32) * 429497; let head_digits = (prod >> 32) as u32; // If s32 is of 6 digits, increase the exponent by 5. // Otherwise, increase it by 4. *exponent += 4 + i32::from(head_digits >= 10); // Write the first digit and the decimal point. print_head_chars(head_digits, *buffer); // This third character may be overwritten later but we don't care. *buffer.add(2) = RADIX_100_TABLE.get_unchecked(head_digits as usize)[1]; // Remaining 4 digits are all zero? if prod as u32 <= ((1u64 << 32) / 1_0000) as u32 { // The number of characters actually written is 1 or 3, similarly to the case of // 7 or 8 digits. *buffer = buffer .add(1 + (usize::from(head_digits >= 10) & usize::from(*buffer.add(2) > b'0')) * 2); } else { // At least one of the remaining 4 digits are nonzero. // After this adjustment, now the first destination becomes buffer + 2. *buffer = buffer.add(usize::from(head_digits >= 10)); // Obtain the next two digits. prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(2)); // Remaining 2 digits are all zero? if prod as u32 <= ((1u64 << 32) / 100) as u32 { *buffer = buffer.add(3 + usize::from(*buffer.add(3) > b'0')); } else { // Obtain the last two digits. prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(4)); *buffer = buffer.add(5 + usize::from(*buffer.add(5) > b'0')); } } } else if s32 >= 100 { // 3 or 4 digits. // 42949673 = ceil(2^32 / 100) let mut prod = u64::from(s32) * 42949673; let head_digits = (prod >> 32) as u32; // If s32 is of 4 digits, increase the exponent by 3. // Otherwise, increase it by 2. *exponent += 2 + i32::from(head_digits >= 10); // Write the first digit and the decimal point. print_head_chars(head_digits, *buffer); // This third character may be overwritten later but we don't care. *buffer.add(2) = RADIX_100_TABLE.get_unchecked(head_digits as usize)[1]; // Remaining 2 digits are all zero? if prod as u32 <= ((1u64 << 32) / 100) as u32 { // The number of characters actually written is 1 or 3, similarly to the case of // 7 or 8 digits. *buffer = buffer .add(1 + (usize::from(head_digits >= 10) & usize::from(*buffer.add(2) > b'0')) * 2); } else { // At least one of the remaining 2 digits are nonzero. // After this adjustment, now the first destination becomes buffer + 2. *buffer = buffer.add(usize::from(head_digits >= 10)); // Obtain the last two digits. prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(2)); *buffer = buffer.add(3 + usize::from(*buffer.add(3) > b'0')); } } else { // 1 or 2 digits. // If s32 is of 2 digits, increase the exponent by 1. *exponent += i32::from(s32 >= 10); // Write the first digit and the decimal point. print_head_chars(s32, *buffer); // This third character may be overwritten later but we don't care. *buffer.add(2) = RADIX_100_TABLE.get_unchecked(s32 as usize)[1]; // The number of characters actually written is 1 or 3, similarly to the case of // 7 or 8 digits. *buffer = buffer.add(1 + (usize::from(s32 >= 10) & usize::from(*buffer.add(2) > b'0')) * 2); } } unsafe fn to_chars_detail(significand: u64, mut exponent: i32, mut buffer: *mut u8) -> *mut u8 { // Print significand by decomposing it into a 9-digit block and a 8-digit block. let first_block: u32; let second_block: u32; let no_second_block: bool; if significand >= 1_0000_0000 { first_block = (significand / 1_0000_0000) as u32; second_block = (significand as u32).wrapping_sub(first_block.wrapping_mul(1_0000_0000)); exponent += 8; no_second_block = second_block == 0; } else { first_block = significand as u32; second_block = 0; no_second_block = true; } if no_second_block { print_9_digits(first_block, &mut exponent, &mut buffer); } else { // We proceed similarly to print_9_digits(), but since we do not need to remove // trailing zeros, the procedure is a bit simpler. if first_block >= 1_0000_0000 { // The input is of 17 digits, thus there should be no trailing zero at all. // The first block is of 9 digits. // 1441151882 = ceil(2^57 / 1_0000_0000) + 1 let mut prod = u64::from(first_block) * 1441151882; prod >>= 25; print_head_chars((prod >> 32) as u32, buffer); prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(2)); prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(4)); prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(6)); prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(8)); // The second block is of 8 digits. // 281474978 = ceil(2^48 / 100'0000) + 1 prod = u64::from(second_block) * 281474978; prod >>= 16; prod += 1; print_2_digits((prod >> 32) as u32, buffer.add(10)); prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(12)); prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(14)); prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(16)); exponent += 8; buffer = buffer.add(18); } else { if first_block >= 100_0000 { // 7 or 8 digits. // 281474978 = ceil(2^48 / 100_0000) + 1 let mut prod = u64::from(first_block) * 281474978; prod >>= 16; let head_digits = (prod >> 32) as u32; print_head_chars(head_digits, buffer); *buffer.add(2) = RADIX_100_TABLE.get_unchecked(head_digits as usize)[1]; exponent += 6 + i32::from(head_digits >= 10); buffer = buffer.add(usize::from(head_digits >= 10)); // Print remaining 6 digits. prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(2)); prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(4)); prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(6)); buffer = buffer.add(8); } else if first_block >= 1_0000 { // 5 or 6 digits. // 429497 = ceil(2^32 / 1_0000) let mut prod = u64::from(first_block) * 429497; let head_digits = (prod >> 32) as u32; print_head_chars(head_digits, buffer); *buffer.add(2) = RADIX_100_TABLE.get_unchecked(head_digits as usize)[1]; exponent += 4 + i32::from(head_digits >= 10); buffer = buffer.add(usize::from(head_digits >= 10)); // Print remaining 4 digits. prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(2)); prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(4)); buffer = buffer.add(6); } else if first_block >= 100 { // 3 or 4 digits. // 42949673 = ceil(2^32 / 100) let mut prod = u64::from(first_block) * 42949673; let head_digits = (prod >> 32) as u32; print_head_chars(head_digits, buffer); *buffer.add(2) = RADIX_100_TABLE.get_unchecked(head_digits as usize)[1]; exponent += 2 + i32::from(head_digits >= 10); buffer = buffer.add(usize::from(head_digits >= 10)); // Print remaining 2 digits. prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(2)); buffer = buffer.add(4); } else { // 1 or 2 digits. print_head_chars(first_block, buffer); *buffer.add(2) = RADIX_100_TABLE.get_unchecked(first_block as usize)[1]; exponent += i32::from(first_block >= 10); buffer = buffer.add(2 + usize::from(first_block >= 10)); } // Next, print the second block. // The second block is of 8 digits, but we may have trailing zeros. // 281474978 = ceil(2^48 / 100_0000) + 1 let mut prod = u64::from(second_block) * 281474978; prod >>= 16; prod += 1; print_2_digits((prod >> 32) as u32, buffer); // Remaining 6 digits are all zero? if prod as u32 <= ((1u64 << 32) / 100_0000) as u32 { buffer = buffer.add(1 + usize::from(*buffer.add(1) > b'0')); } else { // Obtain the next two digits. prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(2)); // Remaining 4 digits are all zero? if prod as u32 <= ((1u64 << 32) / 1_0000) as u32 { buffer = buffer.add(3 + usize::from(*buffer.add(3) > b'0')); } else { // Obtain the next two digits. prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(4)); // Remaining 2 digits are all zero? if prod as u32 <= ((1u64 << 32) / 100) as u32 { buffer = buffer.add(5 + usize::from(*buffer.add(5) > b'0')); } else { // Obtain the last two digits. prod = (prod & 0xffffffff) * 100; print_2_digits((prod >> 32) as u32, buffer.add(6)); buffer = buffer.add(7 + usize::from(*buffer.add(7) > b'0')); } } } } } // Print exponent and return if exponent < 0 { ptr::copy_nonoverlapping(b"E-".as_ptr().cast::(), buffer, 2); buffer = buffer.add(2); exponent = -exponent; } else { *buffer = b'E'; buffer = buffer.add(1); } if exponent >= 100 { // d1 = exponent / 10; d2 = exponent % 10; // 6554 = ceil(2^16 / 10) let d1 = (exponent as u32 * 6554) >> 16; let d2 = exponent as u32 - 10 * d1; print_2_digits(d1, buffer); print_1_digit(d2, buffer.add(2)); buffer = buffer.add(3); } else if exponent >= 10 { print_2_digits(exponent as u32, buffer); buffer = buffer.add(2); } else { print_1_digit(exponent as u32, buffer); buffer = buffer.add(1); } buffer } dragonbox_ecma-0.1.12/src/to_chars_ecma.rs000064400000000000000000000270401046102023000166040ustar 00000000000000// https://chromium-review.googlesource.com/c/v8/v8/+/6494437 // Ported from V8's `DoubleToStringView` ECMA-262 compliant implementation // This provides JavaScript Number.toString() behavior with dragonbox performance use core::ptr; // Maximum length of output string for any f64 number // https://viewer.scuttlebot.io/%25LQo5KOMeR%2Baj%2BEj0JVg3qLRqr%2BwiKo74nS8Uz7o0LDM%3D.sha256 // -0.0000015809161985788154 pub(crate) const MAX_OUTPUT_STRING_LENGTH: usize = 25; // Lookup tables for fast digit conversion (direct port from V8) #[rustfmt::skip] static RADIX_100_TABLE: [u8; 200] = [ b'0', b'0', b'0', b'1', b'0', b'2', b'0', b'3', b'0', b'4', b'0', b'5', b'0', b'6', b'0', b'7', b'0', b'8', b'0', b'9', b'1', b'0', b'1', b'1', b'1', b'2', b'1', b'3', b'1', b'4', b'1', b'5', b'1', b'6', b'1', b'7', b'1', b'8', b'1', b'9', b'2', b'0', b'2', b'1', b'2', b'2', b'2', b'3', b'2', b'4', b'2', b'5', b'2', b'6', b'2', b'7', b'2', b'8', b'2', b'9', b'3', b'0', b'3', b'1', b'3', b'2', b'3', b'3', b'3', b'4', b'3', b'5', b'3', b'6', b'3', b'7', b'3', b'8', b'3', b'9', b'4', b'0', b'4', b'1', b'4', b'2', b'4', b'3', b'4', b'4', b'4', b'5', b'4', b'6', b'4', b'7', b'4', b'8', b'4', b'9', b'5', b'0', b'5', b'1', b'5', b'2', b'5', b'3', b'5', b'4', b'5', b'5', b'5', b'6', b'5', b'7', b'5', b'8', b'5', b'9', b'6', b'0', b'6', b'1', b'6', b'2', b'6', b'3', b'6', b'4', b'6', b'5', b'6', b'6', b'6', b'7', b'6', b'8', b'6', b'9', b'7', b'0', b'7', b'1', b'7', b'2', b'7', b'3', b'7', b'4', b'7', b'5', b'7', b'6', b'7', b'7', b'7', b'8', b'7', b'9', b'8', b'0', b'8', b'1', b'8', b'2', b'8', b'3', b'8', b'4', b'8', b'5', b'8', b'6', b'8', b'7', b'8', b'8', b'8', b'9', b'9', b'0', b'9', b'1', b'9', b'2', b'9', b'3', b'9', b'4', b'9', b'5', b'9', b'6', b'9', b'7', b'9', b'8', b'9', b'9', ]; #[rustfmt::skip] static RADIX_100_HEAD_TABLE: [u8; 200] = [ 0x00, 0x00, b'1', 0x00, b'2', 0x00, b'3', 0x00, b'4', 0x00, b'5', 0x00, b'6', 0x00, b'7', 0x00, b'8', 0x00, b'9', 0x00, b'1', b'0', b'1', b'1', b'1', b'2', b'1', b'3', b'1', b'4', b'1', b'5', b'1', b'6', b'1', b'7', b'1', b'8', b'1', b'9', b'2', b'0', b'2', b'1', b'2', b'2', b'2', b'3', b'2', b'4', b'2', b'5', b'2', b'6', b'2', b'7', b'2', b'8', b'2', b'9', b'3', b'0', b'3', b'1', b'3', b'2', b'3', b'3', b'3', b'4', b'3', b'5', b'3', b'6', b'3', b'7', b'3', b'8', b'3', b'9', b'4', b'0', b'4', b'1', b'4', b'2', b'4', b'3', b'4', b'4', b'4', b'5', b'4', b'6', b'4', b'7', b'4', b'8', b'4', b'9', b'5', b'0', b'5', b'1', b'5', b'2', b'5', b'3', b'5', b'4', b'5', b'5', b'5', b'6', b'5', b'7', b'5', b'8', b'5', b'9', b'6', b'0', b'6', b'1', b'6', b'2', b'6', b'3', b'6', b'4', b'6', b'5', b'6', b'6', b'6', b'7', b'6', b'8', b'6', b'9', b'7', b'0', b'7', b'1', b'7', b'2', b'7', b'3', b'7', b'4', b'7', b'5', b'7', b'6', b'7', b'7', b'7', b'8', b'7', b'9', b'8', b'0', b'8', b'1', b'8', b'2', b'8', b'3', b'8', b'4', b'8', b'5', b'8', b'6', b'8', b'7', b'8', b'8', b'8', b'9', b'9', b'0', b'9', b'1', b'9', b'2', b'9', b'3', b'9', b'4', b'9', b'5', b'9', b'6', b'9', b'7', b'9', b'8', b'9', b'9', ]; // Main entry point for number to string conversion pub(crate) unsafe fn to_chars(x: f64, mut buffer: *mut u8) -> *mut u8 { let br = x.to_bits(); let s = crate::remove_exponent_bits(br); if crate::is_nonzero(br) { if crate::is_negative(s) { *buffer = b'-'; buffer = buffer.add(1); } let result = crate::to_decimal(x); to_chars_detail(result.significand, result.exponent, buffer) } else { *buffer = b'0'; buffer.add(1) } } // V8's Convert2Digits function unsafe fn convert_2_digits(n: u8, buffer: *mut u8) { debug_assert!(n < 100); let index = (n as usize) * 2; ptr::copy_nonoverlapping(RADIX_100_TABLE.as_ptr().add(index), buffer, 2); } // V8's ConvertHeadDigits function - returns digit count unsafe fn convert_head_digits(n: u8, buffer: *mut u8) -> u8 { debug_assert!(n < 100); let digit_count = 1 + u8::from(n >= 10); let index = (n as usize) * 2; ptr::copy_nonoverlapping( RADIX_100_HEAD_TABLE.as_ptr().add(index), buffer, digit_count as usize, ); digit_count } // V8's Convert8Digits function unsafe fn convert_8_digits(n: u32, buffer: *mut u8) { const K_UINT32_MASK: u64 = u32::MAX as u64; // 281474978 = ceil(2^48 / 1'000'000) + 1 let mut prod = u64::from(n) * 281474978; prod >>= 16; prod += 1; convert_2_digits((prod >> 32) as u8, buffer); prod = (prod & K_UINT32_MASK) * 100; convert_2_digits((prod >> 32) as u8, buffer.add(2)); prod = (prod & K_UINT32_MASK) * 100; convert_2_digits((prod >> 32) as u8, buffer.add(4)); prod = (prod & K_UINT32_MASK) * 100; convert_2_digits((prod >> 32) as u8, buffer.add(6)); } // V8's ConvertUpTo9Digits function - returns digit count unsafe fn convert_up_to_9_digits(n: u32, mut buffer: *mut u8) -> u8 { const K_UINT32_MASK: u64 = u32::MAX as u64; if n >= 100_000_000 { // 9 digits. // 1441151882 = ceil(2^57 / 100'000'000) + 1 let mut prod = u64::from(n) * 1441151882; prod >>= 25; let head_digit = (prod >> 32) as u8; debug_assert!(head_digit < 10); *buffer = b'0' + head_digit; // Print remaining 8 digits. prod = (prod & K_UINT32_MASK) * 100; convert_2_digits((prod >> 32) as u8, buffer.add(1)); prod = (prod & K_UINT32_MASK) * 100; convert_2_digits((prod >> 32) as u8, buffer.add(3)); prod = (prod & K_UINT32_MASK) * 100; convert_2_digits((prod >> 32) as u8, buffer.add(5)); prod = (prod & K_UINT32_MASK) * 100; convert_2_digits((prod >> 32) as u8, buffer.add(7)); return 9; } if n >= 1_000_000 { // 7 or 8 digits. // 281474978 = ceil(2^48 / 1'000'000) + 1 let mut prod = u64::from(n) * 281474978; prod >>= 16; let head_digits = (prod >> 32) as u8; let head_digit_count = convert_head_digits(head_digits, buffer); buffer = buffer.add(head_digit_count as usize); // Print remaining 6 digits. prod = (prod & K_UINT32_MASK) * 100; convert_2_digits((prod >> 32) as u8, buffer); prod = (prod & K_UINT32_MASK) * 100; convert_2_digits((prod >> 32) as u8, buffer.add(2)); prod = (prod & K_UINT32_MASK) * 100; convert_2_digits((prod >> 32) as u8, buffer.add(4)); return 6 + head_digit_count; } if n >= 10_000 { // 5 or 6 digits. // 429497 = ceil(2^32 / 10'000) let mut prod = u64::from(n) * 429497; let head_digits = (prod >> 32) as u8; let head_digit_count = convert_head_digits(head_digits, buffer); buffer = buffer.add(head_digit_count as usize); // Print remaining 4 digits. prod = (prod & K_UINT32_MASK) * 100; convert_2_digits((prod >> 32) as u8, buffer); prod = (prod & K_UINT32_MASK) * 100; convert_2_digits((prod >> 32) as u8, buffer.add(2)); return 4 + head_digit_count; } if n >= 100 { // 3 or 4 digits. // 42949673 = ceil(2^32 / 100) let mut prod = u64::from(n) * 42949673; let head_digits = (prod >> 32) as u8; let head_digit_count = convert_head_digits(head_digits, buffer); buffer = buffer.add(head_digit_count as usize); // Print remaining 2 digits. prod = (prod & K_UINT32_MASK) * 100; convert_2_digits((prod >> 32) as u8, buffer); return 2 + head_digit_count; } // 1 or 2 digits. convert_head_digits(n as u8, buffer) } // V8's SignificandToChars function - returns digit count unsafe fn significand_to_chars(n: u64, buffer: *mut u8) -> u8 { debug_assert!(n < 99999999999999999); // Only supports up to 17 digits if n >= 100_000_000 { // If we have at least 9 digits, split into 2 blocks. The second one always // has exactly 8 digits. let first_block = (n / 100_000_000) as u32; let second_block = (n % 100_000_000) as u32; let first_block_digits = convert_up_to_9_digits(first_block, buffer); convert_8_digits(second_block, buffer.add(first_block_digits as usize)); first_block_digits + 8 } else { convert_up_to_9_digits(n as u32, buffer) } } // Add exponent helper - ported from V8's more efficient implementation unsafe fn add_exponent(exp: i32, mut buffer: *mut u8) -> *mut u8 { debug_assert!(exp >= 0); debug_assert!(exp <= 999); if exp >= 100 { // d1 = exp / 10; d2 = exp % 10; // 6554 = ceil(2^16 / 10) let d1 = ((exp as u32) * 6554) >> 16; let d2 = (exp as u32) - 10 * d1; convert_2_digits(d1 as u8, buffer); buffer = buffer.add(2); *buffer = b'0' + d2 as u8; buffer = buffer.add(1); } else if exp >= 10 { convert_2_digits(exp as u8, buffer); buffer = buffer.add(2); } else { *buffer = b'0' + exp as u8; buffer = buffer.add(1); } buffer } // Main formatting function that implements ECMA-262 section 9.8.1 unsafe fn to_chars_detail(significand: u64, exponent: i32, mut buffer: *mut u8) -> *mut u8 { // Convert significand to decimal string using V8's optimized functions // No need for temporary buffer since we can write directly to the output buffer let mut decimal_rep = [0u8; 17]; let length = i32::from(significand_to_chars(significand, decimal_rep.as_mut_ptr())); let decimal_point = length as i32 + exponent; if length <= decimal_point && decimal_point <= 21 { // ECMA-262 section 9.8.1 step 6. ptr::copy_nonoverlapping(decimal_rep.as_ptr(), buffer, length as usize); buffer = buffer.add(length as usize); // Add padding zeros for _ in 0..(decimal_point - length) { *buffer = b'0'; buffer = buffer.add(1); } } else if 0 < decimal_point && decimal_point <= 21 { // ECMA-262 section 9.8.1 step 7. ptr::copy_nonoverlapping(decimal_rep.as_ptr(), buffer, decimal_point as usize); buffer = buffer.add(decimal_point as usize); *buffer = b'.'; buffer = buffer.add(1); let remaining = length - decimal_point; ptr::copy_nonoverlapping( decimal_rep.as_ptr().add(decimal_point as usize), buffer, remaining as usize, ); buffer = buffer.add(remaining as usize); } else if decimal_point <= 0 && decimal_point > -6 { // ECMA-262 section 9.8.1 step 8. ptr::copy_nonoverlapping(b"0.".as_ptr(), buffer, 2); buffer = buffer.add(2); // Add leading zeros for _ in 0..(-decimal_point) { *buffer = b'0'; buffer = buffer.add(1); } ptr::copy_nonoverlapping(decimal_rep.as_ptr(), buffer, length as usize); buffer = buffer.add(length as usize); } else { // ECMA-262 section 9.8.1 step 9 and 10 combined. *buffer = decimal_rep[0]; buffer = buffer.add(1); if length != 1 { *buffer = b'.'; buffer = buffer.add(1); ptr::copy_nonoverlapping(decimal_rep.as_ptr().add(1), buffer, (length - 1) as usize); buffer = buffer.add((length - 1) as usize); } *buffer = b'e'; buffer = buffer.add(1); let exp = decimal_point - 1; if exp >= 0 { *buffer = b'+'; } else { *buffer = b'-'; } buffer = buffer.add(1); buffer = add_exponent(exp.abs(), buffer); } buffer } dragonbox_ecma-0.1.12/src/wuint.rs000064400000000000000000000032101046102023000151540ustar 00000000000000// Translated from C++ to Rust. The original C++ code can be found at // https://github.com/jk-jeon/dragonbox and carries the following license: // // Copyright 2020-2025 Junekey Jeon // // The contents of this file may be used under the terms of // the Apache License v2.0 with LLVM Exceptions. // // (See accompanying file LICENSE-Apache or copy at // https://llvm.org/foundation/relicensing/LICENSE.txt) // // Alternatively, the contents of this file may be used under the terms of // the Boost Software License, Version 1.0. // (See accompanying file LICENSE-Boost or copy at // https://www.boost.org/LICENSE_1_0.txt) // // Unless required by applicable law or agreed to in writing, this software // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. use crate::cache::EntryTypeExt as _; // Get high half of the 128-bit result of multiplication of two 64-bit unsigned // integers. pub(crate) fn umul128_upper64(x: u64, y: u64) -> u64 { let p = u128::from(x) * u128::from(y); (p >> 64) as u64 } // Get upper 128-bits of multiplication of a 64-bit unsigned integer and a // 128-bit unsigned integer. pub(crate) fn umul192_upper128(x: u64, y: u128) -> u128 { let mut r = u128::from(x) * u128::from(y.high()); r += u128::from(umul128_upper64(x, y.low())); r } // Get lower 128-bits of multiplication of a 64-bit unsigned integer and a // 128-bit unsigned integer. pub(crate) fn umul192_lower128(x: u64, y: u128) -> u128 { let high = x.wrapping_mul(y.high()); let high_low = u128::from(x) * u128::from(y.low()); (u128::from(high) << 64).wrapping_add(high_low) } dragonbox_ecma-0.1.12/tests/binary64_test.rs000064400000000000000000000253101046102023000170630ustar 00000000000000// Translated from C to Rust. The original C code can be found at // https://github.com/ulfjack/ryu and carries the following license: // // Copyright 2018 Ulf Adams // // The contents of this file may be used under the terms of the Apache License, // Version 2.0. // // (See accompanying file LICENSE-Apache or copy at // http://www.apache.org/licenses/LICENSE-2.0) // // Alternatively, the contents of this file may be used under the terms of // the Boost Software License, Version 1.0. // (See accompanying file LICENSE-Boost or copy at // https://www.boost.org/LICENSE_1_0.txt) // // Unless required by applicable law or agreed to in writing, this software // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. #![allow( clippy::approx_constant, clippy::cast_lossless, clippy::excessive_precision, clippy::float_cmp, clippy::int_plus_one, clippy::non_ascii_literal, clippy::unreadable_literal, clippy::unseparated_literal_suffix )] #[macro_use] mod macros; use dragonbox_ecma as dragonbox; use std::f64; fn to_chars(f: f64) -> String { dragonbox::Buffer::new().format(f).to_owned() } fn ieee_parts_to_double(sign: bool, ieee_exponent: u32, ieee_mantissa: u64) -> f64 { assert!(ieee_exponent <= 2047); assert!(ieee_mantissa <= (1u64 << 53) - 1); f64::from_bits(((sign as u64) << 63) | ((ieee_exponent as u64) << 52) | ieee_mantissa) } #[test] fn test_dragonbox() { check!(3E-1); check!(1.234E15); check!(2.71828E0); check!(1.1E128); check!(1.1E-64); check!(2.718281828459045E0); check!(5E-324); check!(1.7976931348623157E308); } #[test] fn test_random() { let n = if cfg!(miri) { 100 } else { 1000000 }; let mut buffer = dragonbox::Buffer::new(); for _ in 0..n { let f: f64 = rand::random(); assert_eq!(f, buffer.format_finite(f).parse().unwrap()); } } #[test] fn test_basic() { check!(0E0); check!(-0E0); check!(1E0); check!(-1E0); assert_eq!(to_chars(f64::NAN.copysign(1.0)), "NaN"); assert_eq!(to_chars(f64::NAN.copysign(-1.0)), "NaN"); assert_eq!(to_chars(f64::INFINITY), "inf"); assert_eq!(to_chars(f64::NEG_INFINITY), "-inf"); } #[test] fn test_switch_to_subnormal() { check!(2.2250738585072014E-308); } #[test] fn test_min_and_max() { assert_eq!(f64::from_bits(0x7fefffffffffffff), 1.7976931348623157E308); check!(1.7976931348623157E308); assert_eq!(f64::from_bits(1), 5E-324); check!(5E-324); } #[test] fn test_lots_of_trailing_zeros() { check!(2.9802322387695312E-8); } #[test] fn test_regression() { check!(-2.109808898695963E16); check!(4.940656E-318); check!(1.18575755E-316); check!(2.989102097996E-312); check!(9.0608011534336E15); check!(4.708356024711512E18); check!(9.409340012568248E18); check!(1.2345678E0); } #[test] fn test_looks_like_pow5() { // These numbers have a mantissa that is a multiple of the largest power of // 5 that fits, and an exponent that causes the computation for q to result // in 22, which is a corner case for Ryū. assert_eq!(f64::from_bits(0x4830F0CF064DD592), 5.764607523034235E39); check!(5.764607523034235E39); assert_eq!(f64::from_bits(0x4840F0CF064DD592), 1.152921504606847E40); check!(1.152921504606847E40); assert_eq!(f64::from_bits(0x4850F0CF064DD592), 2.305843009213694E40); check!(2.305843009213694E40); } #[test] fn test_output_length() { check!(1E0); // already tested in Basic check!(1.2E0); check!(1.23E0); check!(1.234E0); check!(1.2345E0); check!(1.23456E0); check!(1.234567E0); check!(1.2345678E0); // already tested in Regression check!(1.23456789E0); check!(1.234567895E0); // 1.234567890 would be trimmed check!(1.2345678901E0); check!(1.23456789012E0); check!(1.234567890123E0); check!(1.2345678901234E0); check!(1.23456789012345E0); check!(1.234567890123456E0); check!(1.2345678901234567E0); // Test 32-bit chunking check!(4.294967294E0); // 2^32 - 2 check!(4.294967295E0); // 2^32 - 1 check!(4.294967296E0); // 2^32 check!(4.294967297E0); // 2^32 + 1 check!(4.294967298E0); // 2^32 + 2 } // Test min, max shift values in shiftright128 #[test] fn test_min_max_shift() { let max_mantissa = (1u64 << 53) - 1; // 32-bit opt-size=0: 49 <= dist <= 50 // 32-bit opt-size=1: 30 <= dist <= 50 // 64-bit opt-size=0: 50 <= dist <= 50 // 64-bit opt-size=1: 30 <= dist <= 50 assert_eq!(1.7800590868057611E-307, ieee_parts_to_double(false, 4, 0)); check!(1.7800590868057611E-307); // 32-bit opt-size=0: 49 <= dist <= 49 // 32-bit opt-size=1: 28 <= dist <= 49 // 64-bit opt-size=0: 50 <= dist <= 50 // 64-bit opt-size=1: 28 <= dist <= 50 assert_eq!( 2.8480945388892175E-306, ieee_parts_to_double(false, 6, max_mantissa) ); check!(2.8480945388892175E-306); // 32-bit opt-size=0: 52 <= dist <= 53 // 32-bit opt-size=1: 2 <= dist <= 53 // 64-bit opt-size=0: 53 <= dist <= 53 // 64-bit opt-size=1: 2 <= dist <= 53 assert_eq!(2.446494580089078E-296, ieee_parts_to_double(false, 41, 0)); check!(2.446494580089078E-296); // 32-bit opt-size=0: 52 <= dist <= 52 // 32-bit opt-size=1: 2 <= dist <= 52 // 64-bit opt-size=0: 53 <= dist <= 53 // 64-bit opt-size=1: 2 <= dist <= 53 assert_eq!( 4.8929891601781557E-296, ieee_parts_to_double(false, 40, max_mantissa) ); check!(4.8929891601781557E-296); // 32-bit opt-size=0: 57 <= dist <= 58 // 32-bit opt-size=1: 57 <= dist <= 58 // 64-bit opt-size=0: 58 <= dist <= 58 // 64-bit opt-size=1: 58 <= dist <= 58 assert_eq!(1.8014398509481984E16, ieee_parts_to_double(false, 1077, 0)); check!(1.8014398509481984E16); // 32-bit opt-size=0: 57 <= dist <= 57 // 32-bit opt-size=1: 57 <= dist <= 57 // 64-bit opt-size=0: 58 <= dist <= 58 // 64-bit opt-size=1: 58 <= dist <= 58 assert_eq!( 3.6028797018963964E16, ieee_parts_to_double(false, 1076, max_mantissa) ); check!(3.6028797018963964E16); // 32-bit opt-size=0: 51 <= dist <= 52 // 32-bit opt-size=1: 51 <= dist <= 59 // 64-bit opt-size=0: 52 <= dist <= 52 // 64-bit opt-size=1: 52 <= dist <= 59 assert_eq!(2.900835519859558E-216, ieee_parts_to_double(false, 307, 0)); check!(2.900835519859558E-216); // 32-bit opt-size=0: 51 <= dist <= 51 // 32-bit opt-size=1: 51 <= dist <= 59 // 64-bit opt-size=0: 52 <= dist <= 52 // 64-bit opt-size=1: 52 <= dist <= 59 assert_eq!( 5.801671039719115E-216, ieee_parts_to_double(false, 306, max_mantissa) ); check!(5.801671039719115E-216); // https://github.com/ulfjack/ryu/commit/19e44d16d80236f5de25800f56d82606d1be00b9#commitcomment-30146483 // 32-bit opt-size=0: 49 <= dist <= 49 // 32-bit opt-size=1: 44 <= dist <= 49 // 64-bit opt-size=0: 50 <= dist <= 50 // 64-bit opt-size=1: 44 <= dist <= 50 assert_eq!( 3.196104012172126E-27, ieee_parts_to_double(false, 934, 0x000FA7161A4D6E0C) ); check!(3.196104012172126E-27); } #[test] fn test_small_integers() { check!(9.007199254740991E15); // 2^53-1 check!(9.007199254740992E15); // 2^53 check!(1E0); check!(1.2E1); check!(1.23E2); check!(1.234E3); check!(1.2345E4); check!(1.23456E5); check!(1.234567E6); check!(1.2345678E7); check!(1.23456789E8); check!(1.23456789E9); check!(1.234567895E10); check!(1.2345678901E11); check!(1.23456789012E12); check!(1.234567890123E13); check!(1.2345678901234E14); check!(1.23456789012345E15); check!(1.234567890123456E16); // 10^i check!(1E0); check!(1E1); check!(1E2); check!(1E3); check!(1E4); check!(1E5); check!(1E6); check!(1E7); check!(1E8); check!(1E9); check!(1E10); check!(1E11); check!(1E12); check!(1E13); check!(1E14); check!(1E15); // 10^15 + 10^i check!(1.000000000000001E15); check!(1.00000000000001E15); check!(1.0000000000001E15); check!(1.000000000001E15); check!(1.00000000001E15); check!(1.0000000001E15); check!(1.000000001E15); check!(1.00000001E15); check!(1.0000001E15); check!(1.000001E15); check!(1.00001E15); check!(1.0001E15); check!(1.001E15); check!(1.01E15); check!(1.1E15); // Largest power of 2 <= 10^(i+1) check!(8E0); check!(6.4E1); check!(5.12E2); check!(8.192E3); check!(6.5536E4); check!(5.24288E5); check!(8.388608E6); check!(6.7108864E7); check!(5.36870912E8); check!(8.589934592E9); check!(6.8719476736E10); check!(5.49755813888E11); check!(8.796093022208E12); check!(7.0368744177664E13); check!(5.62949953421312E14); check!(9.007199254740992E15); // 1000 * (Largest power of 2 <= 10^(i+1)) check!(8E3); check!(6.4E4); check!(5.12E5); check!(8.192E6); check!(6.5536E7); check!(5.24288E8); check!(8.388608E9); check!(6.7108864E10); check!(5.36870912E11); check!(8.589934592E12); check!(6.8719476736E13); check!(5.49755813888E14); check!(8.796093022208E15); } #[test] fn test_issue_3() { assert_eq!(to_chars(1.0902420340782359E+57), "1.0902420340782359E57"); assert_eq!(to_chars(5.3461812015486243E+26), "5.346181201548624E26"); assert_eq!(to_chars(2.8674588045599296E+66), "2.8674588045599296E66"); assert_eq!(to_chars(1.2182856909681335E+77), "1.2182856909681335E77"); assert_eq!(to_chars(2.0596292913323055E+69), "2.0596292913323055E69"); assert_eq!(to_chars(1.3331169462028886E+60), "1.3331169462028886E60"); } #[test] fn test_critical_boundary_case() { // See https://github.com/dtolnay/dragonbox/pull/7#discussion_r2169239437 let test_value = f64::from_bits(0x3FF0000000000001); // 1 + 2^-52 let result = to_chars(test_value); let expected = "1.0000000000000002E0"; assert_eq!( result, expected, "Critical boundary case failed. Input: {test_value}, Expected: {expected}, Got: {result}", ); // Also verify round-trip conversion assert_eq!( test_value, result.parse().unwrap(), "Round-trip conversion failed for critical boundary case", ); // Additional test case: A power of 2 boundary that might trigger the condition // This is 2^53 + 1, which should trigger our edge case handling let test_value = f64::from_bits(0x4350000000000001); // 2^53 + 1 let result = to_chars(test_value); // With the correct logic, this should properly round-trip assert_eq!( test_value, result.parse().unwrap(), "Failed for power of 2 boundary case: {test_value}, result: {result}", ); } dragonbox_ecma-0.1.12/tests/binary64_test_ecma.rs000064400000000000000000000253341046102023000200560ustar 00000000000000// Translated from C to Rust. The original C code can be found at // https://github.com/ulfjack/ryu and carries the following license: // // Copyright 2018 Ulf Adams // // The contents of this file may be used under the terms of the Apache License, // Version 2.0. // // (See accompanying file LICENSE-Apache or copy at // http://www.apache.org/licenses/LICENSE-2.0) // // Alternatively, the contents of this file may be used under the terms of // the Boost Software License, Version 1.0. // (See accompanying file LICENSE-Boost or copy at // https://www.boost.org/LICENSE_1_0.txt) // // Unless required by applicable law or agreed to in writing, this software // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. #![allow( clippy::approx_constant, clippy::cast_lossless, clippy::excessive_precision, clippy::float_cmp, clippy::int_plus_one, clippy::non_ascii_literal, clippy::unreadable_literal, clippy::unseparated_literal_suffix )] #[macro_use] mod macros; use dragonbox_ecma as dragonbox; use std::f64; fn to_chars(f: f64) -> String { dragonbox::Buffer::new().format(f).to_owned() } fn ieee_parts_to_double(sign: bool, ieee_exponent: u32, ieee_mantissa: u64) -> f64 { assert!(ieee_exponent <= 2047); assert!(ieee_mantissa <= (1u64 << 53) - 1); f64::from_bits(((sign as u64) << 63) | ((ieee_exponent as u64) << 52) | ieee_mantissa) } #[test] fn test_dragonbox() { check!(0.3); assert_eq!(to_chars(1234000000000000.0), "1234000000000000"); assert_eq!(to_chars(1.234e16), "12340000000000000"); check!(2.71828); assert_eq!(to_chars(1.1e128), "1.1e+128"); check!(1.1e-64); check!(2.718281828459045); check!(5e-324); assert_eq!(to_chars(1.7976931348623157e308), "1.7976931348623157e+308"); } #[test] fn test_random() { let n = if cfg!(miri) { 100 } else { 1000000 }; let mut buffer = dragonbox::Buffer::new(); for _ in 0..n { let f: f64 = rand::random(); assert_eq!(f, buffer.format_finite(f).parse().unwrap()); } } #[test] fn test_basic() { assert_eq!(to_chars(0.0), "0"); assert_eq!(to_chars(-0.0), "0"); assert_eq!(to_chars(1.0), "1"); assert_eq!(to_chars(-1.0), "-1"); assert_eq!(to_chars(f64::NAN.copysign(1.0)), "NaN"); assert_eq!(to_chars(f64::NAN.copysign(-1.0)), "NaN"); assert_eq!(to_chars(f64::INFINITY), "Infinity"); assert_eq!(to_chars(f64::NEG_INFINITY), "-Infinity"); } #[test] fn test_switch_to_subnormal() { check!(2.2250738585072014e-308); } #[test] fn test_min_and_max() { assert_eq!(f64::from_bits(0x7fefffffffffffff), 1.7976931348623157e308); check!(1.7976931348623157e+308); assert_eq!(f64::from_bits(1), 5e-324); check!(5e-324); } #[test] fn test_lots_of_trailing_zeros() { check!(2.9802322387695312e-8); } #[test] fn test_regression() { assert_eq!(to_chars(-21098088986959630.0), "-21098088986959630"); check!(4.940656e-318); check!(1.18575755e-316); check!(2.989102097996e-312); assert_eq!(to_chars(4.708356024711512e+18), "4708356024711512000"); assert_eq!(to_chars(9.409340012568248e+18), "9409340012568248000"); check!(1.2345678); } #[test] fn test_looks_like_pow5() { // These numbers have a mantissa that is a multiple of the largest power of // 5 that fits, and an exponent that causes the computation for q to result // in 22, which is a corner case for Ryū. assert_eq!(f64::from_bits(0x4830F0CF064DD592), 5.764607523034235e39); check!(5.764607523034235e+39); assert_eq!(f64::from_bits(0x4840F0CF064DD592), 1.152921504606847e40); check!(1.152921504606847e+40); assert_eq!(f64::from_bits(0x4850F0CF064DD592), 2.305843009213694e+40); check!(2.305843009213694e+40); } #[test] fn test_output_length() { check!(1.2); check!(1.23); check!(1.234); check!(1.2345); check!(1.23456); check!(1.234567); check!(1.2345678); // already tested in Regression check!(1.23456789); check!(1.234567895); // 1.234567890 would be trimmed check!(1.2345678901); check!(1.23456789012); check!(1.234567890123); check!(1.2345678901234); check!(1.23456789012345); check!(1.234567890123456); check!(1.2345678901234567); // Test 32-bit chunking check!(4.294967294); // 2^32 - 2 check!(4.294967295); // 2^32 - 1 check!(4.294967296); // 2^32 check!(4.294967297); // 2^32 + 1 check!(4.294967298); // 2^32 + 2 } // Test min, max shift values in shiftright128 #[test] fn test_min_max_shift() { let max_mantissa = (1u64 << 53) - 1; // 32-bit opt-size=0: 49 <= dist <= 50 // 32-bit opt-size=1: 30 <= dist <= 50 // 64-bit opt-size=0: 50 <= dist <= 50 // 64-bit opt-size=1: 30 <= dist <= 50 assert_eq!(1.7800590868057611e-307, ieee_parts_to_double(false, 4, 0)); check!(1.7800590868057611e-307); // 32-bit opt-size=0: 49 <= dist <= 49 // 32-bit opt-size=1: 28 <= dist <= 49 // 64-bit opt-size=0: 50 <= dist <= 50 // 64-bit opt-size=1: 28 <= dist <= 50 assert_eq!( 2.8480945388892175e-306, ieee_parts_to_double(false, 6, max_mantissa) ); check!(2.8480945388892175e-306); // 32-bit opt-size=0: 52 <= dist <= 53 // 32-bit opt-size=1: 2 <= dist <= 53 // 64-bit opt-size=0: 53 <= dist <= 53 // 64-bit opt-size=1: 2 <= dist <= 53 assert_eq!(2.446494580089078e-296, ieee_parts_to_double(false, 41, 0)); check!(2.446494580089078e-296); // 32-bit opt-size=0: 52 <= dist <= 52 // 32-bit opt-size=1: 2 <= dist <= 52 // 64-bit opt-size=0: 53 <= dist <= 53 // 64-bit opt-size=1: 2 <= dist <= 53 assert_eq!( 4.8929891601781557e-296, ieee_parts_to_double(false, 40, max_mantissa) ); check!(4.8929891601781557e-296); // 32-bit opt-size=0: 57 <= dist <= 58 // 32-bit opt-size=1: 57 <= dist <= 58 // 64-bit opt-size=0: 58 <= dist <= 58 // 64-bit opt-size=1: 58 <= dist <= 58 assert_eq!(1.8014398509481984e+16, ieee_parts_to_double(false, 1077, 0)); assert_eq!(to_chars(1.8014398509481984e+16), "18014398509481984"); // 32-bit opt-size=0: 57 <= dist <= 57 // 32-bit opt-size=1: 57 <= dist <= 57 // 64-bit opt-size=0: 58 <= dist <= 58 // 64-bit opt-size=1: 58 <= dist <= 58 assert_eq!( 3.6028797018963964e+16, ieee_parts_to_double(false, 1076, max_mantissa) ); assert_eq!(to_chars(3.6028797018963964e+16), "36028797018963964"); // 32-bit opt-size=0: 51 <= dist <= 52 // 32-bit opt-size=1: 51 <= dist <= 59 // 64-bit opt-size=0: 52 <= dist <= 52 // 64-bit opt-size=1: 52 <= dist <= 59 assert_eq!(2.900835519859558e-216, ieee_parts_to_double(false, 307, 0)); check!(2.900835519859558e-216); // 32-bit opt-size=0: 51 <= dist <= 51 // 32-bit opt-size=1: 51 <= dist <= 59 // 64-bit opt-size=0: 52 <= dist <= 52 // 64-bit opt-size=1: 52 <= dist <= 59 assert_eq!( 5.801671039719115e-216, ieee_parts_to_double(false, 306, max_mantissa) ); check!(5.801671039719115e-216); // https://github.com/ulfjack/ryu/commit/19e44d16d80236f5de25800f56d82606d1be00b9#commitcomment-30146483 // 32-bit opt-size=0: 49 <= dist <= 49 // 32-bit opt-size=1: 44 <= dist <= 49 // 64-bit opt-size=0: 50 <= dist <= 50 // 64-bit opt-size=1: 44 <= dist <= 50 assert_eq!( 3.196104012172126e-27, ieee_parts_to_double(false, 934, 0x000FA7161A4D6E0C) ); check!(3.196104012172126e-27); } #[test] fn test_ecma262_compliance() { assert_eq!(to_chars(f64::NAN), "NaN"); assert_eq!(to_chars(f64::INFINITY), "Infinity"); assert_eq!(to_chars(f64::NEG_INFINITY), "-Infinity"); assert_eq!(to_chars(0.0), "0"); assert_eq!(to_chars(9.0), "9"); assert_eq!(to_chars(90.0), "90"); assert_eq!(to_chars(90.12), "90.12"); assert_eq!(to_chars(0.000001), "0.000001"); assert_eq!(to_chars(0.0000001), "1e-7"); assert_eq!(to_chars(3e50), "3e+50"); assert_eq!(to_chars(90.12), "90.12"); assert_eq!(to_chars(111111111111111111111.0), "111111111111111110000"); assert_eq!(to_chars(1111111111111111111111.0), "1.1111111111111111e+21"); assert_eq!( to_chars(11111111111111111111111.0), "1.1111111111111111e+22" ); assert_eq!(to_chars(0.1), "0.1"); assert_eq!(to_chars(0.01), "0.01"); assert_eq!(to_chars(0.001), "0.001"); assert_eq!(to_chars(0.0001), "0.0001"); assert_eq!(to_chars(0.00001), "0.00001"); assert_eq!(to_chars(0.000001), "0.000001"); assert_eq!(to_chars(0.0000001), "1e-7"); assert_eq!(to_chars(0.00000012), "1.2e-7"); assert_eq!(to_chars(0.000000123), "1.23e-7"); assert_eq!(to_chars(0.00000001), "1e-8"); assert_eq!(to_chars(-0.0), "0"); assert_eq!(to_chars(-9.0), "-9"); assert_eq!(to_chars(-90.12), "-90.12"); assert_eq!(to_chars(-0.0000000123), "-1.23e-8"); assert_eq!(to_chars(-111111111111111111111.0), "-111111111111111110000"); assert_eq!( to_chars(-1111111111111111111111.0), "-1.1111111111111111e+21" ); assert_eq!(to_chars(-0.000000123), "-1.23e-7"); assert_eq!( to_chars(123456789010111213141516171819.0), "1.234567890101112e+29" ); } #[test] fn max_size_double_to_string() { // See: https://viewer.scuttlebot.io/%25LQo5KOMeR%2Baj%2BEj0JVg3qLRqr%2BwiKo74nS8Uz7o0LDM%3D.sha256 assert_eq!( to_chars(-0.0000015809161985788154), "-0.0000015809161985788154" ); } #[test] fn test_issue_3() { check!(1.0902420340782359e+57); assert_eq!(to_chars(5.3461812015486243e+26), "5.346181201548624e+26"); check!(2.8674588045599296e+66); check!(1.2182856909681335e+77); check!(2.0596292913323055e+69); check!(1.3331169462028886e+60); } #[test] fn test_critical_boundary_case() { // See https://github.com/dtolnay/dragonbox/pull/7#discussion_r2169239437 let test_value = f64::from_bits(0x3FF0000000000001); // 1 + 2^-52 let result = to_chars(test_value); let expected = "1.0000000000000002"; assert_eq!( result, expected, "Critical boundary case failed. Input: {test_value}, Expected: {expected}, Got: {result}", ); // Also verify round-trip conversion assert_eq!( test_value, result.parse().unwrap(), "Round-trip conversion failed for critical boundary case", ); // Additional test case: A power of 2 boundary that might trigger the condition // This is 2^53 + 1, which should trigger our edge case handling let test_value = f64::from_bits(0x4350000000000001); // 2^53 + 1 let result = to_chars(test_value); // With the correct logic, this should properly round-trip assert_eq!( test_value, result.parse().unwrap(), "Failed for power of 2 boundary case: {test_value}, result: {result}", ); } dragonbox_ecma-0.1.12/tests/macros/mod.rs000064400000000000000000000002731046102023000164320ustar 00000000000000macro_rules! check { ($f:tt) => { assert_eq!(to_chars($f), stringify!($f)); }; (-$f:tt) => { assert_eq!(to_chars(-$f), concat!("-", stringify!($f))); }; }