From ad99cd4f5690f7e16d2c83c8151092ef43ad6b7b Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Mon, 24 Aug 2026 23:58:36 +0200 Subject: [PATCH 1/3] chore: recovery --- .gitignore | 1 + Cargo.lock | 595 +++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 11 +- README.md | 2 - benches/bench.rs | 238 +++++++++++++----- scripts/run_miri.sh | 1 - src/lib.rs | 287 ++++++++++++--------- src/rawsmallvec.rs | 13 - src/tests.rs | 49 ++-- 9 files changed, 961 insertions(+), 236 deletions(-) delete mode 100644 src/rawsmallvec.rs diff --git a/.gitignore b/.gitignore index 858f0d52..5ec74668 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ target +Cargo.lock /fuzz/hfuzz_target /.vscode diff --git a/Cargo.lock b/Cargo.lock index c6d327a4..1900f49b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,18 +2,359 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aho-corasick" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +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.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + [[package]] name = "bytes" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad534f4357a5264cce5019c989cf66a4f0dc4e0d1b1d15f8aacec0ff7360273" +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 = "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.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[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", + "plotters", + "rayon", + "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 = "crossbeam-deque" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "either" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" + +[[package]] +name = "find-msvc-tools" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[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 = "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.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "js-sys" +version = "0.3.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0c1080212aad755ea003d18543e8768dd432c48819efd73a7bf1e39b7a5a3a" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + [[package]] name = "malloc_size_of" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5d719de8b8f230028cf8192ae4c1b25267cd6b8a99d2747d345a70b8c81aa13" +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[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 = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + [[package]] name = "proc-macro2" version = "1.0.107" @@ -32,6 +373,70 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[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 = "serde" version = "1.0.229" @@ -39,6 +444,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", + "serde_derive", ] [[package]] @@ -58,41 +464,216 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.4", ] [[package]] -name = "serde_test" -version = "1.0.177" +name = "serde_json" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f901ee573cab6b3060453d2d5f0bae4e6d628c23c0a962ff9b5f1d7c8d4f1ed" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" dependencies = [ + "itoa", + "memchr", "serde", + "serde_core", + "zmij", ] +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + [[package]] name = "smallvec" version = "2.0.0-alpha.12" dependencies = [ + "bincode", "bytes", + "criterion", "malloc_size_of", "serde_core", - "serde_test", ] [[package]] name = "syn" -version = "3.0.3" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f" 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.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[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 = "wasm-bindgen" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b70935747edd64d89de3efa29d73789b806c15798f8e7dca4d8ac356b50ce70" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77775f8f3f7217702089053b94958f8f54061a3f663417df76e19cbdcca29bc1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e11d33f857dc2fb11b8bc75aee111aa9cbeb12cd9f25efd3d4c2a3dd4e235284" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.119", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef64dbcc55df09c7e5a46182d181c2cfa3e925f3da937ea764728b4bbb9dcbf" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c435338968042f4f59a557f690a253676d47ce13ceb55d70100e7facf6620a30" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[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 = "zerocopy" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/Cargo.toml b/Cargo.toml index 19391ffb..1deb55b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,14 +11,13 @@ keywords = ["small", "vec", "vector", "stack", "no_std"] categories = ["data-structures"] readme = "README.md" documentation = "https://docs.rs/smallvec/" -exclude = [".gitignore", "tests/", "scripts/", "fuzz/", "benches/", ".github/"] [features] std = [] specialization = [] may_dangle = [] +extract_if = [] serde = ["dep:serde_core"] -internals = [] [dependencies] bytes = { version = "1", optional = true, default-features = false } @@ -26,8 +25,14 @@ serde_core = { version = "1.0.221", optional = true, default-features = false } malloc_size_of = { version = "0.1.1", optional = true, default-features = false } [dev-dependencies] -serde_test = "1.0" +bincode = "1.0.1" +criterion = "0.8" [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] + +[[bench]] +name = "bench" +path = "benches/bench.rs" +harness = false diff --git a/README.md b/README.md index e9b253c1..a485d2d5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ rust-smallvec > **⚠️ Note:** > This is the code for smallvec 2.0, which is not yet ready for release. For > details about the changes in version 2.0, please see [#183], [#240], and [#284]. -> The status of the v2 branch is tracked on [#425]. > > The source code for the latest smallvec 1.x.y release can be found on the > [v1 branch]. Bug fixes for smallvec 1 should be based on that branch, while @@ -14,7 +13,6 @@ rust-smallvec [#183]: https://github.com/servo/rust-smallvec/issues/183 [#240]: https://github.com/servo/rust-smallvec/issues/240 [#284]: https://github.com/servo/rust-smallvec/issues/284 -[#425]: https://github.com/servo/rust-smallvec/issues/425 ## About smallvec diff --git a/benches/bench.rs b/benches/bench.rs index 23864009..bded165b 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,10 +1,8 @@ -#![feature(test)] #![allow(deprecated)] -extern crate test; - +use criterion::{criterion_group, criterion_main, Bencher, Criterion}; use smallvec::{smallvec, SmallVec}; -use test::Bencher; +use std::hint::black_box; const VEC_SIZE: usize = 16; const SPILLED_SIZE: usize = 100; @@ -18,87 +16,90 @@ trait Vector: for<'a> From<&'a [T]> + Extend { fn from_elem(val: T, n: usize) -> Self; fn from_elems(val: &[T]) -> Self; fn extend_from_slice(&mut self, other: &[T]); + fn retain_mut(&mut self, f: F) + where + F: FnMut(&mut T) -> bool; } impl Vector for Vec { fn new() -> Self { Self::with_capacity(VEC_SIZE) } - fn push(&mut self, val: T) { self.push(val) } - fn pop(&mut self) -> Option { self.pop() } - fn remove(&mut self, p: usize) -> T { self.remove(p) } - fn insert(&mut self, n: usize, val: T) { self.insert(n, val) } - fn from_elem(val: T, n: usize) -> Self { vec![val; n] } - fn from_elems(val: &[T]) -> Self { val.to_owned() } - fn extend_from_slice(&mut self, other: &[T]) { Vec::extend_from_slice(self, other) } + fn retain_mut(&mut self, f: F) + where + F: FnMut(&mut T) -> bool, + { + self.retain_mut(f) + } } impl Vector for SmallVec { fn new() -> Self { Self::new() } - fn push(&mut self, val: T) { self.push(val) } - fn pop(&mut self) -> Option { self.pop() } - fn remove(&mut self, p: usize) -> T { self.remove(p) } - fn insert(&mut self, n: usize, val: T) { self.insert(n, val) } - fn from_elem(val: T, n: usize) -> Self { smallvec![val; n] } - fn from_elems(val: &[T]) -> Self { SmallVec::from(val) } - fn extend_from_slice(&mut self, other: &[T]) { SmallVec::extend_from_slice(self, other) } + fn retain_mut(&mut self, f: F) + where + F: FnMut(&mut T) -> bool, + { + self.retain_mut(f) + } } macro_rules! make_benches { ($typ:ty { $($b_name:ident => $g_name:ident($($args:expr),*),)* }) => { $( - #[bench] - fn $b_name(b: &mut Bencher) { - $g_name::<$typ>($($args,)* b) + fn $b_name(c: &mut Criterion) { + c.bench_function(stringify!($b_name), |b: &mut Bencher| { + $g_name::<$typ>($($args,)* b) + }); } )* } } +/* ---------- Bench generation (same list, just using the new macro) ---------- */ make_benches! { SmallVec { bench_push => gen_push(SPILLED_SIZE as _), @@ -122,6 +123,12 @@ make_benches! { bench_macro_from_elem => gen_from_elem(SPILLED_SIZE as _), bench_macro_from_elem_small => gen_from_elem(VEC_SIZE as _), bench_pushpop => gen_pushpop(), + bench_retain_mut_half => gen_retain_mut_half(SPILLED_SIZE as _), + bench_retain_mut_half_small => gen_retain_mut_half(VEC_SIZE as _), + bench_retain_mut_all => gen_retain_mut_all(SPILLED_SIZE as _), + bench_retain_mut_all_small => gen_retain_mut_all(VEC_SIZE as _), + bench_retain_mut_none => gen_retain_mut_none(SPILLED_SIZE as _), + bench_retain_mut_none_small => gen_retain_mut_none(VEC_SIZE as _), } } @@ -148,156 +155,257 @@ make_benches! { bench_macro_from_elem_vec => gen_from_elem(SPILLED_SIZE as _), bench_macro_from_elem_vec_small => gen_from_elem(VEC_SIZE as _), bench_pushpop_vec => gen_pushpop(), + bench_retain_mut_vec_half => gen_retain_mut_half(SPILLED_SIZE as _), + bench_retain_mut_vec_half_small => gen_retain_mut_half(VEC_SIZE as _), + bench_retain_mut_vec_all => gen_retain_mut_all(SPILLED_SIZE as _), + bench_retain_mut_vec_all_small => gen_retain_mut_all(VEC_SIZE as _), + bench_retain_mut_vec_none => gen_retain_mut_none(SPILLED_SIZE as _), + bench_retain_mut_vec_none_small => gen_retain_mut_none(VEC_SIZE as _), } } +/* ---------- Benchmark helpers – unchanged except for Bencher type ---------- */ fn gen_push>(n: u64, b: &mut Bencher) { #[inline(never)] fn push_noinline>(vec: &mut V, x: u64) { - vec.push(x); + vec.push(black_box(x)); } b.iter(|| { + let n = black_box(n); let mut vec = V::new(); for x in 0..n { push_noinline(&mut vec, x); } - vec + black_box(vec) }); } fn gen_insert_push>(n: u64, b: &mut Bencher) { #[inline(never)] fn insert_push_noinline>(vec: &mut V, x: u64) { - vec.insert(x as usize, x); + vec.insert(black_box(x) as usize, black_box(x)); } b.iter(|| { + let n = black_box(n); let mut vec = V::new(); for x in 0..n { insert_push_noinline(&mut vec, x); } - vec + black_box(vec) }); } fn gen_insert>(n: u64, b: &mut Bencher) { #[inline(never)] fn insert_noinline>(vec: &mut V, p: usize, x: u64) { - vec.insert(p, x) + vec.insert(black_box(p), black_box(x)) } b.iter(|| { + let n = black_box(n); let mut vec = V::new(); - // Always insert at position 0 so that we are subject to shifts of - // many different lengths. vec.push(0); for x in 0..n { insert_noinline(&mut vec, 0, x); } - vec + black_box(vec) }); } fn gen_remove>(n: usize, b: &mut Bencher) { #[inline(never)] fn remove_noinline>(vec: &mut V, p: usize) -> u64 { - vec.remove(p) + vec.remove(black_box(p)) } b.iter(|| { + let n = black_box(n); let mut vec = V::from_elem(0, n as _); - for _ in 0..n { - remove_noinline(&mut vec, 0); + black_box(remove_noinline(&mut vec, 0)); } + black_box(vec) }); } fn gen_extend>(n: u64, b: &mut Bencher) { b.iter(|| { + let n = black_box(n); let mut vec = V::new(); vec.extend(0..n); - vec + black_box(vec) }); } fn gen_extend_filtered>(n: u64, b: &mut Bencher) { b.iter(|| { let mut vec = V::new(); - vec.extend((0..n).filter(|i| i % 2 == 0)); - vec + vec.extend((0..black_box(n)).filter(|i| black_box(*i) % 2 == 0)); + black_box(vec) }); } fn gen_from_iter>(n: u64, b: &mut Bencher) { - let v: Vec = (0..n).collect(); + let v: Vec = (0..black_box(n)).collect(); b.iter(|| { - let vec = V::from(&v); - vec + let vec = V::from(black_box(&v)); + black_box(vec) }); } fn gen_from_slice>(n: u64, b: &mut Bencher) { - let v: Vec = (0..n).collect(); + let v: Vec = (0..black_box(n)).collect(); b.iter(|| { - let vec = V::from_elems(&v); - vec + let vec = V::from_elems(black_box(&v)); + black_box(vec) }); } fn gen_extend_from_slice>(n: u64, b: &mut Bencher) { - let v: Vec = (0..n).collect(); + let v: Vec = (0..black_box(n)).collect(); b.iter(|| { let mut vec = V::new(); - vec.extend_from_slice(&v); - vec + vec.extend_from_slice(black_box(&v)); + black_box(vec) }); } fn gen_pushpop>(b: &mut Bencher) { #[inline(never)] fn pushpop_noinline>(vec: &mut V, x: u64) -> Option { - vec.push(x); + vec.push(black_box(x)); vec.pop() } b.iter(|| { let mut vec = V::new(); for x in 0..SPILLED_SIZE as _ { - pushpop_noinline(&mut vec, x); + black_box(pushpop_noinline(&mut vec, x)); } - vec + black_box(vec) }); } fn gen_from_elem>(n: usize, b: &mut Bencher) { b.iter(|| { - let vec = V::from_elem(42, n); - vec + let n = black_box(n); + let vec = V::from_elem(black_box(42), n); + black_box(vec) + }); +} + +fn gen_retain_mut_half>(n: usize, b: &mut Bencher) { + b.iter(|| { + let n = black_box(n); + let mut vec = V::from_elem(16, n); + vec.retain_mut(|x| black_box(*x) % 2 == 0); + black_box(vec) }); } -#[bench] -fn bench_macro_from_list(b: &mut Bencher) { +fn gen_retain_mut_all>(n: usize, b: &mut Bencher) { b.iter(|| { - let vec: SmallVec = smallvec![ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, 0x40, 0x80, - 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000, - 0x80000, 0x100000, - ]; - vec + let n = black_box(n); + let mut vec = V::from_elem(16, n); + vec.retain_mut(|_| true); + black_box(vec) }); } -#[bench] -fn bench_macro_from_list_vec(b: &mut Bencher) { +fn gen_retain_mut_none>(n: usize, b: &mut Bencher) { b.iter(|| { - let vec: Vec = vec![ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, 0x40, 0x80, - 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000, - 0x80000, 0x100000, - ]; - vec + let n = black_box(n); + let mut vec = V::from_elem(16, n); + vec.retain_mut(|_| false); + black_box(vec) }); } + +fn bench_macro_from_list(c: &mut Criterion) { + c.bench_function("bench_macro_from_list", |b| { + b.iter(|| { + let vec: SmallVec = smallvec![ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, 0x40, + 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, + 0x40000, 0x80000, 0x100000, + ]; + vec + }) + }); +} + +fn bench_macro_from_list_vec(c: &mut Criterion) { + c.bench_function("bench_macro_from_list_vec", |b| { + b.iter(|| { + let vec: Vec = vec![ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, 0x40, + 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, + 0x40000, 0x80000, 0x100000, + ]; + vec + }) + }); +} + +criterion_group!( + benches, + bench_push, + bench_push_small, + bench_insert_push, + bench_insert_push_small, + bench_insert, + bench_insert_small, + bench_remove, + bench_remove_small, + bench_extend, + bench_extend_small, + bench_extend_filtered, + bench_extend_filtered_small, + bench_from_iter, + bench_from_iter_small, + bench_from_slice, + bench_from_slice_small, + bench_extend_from_slice, + bench_extend_from_slice_small, + bench_macro_from_elem, + bench_macro_from_elem_small, + bench_pushpop, + bench_retain_mut_half, + bench_retain_mut_half_small, + bench_retain_mut_all, + bench_retain_mut_all_small, + bench_retain_mut_none, + bench_retain_mut_none_small, + bench_push_vec, + bench_push_vec_small, + bench_insert_push_vec, + bench_insert_push_vec_small, + bench_insert_vec, + bench_insert_vec_small, + bench_remove_vec, + bench_remove_vec_small, + bench_extend_vec, + bench_extend_vec_small, + bench_extend_vec_filtered, + bench_extend_vec_filtered_small, + bench_from_iter_vec, + bench_from_iter_vec_small, + bench_from_slice_vec, + bench_from_slice_vec_small, + bench_extend_from_slice_vec, + bench_extend_from_slice_vec_small, + bench_macro_from_elem_vec, + bench_macro_from_elem_vec_small, + bench_pushpop_vec, + bench_retain_mut_vec_half, + bench_retain_mut_vec_half_small, + bench_retain_mut_vec_all, + bench_retain_mut_vec_all_small, + bench_retain_mut_vec_none, + bench_retain_mut_vec_none_small, + bench_macro_from_list, + bench_macro_from_list_vec +); +criterion_main!(benches); diff --git a/scripts/run_miri.sh b/scripts/run_miri.sh index ad9b596e..a5977df2 100644 --- a/scripts/run_miri.sh +++ b/scripts/run_miri.sh @@ -17,5 +17,4 @@ rustup component add miri cargo miri setup cargo miri test --verbose -cargo clean cargo miri test --verbose --all-features diff --git a/src/lib.rs b/src/lib.rs index f7b1bba1..99fd5a97 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,6 @@ pub extern crate alloc; #[cfg(any(test, feature = "std"))] extern crate std; -mod rawsmallvec; #[cfg(test)] mod tests; @@ -80,6 +79,8 @@ use core::mem::align_of; use core::mem::size_of; use core::mem::ManuallyDrop; use core::mem::MaybeUninit; +use core::ptr::addr_of; +use core::ptr::addr_of_mut; use core::ptr::copy; use core::ptr::copy_nonoverlapping; use core::ptr::NonNull; @@ -96,11 +97,6 @@ use serde_core::{ #[cfg(feature = "std")] use std::io; -#[cfg(feature = "internals")] -pub use rawsmallvec::RawSmallVec; -#[cfg(not(feature = "internals"))] -use rawsmallvec::RawSmallVec; - /// Error type for APIs with fallible heap allocation #[derive(Debug)] pub enum CollectionAllocErr { @@ -120,6 +116,18 @@ impl core::fmt::Display for CollectionAllocErr { impl core::error::Error for CollectionAllocErr {} +/// Either a stack array with `length <= N` or a heap array +/// whose pointer and capacity are stored here. +/// +/// We store a `NonNull` instead of a `*mut T`, so that +/// niche-optimization can be performed and the type is covariant +/// with respect to `T`. +#[repr(C)] +pub union RawSmallVec { + inline: ManuallyDrop>, + heap: (NonNull, usize), +} + #[inline] fn infallible(result: Result) -> T { match result { @@ -129,12 +137,6 @@ fn infallible(result: Result) -> T { } } -/// Helper function to check if a type is a ZST. -#[inline] -const fn is_zst() -> bool { - const { size_of::() == 0 } -} - #[inline] /// A local copy of [`core::slice::range`]. The latter function is unstable /// and thus cannot be used yet. @@ -171,7 +173,10 @@ where } impl RawSmallVec { - const IS_ZST: bool = is_zst::(); + #[inline] + const fn is_zst() -> bool { + size_of::() == 0 + } #[inline] const fn new() -> Self { @@ -192,16 +197,16 @@ impl RawSmallVec { #[inline] const fn as_ptr_inline(&self) -> *const T { - // SAFETY: it is safe because we aren't reading the value, just getting a - // reference to it. reading it would be UB potentially, but for that downstream - // unsafe is required - (unsafe { &raw const self.inline }) as *mut T + // SAFETY: This is safe because we don't read the value. We only get a pointer to the data. + // Dereferencing the pointer is unsafe so unsafe code is required to misuse the return + // value. + (unsafe { addr_of!(self.inline) }) as *const T } #[inline] const fn as_mut_ptr_inline(&mut self) -> *mut T { - // SAFETY: same as above - (unsafe { &raw mut self.inline }) as *mut T + // SAFETY: See above. + (unsafe { addr_of_mut!(self.inline) }) as *mut T } /// # Safety @@ -226,21 +231,21 @@ impl RawSmallVec { /// T must not be a ZST. unsafe fn try_grow_raw( &mut self, - len: TaggedLen, + len: TaggedLen, new_capacity: usize, ) -> Result<(), CollectionAllocErr> { use alloc::alloc::{alloc, realloc}; - debug_assert!(!Self::IS_ZST); + debug_assert!(!Self::is_zst()); debug_assert!(new_capacity > 0); - debug_assert!(new_capacity >= len.value()); + debug_assert!(new_capacity >= len.value(Self::is_zst())); - let was_on_heap = len.on_heap(); + let was_on_heap = len.on_heap(Self::is_zst()); let ptr = if was_on_heap { self.as_mut_ptr_heap() } else { self.as_mut_ptr_inline() }; - let len = len.value(); + let len = len.value(Self::is_zst()); let new_layout = Layout::array::(new_capacity).map_err(|_| CollectionAllocErr::CapacityOverflow)?; @@ -284,40 +289,25 @@ impl RawSmallVec { /// /// For a ZST, we never use the heap, so we just store the length directly. #[repr(transparent)] -struct TaggedLen(usize, PhantomData); - -// Clone and Copy must be manually implemented because the generic interferes with the derive attribute implementations. -impl Clone for TaggedLen { - #[inline] - fn clone(&self) -> Self { - Self(self.0, PhantomData) - } - - #[inline] - fn clone_from(&mut self, source: &Self) { - self.0 = source.0; - } -} - -impl Copy for TaggedLen {} +#[derive(Clone, Copy)] +struct TaggedLen(usize); -impl TaggedLen { - const IS_ZST: bool = is_zst::(); +impl TaggedLen { #[inline] - pub const fn new(len: usize, on_heap: bool) -> Self { - if Self::IS_ZST { + pub const fn new(len: usize, on_heap: bool, is_zst: bool) -> Self { + if is_zst { debug_assert!(!on_heap); - Self(len, PhantomData) + TaggedLen(len) } else { debug_assert!(len < isize::MAX as usize); - Self((len << 1) | on_heap as usize, PhantomData) + TaggedLen((len << 1) | on_heap as usize) } } #[inline] #[must_use] - pub const fn on_heap(self) -> bool { - if Self::IS_ZST { + pub const fn on_heap(self, is_zst: bool) -> bool { + if is_zst { false } else { (self.0 & 1_usize) == 1 @@ -325,8 +315,8 @@ impl TaggedLen { } #[inline] - pub const fn value(self) -> usize { - if Self::IS_ZST { + pub const fn value(self, is_zst: bool) -> usize { + if is_zst { self.0 } else { self.0 >> 1 @@ -336,7 +326,7 @@ impl TaggedLen { #[repr(C)] pub struct SmallVec { - len: TaggedLen, + len: TaggedLen, raw: RawSmallVec, _marker: PhantomData, } @@ -437,7 +427,7 @@ impl<'a, T: 'a, const N: usize> Drop for Drain<'a, T, N> { let mut vec = self.vec; - if SmallVec::::IS_ZST { + if SmallVec::::is_zst() { // ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount. // this can be achieved by manipulating the Vec length instead of moving values out from `iter`. unsafe { @@ -532,6 +522,7 @@ impl Drain<'_, T, N> { } } +#[cfg(feature = "extract_if")] /// An iterator which uses a closure to determine if an element should be removed. /// /// Returned from [`SmallVec::extract_if`][1]. @@ -554,6 +545,7 @@ where pred: F, } +#[cfg(feature = "extract_if")] impl core::fmt::Debug for ExtractIf<'_, T, N, F> where F: FnMut(&mut T) -> bool, @@ -566,6 +558,7 @@ where } } +#[cfg(feature = "extract_if")] impl Iterator for ExtractIf<'_, T, N, F> where F: FnMut(&mut T) -> bool, @@ -601,6 +594,7 @@ where } } +#[cfg(feature = "extract_if")] impl Drop for ExtractIf<'_, T, N, F> where F: FnMut(&mut T) -> bool, @@ -722,7 +716,7 @@ pub struct IntoIter { // The members from begin..end are initialized raw: RawSmallVec, begin: usize, - end: TaggedLen, + end: TaggedLen, _marker: PhantomData, } @@ -732,9 +726,14 @@ unsafe impl Send for IntoIter where T: Send {} unsafe impl Sync for IntoIter where T: Sync {} impl IntoIter { + #[inline] + const fn is_zst() -> bool { + size_of::() == 0 + } + #[inline] const fn as_ptr(&self) -> *const T { - let on_heap = self.end.on_heap(); + let on_heap = self.end.on_heap(Self::is_zst()); if on_heap { // SAFETY: vector is on the heap unsafe { self.raw.as_ptr_heap() } @@ -745,7 +744,7 @@ impl IntoIter { #[inline] const fn as_mut_ptr(&mut self) -> *mut T { - let on_heap = self.end.on_heap(); + let on_heap = self.end.on_heap(Self::is_zst()); if on_heap { // SAFETY: vector is on the heap unsafe { self.raw.as_mut_ptr_heap() } @@ -760,7 +759,10 @@ impl IntoIter { // So the pointer arithmetic is valid, and so is the construction of the slice unsafe { let ptr = self.as_ptr(); - core::slice::from_raw_parts(ptr.add(self.begin), self.end.value() - self.begin) + core::slice::from_raw_parts( + ptr.add(self.begin), + self.end.value(Self::is_zst()) - self.begin, + ) } } @@ -769,7 +771,10 @@ impl IntoIter { // SAFETY: see above unsafe { let ptr = self.as_mut_ptr(); - core::slice::from_raw_parts_mut(ptr.add(self.begin), self.end.value() - self.begin) + core::slice::from_raw_parts_mut( + ptr.add(self.begin), + self.end.value(Self::is_zst()) - self.begin, + ) } } } @@ -779,7 +784,7 @@ impl Iterator for IntoIter { #[inline] fn next(&mut self) -> Option { - if self.begin == self.end.value() { + if self.begin == self.end.value(Self::is_zst()) { None } else { // SAFETY: see above @@ -794,7 +799,7 @@ impl Iterator for IntoIter { #[inline] fn size_hint(&self) -> (usize, Option) { - let size = self.end.value() - self.begin; + let size = self.end.value(Self::is_zst()) - self.begin; (size, Some(size)) } } @@ -802,16 +807,16 @@ impl Iterator for IntoIter { impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { - let mut end = self.end.value(); + let mut end = self.end.value(Self::is_zst()); if self.begin == end { None } else { // SAFETY: see above unsafe { let ptr = self.as_mut_ptr(); - let on_heap = self.end.on_heap(); + let on_heap = self.end.on_heap(Self::is_zst()); end -= 1; - self.end = TaggedLen::new(end, on_heap); + self.end = TaggedLen::new(end, on_heap, Self::is_zst()); let value = ptr.add(end).read(); Some(value) } @@ -825,7 +830,7 @@ impl SmallVec { #[inline] pub const fn new() -> SmallVec { Self { - len: TaggedLen::new(0, false), + len: TaggedLen::new(0, false, Self::is_zst()), raw: RawSmallVec::new(), _marker: PhantomData, } @@ -846,7 +851,7 @@ impl SmallVec { assert!(S <= N); } - // Although we create a new buffer, since S and N are known at compile time, + // Althought we create a new buffer, since S and N are known at compile time, // even with `-C opt-level=1`, it gets optimized as best as it could be. (Checked with ) let mut buf: MaybeUninit<[T; N]> = MaybeUninit::uninit(); @@ -857,12 +862,12 @@ impl SmallVec { copy_nonoverlapping(elements.as_ptr(), buf.as_mut_ptr() as *mut T, S); } - // `elements` have been moved into buf and will be dropped by SmallVec + // `elements` have been moved into buf and will be droped by SmallVec core::mem::forget(elements); // SAFETY: all the members in 0..S are initialized Self { - len: TaggedLen::new(S, false), + len: TaggedLen::new(S, false, Self::is_zst()), raw: RawSmallVec::new_inline(buf), _marker: PhantomData, } @@ -873,7 +878,7 @@ impl SmallVec { assert!(len <= N); // SAFETY: all the members in 0..len are initialized let mut vec = Self { - len: TaggedLen::new(len, false), + len: TaggedLen::new(len, false, Self::is_zst()), raw: RawSmallVec::new_inline(MaybeUninit::new(buf)), _marker: PhantomData, }; @@ -916,7 +921,7 @@ impl SmallVec { pub const unsafe fn from_buf_and_len_unchecked(buf: MaybeUninit<[T; N]>, len: usize) -> Self { debug_assert!(len <= N); Self { - len: TaggedLen::new(len, false), + len: TaggedLen::new(len, false, Self::is_zst()), raw: RawSmallVec::new_inline(buf), _marker: PhantomData, } @@ -924,7 +929,10 @@ impl SmallVec { } impl SmallVec { - const IS_ZST: bool = is_zst::(); + #[inline] + const fn is_zst() -> bool { + size_of::() == 0 + } #[inline] pub fn from_vec(vec: Vec) -> Self { @@ -932,7 +940,7 @@ impl SmallVec { return Self::new(); } - if Self::IS_ZST { + if Self::is_zst() { // "Move" elements to stack buffer. They're ZST so we don't actually have to do // anything. Just make sure they're not dropped. // We don't wrap the vector in ManuallyDrop so that when it's dropped, the memory is @@ -944,7 +952,7 @@ impl SmallVec { // old_len..new_len is an empty range. So there are no uninitialized elements unsafe { vec.set_len(0) }; Self { - len: TaggedLen::new(len, false), + len: TaggedLen::new(len, false, Self::is_zst()), raw: RawSmallVec::new(), _marker: PhantomData, } @@ -957,7 +965,7 @@ impl SmallVec { let ptr = unsafe { NonNull::new_unchecked(vec.as_mut_ptr()) }; Self { - len: TaggedLen::new(len, true), + len: TaggedLen::new(len, true, Self::is_zst()), raw: RawSmallVec::new_heap(ptr, cap), _marker: PhantomData, } @@ -971,7 +979,7 @@ impl SmallVec { /// The active union member must be the self.raw.heap #[inline] unsafe fn set_on_heap(&mut self) { - self.len = TaggedLen::new(self.len(), true); + self.len = TaggedLen::new(self.len(), true, Self::is_zst()); } /// Sets the tag to be inline @@ -981,7 +989,7 @@ impl SmallVec { /// The active union member must be the self.raw.inline #[inline] unsafe fn set_inline(&mut self) { - self.len = TaggedLen::new(self.len(), false); + self.len = TaggedLen::new(self.len(), false, Self::is_zst()); } /// Sets the length of a vector. @@ -996,13 +1004,13 @@ impl SmallVec { #[inline] pub unsafe fn set_len(&mut self, new_len: usize) { debug_assert!(new_len <= self.capacity()); - let on_heap = self.len.on_heap(); - self.len = TaggedLen::new(new_len, on_heap); + let on_heap = self.len.on_heap(Self::is_zst()); + self.len = TaggedLen::new(new_len, on_heap, Self::is_zst()); } #[inline] pub const fn inline_size() -> usize { - if Self::IS_ZST { + if Self::is_zst() { usize::MAX } else { N @@ -1011,7 +1019,7 @@ impl SmallVec { #[inline] pub const fn len(&self) -> usize { - self.len.value() + self.len.value(Self::is_zst()) } #[must_use] @@ -1022,7 +1030,7 @@ impl SmallVec { #[inline] pub const fn capacity(&self) -> usize { - if self.len.on_heap() { + if self.len.on_heap(Self::is_zst()) { // SAFETY: raw.heap is active unsafe { self.raw.heap.1 } } else { @@ -1032,7 +1040,7 @@ impl SmallVec { #[inline] pub const fn spilled(&self) -> bool { - self.len.on_heap() + self.len.on_heap(Self::is_zst()) } /// Splits the collection into two at the given index. @@ -1103,6 +1111,7 @@ impl SmallVec { } } + #[cfg(feature = "extract_if")] /// Creates an iterator which uses a closure to determine if element in the range should be removed. /// /// If the closure returns true, then the element is removed and yielded. @@ -1222,15 +1231,16 @@ impl SmallVec { #[inline] pub fn pop(&mut self) -> Option { - if self.is_empty() { + let len = self.len(); + if len == 0 { None } else { - let len = self.len() - 1; - // SAFETY: len < old_len since this can't overflow, because the old length is non zero - unsafe { self.set_len(len) }; + let new_len = len - 1; + // SAFETY: new_len < len since len is non-zero + unsafe { self.set_len(new_len) }; // SAFETY: this element was initialized and we just gave up ownership of it, so we can // give it away - let value = unsafe { self.as_mut_ptr().add(len).read() }; + let value = unsafe { self.as_mut_ptr().add(new_len).read() }; Some(value) } } @@ -1271,7 +1281,7 @@ impl SmallVec { #[cold] pub fn try_grow(&mut self, new_capacity: usize) -> Result<(), CollectionAllocErr> { - if Self::IS_ZST { + if Self::is_zst() { return Ok(()); } @@ -1311,16 +1321,26 @@ impl SmallVec { } #[inline] + #[track_caller] pub fn reserve(&mut self, additional: usize) { - // can't overflow since len <= capacity - if additional > self.capacity() - self.len() { + // Callers expect this function to be very cheap when there is already sufficient capacity. + // Therefore, we move all the resizing and error-handling logic behind a call, while making + // sure that this function is likely to be inlined as just a comparison and a call if the + // comparison fails. + #[cold] + fn do_reserve_and_handle(slf: &mut SmallVec, additional: usize) { let new_capacity = infallible( - self.len() + slf.len() .checked_add(additional) .and_then(usize::checked_next_power_of_two) .ok_or(CollectionAllocErr::CapacityOverflow), ); - self.grow(new_capacity); + slf.grow(new_capacity); + } + + // can't overflow since len <= capacity + if additional > self.capacity() - self.len() { + do_reserve_and_handle(self, additional); } } @@ -1332,22 +1352,30 @@ impl SmallVec { .checked_add(additional) .and_then(usize::checked_next_power_of_two) .ok_or(CollectionAllocErr::CapacityOverflow)?; - self.try_grow(new_capacity) - } else { - Ok(()) + self.try_grow(new_capacity)?; } + Ok(()) } #[inline] + #[track_caller] pub fn reserve_exact(&mut self, additional: usize) { - // can't overflow since len <= capacity - if additional > self.capacity() - self.len() { + #[cold] + fn do_reserve_exact_and_handle( + slf: &mut SmallVec, + additional: usize, + ) { let new_capacity = infallible( - self.len() + slf.len() .checked_add(additional) .ok_or(CollectionAllocErr::CapacityOverflow), ); - self.grow(new_capacity); + slf.grow(new_capacity); + } + + // can't overflow since len <= capacity + if additional > self.capacity() - self.len() { + do_reserve_exact_and_handle(self, additional); } } @@ -1358,10 +1386,9 @@ impl SmallVec { .len() .checked_add(additional) .ok_or(CollectionAllocErr::CapacityOverflow)?; - self.try_grow(new_capacity) - } else { - Ok(()) + self.try_grow(new_capacity)?; } + Ok(()) } #[inline] @@ -1533,7 +1560,7 @@ impl SmallVec { #[inline] pub const fn as_ptr(&self) -> *const T { - if self.len.on_heap() { + if self.len.on_heap(Self::is_zst()) { // SAFETY: heap member is active unsafe { self.raw.as_ptr_heap() } } else { @@ -1543,7 +1570,7 @@ impl SmallVec { #[inline] pub const fn as_mut_ptr(&mut self) -> *mut T { - if self.len.on_heap() { + if self.len.on_heap(Self::is_zst()) { // SAFETY: see above unsafe { self.raw.as_mut_ptr_heap() } } else { @@ -1610,21 +1637,28 @@ impl SmallVec { #[inline] pub fn retain_mut bool>(&mut self, mut f: F) { - let mut del = 0; let len = self.len(); + + if len == 0 { + // return early as hint to llvm, like what std does + return; + } + let ptr = self.as_mut_ptr(); - for i in 0..len { + let mut write_idx = 0; + + for read_idx in 0..len { // SAFETY: all the pointers are in bounds - // `i - del` never overflows since `del <= i` is a maintained invariant unsafe { - if !f(&mut *ptr.add(i)) { - del += 1; - } else if del > 0 { - core::ptr::swap(ptr.add(i), ptr.add(i - del)); + if f(&mut *ptr.add(read_idx)) { + if write_idx < read_idx { + core::ptr::swap(ptr.add(read_idx), ptr.add(write_idx)); + } + write_idx += 1; } } } - self.truncate(len - del); + self.truncate(write_idx); } #[inline] @@ -1772,7 +1806,7 @@ impl SmallVec { /// ``` #[inline] pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> SmallVec { - assert!(!Self::IS_ZST); + assert!(!Self::is_zst()); // SAFETY: We require caller to provide same ptr as we alloc // and we never alloc null pointer. @@ -1782,7 +1816,7 @@ impl SmallVec { }; SmallVec { - len: TaggedLen::new(length, true), + len: TaggedLen::new(length, true, Self::is_zst()), raw: RawSmallVec::new_heap(ptr, capacity), _marker: PhantomData, } @@ -1994,9 +2028,10 @@ impl Drop for IntoIter { fn drop(&mut self) { // SAFETY: see above unsafe { - let on_heap = self.end.on_heap(); + let is_zst = size_of::() == 0; + let on_heap = self.end.on_heap(is_zst); let begin = self.begin; - let end = self.end.value(); + let end = self.end.value(is_zst); let ptr = self.as_mut_ptr(); let _drop_dealloc = if on_heap { let capacity = self.raw.heap.1; @@ -2172,7 +2207,7 @@ mod spec_traits { } // Mark the iterator as fully consumed. - iter.begin = iter.end.value(); + iter.begin = iter.end.value(Self::is_zst()); } } @@ -2245,7 +2280,7 @@ mod spec_traits { let len = src.len(); // SAFETY: The caller ensures that the vector has spare capacity - // for at least `src.len()` elements. This is also the amount of memory + // for at least `src.len()` elements. This is alse the amount of memory // accessed when the data is copied. unsafe { let ptr = self.as_mut_ptr(); @@ -2606,7 +2641,7 @@ impl Clone for SmallVec { #[cfg(not(feature = "specialization"))] { - self.clone_from_fallback(&*source); + self.clone_from_fallback(source); } } } @@ -2665,11 +2700,23 @@ impl core::iter::FromIterator for SmallVec { #[macro_export] macro_rules! smallvec { + // count helper: transform any expression into 1 + (@one $x:expr) => (1usize); + () => ( + $crate::SmallVec::new() + ); ($elem:expr; $n:expr) => ({ $crate::from_elem($elem, $n) }); - ($($($x:expr),+$(,)?)?) => ({ - $crate::SmallVec::from([$($($x),+)?]) + ($($x:expr),+$(,)?) => ({ + const COUNT: usize = 0usize $(+ $crate::smallvec!(@one $x))+; + let mut vec = $crate::SmallVec::new(); + if COUNT <= vec.capacity() { + $(vec.push($x);)* + vec + } else { + $crate::SmallVec::from_vec($crate::alloc::vec![$($x,)+]) + } }); } @@ -2682,7 +2729,7 @@ macro_rules! smallvec_inline { }); ($($x:expr),+ $(,)?) => ({ const N: usize = 0usize $(+ $crate::smallvec_inline!(@one $x))*; - $crate::SmallVec::<_, N>::from_buf([$($x),*]) + $crate::SmallVec::<_, N>::from_buf([$($x,)*]) }); } diff --git a/src/rawsmallvec.rs b/src/rawsmallvec.rs deleted file mode 100644 index dadbf958..00000000 --- a/src/rawsmallvec.rs +++ /dev/null @@ -1,13 +0,0 @@ -use core::mem::{ManuallyDrop, MaybeUninit}; -use core::ptr::NonNull; - -/// Either a stack array with `length <= N` or a heap array -/// whose pointer and capacity are stored here. -/// -/// We store a `NonNull` instead of a `*mut T` so that type is covariant -/// with respect to `T`, and since the heap pointer is never null. -#[repr(C)] -pub union RawSmallVec { - pub inline: ManuallyDrop>, - pub heap: (NonNull, usize), -} diff --git a/src/tests.rs b/src/tests.rs index cfd801b4..989f9fb7 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -155,7 +155,7 @@ fn splice() { let new = [7, 8, 9, 10]; let u: SmallVec = v.splice(1..1, new).collect(); assert_eq!(v, [0, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6]); - assert_eq!(u, [0u8; 0]); + assert_eq!(u, []); // The range is at the beginning and nonempty. let mut v: SmallVec = smallvec![0, 1, 2, 3, 4, 5, 6]; @@ -328,7 +328,7 @@ fn test_split_off_take_all() { let orig_capacity: usize = vec.capacity(); let split_off = vec.split_off(0); - assert_eq!(&vec[..], &[0u32; 0]); + assert_eq!(&vec[..], &[]); assert_eq!(&split_off[..], &[1, 2, 3, 4, 5, 6]); assert_eq!(vec.capacity(), orig_capacity); assert_eq!(vec.as_ptr(), orig_ptr); @@ -370,7 +370,7 @@ fn test_invalid_grow() { #[should_panic] fn drain_overflow() { let mut v: SmallVec = smallvec![0]; - v.drain(..=usize::MAX); + v.drain(..=std::usize::MAX); } #[test] @@ -538,7 +538,7 @@ fn test_from() { let vec = vec![]; let small_vec: SmallVec = SmallVec::from(vec); - assert_eq!(&*small_vec, &[0u8; 0]); + assert_eq!(&*small_vec, &[]); drop(small_vec); let vec = vec![1, 2, 3, 4, 5]; @@ -684,12 +684,12 @@ fn test_into_inner() { fn test_from_vec() { let vec = vec![]; let small_vec: SmallVec = SmallVec::from_vec(vec); - assert_eq!(&*small_vec, &[0u8; 0]); + assert_eq!(&*small_vec, &[]); drop(small_vec); let vec = vec![]; let small_vec: SmallVec = SmallVec::from_vec(vec); - assert_eq!(&*small_vec, &[0u8; 0]); + assert_eq!(&*small_vec, &[]); drop(small_vec); let vec = vec![1]; @@ -798,26 +798,20 @@ fn test_write() { #[cfg(feature = "serde")] #[test] fn test_serde() { - use serde_test::{assert_tokens, Token}; + use bincode::{config, deserialize}; let mut small_vec: SmallVec = SmallVec::new(); - assert_tokens(&small_vec, &[Token::Seq { len: Some(0) }, Token::SeqEnd]); small_vec.push(1); - assert_tokens( - &small_vec, - &[Token::Seq { len: Some(1) }, Token::I32(1), Token::SeqEnd], - ); - small_vec.extend([2, 3, 4]); - assert_tokens( - &small_vec, - &[ - Token::Seq { len: Some(4) }, - Token::I32(1), - Token::I32(2), - Token::I32(3), - Token::I32(4), - Token::SeqEnd, - ], - ); + let encoded = config().limit(100).serialize(&small_vec).unwrap(); + let decoded: SmallVec = deserialize(&encoded).unwrap(); + assert_eq!(small_vec, decoded); + small_vec.push(2); + // Spill the vec + small_vec.push(3); + small_vec.push(4); + // Check again after spilling. + let encoded = config().limit(100).serialize(&small_vec).unwrap(); + let decoded: SmallVec = deserialize(&encoded).unwrap(); + assert_eq!(small_vec, decoded); } #[test] @@ -932,6 +926,7 @@ fn test_clone_from() { assert_eq!(&*b, &[20, 21, 22]); } +#[cfg(feature = "extract_if")] #[test] fn test_extract_if() { let mut a: SmallVec = smallvec![0, 1u8, 2, 3, 4, 5, 6, 7, 8, 0]; @@ -992,7 +987,11 @@ fn collect_from_iter() { // A length of 3 is fine to trigger this bug under valgrind, but making the vector 1 million // elements makes it crash - which is much easier to detect. - let iter = IterNoHint(std::iter::repeat(1u8).take(1_000_000)); + #[cfg(miri)] + const ELEMENTS: usize = 1000; + #[cfg(not(miri))] + const ELEMENTS: usize = 1_000_000; + let iter = IterNoHint(std::iter::repeat(1u8).take(ELEMENTS)); let _y: SmallVec = SmallVec::from_iter(iter); } From ac731e65fcac7c160fd563f56fabd5ee20f904f6 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Tue, 25 Aug 2026 00:01:44 +0200 Subject: [PATCH 2/3] chore: downgraded criterion to v0.7 --- Cargo.lock | 79 +++--------------------------------------------------- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1900f49b..ba03a9bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,15 +11,6 @@ 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" @@ -65,16 +56,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" -[[package]] -name = "cc" -version = "1.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad534f4357a5264cce5019c989cf66a4f0dc4e0d1b1d15f8aacec0ff7360273" -dependencies = [ - "find-msvc-tools", - "shlex", -] - [[package]] name = "cfg-if" version = "1.0.4" @@ -135,11 +116,10 @@ checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "criterion" -version = "0.8.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "950046b2aa2492f9a536f5f4f9a3de7b9e2476e575e05bd6c333371add4d98f3" +checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" dependencies = [ - "alloca", "anes", "cast", "ciborium", @@ -148,7 +128,6 @@ dependencies = [ "itertools", "num-traits", "oorandom", - "page_size", "plotters", "rayon", "regex", @@ -160,9 +139,9 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.8.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29ea" +checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" dependencies = [ "cast", "itertools", @@ -205,12 +184,6 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" -[[package]] -name = "find-msvc-tools" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" - [[package]] name = "futures-core" version = "0.3.34" @@ -272,12 +245,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "libc" -version = "0.2.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" - [[package]] name = "malloc_size_of" version = "0.1.1" @@ -311,16 +278,6 @@ 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 = "pin-project-lite" version = "0.2.17" @@ -480,12 +437,6 @@ dependencies = [ "zmij", ] -[[package]] -name = "shlex" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" - [[package]] name = "slab" version = "0.4.12" @@ -606,22 +557,6 @@ dependencies = [ "wasm-bindgen", ] -[[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" @@ -631,12 +566,6 @@ 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" diff --git a/Cargo.toml b/Cargo.toml index 1deb55b7..a1b1110f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ malloc_size_of = { version = "0.1.1", optional = true, default-features = false [dev-dependencies] bincode = "1.0.1" -criterion = "0.8" +criterion = "0.7" [package.metadata.docs.rs] all-features = true From dd33da31c4c4443d53ae7cb6b8df2f0b8c5e9c46 Mon Sep 17 00:00:00 2001 From: Alejandro Vaz Date: Tue, 25 Aug 2026 00:10:31 +0200 Subject: [PATCH 3/3] fix: downgraded to criterion 0.4 --- Cargo.lock | 127 +++++++++++++++++++++++++++++++++++++++++++---------- Cargo.toml | 2 +- 2 files changed, 105 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ba03a9bf..c2cf92db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,10 +18,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] -name = "anstyle" -version = "1.0.14" +name = "atty" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] [[package]] name = "autocfg" @@ -38,6 +43,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bumpalo" version = "3.20.3" @@ -91,47 +102,46 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.6" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ - "clap_builder", -] - -[[package]] -name = "clap_builder" -version = "4.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889" -dependencies = [ - "anstyle", + "bitflags", "clap_lex", + "indexmap", + "textwrap", ] [[package]] name = "clap_lex" -version = "1.1.0" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] [[package]] name = "criterion" -version = "0.7.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" dependencies = [ "anes", + "atty", "cast", "ciborium", "clap", "criterion-plot", "itertools", + "lazy_static", "num-traits", "oorandom", "plotters", "rayon", "regex", "serde", + "serde_derive", "serde_json", "tinytemplate", "walkdir", @@ -139,9 +149,9 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.6.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", "itertools", @@ -219,11 +229,36 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + [[package]] name = "itertools" -version = "0.13.0" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] @@ -245,6 +280,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + [[package]] name = "malloc_size_of" version = "0.1.1" @@ -278,6 +325,12 @@ version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + [[package]] name = "pin-project-lite" version = "0.2.17" @@ -476,6 +529,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" + [[package]] name = "tinytemplate" version = "1.2.1" @@ -557,6 +616,22 @@ dependencies = [ "wasm-bindgen", ] +[[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" @@ -566,6 +641,12 @@ 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" diff --git a/Cargo.toml b/Cargo.toml index a1b1110f..df9eb4b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ malloc_size_of = { version = "0.1.1", optional = true, default-features = false [dev-dependencies] bincode = "1.0.1" -criterion = "0.7" +criterion = "0.4" [package.metadata.docs.rs] all-features = true