From 4b35d95e23a64f02656e83d970a421b2d5bf07dc Mon Sep 17 00:00:00 2001 From: Erik McClure Date: Mon, 13 Oct 2025 23:58:24 -0700 Subject: [PATCH 01/12] intermediate commit --- Cargo.lock | 429 +++++++++++++++++--------------------------- Cargo.toml | 11 +- src/nodes/rrb.rs | 100 +++++++++++ src/vector/focus.rs | 6 +- src/vector/mod.rs | 271 +++++++++++++++++++++++++++- 5 files changed, 544 insertions(+), 273 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 64c95e5..d18bc1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,30 +19,30 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "arbitrary" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" [[package]] name = "archery" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae2ed21cd55021f05707a807a5fc85695dafb98832921f6cfa06db67ca5b869" +checksum = "70e0a5f99dfebb87bb342d0f53bb92c81842e100bbb915223e38349580e5441d" dependencies = [ "triomphe", ] [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bincode" @@ -71,9 +71,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "bitmaps" @@ -87,12 +87,6 @@ version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "cast" version = "0.3.0" @@ -101,9 +95,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "ciborium" @@ -134,18 +128,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.43" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50fd97c9dc2399518aa331917ac6f274280ec5eb34e555dd291899745c48ec6f" +checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.43" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35b5830294e1fa0462034af85cc95225a4cb07092c088c55bda3147cfcd8f65" +checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" dependencies = [ "anstyle", "clap_lex", @@ -159,25 +153,22 @@ checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "criterion" -version = "0.5.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" dependencies = [ "anes", "cast", "ciborium", "clap", "criterion-plot", - "is-terminal", "itertools", "num-traits", - "once_cell", "oorandom", "plotters", "rayon", "regex", "serde", - "serde_derive", "serde_json", "tinytemplate", "walkdir", @@ -185,9 +176,9 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" dependencies = [ "cast", "itertools", @@ -232,9 +223,9 @@ checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "env_logger" @@ -248,9 +239,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.10" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", "windows-sys", @@ -270,43 +261,38 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets", + "r-efi", + "wasi 0.14.7+wasi-0.2.4", ] [[package]] name = "half" -version = "2.4.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "e54c115d4f30f52c67202f079c5f9d8b49db4691f460fdb0b4c2e838261b2ba5" dependencies = [ "cfg-if", "crunchy", + "zerocopy", ] -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - [[package]] name = "imbl" version = "6.1.0" @@ -323,8 +309,8 @@ dependencies = [ "proptest", "proptest-derive", "quickcheck", - "rand 0.9.0", - "rand_core 0.9.0", + "rand 0.9.2", + "rand_core 0.9.3", "rand_xoshiro", "rayon", "rpds", @@ -343,37 +329,26 @@ dependencies = [ "bitmaps", ] -[[package]] -name = "is-terminal" -version = "0.4.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys", -] - [[package]] name = "itertools" -version = "0.10.5" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" dependencies = [ "once_cell", "wasm-bindgen", @@ -387,27 +362,27 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.169" +version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "linux-raw-sys" -version = "0.4.15" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "log" -version = "0.4.25" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "metrohash" @@ -426,9 +401,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.3" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "oorandom" @@ -466,11 +441,11 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -485,26 +460,26 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" +checksum = "2bb0be07becd10686a0bb407298fb425360a5c44a663774406340c59a22de4ce" dependencies = [ "bit-set", "bit-vec", "bitflags", "lazy_static", "num-traits", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand 0.9.2", + "rand_chacha", "rand_xorshift", "regex-syntax", "rusty-fork", @@ -542,43 +517,36 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.38" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" 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.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "libc", - "rand_chacha 0.3.1", "rand_core 0.6.4", ] [[package]] name = "rand" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.0", - "zerocopy 0.8.17", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", + "rand_chacha", + "rand_core 0.9.3", ] [[package]] @@ -588,7 +556,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.0", + "rand_core 0.9.3", ] [[package]] @@ -597,26 +565,25 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] name = "rand_core" -version = "0.9.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.1", - "zerocopy 0.8.17", + "getrandom 0.3.3", ] [[package]] name = "rand_xorshift" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.6.4", + "rand_core 0.9.3", ] [[package]] @@ -625,14 +592,14 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41" dependencies = [ - "rand_core 0.9.0", + "rand_core 0.9.3", ] [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -640,9 +607,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -650,9 +617,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" dependencies = [ "aho-corasick", "memchr", @@ -662,9 +629,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" dependencies = [ "aho-corasick", "memchr", @@ -673,24 +640,24 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "rpds" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0e15515d3ce3313324d842629ea4905c25a13f81953eadb88f85516f59290a4" +checksum = "acb4efcdbf5d5489a878f48686e08e0e38da594e98295235b5aeeabe905fbff6" dependencies = [ "archery", ] [[package]] name = "rustix" -version = "0.38.44" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags", "errno", @@ -707,9 +674,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "rusty-fork" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" dependencies = [ "fnv", "quick-error", @@ -719,9 +686,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -734,9 +701,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.224" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aaeb1e94f53b16384af593c71e20b095e958dab1d26939c1b70645c5cfbcc0b" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -744,18 +711,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.224" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f39390fa6346e24defbcdd3d9544ba8a19985d0af74df8501fbfe9a64341ab" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.224" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ff78ab5e8561c9a675bfc1785cb07ae721f0ee53329a595cefd8c04c2ac4e0" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -764,14 +731,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.138" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -782,9 +750,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "syn" -version = "2.0.104" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -793,13 +761,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.16.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ - "cfg-if", "fastrand", - "getrandom 0.3.1", + "getrandom 0.3.3", "once_cell", "rustix", "windows-sys", @@ -817,9 +784,9 @@ dependencies = [ [[package]] name = "triomphe" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8f7726da4807b58ea5c96fdc122f80702030edc33b35aff9190a51148ccc85" +checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39" [[package]] name = "unarray" @@ -829,9 +796,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.16" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unty" @@ -866,36 +833,46 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.7+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" dependencies = [ - "wit-bindgen-rt", + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" dependencies = [ "bumpalo", "log", @@ -907,9 +884,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -917,9 +894,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", @@ -930,18 +907,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" dependencies = [ "js-sys", "wasm-bindgen", @@ -949,94 +926,33 @@ dependencies = [ [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ "windows-sys", ] [[package]] -name = "windows-sys" -version = "0.59.0" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows-targets" -version = "0.52.6" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows-link", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "wit-bindgen-rt" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" -dependencies = [ - "bitflags", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "yansi" @@ -1046,39 +962,18 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive 0.7.35", -] - -[[package]] -name = "zerocopy" -version = "0.8.17" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ - "zerocopy-derive 0.8.17", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.17" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 0859532..d1d5fb0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,10 @@ proptest = { version = "1.0", optional = true } serde_core = { version = "1.0.224", optional = true } rayon = { version = "1", optional = true } arbitrary = { version = "1.0", optional = true } -bincode = {version = "2.0.1", optional = true, default-features=false, features = ["alloc", "std"]} +bincode = { version = "2.0.1", optional = true, default-features = false, features = [ + "alloc", + "std", +] } [dev-dependencies] proptest = "1.0" @@ -64,9 +67,9 @@ proptest-derive = "0.6" static_assertions = "1.1.0" # criterion, rpds and half versions are fixed to the latest versions # that work with the current minimum Rust version -criterion = "0.5" -rpds = { version = "=1.1.0" } -half = "=2.4" +criterion = "0.7" +rpds = { version = "1.1.0" } +half = "2.7" # Include debug symbols when benchmarking, this is useful for profiling [profile.bench] diff --git a/src/nodes/rrb.rs b/src/nodes/rrb.rs index b2befe1..fb6b3c9 100644 --- a/src/nodes/rrb.rs +++ b/src/nodes/rrb.rs @@ -1104,6 +1104,20 @@ impl Node { Self::merge_rebalance(level, left, merged, right) } } + + pub fn ptr_eq(&self, rhs: &Self) -> bool { + match (&self.children, &rhs.children) { + (Nodes(lsize, l), Nodes(rsize, r)) => { + SharedPointer::, CHUNK_SIZE>, P>::ptr_eq(l, r) + && lsize.size() == rsize.size() + } + (Values(l), Values(r)) => { + SharedPointer::, P>::ptr_eq(l, r) + } + (Empty, Empty) => true, + _ => false, + } + } } // fn print_indent(f: &mut W, indent: usize) -> Result<(), fmt::Error> @@ -1115,3 +1129,89 @@ impl Node { // } // Ok(()) // } + +pub(crate) fn map_subsequence( + prev_in: &Node, + next_in: &Node, + level: usize, + prev_out: &Node, + f: &mut impl FnMut(&In) -> Out, +) -> Node { + if prev_in.ptr_eq(next_in) { + prev_out.clone() + } else { + match &next_in.children { + Entry::Values(xs) => { + return Node::from_chunk( + level, + SharedPointer::new(Chunk::collect_from( + &mut xs.iter().map(|x| f(x)), + CHUNK_SIZE, + )), + ) + } + Entry::Nodes(_, children) => { + let Entry::Nodes(_, prev_children) = &prev_in.children else { + return Node::parent( + level, + Chunk::collect_from( + &mut children + .iter() + .map(|x| map_subseq_unpaired(x, level - 1, f)), + CHUNK_SIZE, + ), + ); + }; + let Entry::Nodes(_, prev_out_children) = &prev_out.children else { + panic!("previous out structure doesn't match previous in structure") + }; + return Node::parent( + level, + Chunk::collect_from( + &mut prev_children + .iter() + .zip(children.iter()) + .zip(prev_out_children.iter()) + .map(|((prev_child_in, next_child_in), prev_child_out)| { + map_subsequence( + prev_child_in, + next_child_in, + level - 1, + prev_child_out, + f, + ) + }), + CHUNK_SIZE, + ), + ); + } + Entry::Empty => Node::new(), + } + } +} + +fn map_subseq_unpaired( + next_in: &Node, + level: usize, + f: &mut impl FnMut(&In) -> Out, +) -> Node { + match &next_in.children { + Entry::Values(xs) => Node::from_chunk( + level, + SharedPointer::new(Chunk::collect_from( + &mut xs.iter().map(|x| f(x)), + CHUNK_SIZE, + )), + ), + Entry::Nodes(_, children) => Node::parent( + level, + Chunk::collect_from( + &mut children + .iter() + .map(|x| map_subseq_unpaired(x, level - 1, f)), + CHUNK_SIZE, + ), + ), + Entry::Empty => Node::new(), + } +} diff --git a/src/vector/focus.rs b/src/vector/focus.rs index cf577d0..ac9503d 100644 --- a/src/vector/focus.rs +++ b/src/vector/focus.rs @@ -114,7 +114,11 @@ where /// /// [Vector]: type.Vector.html pub fn new(vector: &'a GenericVector) -> Self { - match &vector.vector { + Self::new_inner(&vector.vector) + } + + pub(super) fn new_inner(vector: &'a crate::vector::VectorInner) -> Self { + match vector { Inline(chunk) => Focus::Single(chunk), Single(chunk) => Focus::Single(chunk), Full(tree) => Focus::Full(TreeFocus::new(tree)), diff --git a/src/vector/mod.rs b/src/vector/mod.rs index 8c15725..f7696e8 100644 --- a/src/vector/mod.rs +++ b/src/vector/mod.rs @@ -170,6 +170,21 @@ pub struct RRB { outer_b: SharedPointer, P>, } +fn rrb_from_chunk( + chunk: SharedPointer, P>, + front: bool, +) -> RRB { + RRB { + length: chunk.len(), + middle_level: 0, + outer_f: SharedPointer::default(), + inner_f: chunk, + middle: SharedPointer::new(Node::new()), + inner_b: SharedPointer::default(), + outer_b: SharedPointer::default(), + } +} + impl Clone for RRB { fn clone(&self) -> Self { RRB { @@ -391,7 +406,7 @@ impl GenericVector { #[inline] #[must_use] pub fn focus(&self) -> Focus<'_, A, P> { - Focus::new(self) + Focus::new_inner(&self.vector) } /// Get a reference to the value at index `index` in a vector. @@ -2914,3 +2929,257 @@ mod test { // } } } + +/// Represents a stateful map between two persistent [`imbl::Vector`]s. Internally remembers the previous state that was passed in, so +/// as much of the output Vector can be re-used as possible. +pub struct MapSeqWithKey { + previous_in: VectorInner, + previous_out: VectorInner, + keylookup: std::collections::HashMap, +} + +impl MapSeqWithKey { + /// Initializes a new empty map state + pub fn new() -> Self { + Self { + previous_in: Inline(InlineArray::new()), + previous_out: Inline(InlineArray::new()), + keylookup: std::collections::HashMap::new(), + } + } + + fn clear_prev_in<'a>( + keylookup: &mut std::collections::HashMap, + prev_in: impl Iterator, + ex: &impl Fn(&In) -> Key, + ) where + In: 'a, + { + for item in prev_in { + if let std::collections::hash_map::Entry::Occupied(mut o) = keylookup.entry(ex(item)) { + if o.get().1 <= 1 { + o.remove(); + } else { + o.get_mut().1 -= 1; + } + } + } + } + + /// Produces an output vector from the input vector using a map function and a key extractor. + pub fn map( + &mut self, + from: &GenericVector, + mut ma: impl FnMut(&In) -> Out, + ex: impl Fn(&In) -> Key, + ) -> GenericVector { + match &from.vector { + Inline(chunk) => { + let mut inline = InlineArray::new(); + for item in chunk { + inline.push( + self.keylookup + .entry(ex(item)) + .and_modify(|x| x.1 += 1) + .or_insert_with(|| (ma(item), 1)) + .0 + .clone(), + ); + } + Self::clear_prev_in( + &mut self.keylookup, + Iter::from_focus(focus::Focus::new_inner(&self.previous_in)), + &ex, + ); + self.previous_in = VectorInner::Inline(chunk.clone()); + GenericVector { + vector: VectorInner::Inline(inline), + } + } + Single(p) => { + let mut pending_rrb = None; + match &mut self.previous_in { + Inline(chunk) => self.previous_in = Single(SharedPointer::new(chunk.into())), + Single(p) => (), + Full(rrb) => { + pending_rrb = Some(rrb); + self.previous_in = VectorInner::Single(SharedPointer::new(Chunk::new())) + } + } + match &mut self.previous_out { + Inline(chunk) => self.previous_out = Single(SharedPointer::new(chunk.into())), + Single(p) => (), + Full(_) => { + self.previous_out = VectorInner::Single(SharedPointer::new(Chunk::new())) + } + } + + let (VectorInner::Single(prev_in), VectorInner::Single(prev_out), keylookup) = + (&self.previous_in, &self.previous_out, &mut self.keylookup) + else { + panic!("invalid internal state"); + }; + + let out = GenericVector { + vector: VectorInner::Single(Self::map_subvalues( + &prev_in, &p, &prev_out, keylookup, &ex, &mut ma, + )), + }; + out + } + Full(rrb) => GenericVector { + vector: VectorInner::Full(Self::map_with_key_internal(self, rrb, &ex, ma)), + }, + } + } + + fn map_subvalues( + prev_in: &SharedPointer, P>, + next_in: &SharedPointer, P>, + prev_out: &SharedPointer, P>, + keylookup: &mut std::collections::HashMap, + ex: &impl Fn(&In) -> Key, + mut ma: impl FnMut(&In) -> Out, + ) -> SharedPointer, P> { + if SharedPointer::, P>::ptr_eq(prev_in, next_in) { + prev_out.clone() + } else { + let chunk = SharedPointer::new(Chunk::collect_from( + &mut next_in.iter().map(|x| { + keylookup + .entry(ex(x)) + .and_modify(|v| v.1 += 1) + .or_insert_with(|| (ma(x), 1)) + .0 + .clone() + }), + CHUNK_SIZE, + )); + Self::clear_prev_in(keylookup, prev_in.iter(), &ex); + chunk + } + } + + fn map_with_key_internal( + state: &mut MapSeqWithKey, + next_in: &RRB, + ex: &impl Fn(&In) -> Key, + mut ma: impl FnMut(&In) -> Out, + ) -> RRB { + use crate::nodes::rrb::map_subsequence; + + match &mut state.previous_in { + Inline(chunk) => { + state.previous_in = + VectorInner::Full(rrb_from_chunk(SharedPointer::new(chunk.into()), true)) + } + Single(chunk) => { + state.previous_in = VectorInner::Full(rrb_from_chunk(chunk.clone(), true)) + } + Full(_) => (), + } + + match &mut state.previous_out { + Inline(chunk) => { + state.previous_out = + VectorInner::Full(rrb_from_chunk(SharedPointer::new(chunk.into()), true)) + } + Single(chunk) => { + state.previous_out = VectorInner::Full(rrb_from_chunk(chunk.clone(), true)) + } + Full(_) => (), + } + + let (VectorInner::Full(prev_in), VectorInner::Full(prev_out), keylookup) = ( + &state.previous_in, + &state.previous_out, + &mut state.keylookup, + ) else { + panic!("invalid internal state"); + }; + + let outer_f = Self::map_subvalues( + &prev_in.outer_f, + &next_in.outer_f, + &prev_out.outer_f, + keylookup, + ex, + &mut ma, + ); + let inner_f = Self::map_subvalues( + &prev_in.inner_f, + &next_in.inner_f, + &prev_out.inner_f, + keylookup, + ex, + &mut ma, + ); + let inner_b = Self::map_subvalues( + &prev_in.inner_b, + &next_in.inner_b, + &prev_out.inner_b, + keylookup, + ex, + &mut ma, + ); + let outer_b = Self::map_subvalues( + &prev_in.outer_b, + &next_in.outer_b, + &prev_out.outer_b, + keylookup, + ex, + &mut ma, + ); + + let middle = map_subsequence( + &prev_in.middle, + &next_in.middle, + next_in.middle_level, + &prev_out.middle, + &mut |x| { + keylookup + .entry(ex(x)) + .and_modify(|v| v.1 += 1) + .or_insert_with(|| (ma(x), 1)) + .0 + .clone() + }, + ); + + let next_out = RRB { + length: next_in.length, + middle_level: next_in.middle_level, + outer_f, + inner_f, + middle: SharedPointer::new(middle), + inner_b, + outer_b, + }; + + state.previous_in = VectorInner::Full(next_in.clone()); + state.previous_out = VectorInner::Full(next_out.clone()); + + next_out + } +} + +#[test] +fn test_vector_map_basic() { + let a = vector![1, 2, 3, 4]; + + let mut map = MapSeqWithKey::::new(); + + let b = map.map(&a, |x| *x * *x, |x| *x); + + println!("{b:?}") +} + +#[test] +fn test_vector_map_big() { + let mut a = Vector::from_iter(0..100); + let mut map = MapSeqWithKey::::new(); + + let b = map.map(&a, |x| *x * *x, |x| *x); + + println!("{b:?}") +} From fb89e3245981332443d6f6782aff1dbccb30b9f0 Mon Sep 17 00:00:00 2001 From: Erik McClure Date: Wed, 15 Oct 2025 14:52:56 -0700 Subject: [PATCH 02/12] Add persistent-map --- Cargo.lock | 57 +++++------ src/lib.rs | 1 + src/nodes/rrb.rs | 64 +++++++------ src/vector/mod.rs | 235 +++++++++++++++++++++++++++------------------- 4 files changed, 196 insertions(+), 161 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d18bc1d..968b986 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,9 +95,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "ciborium" @@ -128,18 +128,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.48" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" +checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.48" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" +checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730" dependencies = [ "anstyle", "clap_lex", @@ -147,9 +147,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "criterion" @@ -267,26 +267,26 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.7+wasi-0.2.4", + "wasip2", ] [[package]] name = "half" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54c115d4f30f52c67202f079c5f9d8b49db4691f460fdb0b4c2e838261b2ba5" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", @@ -362,9 +362,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.176" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "linux-raw-sys" @@ -574,7 +574,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] @@ -617,9 +617,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.3" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -629,9 +629,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -640,9 +640,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rpds" @@ -766,7 +766,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", "rustix", "windows-sys", @@ -837,15 +837,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasi" -version = "0.14.7+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" -dependencies = [ - "wasip2", -] - [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" diff --git a/src/lib.rs b/src/lib.rs index c7fcb6f..a13ccc4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -331,6 +331,7 @@ mod config; mod nodes; mod sort; mod sync; +pub use archery; #[macro_use] mod ord; diff --git a/src/nodes/rrb.rs b/src/nodes/rrb.rs index fb6b3c9..7f7f427 100644 --- a/src/nodes/rrb.rs +++ b/src/nodes/rrb.rs @@ -2,6 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use std::iter::FromIterator; use std::mem::replace; use std::ops::Range; @@ -602,6 +603,18 @@ impl Node { // } // } // } + + pub(crate) fn process(&self, f: &mut impl FnMut(&Chunk)) { + match &self.children { + Entry::Values(xs) => f(&xs), + Entry::Nodes(_, children) => { + for child in children.iter() { + child.process(f); + } + } + Entry::Empty => (), + } + } } impl Node { @@ -1105,7 +1118,7 @@ impl Node { } } - pub fn ptr_eq(&self, rhs: &Self) -> bool { + pub(crate) fn ptr_eq(&self, rhs: &Self) -> bool { match (&self.children, &rhs.children) { (Nodes(lsize, l), Nodes(rsize, r)) => { SharedPointer::, CHUNK_SIZE>, P>::ptr_eq(l, r) @@ -1135,40 +1148,39 @@ pub(crate) fn map_subsequence( next_in: &Node, level: usize, prev_out: &Node, - f: &mut impl FnMut(&In) -> Out, + f: &mut impl FnMut(&Chunk, bool) -> Option>, ) -> Node { if prev_in.ptr_eq(next_in) { prev_out.clone() } else { match &next_in.children { Entry::Values(xs) => { - return Node::from_chunk( - level, - SharedPointer::new(Chunk::collect_from( - &mut xs.iter().map(|x| f(x)), - CHUNK_SIZE, - )), - ) + let result = Node::from_chunk(level, SharedPointer::new(f(&xs, false).unwrap())); + prev_in.process(&mut |chunk| { + f(chunk, true); + }); + return result; } Entry::Nodes(_, children) => { let Entry::Nodes(_, prev_children) = &prev_in.children else { - return Node::parent( + let result = Node::parent( level, - Chunk::collect_from( - &mut children - .iter() - .map(|x| map_subseq_unpaired(x, level - 1, f)), - CHUNK_SIZE, - ), + Chunk::from_iter(&mut children.iter().map(|x| { + map_subseq_unpaired(x, level - 1, &mut |chunk| f(chunk, false).unwrap()) + })), ); + prev_in.process(&mut |chunk| { + f(chunk, true); + }); + return result; }; let Entry::Nodes(_, prev_out_children) = &prev_out.children else { panic!("previous out structure doesn't match previous in structure") }; return Node::parent( level, - Chunk::collect_from( - &mut prev_children + Chunk::from_iter( + prev_children .iter() .zip(children.iter()) .zip(prev_out_children.iter()) @@ -1181,7 +1193,6 @@ pub(crate) fn map_subsequence( f, ) }), - CHUNK_SIZE, ), ); } @@ -1193,23 +1204,16 @@ pub(crate) fn map_subsequence( fn map_subseq_unpaired( next_in: &Node, level: usize, - f: &mut impl FnMut(&In) -> Out, + f: &mut impl FnMut(&Chunk) -> Chunk, ) -> Node { match &next_in.children { - Entry::Values(xs) => Node::from_chunk( - level, - SharedPointer::new(Chunk::collect_from( - &mut xs.iter().map(|x| f(x)), - CHUNK_SIZE, - )), - ), + Entry::Values(xs) => Node::from_chunk(level, SharedPointer::new(f(&xs))), Entry::Nodes(_, children) => Node::parent( level, - Chunk::collect_from( - &mut children + Chunk::from_iter( + children .iter() .map(|x| map_subseq_unpaired(x, level - 1, f)), - CHUNK_SIZE, ), ), Entry::Empty => Node::new(), diff --git a/src/vector/mod.rs b/src/vector/mod.rs index f7696e8..da416aa 100644 --- a/src/vector/mod.rs +++ b/src/vector/mod.rs @@ -170,10 +170,7 @@ pub struct RRB { outer_b: SharedPointer, P>, } -fn rrb_from_chunk( - chunk: SharedPointer, P>, - front: bool, -) -> RRB { +fn rrb_from_chunk(chunk: SharedPointer, P>) -> RRB { RRB { length: chunk.len(), middle_level: 0, @@ -228,15 +225,7 @@ impl GenericVector { Inline(chunk) => Single(SharedPointer::new(chunk.into())), Single(chunk) => { let chunk = chunk.clone(); - Full(RRB { - length: chunk.len(), - middle_level: 0, - outer_f: SharedPointer::default(), - inner_f: chunk, - middle: SharedPointer::new(Node::new()), - inner_b: SharedPointer::default(), - outer_b: SharedPointer::default(), - }) + Full(rrb_from_chunk(chunk)) } Full(_) => return, } @@ -2038,6 +2027,12 @@ impl Clone for Iter<'_, A, P> { } } +impl std::fmt::Debug for Iter<'_, A, P> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + impl<'a, A, P: SharedPointerKind + 'a> Iterator for Iter<'a, A, P> { type Item = &'a A; @@ -2932,13 +2927,13 @@ mod test { /// Represents a stateful map between two persistent [`imbl::Vector`]s. Internally remembers the previous state that was passed in, so /// as much of the output Vector can be re-used as possible. -pub struct MapSeqWithKey { +pub struct PersistentMap { previous_in: VectorInner, previous_out: VectorInner, keylookup: std::collections::HashMap, } -impl MapSeqWithKey { +impl PersistentMap { /// Initializes a new empty map state pub fn new() -> Self { Self { @@ -2966,6 +2961,44 @@ impl MapSeqWithKey< } } + fn map_next_in<'a>( + keylookup: &'a mut std::collections::HashMap, + next_in: impl Iterator, + ex: &impl Fn(&In) -> Key, + ma: &mut impl FnMut(&In) -> Out, + mut f: impl FnMut(&Out), + ) where + In: 'a, + { + for item in next_in { + f(&keylookup + .entry(ex(item)) + .and_modify(|x| x.1 += 1) + .or_insert_with(|| (ma(item), 1)) + .0) + } + } + + fn map_chunk( + prev_in: &SharedPointer, P>, + next_in: &SharedPointer, P>, + prev_out: &SharedPointer, P>, + keylookup: &mut std::collections::HashMap, + ex: &impl Fn(&In) -> Key, + ma: &mut impl FnMut(&In) -> Out, + ) -> SharedPointer, P> { + if SharedPointer::, P>::ptr_eq(prev_in, next_in) { + prev_out.clone() + } else { + let mut chunk = Chunk::new(); + Self::map_next_in(keylookup, next_in.iter(), ex, ma, |item| { + chunk.push_back(item.clone()) + }); + Self::clear_prev_in(keylookup, prev_in.iter(), &ex); + SharedPointer::new(chunk) + } + } + /// Produces an output vector from the input vector using a map function and a key extractor. pub fn map( &mut self, @@ -2974,56 +3007,70 @@ impl MapSeqWithKey< ex: impl Fn(&In) -> Key, ) -> GenericVector { match &from.vector { - Inline(chunk) => { + Inline(next_in) => { let mut inline = InlineArray::new(); - for item in chunk { - inline.push( - self.keylookup - .entry(ex(item)) - .and_modify(|x| x.1 += 1) - .or_insert_with(|| (ma(item), 1)) - .0 - .clone(), - ); - } + Self::map_next_in(&mut self.keylookup, next_in.iter(), &ex, &mut ma, |item| { + inline.push(item.clone()) + }); Self::clear_prev_in( &mut self.keylookup, Iter::from_focus(focus::Focus::new_inner(&self.previous_in)), &ex, ); - self.previous_in = VectorInner::Inline(chunk.clone()); + self.previous_in = VectorInner::Inline(next_in.clone()); GenericVector { vector: VectorInner::Inline(inline), } } - Single(p) => { - let mut pending_rrb = None; - match &mut self.previous_in { - Inline(chunk) => self.previous_in = Single(SharedPointer::new(chunk.into())), - Single(p) => (), - Full(rrb) => { - pending_rrb = Some(rrb); - self.previous_in = VectorInner::Single(SharedPointer::new(Chunk::new())) - } - } + Single(next_in) => { match &mut self.previous_out { Inline(chunk) => self.previous_out = Single(SharedPointer::new(chunk.into())), - Single(p) => (), + Single(_) => (), Full(_) => { - self.previous_out = VectorInner::Single(SharedPointer::new(Chunk::new())) + let mut chunk = Chunk::new(); + Self::map_next_in(&mut self.keylookup, next_in.iter(), &ex, &mut ma, |v| { + chunk.push_back(v.clone()) + }); + Self::clear_prev_in( + &mut self.keylookup, + Iter::from_focus(focus::Focus::new_inner(&self.previous_in)), + &ex, + ); + return GenericVector { + vector: VectorInner::Single(SharedPointer::new(chunk)), + }; } } - let (VectorInner::Single(prev_in), VectorInner::Single(prev_out), keylookup) = - (&self.previous_in, &self.previous_out, &mut self.keylookup) - else { - panic!("invalid internal state"); + let inner = match &self.previous_in { + Single(prev_in) => { + let (VectorInner::Single(prev_out), keylookup) = + (&self.previous_out, &mut self.keylookup) + else { + panic!("invalid internal state"); + }; + Self::map_chunk(&prev_in, next_in, &prev_out, keylookup, &ex, &mut ma) + } + Inline(_) | Full(_) => { + let mut chunk = Chunk::new(); + Self::map_next_in( + &mut self.keylookup, + next_in.iter(), + &ex, + &mut ma, + |item| chunk.push_back(item.clone()), + ); + Self::clear_prev_in( + &mut self.keylookup, + Iter::from_focus(focus::Focus::new_inner(&self.previous_in)), + &ex, + ); + SharedPointer::new(chunk) + } }; let out = GenericVector { - vector: VectorInner::Single(Self::map_subvalues( - &prev_in, &p, &prev_out, keylookup, &ex, &mut ma, - )), + vector: VectorInner::Single(inner), }; out } @@ -3033,35 +3080,8 @@ impl MapSeqWithKey< } } - fn map_subvalues( - prev_in: &SharedPointer, P>, - next_in: &SharedPointer, P>, - prev_out: &SharedPointer, P>, - keylookup: &mut std::collections::HashMap, - ex: &impl Fn(&In) -> Key, - mut ma: impl FnMut(&In) -> Out, - ) -> SharedPointer, P> { - if SharedPointer::, P>::ptr_eq(prev_in, next_in) { - prev_out.clone() - } else { - let chunk = SharedPointer::new(Chunk::collect_from( - &mut next_in.iter().map(|x| { - keylookup - .entry(ex(x)) - .and_modify(|v| v.1 += 1) - .or_insert_with(|| (ma(x), 1)) - .0 - .clone() - }), - CHUNK_SIZE, - )); - Self::clear_prev_in(keylookup, prev_in.iter(), &ex); - chunk - } - } - fn map_with_key_internal( - state: &mut MapSeqWithKey, + state: &mut PersistentMap, next_in: &RRB, ex: &impl Fn(&In) -> Key, mut ma: impl FnMut(&In) -> Out, @@ -3071,22 +3091,18 @@ impl MapSeqWithKey< match &mut state.previous_in { Inline(chunk) => { state.previous_in = - VectorInner::Full(rrb_from_chunk(SharedPointer::new(chunk.into()), true)) - } - Single(chunk) => { - state.previous_in = VectorInner::Full(rrb_from_chunk(chunk.clone(), true)) + VectorInner::Full(rrb_from_chunk(SharedPointer::new(chunk.into()))) } + Single(chunk) => state.previous_in = VectorInner::Full(rrb_from_chunk(chunk.clone())), Full(_) => (), } match &mut state.previous_out { Inline(chunk) => { state.previous_out = - VectorInner::Full(rrb_from_chunk(SharedPointer::new(chunk.into()), true)) - } - Single(chunk) => { - state.previous_out = VectorInner::Full(rrb_from_chunk(chunk.clone(), true)) + VectorInner::Full(rrb_from_chunk(SharedPointer::new(chunk.into()))) } + Single(chunk) => state.previous_out = VectorInner::Full(rrb_from_chunk(chunk.clone())), Full(_) => (), } @@ -3098,7 +3114,7 @@ impl MapSeqWithKey< panic!("invalid internal state"); }; - let outer_f = Self::map_subvalues( + let outer_f = Self::map_chunk( &prev_in.outer_f, &next_in.outer_f, &prev_out.outer_f, @@ -3106,7 +3122,7 @@ impl MapSeqWithKey< ex, &mut ma, ); - let inner_f = Self::map_subvalues( + let inner_f = Self::map_chunk( &prev_in.inner_f, &next_in.inner_f, &prev_out.inner_f, @@ -3114,7 +3130,7 @@ impl MapSeqWithKey< ex, &mut ma, ); - let inner_b = Self::map_subvalues( + let inner_b = Self::map_chunk( &prev_in.inner_b, &next_in.inner_b, &prev_out.inner_b, @@ -3122,7 +3138,7 @@ impl MapSeqWithKey< ex, &mut ma, ); - let outer_b = Self::map_subvalues( + let outer_b = Self::map_chunk( &prev_in.outer_b, &next_in.outer_b, &prev_out.outer_b, @@ -3136,13 +3152,17 @@ impl MapSeqWithKey< &next_in.middle, next_in.middle_level, &prev_out.middle, - &mut |x| { - keylookup - .entry(ex(x)) - .and_modify(|v| v.1 += 1) - .or_insert_with(|| (ma(x), 1)) - .0 - .clone() + &mut |next_in, undo| { + if undo { + Self::clear_prev_in(keylookup, next_in.iter(), ex); + None + } else { + let mut chunk = Chunk::new(); + Self::map_next_in(keylookup, next_in.iter(), ex, &mut ma, |item| { + chunk.push_back(item.clone()) + }); + Some(chunk) + } }, ); @@ -3167,7 +3187,7 @@ impl MapSeqWithKey< fn test_vector_map_basic() { let a = vector![1, 2, 3, 4]; - let mut map = MapSeqWithKey::::new(); + let mut map = PersistentMap::::new(); let b = map.map(&a, |x| *x * *x, |x| *x); @@ -3176,10 +3196,29 @@ fn test_vector_map_basic() { #[test] fn test_vector_map_big() { - let mut a = Vector::from_iter(0..100); - let mut map = MapSeqWithKey::::new(); + const COUNT: usize = 10000; + let mut a = Vector::from_iter((0..COUNT).map(|i| i as i64)); + let mut map = PersistentMap::::new(); - let b = map.map(&a, |x| *x * *x, |x| *x); + let mut b = map.map(&a, |x| *x + 1, |x| *x as usize); - println!("{b:?}") + let mut mutation_count = 0; + + for i in 0..COUNT { + a[i] *= a[i]; + b = map.map( + &a, + |x| { + mutation_count += 1; + *x + 1 + }, + |x| *x as usize, + ); + } + + for i in 0..COUNT as i64 { + assert_eq!(b[i as usize], (i * i) + 1); + } + assert_eq!(map.keylookup.len(), COUNT); + assert!(mutation_count < map.keylookup.len()); } From 2ec4a669f8a06f8ace23468c8b99f3a31fbba8d8 Mon Sep 17 00:00:00 2001 From: Erik McClure Date: Thu, 16 Oct 2025 00:23:10 -0700 Subject: [PATCH 03/12] Update mod.rs --- src/vector/mod.rs | 156 ++++++++++++++++++++++++++++------------------ 1 file changed, 94 insertions(+), 62 deletions(-) diff --git a/src/vector/mod.rs b/src/vector/mod.rs index da416aa..7f0e7a6 100644 --- a/src/vector/mod.rs +++ b/src/vector/mod.rs @@ -2927,19 +2927,38 @@ mod test { /// Represents a stateful map between two persistent [`imbl::Vector`]s. Internally remembers the previous state that was passed in, so /// as much of the output Vector can be re-used as possible. -pub struct PersistentMap { +pub struct PersistentMap< + In, + Out, + Key: Eq + Hash, + P: SharedPointerKind, + F: FnMut(&In) -> Out, + Ex: Fn(&In) -> Key, +> { previous_in: VectorInner, previous_out: VectorInner, keylookup: std::collections::HashMap, + f: F, + ex: Ex, } -impl PersistentMap { +impl< + In: Clone, + Out: Clone, + Key: Eq + Hash, + P: SharedPointerKind, + F: FnMut(&In) -> Out, + Ex: Fn(&In) -> Key, + > PersistentMap +{ /// Initializes a new empty map state - pub fn new() -> Self { + pub fn new(f: F, ex: Ex) -> Self { Self { previous_in: Inline(InlineArray::new()), previous_out: Inline(InlineArray::new()), keylookup: std::collections::HashMap::new(), + f, + ex, } } @@ -3000,22 +3019,21 @@ impl PersistentMap< } /// Produces an output vector from the input vector using a map function and a key extractor. - pub fn map( - &mut self, - from: &GenericVector, - mut ma: impl FnMut(&In) -> Out, - ex: impl Fn(&In) -> Key, - ) -> GenericVector { + pub fn map(&mut self, from: &GenericVector) -> GenericVector { match &from.vector { Inline(next_in) => { let mut inline = InlineArray::new(); - Self::map_next_in(&mut self.keylookup, next_in.iter(), &ex, &mut ma, |item| { - inline.push(item.clone()) - }); + Self::map_next_in( + &mut self.keylookup, + next_in.iter(), + &self.ex, + &mut self.f, + |item| inline.push(item.clone()), + ); Self::clear_prev_in( &mut self.keylookup, Iter::from_focus(focus::Focus::new_inner(&self.previous_in)), - &ex, + &self.ex, ); self.previous_in = VectorInner::Inline(next_in.clone()); GenericVector { @@ -3028,13 +3046,17 @@ impl PersistentMap< Single(_) => (), Full(_) => { let mut chunk = Chunk::new(); - Self::map_next_in(&mut self.keylookup, next_in.iter(), &ex, &mut ma, |v| { - chunk.push_back(v.clone()) - }); + Self::map_next_in( + &mut self.keylookup, + next_in.iter(), + &self.ex, + &mut self.f, + |v| chunk.push_back(v.clone()), + ); Self::clear_prev_in( &mut self.keylookup, Iter::from_focus(focus::Focus::new_inner(&self.previous_in)), - &ex, + &self.ex, ); return GenericVector { vector: VectorInner::Single(SharedPointer::new(chunk)), @@ -3049,21 +3071,28 @@ impl PersistentMap< else { panic!("invalid internal state"); }; - Self::map_chunk(&prev_in, next_in, &prev_out, keylookup, &ex, &mut ma) + Self::map_chunk( + &prev_in, + next_in, + &prev_out, + keylookup, + &self.ex, + &mut self.f, + ) } Inline(_) | Full(_) => { let mut chunk = Chunk::new(); Self::map_next_in( &mut self.keylookup, next_in.iter(), - &ex, - &mut ma, + &self.ex, + &mut self.f, |item| chunk.push_back(item.clone()), ); Self::clear_prev_in( &mut self.keylookup, Iter::from_focus(focus::Focus::new_inner(&self.previous_in)), - &ex, + &self.ex, ); SharedPointer::new(chunk) } @@ -3075,41 +3104,38 @@ impl PersistentMap< out } Full(rrb) => GenericVector { - vector: VectorInner::Full(Self::map_with_key_internal(self, rrb, &ex, ma)), + vector: VectorInner::Full(self.map_with_key_internal(rrb)), }, } } - fn map_with_key_internal( - state: &mut PersistentMap, - next_in: &RRB, - ex: &impl Fn(&In) -> Key, - mut ma: impl FnMut(&In) -> Out, - ) -> RRB { + fn map_with_key_internal(&mut self, next_in: &RRB) -> RRB { use crate::nodes::rrb::map_subsequence; - match &mut state.previous_in { + match &mut self.previous_in { Inline(chunk) => { - state.previous_in = + self.previous_in = VectorInner::Full(rrb_from_chunk(SharedPointer::new(chunk.into()))) } - Single(chunk) => state.previous_in = VectorInner::Full(rrb_from_chunk(chunk.clone())), + Single(chunk) => self.previous_in = VectorInner::Full(rrb_from_chunk(chunk.clone())), Full(_) => (), } - match &mut state.previous_out { + match &mut self.previous_out { Inline(chunk) => { - state.previous_out = + self.previous_out = VectorInner::Full(rrb_from_chunk(SharedPointer::new(chunk.into()))) } - Single(chunk) => state.previous_out = VectorInner::Full(rrb_from_chunk(chunk.clone())), + Single(chunk) => self.previous_out = VectorInner::Full(rrb_from_chunk(chunk.clone())), Full(_) => (), } - let (VectorInner::Full(prev_in), VectorInner::Full(prev_out), keylookup) = ( - &state.previous_in, - &state.previous_out, - &mut state.keylookup, + let (VectorInner::Full(prev_in), VectorInner::Full(prev_out), keylookup, ex, ma) = ( + &self.previous_in, + &self.previous_out, + &mut self.keylookup, + &self.ex, + &mut self.f, ) else { panic!("invalid internal state"); }; @@ -3120,7 +3146,7 @@ impl PersistentMap< &prev_out.outer_f, keylookup, ex, - &mut ma, + ma, ); let inner_f = Self::map_chunk( &prev_in.inner_f, @@ -3128,7 +3154,7 @@ impl PersistentMap< &prev_out.inner_f, keylookup, ex, - &mut ma, + ma, ); let inner_b = Self::map_chunk( &prev_in.inner_b, @@ -3136,7 +3162,7 @@ impl PersistentMap< &prev_out.inner_b, keylookup, ex, - &mut ma, + ma, ); let outer_b = Self::map_chunk( &prev_in.outer_b, @@ -3144,7 +3170,7 @@ impl PersistentMap< &prev_out.outer_b, keylookup, ex, - &mut ma, + ma, ); let middle = map_subsequence( @@ -3158,7 +3184,7 @@ impl PersistentMap< None } else { let mut chunk = Chunk::new(); - Self::map_next_in(keylookup, next_in.iter(), ex, &mut ma, |item| { + Self::map_next_in(keylookup, next_in.iter(), ex, ma, |item| { chunk.push_back(item.clone()) }); Some(chunk) @@ -3176,8 +3202,8 @@ impl PersistentMap< outer_b, }; - state.previous_in = VectorInner::Full(next_in.clone()); - state.previous_out = VectorInner::Full(next_out.clone()); + self.previous_in = VectorInner::Full(next_in.clone()); + self.previous_out = VectorInner::Full(next_out.clone()); next_out } @@ -3187,38 +3213,44 @@ impl PersistentMap< fn test_vector_map_basic() { let a = vector![1, 2, 3, 4]; - let mut map = PersistentMap::::new(); + let mut map = PersistentMap::::new(|x| *x * *x, |x| *x); - let b = map.map(&a, |x| *x * *x, |x| *x); + let b = map.map(&a); - println!("{b:?}") + assert_eq!(b[0], 1); + assert_eq!(b[1], 4); + assert_eq!(b[2], 9); + assert_eq!(b[3], 16); } #[test] fn test_vector_map_big() { const COUNT: usize = 10000; let mut a = Vector::from_iter((0..COUNT).map(|i| i as i64)); - let mut map = PersistentMap::::new(); - - let mut b = map.map(&a, |x| *x + 1, |x| *x as usize); - let mut mutation_count = 0; - for i in 0..COUNT { - a[i] *= a[i]; - b = map.map( - &a, + let len = { + let mut map = PersistentMap::::new( |x| { mutation_count += 1; *x + 1 }, |x| *x as usize, ); - } - for i in 0..COUNT as i64 { - assert_eq!(b[i as usize], (i * i) + 1); - } - assert_eq!(map.keylookup.len(), COUNT); - assert!(mutation_count < map.keylookup.len()); + let mut b = map.map(&a); + + for i in 0..COUNT { + a[i] *= a[i]; + b = map.map(&a); + } + + for i in 0..COUNT as i64 { + assert_eq!(b[i as usize], (i * i) + 1); + } + assert_eq!(map.keylookup.len(), COUNT); + map.keylookup.len() + }; + + assert!(mutation_count < len * 2); } From 5bececebef69a0dbf0651742fae4ecb3fc7900f8 Mon Sep 17 00:00:00 2001 From: Erik McClure Date: Fri, 17 Oct 2025 20:26:58 -0700 Subject: [PATCH 04/12] Support arbitrary chunks --- benches/vector.rs | 75 ++++----- src/hash/set.rs | 10 +- src/nodes/mod.rs | 3 +- src/nodes/rrb.rs | 104 ++++++------ src/ser.rs | 10 +- src/sort.rs | 13 +- src/vector/focus.rs | 79 +++++----- src/vector/mod.rs | 375 ++++++++++++++++++++++++++++---------------- src/vector/rayon.rs | 42 ++--- 9 files changed, 419 insertions(+), 292 deletions(-) diff --git a/benches/vector.rs b/benches/vector.rs index f3bfeb4..80d3154 100644 --- a/benches/vector.rs +++ b/benches/vector.rs @@ -1,14 +1,15 @@ use criterion::{criterion_group, criterion_main, Bencher, Criterion}; +use imbl::shared_ptr::DefaultSharedPtr; use imbl::vector::Vector; +use imbl::GenericVector; use rand::seq::SliceRandom; use std::collections::VecDeque; use std::hint::black_box; use std::iter::FromIterator; - mod utils; // Trait to abstract over different vector-like implementations -trait BenchVector: Clone + FromIterator +trait BenchVector: Clone + FromIterator where T: Clone, { @@ -36,44 +37,46 @@ where fn supports_focus() -> bool { false } - fn focus(&self) -> Option> { + fn focus(&self) -> Option> { None } - fn focus_mut(&mut self) -> Option> { + fn focus_mut(&mut self) -> Option> { None } } // Wrapper types for Vector's focus feature -struct VectorFocus<'a, T> { - focus: imbl::vector::Focus<'a, T, imbl::shared_ptr::DefaultSharedPtr>, +struct VectorFocus<'a, T, const CHUNK_SIZE: usize> { + focus: imbl::vector::Focus<'a, T, imbl::shared_ptr::DefaultSharedPtr, CHUNK_SIZE>, } -impl<'a, T> VectorFocus<'a, T> { +impl<'a, T, const CHUNK_SIZE: usize> VectorFocus<'a, T, CHUNK_SIZE> { fn get(&mut self, index: usize) -> Option<&T> { self.focus.get(index) } } -struct VectorFocusMut<'a, T> { - focus: imbl::vector::FocusMut<'a, T, imbl::shared_ptr::DefaultSharedPtr>, +struct VectorFocusMut<'a, T, const CHUNK_SIZE: usize> { + focus: imbl::vector::FocusMut<'a, T, imbl::shared_ptr::DefaultSharedPtr, CHUNK_SIZE>, } -impl<'a, T: Clone> VectorFocusMut<'a, T> { +impl<'a, T: Clone, const CHUNK_SIZE: usize> VectorFocusMut<'a, T, CHUNK_SIZE> { fn get(&mut self, index: usize) -> Option<&T> { self.focus.get(index) } } // Implementation for imbl::Vector -impl BenchVector for Vector { +impl BenchVector + for GenericVector +{ type Iter<'a> - = imbl::vector::Iter<'a, T, imbl::shared_ptr::DefaultSharedPtr> + = imbl::vector::Iter<'a, T, imbl::shared_ptr::DefaultSharedPtr, CHUNK_SIZE> where T: 'a; fn new() -> Self { - Vector::new() + GenericVector::new() } fn push_front(&mut self, value: T) { @@ -119,13 +122,13 @@ impl BenchVector for Vector { true } - fn focus(&self) -> Option> { + fn focus(&self) -> Option> { Some(VectorFocus { focus: self.focus(), }) } - fn focus_mut(&mut self) -> Option> { + fn focus_mut(&mut self) -> Option> { Some(VectorFocusMut { focus: self.focus_mut(), }) @@ -133,7 +136,7 @@ impl BenchVector for Vector { } // Implementation for std::collections::VecDeque -impl BenchVector for VecDeque { +impl BenchVector for VecDeque { type Iter<'a> = std::collections::vec_deque::Iter<'a, T> where @@ -183,8 +186,10 @@ impl BenchVector for VecDeque { } } +const DEFAULT_CHUNK: usize = 64; + // Generic benchmark functions -fn bench_sort_sorted>(b: &mut Bencher, size: usize) { +fn bench_sort_sorted>(b: &mut Bencher, size: usize) { b.iter(|| { let mut v: V = (0..size).collect(); v.sort(); @@ -192,7 +197,7 @@ fn bench_sort_sorted>(b: &mut Bencher, size: usize) { }); } -fn bench_sort_reverse>(b: &mut Bencher, size: usize) { +fn bench_sort_reverse>(b: &mut Bencher, size: usize) { b.iter(|| { let mut v: V = (0..size).rev().collect(); v.sort(); @@ -200,7 +205,7 @@ fn bench_sort_reverse>(b: &mut Bencher, size: usize) { }); } -fn bench_sort_shuffled>(b: &mut Bencher, size: usize) { +fn bench_sort_shuffled>(b: &mut Bencher, size: usize) { let mut rng = rand::rng(); b.iter(|| { let mut v: Vec<_> = (0..size).collect(); @@ -211,7 +216,7 @@ fn bench_sort_shuffled>(b: &mut Bencher, size: usize) { }); } -fn bench_push_front>(b: &mut Bencher, size: usize) { +fn bench_push_front>(b: &mut Bencher, size: usize) { b.iter(|| { let mut v = V::new(); for i in 0..size { @@ -221,7 +226,7 @@ fn bench_push_front>(b: &mut Bencher, size: usize) { }); } -fn bench_push_back>(b: &mut Bencher, size: usize) { +fn bench_push_back>(b: &mut Bencher, size: usize) { b.iter(|| { let mut v = V::new(); for i in 0..size { @@ -231,7 +236,7 @@ fn bench_push_back>(b: &mut Bencher, size: usize) { }); } -fn bench_pop_front>(b: &mut Bencher, size: usize) { +fn bench_pop_front>(b: &mut Bencher, size: usize) { let v: V = (0..size).collect(); b.iter(|| { let mut v = v.clone(); @@ -242,7 +247,7 @@ fn bench_pop_front>(b: &mut Bencher, size: usize) { }); } -fn bench_pop_back>(b: &mut Bencher, size: usize) { +fn bench_pop_back>(b: &mut Bencher, size: usize) { let v: V = (0..size).collect(); b.iter(|| { let mut v = v.clone(); @@ -253,7 +258,7 @@ fn bench_pop_back>(b: &mut Bencher, size: usize) { }); } -fn bench_split>(b: &mut Bencher, size: usize) { +fn bench_split>(b: &mut Bencher, size: usize) { let v: V = (0..size).collect(); b.iter(|| { let mut v = v.clone(); @@ -261,7 +266,7 @@ fn bench_split>(b: &mut Bencher, size: usize) { }); } -fn bench_append>(b: &mut Bencher, size: usize) { +fn bench_append>(b: &mut Bencher, size: usize) { let v1: V = (0..size / 2).collect(); let v2: V = (size / 2..size).collect(); b.iter(|| { @@ -271,7 +276,7 @@ fn bench_append>(b: &mut Bencher, size: usize) { }); } -fn bench_iter>(b: &mut Bencher, size: usize) { +fn bench_iter>(b: &mut Bencher, size: usize) { let v: V = (0..size).collect(); b.iter(|| { for item in v.iter() { @@ -280,7 +285,7 @@ fn bench_iter>(b: &mut Bencher, size: usize) { }); } -fn bench_get_seq>(b: &mut Bencher, size: usize) { +fn bench_get_seq>(b: &mut Bencher, size: usize) { let v: V = (0..size).collect(); b.iter(|| { for i in 0..size { @@ -289,7 +294,7 @@ fn bench_get_seq>(b: &mut Bencher, size: usize) { }); } -fn bench_get_seq_focus>(b: &mut Bencher, size: usize) { +fn bench_get_seq_focus>(b: &mut Bencher, size: usize) { if !V::supports_focus() { return; } @@ -303,7 +308,7 @@ fn bench_get_seq_focus>(b: &mut Bencher, size: usize) { } } -fn bench_get_seq_focus_mut>(b: &mut Bencher, size: usize) { +fn bench_get_seq_focus_mut>(b: &mut Bencher, size: usize) { if !V::supports_focus() { return; } @@ -318,13 +323,13 @@ fn bench_get_seq_focus_mut>(b: &mut Bencher, size: usize) }); } -fn bench_iter_max>(b: &mut Bencher, size: usize) { +fn bench_iter_max>(b: &mut Bencher, size: usize) { let v: V = (0..size).collect(); b.iter(|| black_box(v.iter().max())); } // Helper function to run sort benchmarks -fn bench_sort_group>(c: &mut Criterion, group_name: &str) { +fn bench_sort_group>(c: &mut Criterion, group_name: &str) { let mut group = c.benchmark_group(format!("{}_sort", group_name)); for size in &[500, 1000, 1500, 2000, 2500] { @@ -345,7 +350,7 @@ fn bench_sort_group>(c: &mut Criterion, group_name: &str) } // Helper function to run vector operation benchmarks -fn bench_ops_group>(c: &mut Criterion, group_name: &str) { +fn bench_ops_group>(c: &mut Criterion, group_name: &str) { let mut group = c.benchmark_group(format!("{}_ops", group_name)); for size in &[100, 1000, 100000] { @@ -373,7 +378,7 @@ fn bench_ops_group>(c: &mut Criterion, group_name: &str) { bench_get_seq::(b, *size) }); - if >::supports_focus() { + if >::supports_focus() { group.bench_function(format!("get_seq_focus_{}", size), |b| { bench_get_seq_focus::(b, *size) }); @@ -401,8 +406,8 @@ fn bench_ops_group>(c: &mut Criterion, group_name: &str) { // Benchmark functions for each vector type fn bench_vector(c: &mut Criterion) { - bench_sort_group::>(c, "vector"); - bench_ops_group::>(c, "vector"); + bench_sort_group::>(c, "vector"); + bench_ops_group::>(c, "vector"); } fn bench_vecdeque(c: &mut Criterion) { diff --git a/src/hash/set.rs b/src/hash/set.rs index 50792ec..fa18d19 100644 --- a/src/hash/set.rs +++ b/src/hash/set.rs @@ -945,26 +945,28 @@ where } } -impl From> for GenericHashSet +impl From> + for GenericHashSet where A: Hash + Eq + Clone, S: BuildHasher + Default + Clone, P1: SharedPointerKind, P2: SharedPointerKind, { - fn from(vector: GenericVector) -> Self { + fn from(vector: GenericVector) -> Self { vector.into_iter().collect() } } -impl From<&GenericVector> for GenericHashSet +impl From<&GenericVector> + for GenericHashSet where A: Hash + Eq + Clone, S: BuildHasher + Default + Clone, P1: SharedPointerKind, P2: SharedPointerKind, { - fn from(vector: &GenericVector) -> Self { + fn from(vector: &GenericVector) -> Self { vector.iter().cloned().collect() } } diff --git a/src/nodes/mod.rs b/src/nodes/mod.rs index e30bb6e..ba3a6bc 100644 --- a/src/nodes/mod.rs +++ b/src/nodes/mod.rs @@ -7,8 +7,7 @@ pub(crate) mod hamt; pub(crate) mod rrb; pub(crate) mod chunk { - pub(crate) use crate::config::VECTOR_CHUNK_SIZE as CHUNK_SIZE; use imbl_sized_chunks as sc; - pub(crate) type Chunk = sc::sized_chunk::Chunk; + pub(crate) type Chunk = sc::sized_chunk::Chunk; } diff --git a/src/nodes/rrb.rs b/src/nodes/rrb.rs index 7f7f427..2db05d2 100644 --- a/src/nodes/rrb.rs +++ b/src/nodes/rrb.rs @@ -8,21 +8,19 @@ use std::ops::Range; use archery::{SharedPointer, SharedPointerKind}; -use crate::nodes::chunk::{Chunk, CHUNK_SIZE}; +use crate::nodes::chunk::Chunk; use crate::util::clone_ref; use crate::util::Side::{self, Left, Right}; use self::Entry::*; -pub(crate) const NODE_SIZE: usize = CHUNK_SIZE; - #[derive(Debug)] -enum Size { +enum Size { Size(usize), - Table(SharedPointer, P>), + Table(SharedPointer, P>), } -impl Clone for Size

{ +impl Clone for Size { fn clone(&self) -> Self { match *self { Size::Size(size) => Size::Size(size), @@ -31,7 +29,7 @@ impl Clone for Size

{ } } -impl Size

{ +impl Size { fn size(&self) -> usize { match self { Size::Size(s) => *s, @@ -157,13 +155,16 @@ pub(crate) enum SplitResult { } // Invariants: Nodes only at level > 0, Values/Empty only at level = 0 -enum Entry { - Nodes(Size

, SharedPointer>, P>), - Values(SharedPointer, P>), +enum Entry { + Nodes( + Size, + SharedPointer, NODE_SIZE>, P>, + ), + Values(SharedPointer, P>), Empty, } -impl Clone for Entry { +impl Clone for Entry { fn clone(&self) -> Self { match *self { Nodes(ref size, ref nodes) => Nodes(size.clone(), nodes.clone()), @@ -173,7 +174,7 @@ impl Clone for Entry { } } -impl Entry { +impl Entry { fn len(&self) -> usize { match self { Nodes(_, ref nodes) => nodes.len(), @@ -190,14 +191,14 @@ impl Entry { } } - fn unwrap_values(&self) -> &Chunk { + fn unwrap_values(&self) -> &Chunk { match self { Values(ref values) => values, _ => panic!("rrb::Entry::unwrap_values: expected values, found nodes"), } } - fn unwrap_nodes(&self) -> &Chunk> { + fn unwrap_nodes(&self) -> &Chunk, NODE_SIZE> { match self { Nodes(_, ref nodes) => nodes, _ => panic!("rrb::Entry::unwrap_nodes: expected nodes, found values"), @@ -209,29 +210,29 @@ impl Entry { } } -impl Entry { - fn unwrap_values_mut(&mut self) -> &mut Chunk { +impl Entry { + fn unwrap_values_mut(&mut self) -> &mut Chunk { match self { Values(ref mut values) => SharedPointer::make_mut(values), _ => panic!("rrb::Entry::unwrap_values_mut: expected values, found nodes"), } } - fn unwrap_nodes_mut(&mut self) -> &mut Chunk> { + fn unwrap_nodes_mut(&mut self) -> &mut Chunk, NODE_SIZE> { match self { Nodes(_, ref mut nodes) => SharedPointer::make_mut(nodes), _ => panic!("rrb::Entry::unwrap_nodes_mut: expected nodes, found values"), } } - fn values(self) -> Chunk { + fn values(self) -> Chunk { match self { Values(values) => clone_ref(values), _ => panic!("rrb::Entry::values: expected values, found nodes"), } } - fn nodes(self) -> Chunk> { + fn nodes(self) -> Chunk, NODE_SIZE> { match self { Nodes(_, nodes) => clone_ref(nodes), _ => panic!("rrb::Entry::nodes: expected nodes, found values"), @@ -241,11 +242,11 @@ impl Entry { // Node -pub(crate) struct Node { - children: Entry, +pub(crate) struct Node { + children: Entry, } -impl Clone for Node { +impl Clone for Node { fn clone(&self) -> Self { Node { children: self.children.clone(), @@ -253,18 +254,18 @@ impl Clone for Node { } } -impl Default for Node { +impl Default for Node { fn default() -> Self { Self::new() } } -impl Node { +impl Node { pub(crate) fn new() -> Self { Node { children: Empty } } - pub(crate) fn parent(level: usize, children: Chunk) -> Self { + pub(crate) fn parent(level: usize, children: Chunk) -> Self { let mut size = Size::Size(0); let mut dense = true; @@ -292,7 +293,7 @@ impl Node { self.children = Empty; } - pub(crate) fn from_chunk(level: usize, chunk: SharedPointer, P>) -> Self { + pub(crate) fn from_chunk(level: usize, chunk: SharedPointer, P>) -> Self { let node = Node { children: Values(chunk), }; @@ -481,11 +482,11 @@ impl Node { level: usize, base: usize, index: usize, - ) -> (Range, *const Chunk) { + ) -> (Range, *const Chunk) { if level == 0 { ( base..(base + self.children.len()), - self.children.unwrap_values() as *const Chunk, + self.children.unwrap_values() as *const Chunk, ) } else { let target_idx = self.index_in(level, index).unwrap(); @@ -604,7 +605,7 @@ impl Node { // } // } - pub(crate) fn process(&self, f: &mut impl FnMut(&Chunk)) { + pub(crate) fn process(&self, f: &mut impl FnMut(&Chunk)) { match &self.children { Entry::Values(xs) => f(&xs), Entry::Nodes(_, children) => { @@ -617,7 +618,7 @@ impl Node { } } -impl Node { +impl Node { pub(crate) fn index_mut(&mut self, level: usize, index: usize) -> &mut A { if level == 0 { &mut self.children.unwrap_values_mut()[index] @@ -634,11 +635,11 @@ impl Node { level: usize, base: usize, index: usize, - ) -> (Range, *mut Chunk) { + ) -> (Range, *mut Chunk) { if level == 0 { ( base..(base + self.children.len()), - self.children.unwrap_values_mut() as *mut Chunk, + self.children.unwrap_values_mut() as *mut Chunk, ) } else { let target_idx = self.index_in(level, index).unwrap(); @@ -650,7 +651,7 @@ impl Node { } } - fn push_child_node(&mut self, side: Side, child: Node) { + fn push_child_node(&mut self, side: Side, child: Node) { let children = self.children.unwrap_nodes_mut(); match side { Left => children.push_front(child), @@ -658,7 +659,7 @@ impl Node { } } - fn pop_child_node(&mut self, side: Side) -> Node { + fn pop_child_node(&mut self, side: Side) -> Node { let children = self.children.unwrap_nodes_mut(); match side { Left => children.pop_front(), @@ -670,8 +671,8 @@ impl Node { &mut self, level: usize, side: Side, - mut chunk: SharedPointer, P>, - ) -> PushResult, P>> { + mut chunk: SharedPointer, P>, + ) -> PushResult, P>> { if chunk.is_empty() { return PushResult::Done; } @@ -812,7 +813,7 @@ impl Node { &mut self, level: usize, side: Side, - ) -> PopResult, P>> { + ) -> PopResult, P>> { if self.is_empty() { return PopResult::Empty; } @@ -1121,11 +1122,11 @@ impl Node { pub(crate) fn ptr_eq(&self, rhs: &Self) -> bool { match (&self.children, &rhs.children) { (Nodes(lsize, l), Nodes(rsize, r)) => { - SharedPointer::, CHUNK_SIZE>, P>::ptr_eq(l, r) + SharedPointer::, _>, P>::ptr_eq(l, r) && lsize.size() == rsize.size() } (Values(l), Values(r)) => { - SharedPointer::, P>::ptr_eq(l, r) + SharedPointer::, P>::ptr_eq(l, r) } (Empty, Empty) => true, _ => false, @@ -1143,13 +1144,18 @@ impl Node { // Ok(()) // } -pub(crate) fn map_subsequence( - prev_in: &Node, - next_in: &Node, +pub(crate) fn map_subsequence< + In: Clone, + Out: Clone, + P: SharedPointerKind, + const NODE_SIZE: usize, +>( + prev_in: &Node, + next_in: &Node, level: usize, - prev_out: &Node, - f: &mut impl FnMut(&Chunk, bool) -> Option>, -) -> Node { + prev_out: &Node, + f: &mut impl FnMut(&Chunk, bool) -> Option>, +) -> Node { if prev_in.ptr_eq(next_in) { prev_out.clone() } else { @@ -1201,11 +1207,11 @@ pub(crate) fn map_subsequence( } } -fn map_subseq_unpaired( - next_in: &Node, +fn map_subseq_unpaired( + next_in: &Node, level: usize, - f: &mut impl FnMut(&Chunk) -> Chunk, -) -> Node { + f: &mut impl FnMut(&Chunk) -> Chunk, +) -> Node { match &next_in.children { Entry::Values(xs) => Node::from_chunk(level, SharedPointer::new(f(&xs))), Entry::Nodes(_, children) => Node::parent( diff --git a/src/ser.rs b/src/ser.rs index d8ba69d..21664d6 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -224,18 +224,20 @@ impl S // Vector -impl<'de, A: Clone + Deserialize<'de>, P: SharedPointerKind> Deserialize<'de> - for GenericVector +impl<'de, A: Clone + Deserialize<'de>, P: SharedPointerKind, const CHUNK_SIZE: usize> + Deserialize<'de> for GenericVector { fn deserialize(des: D) -> Result where D: Deserializer<'de>, { - des.deserialize_seq(SeqVisitor::<'de, GenericVector, A>::new()) + des.deserialize_seq(SeqVisitor::<'de, GenericVector, A>::new()) } } -impl Serialize for GenericVector { +impl Serialize + for GenericVector +{ fn serialize(&self, ser: S) -> Result where S: Serializer, diff --git a/src/sort.rs b/src/sort.rs index e500ad6..19f5e00 100644 --- a/src/sort.rs +++ b/src/sort.rs @@ -20,8 +20,11 @@ fn gen_range(rng: &mut R, min: usize, max: usize) -> usize { // additional passes to find the exact partition places. This allows us to split the focus into // three correctly sized parts for less than, equal to and greater than items. As a bonus this // doesn't need to reorder the equal items to the center of the vector. -fn do_quicksort(vector: FocusMut<'_, A, P>, cmp: &F, rng: &mut R) -where +fn do_quicksort( + vector: FocusMut<'_, A, P, CHUNK_SIZE>, + cmp: &F, + rng: &mut R, +) where A: Clone, F: Fn(&A, &A) -> Ordering, R: RngCore, @@ -174,8 +177,10 @@ where } } -pub(crate) fn quicksort(vector: FocusMut<'_, A, P>, cmp: &F) -where +pub(crate) fn quicksort( + vector: FocusMut<'_, A, P, CHUNK_SIZE>, + cmp: &F, +) where A: Clone, F: Fn(&A, &A) -> Ordering, P: SharedPointerKind, diff --git a/src/vector/focus.rs b/src/vector/focus.rs index ac9503d..b37c4cd 100644 --- a/src/vector/focus.rs +++ b/src/vector/focus.rs @@ -97,27 +97,27 @@ fn check_indices(len: usize, indices: &[usize; N]) -> Option<()> /// [Iter]: struct.Iter.html /// [narrow]: #method.narrow /// [split_at]: #method.split_at -pub enum Focus<'a, A, P: SharedPointerKind> { +pub enum Focus<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> { #[doc(hidden)] /// The Single variant is a focus of a simple Vector that can be represented as a single slice. Single(&'a [A]), #[doc(hidden)] /// The Full variant is a focus of a more complex Vector that cannot be represented as a single slice. - Full(TreeFocus), + Full(TreeFocus), } -impl<'a, A, P: SharedPointerKind> Focus<'a, A, P> +impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> Focus<'a, A, P, CHUNK_SIZE> where A: 'a, { /// Construct a `Focus` for a [`Vector`][Vector]. /// /// [Vector]: type.Vector.html - pub fn new(vector: &'a GenericVector) -> Self { + pub fn new(vector: &'a GenericVector) -> Self { Self::new_inner(&vector.vector) } - pub(super) fn new_inner(vector: &'a crate::vector::VectorInner) -> Self { + pub(super) fn new_inner(vector: &'a crate::vector::VectorInner) -> Self { match vector { Inline(chunk) => Focus::Single(chunk), Single(chunk) => Focus::Single(chunk), @@ -253,19 +253,20 @@ where } } -impl<'a, A, P: SharedPointerKind + 'a> IntoIterator for Focus<'a, A, P> +impl<'a, A, P: SharedPointerKind + 'a, const CHUNK_SIZE: usize> IntoIterator + for Focus<'a, A, P, CHUNK_SIZE> where A: Clone + 'a, { type Item = &'a A; - type IntoIter = Iter<'a, A, P>; + type IntoIter = Iter<'a, A, P, CHUNK_SIZE>; fn into_iter(self) -> Self::IntoIter { Iter::from_focus(self) } } -impl<'a, A, P: SharedPointerKind> Clone for Focus<'a, A, P> +impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> Clone for Focus<'a, A, P, CHUNK_SIZE> where A: Clone + 'a, { @@ -277,10 +278,10 @@ where } } -pub struct TreeFocus { +pub struct TreeFocus { /// A clone of the Vector's internal tree that this focus points to. A clone ensures that we don't require a /// reference to the original tree. - tree: RRB, + tree: RRB, /// The view represents the range of the tree that this TreeFocus can see. The view can be narrowed by calling /// either the narrow or split_at methods. view: Range, @@ -291,10 +292,10 @@ pub struct TreeFocus { /// chunks front/back chunks or one of the leaves of the tree. The target_ptr is the pointer to the actual chunk /// in question. The target_range is the range that the chunk represents. target_range: Range, - target_ptr: *const Chunk, + target_ptr: *const Chunk, } -impl Clone for TreeFocus { +impl Clone for TreeFocus { fn clone(&self) -> Self { let tree = self.tree.clone(); TreeFocus { @@ -307,17 +308,23 @@ impl Clone for TreeFocus { } } -unsafe impl Send for TreeFocus {} -unsafe impl Sync for TreeFocus {} +unsafe impl Send + for TreeFocus +{ +} +unsafe impl Sync + for TreeFocus +{ +} #[inline] fn contains(range: &Range, index: &A) -> bool { *index >= range.start && *index < range.end } -impl TreeFocus { +impl TreeFocus { /// Creates a new TreeFocus for a Vector's RRB tree. - fn new(tree: &RRB) -> Self { + fn new(tree: &RRB) -> Self { let middle_start = tree.outer_f.len() + tree.inner_f.len(); let middle_end = middle_start + tree.middle.len(); TreeFocus { @@ -400,7 +407,7 @@ impl TreeFocus { } /// Gets the chunk that this TreeFocus is focused on. - fn get_focus(&self) -> &Chunk { + fn get_focus(&self) -> &Chunk { unsafe { &*self.target_ptr } } @@ -493,16 +500,16 @@ impl TreeFocus { /// ``` /// /// [Focus]: enum.Focus.html -pub enum FocusMut<'a, A, P: SharedPointerKind> { +pub enum FocusMut<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> { #[doc(hidden)] /// The Single variant is a focusmut of a simple Vector that can be represented as a single slice. Single(&'a mut [A]), #[doc(hidden)] /// The Full variant is a focus of a more complex Vector that cannot be represented as a single slice. - Full(TreeFocusMut<'a, A, P>), + Full(TreeFocusMut<'a, A, P, CHUNK_SIZE>), } -impl<'a, A, P: SharedPointerKind> FocusMut<'a, A, P> +impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> FocusMut<'a, A, P, CHUNK_SIZE> where A: 'a, { @@ -608,7 +615,7 @@ where } /// Convert a `FocusMut` into a `Focus`. - pub fn unmut(self) -> Focus<'a, A, P> { + pub fn unmut(self) -> Focus<'a, A, P, CHUNK_SIZE> { match self { FocusMut::Single(chunk) => Focus::Single(chunk), FocusMut::Full(mut tree) => Focus::Full(TreeFocus { @@ -625,12 +632,12 @@ where } } -impl<'a, A, P: SharedPointerKind> FocusMut<'a, A, P> +impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> FocusMut<'a, A, P, CHUNK_SIZE> where A: Clone + 'a, { /// Construct a `FocusMut` for a `Vector`. - pub fn new(vector: &'a mut GenericVector) -> Self { + pub fn new(vector: &'a mut GenericVector) -> Self { match &mut vector.vector { Inline(chunk) => FocusMut::Single(chunk), Single(chunk) => FocusMut::Single(SharedPointer::make_mut(chunk).as_mut_slice()), @@ -786,34 +793,36 @@ where } } -impl<'a, A, P: SharedPointerKind> IntoIterator for FocusMut<'a, A, P> +impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> IntoIterator + for FocusMut<'a, A, P, CHUNK_SIZE> where A: Clone + 'a, { type Item = &'a mut A; - type IntoIter = IterMut<'a, A, P>; + type IntoIter = IterMut<'a, A, P, CHUNK_SIZE>; fn into_iter(self) -> Self::IntoIter { IterMut::from_focus(self) } } -impl<'a, A, P: SharedPointerKind> From> for Focus<'a, A, P> +impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> From> + for Focus<'a, A, P, CHUNK_SIZE> where A: Clone + 'a, { - fn from(f: FocusMut<'a, A, P>) -> Focus<'a, A, P> { + fn from(f: FocusMut<'a, A, P, CHUNK_SIZE>) -> Self { f.unmut() } } // NOTE: The documentation the mutable version is similar to the non-mutable version. I will comment for the places // where there are differences, otherwise the documentation is copied directly. -pub struct TreeFocusMut<'a, A, P: SharedPointerKind> { +pub struct TreeFocusMut<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> { /// The tree that this TreeFocusMut refers to. Unlike the non-mutable version, TreeFocusMut needs to store a /// mutable reference. Additionally, there may be multiple TreeFocusMuts that refer to the same tree so we need a /// Lock to synchronise the changes. - tree: Lock<&'a mut RRB>, + tree: Lock<&'a mut RRB>, /// The view represents the range of the tree that this TreeFocusMut can see. The view can be narrowed by calling /// either the narrow or split_at methods. view: Range, @@ -826,15 +835,15 @@ pub struct TreeFocusMut<'a, A, P: SharedPointerKind> { target_range: Range, /// Not actually sure why this needs to be an atomic, it seems like it is unneccessary. This is just a pointer to /// the chunk referred to above. - target_ptr: AtomicPtr>, + target_ptr: AtomicPtr>, } -impl<'a, A, P: SharedPointerKind> TreeFocusMut<'a, A, P> +impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> TreeFocusMut<'a, A, P, CHUNK_SIZE> where A: 'a, { /// Creates a new TreeFocusMut for a Vector's RRB tree. - fn new(tree: &'a mut RRB) -> Self { + fn new(tree: &'a mut RRB) -> Self { let middle_start = tree.outer_f.len() + tree.inner_f.len(); let middle_end = middle_start + tree.middle.len(); TreeFocusMut { @@ -898,16 +907,16 @@ where } /// Gets the chunk for an index and its corresponding range within the TreeFocusMut. - fn get_focus(&mut self) -> &mut Chunk { + fn get_focus(&mut self) -> &mut Chunk { unsafe { &mut *self.target_ptr.load(Ordering::Relaxed) } } - fn get_focus_ptr(&mut self) -> *mut Chunk { + fn get_focus_ptr(&mut self) -> *mut Chunk { self.target_ptr.load(Ordering::Relaxed) } } -impl<'a, A, P: SharedPointerKind> TreeFocusMut<'a, A, P> +impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> TreeFocusMut<'a, A, P, CHUNK_SIZE> where A: Clone + 'a, { diff --git a/src/vector/mod.rs b/src/vector/mod.rs index 7f0e7a6..016d1b3 100644 --- a/src/vector/mod.rs +++ b/src/vector/mod.rs @@ -57,7 +57,7 @@ use std::ops::{Add, Index, IndexMut, RangeBounds}; use archery::{SharedPointer, SharedPointerKind}; use imbl_sized_chunks::InlineArray; -use crate::nodes::chunk::{Chunk, CHUNK_SIZE}; +use crate::nodes::chunk::Chunk; use crate::nodes::rrb::{Node, PopResult, PushResult, SplitResult}; use crate::shared_ptr::DefaultSharedPtr; use crate::sort; @@ -111,7 +111,7 @@ macro_rules! vector { /// /// [GenericVector]: ./struct.GenericVector.html /// [DefaultSharedPtr]: ../shared_ptr/type.DefaultSharedPtr.html -pub type Vector = GenericVector; +pub type Vector = GenericVector; /// A persistent vector. /// @@ -149,28 +149,30 @@ pub type Vector = GenericVector; /// [chunkedseq]: http://deepsea.inria.fr/pasl/chunkedseq.pdf /// [Vec]: https://doc.rust-lang.org/std/vec/struct.Vec.html /// [VecDeque]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html -pub struct GenericVector { - vector: VectorInner, +pub struct GenericVector { + vector: VectorInner, } -enum VectorInner { - Inline(InlineArray>), - Single(SharedPointer, P>), - Full(RRB), +enum VectorInner { + Inline(InlineArray>), + Single(SharedPointer, P>), + Full(RRB), } #[doc(hidden)] -pub struct RRB { +pub struct RRB { length: usize, middle_level: usize, - outer_f: SharedPointer, P>, - inner_f: SharedPointer, P>, - middle: SharedPointer, P>, - inner_b: SharedPointer, P>, - outer_b: SharedPointer, P>, + outer_f: SharedPointer, P>, + inner_f: SharedPointer, P>, + middle: SharedPointer, P>, + inner_b: SharedPointer, P>, + outer_b: SharedPointer, P>, } -fn rrb_from_chunk(chunk: SharedPointer, P>) -> RRB { +fn rrb_from_chunk( + chunk: SharedPointer, P>, +) -> RRB { RRB { length: chunk.len(), middle_level: 0, @@ -182,7 +184,7 @@ fn rrb_from_chunk(chunk: SharedPointer, P>) -> } } -impl Clone for RRB { +impl Clone for RRB { fn clone(&self) -> Self { RRB { length: self.length, @@ -196,7 +198,7 @@ impl Clone for RRB { } } -impl GenericVector { +impl GenericVector { /// True if a vector is a full inline or single chunk, ie. must be promoted /// to grow further. fn needs_promotion(&self) -> bool { @@ -304,7 +306,7 @@ impl GenericVector { /// Test whether a vector is currently inlined. /// /// Vectors small enough that their contents could be stored entirely inside - /// the space of `std::mem::size_of::>()` bytes are stored inline on + /// the space of `std::mem::size_of::>()` bytes are stored inline on /// the stack instead of allocating any chunks. This method returns `true` if /// this vector is currently inlined, or `false` if it currently has chunks allocated /// on the heap. @@ -338,9 +340,9 @@ impl GenericVector { /// Time: O(1) #[must_use] pub fn ptr_eq(&self, other: &Self) -> bool { - fn cmp_chunk( - left: &SharedPointer, P>, - right: &SharedPointer, P>, + fn cmp_chunk( + left: &SharedPointer, P>, + right: &SharedPointer, P>, ) -> bool { (left.is_empty() && right.is_empty()) || SharedPointer::ptr_eq(left, right) } @@ -368,7 +370,7 @@ impl GenericVector { /// Time: O(1) #[inline] #[must_use] - pub fn iter(&self) -> Iter<'_, A, P> { + pub fn iter(&self) -> Iter<'_, A, P, CHUNK_SIZE> { Iter::new(self) } @@ -383,7 +385,7 @@ impl GenericVector { /// [Chunk]: ../chunk/struct.Chunk.html #[inline] #[must_use] - pub fn leaves(&self) -> Chunks<'_, A, P> { + pub fn leaves(&self) -> Chunks<'_, A, P, CHUNK_SIZE> { Chunks::new(self) } @@ -394,7 +396,7 @@ impl GenericVector { /// [Focus]: enum.Focus.html #[inline] #[must_use] - pub fn focus(&self) -> Focus<'_, A, P> { + pub fn focus(&self) -> Focus<'_, A, P, CHUNK_SIZE> { Focus::new_inner(&self.vector) } @@ -663,7 +665,7 @@ impl GenericVector { #[inline] #[must_use] pub fn unit(a: A) -> Self { - if InlineArray::>::CAPACITY > 0 { + if InlineArray::>::CAPACITY > 0 { let mut array = InlineArray::new(); array.push(a); Self { @@ -704,7 +706,7 @@ impl GenericVector { } } -impl GenericVector { +impl GenericVector { /// Get a mutable reference to the value at index `index` in a /// vector. /// @@ -799,7 +801,7 @@ impl GenericVector { /// [FocusMut]: enum.FocusMut.html #[inline] #[must_use] - pub fn focus_mut(&mut self) -> FocusMut<'_, A, P> { + pub fn focus_mut(&mut self) -> FocusMut<'_, A, P, CHUNK_SIZE> { FocusMut::new(self) } @@ -808,7 +810,7 @@ impl GenericVector { /// Time: O(1) #[inline] #[must_use] - pub fn iter_mut(&mut self) -> IterMut<'_, A, P> { + pub fn iter_mut(&mut self) -> IterMut<'_, A, P, CHUNK_SIZE> { IterMut::new(self) } @@ -823,7 +825,7 @@ impl GenericVector { /// [Chunk]: ../chunk/struct.Chunk.html #[inline] #[must_use] - pub fn leaves_mut(&mut self) -> ChunksMut<'_, A, P> { + pub fn leaves_mut(&mut self) -> ChunksMut<'_, A, P, CHUNK_SIZE> { ChunksMut::new(self) } @@ -1589,7 +1591,7 @@ impl GenericVector { // Implementation details -impl RRB { +impl RRB { fn new() -> Self { RRB { length: 0, @@ -1612,7 +1614,7 @@ impl RRB { } } -impl RRB { +impl RRB { fn prune(&mut self) { if self.middle.is_empty() { self.middle = SharedPointer::new(Node::new()); @@ -1702,7 +1704,7 @@ impl RRB { outer_b.push_back(value) } - fn push_middle(&mut self, side: Side, chunk: SharedPointer, P>) { + fn push_middle(&mut self, side: Side, chunk: SharedPointer, P>) { if chunk.is_empty() { return; } @@ -1726,7 +1728,7 @@ impl RRB { self.middle = new_middle; } - fn pop_middle(&mut self, side: Side) -> Option, P>> { + fn pop_middle(&mut self, side: Side) -> Option, P>> { let chunk = { let middle = SharedPointer::make_mut(&mut self.middle); match middle.pop_chunk(self.middle_level, side) { @@ -1752,13 +1754,15 @@ fn replace_shared_pointer( // Core traits -impl Default for GenericVector { +impl Default for GenericVector { fn default() -> Self { Self::new() } } -impl Clone for GenericVector { +impl Clone + for GenericVector +{ /// Clone a vector. /// /// Time: O(1), or O(n) with a very small, bounded *n* for an inline vector. @@ -1773,7 +1777,9 @@ impl Clone for GenericVector { } } -impl Debug for GenericVector { +impl Debug + for GenericVector +{ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { f.debug_list().entries(self.iter()).finish() // match self { @@ -1787,27 +1793,35 @@ impl Debug for GenericVector { } } -impl PartialEq for GenericVector { +impl PartialEq + for GenericVector +{ fn eq(&self, other: &Self) -> bool { self.len() == other.len() && self.iter().eq(other.iter()) } } -impl Eq for GenericVector {} +impl Eq for GenericVector {} -impl PartialOrd for GenericVector { +impl PartialOrd + for GenericVector +{ fn partial_cmp(&self, other: &Self) -> Option { self.iter().partial_cmp(other.iter()) } } -impl Ord for GenericVector { +impl Ord + for GenericVector +{ fn cmp(&self, other: &Self) -> Ordering { self.iter().cmp(other.iter()) } } -impl Hash for GenericVector { +impl Hash + for GenericVector +{ fn hash(&self, state: &mut H) { for i in self { i.hash(state) @@ -1815,7 +1829,9 @@ impl Hash for GenericVector { } } -impl Sum for GenericVector { +impl Sum + for GenericVector +{ fn sum(it: I) -> Self where I: Iterator, @@ -1824,8 +1840,10 @@ impl Sum for GenericVector { } } -impl Add for GenericVector { - type Output = GenericVector; +impl Add + for GenericVector +{ + type Output = GenericVector; /// Concatenate two vectors. /// @@ -1836,8 +1854,10 @@ impl Add for GenericVector { } } -impl Add for &GenericVector { - type Output = GenericVector; +impl Add + for &GenericVector +{ + type Output = GenericVector; /// Concatenate two vectors. /// @@ -1849,7 +1869,9 @@ impl Add for &GenericVector { } } -impl Extend for GenericVector { +impl Extend + for GenericVector +{ /// Add values to the end of a vector by consuming an iterator. /// /// Time: O(n) @@ -1863,7 +1885,9 @@ impl Extend for GenericVector { } } -impl Index for GenericVector { +impl Index + for GenericVector +{ type Output = A; /// Get a reference to the value at index `index` in the vector. /// @@ -1880,7 +1904,9 @@ impl Index for GenericVector { } } -impl IndexMut for GenericVector { +impl IndexMut + for GenericVector +{ /// Get a mutable reference to the value at index `index` in the /// vector. /// @@ -1895,31 +1921,39 @@ impl IndexMut for GenericVector { // Conversions -impl<'a, A, P: SharedPointerKind> IntoIterator for &'a GenericVector { +impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> IntoIterator + for &'a GenericVector +{ type Item = &'a A; - type IntoIter = Iter<'a, A, P>; + type IntoIter = Iter<'a, A, P, CHUNK_SIZE>; fn into_iter(self) -> Self::IntoIter { self.iter() } } -impl<'a, A: Clone, P: SharedPointerKind> IntoIterator for &'a mut GenericVector { +impl<'a, A: Clone, P: SharedPointerKind, const CHUNK_SIZE: usize> IntoIterator + for &'a mut GenericVector +{ type Item = &'a mut A; - type IntoIter = IterMut<'a, A, P>; + type IntoIter = IterMut<'a, A, P, CHUNK_SIZE>; fn into_iter(self) -> Self::IntoIter { self.iter_mut() } } -impl IntoIterator for GenericVector { +impl IntoIterator + for GenericVector +{ type Item = A; - type IntoIter = ConsumingIter; + type IntoIter = ConsumingIter; fn into_iter(self) -> Self::IntoIter { ConsumingIter::new(self) } } -impl FromIterator for GenericVector { +impl FromIterator + for GenericVector +{ /// Create a vector from an iterator. /// /// Time: O(n) @@ -1935,19 +1969,21 @@ impl FromIterator for GenericVector { } } -impl From<&GenericVector<&A, P2>> for GenericVector +impl From<&GenericVector<&A, P2, CHUNK_SIZE>> + for GenericVector where A: ToOwned, OA: Borrow + Clone, P1: SharedPointerKind, P2: SharedPointerKind, { - fn from(vec: &GenericVector<&A, P2>) -> Self { + fn from(vec: &GenericVector<&A, P2, CHUNK_SIZE>) -> Self { vec.iter().map(|a| (*a).to_owned()).collect() } } -impl From<[A; N]> for GenericVector +impl From<[A; N]> + for GenericVector where A: Clone, { @@ -1956,13 +1992,17 @@ where } } -impl From<&[A]> for GenericVector { +impl From<&[A]> + for GenericVector +{ fn from(slice: &[A]) -> Self { slice.iter().cloned().collect() } } -impl From> for GenericVector { +impl From> + for GenericVector +{ /// Create a vector from a [`std::vec::Vec`][vec]. /// /// Time: O(n) @@ -1973,7 +2013,9 @@ impl From> for GenericVector { } } -impl From<&Vec> for GenericVector { +impl From<&Vec> + for GenericVector +{ /// Create a vector from a [`std::vec::Vec`][vec]. /// /// Time: O(n) @@ -1993,14 +2035,14 @@ impl From<&Vec> for GenericVector { /// [iter]: type.Vector.html#method.iter // TODO: we'd like to support Clone even if A is not Clone, but it isn't trivial because // the TreeFocus variant of Focus does need A to be Clone. -pub struct Iter<'a, A, P: SharedPointerKind> { - focus: Focus<'a, A, P>, +pub struct Iter<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> { + focus: Focus<'a, A, P, CHUNK_SIZE>, front_index: usize, back_index: usize, } -impl<'a, A, P: SharedPointerKind> Iter<'a, A, P> { - fn new(seq: &'a GenericVector) -> Self { +impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> Iter<'a, A, P, CHUNK_SIZE> { + fn new(seq: &'a GenericVector) -> Self { Iter { focus: seq.focus(), front_index: 0, @@ -2008,7 +2050,7 @@ impl<'a, A, P: SharedPointerKind> Iter<'a, A, P> { } } - fn from_focus(focus: Focus<'a, A, P>) -> Self { + fn from_focus(focus: Focus<'a, A, P, CHUNK_SIZE>) -> Self { Iter { front_index: 0, back_index: focus.len(), @@ -2017,7 +2059,7 @@ impl<'a, A, P: SharedPointerKind> Iter<'a, A, P> { } } -impl Clone for Iter<'_, A, P> { +impl Clone for Iter<'_, A, P, CHUNK_SIZE> { fn clone(&self) -> Self { Iter { focus: self.focus.clone(), @@ -2027,13 +2069,17 @@ impl Clone for Iter<'_, A, P> { } } -impl std::fmt::Debug for Iter<'_, A, P> { +impl std::fmt::Debug + for Iter<'_, A, P, CHUNK_SIZE> +{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_list().entries(self.clone()).finish() } } -impl<'a, A, P: SharedPointerKind + 'a> Iterator for Iter<'a, A, P> { +impl<'a, A, P: SharedPointerKind + 'a, const CHUNK_SIZE: usize> Iterator + for Iter<'a, A, P, CHUNK_SIZE> +{ type Item = &'a A; /// Advance the iterator and return the next value. @@ -2043,7 +2089,8 @@ impl<'a, A, P: SharedPointerKind + 'a> Iterator for Iter<'a, A, P> { if self.front_index >= self.back_index { return None; } - let focus: &'a mut Focus<'a, A, P> = unsafe { &mut *(&mut self.focus as *mut _) }; + let focus: &'a mut Focus<'a, A, P, CHUNK_SIZE> = + unsafe { &mut *(&mut self.focus as *mut _) }; let value = focus.get(self.front_index); self.front_index += 1; value @@ -2055,7 +2102,9 @@ impl<'a, A, P: SharedPointerKind + 'a> Iterator for Iter<'a, A, P> { } } -impl<'a, A, P: SharedPointerKind + 'a> DoubleEndedIterator for Iter<'a, A, P> { +impl<'a, A, P: SharedPointerKind + 'a, const CHUNK_SIZE: usize> DoubleEndedIterator + for Iter<'a, A, P, CHUNK_SIZE> +{ /// Advance the iterator and return the next value. /// /// Time: O(1)* @@ -2064,28 +2113,35 @@ impl<'a, A, P: SharedPointerKind + 'a> DoubleEndedIterator for Iter<'a, A, P> { return None; } self.back_index -= 1; - let focus: &'a mut Focus<'a, A, P> = unsafe { &mut *(&mut self.focus as *mut _) }; + let focus: &'a mut Focus<'a, A, P, CHUNK_SIZE> = + unsafe { &mut *(&mut self.focus as *mut _) }; focus.get(self.back_index) } } -impl<'a, A, P: SharedPointerKind + 'a> ExactSizeIterator for Iter<'a, A, P> {} +impl<'a, A, P: SharedPointerKind + 'a, const CHUNK_SIZE: usize> ExactSizeIterator + for Iter<'a, A, P, CHUNK_SIZE> +{ +} -impl<'a, A, P: SharedPointerKind + 'a> FusedIterator for Iter<'a, A, P> {} +impl<'a, A, P: SharedPointerKind + 'a, const CHUNK_SIZE: usize> FusedIterator + for Iter<'a, A, P, CHUNK_SIZE> +{ +} /// A mutable iterator over vectors with values of type `A`. /// /// To obtain one, use [`Vector::iter_mut()`][iter_mut]. /// /// [iter_mut]: type.Vector.html#method.iter_mut -pub struct IterMut<'a, A, P: SharedPointerKind> { - focus: FocusMut<'a, A, P>, +pub struct IterMut<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> { + focus: FocusMut<'a, A, P, CHUNK_SIZE>, front_index: usize, back_index: usize, } -impl<'a, A, P: SharedPointerKind> IterMut<'a, A, P> { - fn from_focus(focus: FocusMut<'a, A, P>) -> Self { +impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> IterMut<'a, A, P, CHUNK_SIZE> { + fn from_focus(focus: FocusMut<'a, A, P, CHUNK_SIZE>) -> Self { IterMut { front_index: 0, back_index: focus.len(), @@ -2094,8 +2150,8 @@ impl<'a, A, P: SharedPointerKind> IterMut<'a, A, P> { } } -impl<'a, A: Clone, P: SharedPointerKind> IterMut<'a, A, P> { - fn new(seq: &'a mut GenericVector) -> Self { +impl<'a, A: Clone, P: SharedPointerKind, const CHUNK_SIZE: usize> IterMut<'a, A, P, CHUNK_SIZE> { + fn new(seq: &'a mut GenericVector) -> Self { let focus = seq.focus_mut(); let len = focus.len(); IterMut { @@ -2106,7 +2162,8 @@ impl<'a, A: Clone, P: SharedPointerKind> IterMut<'a, A, P> { } } -impl<'a, A, P: SharedPointerKind> Iterator for IterMut<'a, A, P> +impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> Iterator + for IterMut<'a, A, P, CHUNK_SIZE> where A: 'a + Clone, { @@ -2119,7 +2176,8 @@ where if self.front_index >= self.back_index { return None; } - let focus: &'a mut FocusMut<'a, A, P> = unsafe { &mut *(&mut self.focus as *mut _) }; + let focus: &'a mut FocusMut<'a, A, P, CHUNK_SIZE> = + unsafe { &mut *(&mut self.focus as *mut _) }; let value = focus.get_mut(self.front_index); self.front_index += 1; value @@ -2131,7 +2189,8 @@ where } } -impl<'a, A, P: SharedPointerKind> DoubleEndedIterator for IterMut<'a, A, P> +impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> DoubleEndedIterator + for IterMut<'a, A, P, CHUNK_SIZE> where A: 'a + Clone, { @@ -2143,27 +2202,36 @@ where return None; } self.back_index -= 1; - let focus: &'a mut FocusMut<'a, A, P> = unsafe { &mut *(&mut self.focus as *mut _) }; + let focus: &'a mut FocusMut<'a, A, P, CHUNK_SIZE> = + unsafe { &mut *(&mut self.focus as *mut _) }; focus.get_mut(self.back_index) } } -impl<'a, A: Clone, P: SharedPointerKind> ExactSizeIterator for IterMut<'a, A, P> {} +impl<'a, A: Clone, P: SharedPointerKind, const CHUNK_SIZE: usize> ExactSizeIterator + for IterMut<'a, A, P, CHUNK_SIZE> +{ +} -impl<'a, A: Clone, P: SharedPointerKind> FusedIterator for IterMut<'a, A, P> {} +impl<'a, A: Clone, P: SharedPointerKind, const CHUNK_SIZE: usize> FusedIterator + for IterMut<'a, A, P, CHUNK_SIZE> +{ +} /// A consuming iterator over vectors with values of type `A`. -pub struct ConsumingIter { - vector: GenericVector, +pub struct ConsumingIter { + vector: GenericVector, } -impl ConsumingIter { - fn new(vector: GenericVector) -> Self { +impl ConsumingIter { + fn new(vector: GenericVector) -> Self { Self { vector } } } -impl Iterator for ConsumingIter { +impl Iterator + for ConsumingIter +{ type Item = A; /// Advance the iterator and return the next value. @@ -2179,7 +2247,9 @@ impl Iterator for ConsumingIter { } } -impl DoubleEndedIterator for ConsumingIter { +impl DoubleEndedIterator + for ConsumingIter +{ /// Remove and return an element from the back of the iterator. /// /// Time: O(1)* @@ -2188,23 +2258,29 @@ impl DoubleEndedIterator for ConsumingIter } } -impl ExactSizeIterator for ConsumingIter {} +impl ExactSizeIterator + for ConsumingIter +{ +} -impl FusedIterator for ConsumingIter {} +impl FusedIterator + for ConsumingIter +{ +} /// An iterator over the leaf nodes of a vector. /// /// To obtain one, use [`Vector::chunks()`][chunks]. /// /// [chunks]: type.Vector.html#method.chunks -pub struct Chunks<'a, A, P: SharedPointerKind> { - focus: Focus<'a, A, P>, +pub struct Chunks<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> { + focus: Focus<'a, A, P, CHUNK_SIZE>, front_index: usize, back_index: usize, } -impl<'a, A, P: SharedPointerKind> Chunks<'a, A, P> { - fn new(seq: &'a GenericVector) -> Self { +impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> Chunks<'a, A, P, CHUNK_SIZE> { + fn new(seq: &'a GenericVector) -> Self { Chunks { focus: seq.focus(), front_index: 0, @@ -2213,7 +2289,9 @@ impl<'a, A, P: SharedPointerKind> Chunks<'a, A, P> { } } -impl<'a, A, P: SharedPointerKind + 'a> Iterator for Chunks<'a, A, P> { +impl<'a, A, P: SharedPointerKind + 'a, const CHUNK_SIZE: usize> Iterator + for Chunks<'a, A, P, CHUNK_SIZE> +{ type Item = &'a [A]; /// Advance the iterator and return the next value. @@ -2223,14 +2301,17 @@ impl<'a, A, P: SharedPointerKind + 'a> Iterator for Chunks<'a, A, P> { if self.front_index >= self.back_index { return None; } - let focus: &'a mut Focus<'a, A, P> = unsafe { &mut *(&mut self.focus as *mut _) }; + let focus: &'a mut Focus<'a, A, P, CHUNK_SIZE> = + unsafe { &mut *(&mut self.focus as *mut _) }; let (range, value) = focus.chunk_at(self.front_index); self.front_index = range.end; Some(value) } } -impl<'a, A, P: SharedPointerKind + 'a> DoubleEndedIterator for Chunks<'a, A, P> { +impl<'a, A, P: SharedPointerKind + 'a, const CHUNK_SIZE: usize> DoubleEndedIterator + for Chunks<'a, A, P, CHUNK_SIZE> +{ /// Remove and return an element from the back of the iterator. /// /// Time: O(1)* @@ -2239,28 +2320,32 @@ impl<'a, A, P: SharedPointerKind + 'a> DoubleEndedIterator for Chunks<'a, A, P> return None; } self.back_index -= 1; - let focus: &'a mut Focus<'a, A, P> = unsafe { &mut *(&mut self.focus as *mut _) }; + let focus: &'a mut Focus<'a, A, P, CHUNK_SIZE> = + unsafe { &mut *(&mut self.focus as *mut _) }; let (range, value) = focus.chunk_at(self.back_index); self.back_index = range.start; Some(value) } } -impl<'a, A, P: SharedPointerKind + 'a> FusedIterator for Chunks<'a, A, P> {} +impl<'a, A, P: SharedPointerKind + 'a, const CHUNK_SIZE: usize> FusedIterator + for Chunks<'a, A, P, CHUNK_SIZE> +{ +} /// A mutable iterator over the leaf nodes of a vector. /// /// To obtain one, use [`Vector::chunks_mut()`][chunks_mut]. /// /// [chunks_mut]: type.Vector.html#method.chunks_mut -pub struct ChunksMut<'a, A, P: SharedPointerKind> { - focus: FocusMut<'a, A, P>, +pub struct ChunksMut<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> { + focus: FocusMut<'a, A, P, CHUNK_SIZE>, front_index: usize, back_index: usize, } -impl<'a, A: Clone, P: SharedPointerKind> ChunksMut<'a, A, P> { - fn new(seq: &'a mut GenericVector) -> Self { +impl<'a, A: Clone, P: SharedPointerKind, const CHUNK_SIZE: usize> ChunksMut<'a, A, P, CHUNK_SIZE> { + fn new(seq: &'a mut GenericVector) -> Self { let len = seq.len(); ChunksMut { focus: seq.focus_mut(), @@ -2270,7 +2355,9 @@ impl<'a, A: Clone, P: SharedPointerKind> ChunksMut<'a, A, P> { } } -impl<'a, A: Clone, P: SharedPointerKind> Iterator for ChunksMut<'a, A, P> { +impl<'a, A: Clone, P: SharedPointerKind, const CHUNK_SIZE: usize> Iterator + for ChunksMut<'a, A, P, CHUNK_SIZE> +{ type Item = &'a mut [A]; /// Advance the iterator and return the next value. @@ -2280,14 +2367,17 @@ impl<'a, A: Clone, P: SharedPointerKind> Iterator for ChunksMut<'a, A, P> { if self.front_index >= self.back_index { return None; } - let focus: &'a mut FocusMut<'a, A, P> = unsafe { &mut *(&mut self.focus as *mut _) }; + let focus: &'a mut FocusMut<'a, A, P, CHUNK_SIZE> = + unsafe { &mut *(&mut self.focus as *mut _) }; let (range, value) = focus.chunk_at(self.front_index); self.front_index = range.end; Some(value) } } -impl<'a, A: Clone, P: SharedPointerKind> DoubleEndedIterator for ChunksMut<'a, A, P> { +impl<'a, A: Clone, P: SharedPointerKind, const CHUNK_SIZE: usize> DoubleEndedIterator + for ChunksMut<'a, A, P, CHUNK_SIZE> +{ /// Remove and return an element from the back of the iterator. /// /// Time: O(1)* @@ -2296,14 +2386,18 @@ impl<'a, A: Clone, P: SharedPointerKind> DoubleEndedIterator for ChunksMut<'a, A return None; } self.back_index -= 1; - let focus: &'a mut FocusMut<'a, A, P> = unsafe { &mut *(&mut self.focus as *mut _) }; + let focus: &'a mut FocusMut<'a, A, P, CHUNK_SIZE> = + unsafe { &mut *(&mut self.focus as *mut _) }; let (range, value) = focus.chunk_at(self.back_index); self.back_index = range.start; Some(value) } } -impl<'a, A: Clone, P: SharedPointerKind> FusedIterator for ChunksMut<'a, A, P> {} +impl<'a, A: Clone, P: SharedPointerKind, const CHUNK_SIZE: usize> FusedIterator + for ChunksMut<'a, A, P, CHUNK_SIZE> +{ +} // Proptest #[cfg(any(test, feature = "proptest"))] @@ -2476,11 +2570,8 @@ mod test { #[test] fn issue_70() { - // This test assumes that chunks are of size 64. - if CHUNK_SIZE != 64 { - return; - } - let mut x = Vector::new(); + // This tests assumes a chunk size of 64 + let mut x = GenericVector::::new(); for _ in 0..262 { x.push_back(0); } @@ -2537,12 +2628,12 @@ mod test { #[test] fn issue_74_simple_size() { - use crate::nodes::rrb::NODE_SIZE; - let mut x = Vector::new(); + const CHUNK_SIZE: usize = 64; + let mut x = GenericVector::::new(); for _ in 0..(CHUNK_SIZE * ( 1 // inner_f - + (2 * NODE_SIZE) // middle: two full Entry::Nodes (4096 elements each) + + (2 * CHUNK_SIZE) // middle: two full Entry::Nodes (4096 elements each) + 1 // inner_b + 1 // outer_b @@ -2551,7 +2642,7 @@ mod test { x.push_back(0u32); } let middle_first_node_start = CHUNK_SIZE; - let middle_second_node_start = middle_first_node_start + NODE_SIZE * CHUNK_SIZE; + let middle_second_node_start = middle_first_node_start + CHUNK_SIZE * CHUNK_SIZE; // This reduces the size of the second node to 4095. x.remove(middle_second_node_start); // As outer_b is full, this will cause inner_b (length 64) to be pushed @@ -2560,11 +2651,9 @@ mod test { x.push_back(0u32); match x.vector { VectorInner::Full(tree) => { - if CHUNK_SIZE == 64 { - assert_eq!(3, tree.middle.number_of_children()); - } + assert_eq!(3, tree.middle.number_of_children()); assert_eq!( - 2 * NODE_SIZE * CHUNK_SIZE + CHUNK_SIZE - 1, + 2 * CHUNK_SIZE * CHUNK_SIZE + CHUNK_SIZE - 1, tree.middle.len() ); } @@ -2853,7 +2942,7 @@ mod test { fn focus_mut_split(ref input in vector(i32::ANY, 0..10000)) { let mut vec = input.clone(); - fn split_down(focus: FocusMut<'_, i32, DefaultSharedPtr>) { + fn split_down(focus: FocusMut<'_, i32, DefaultSharedPtr, CHUNK_SIZE>) { let len = focus.len(); if len < 8 { for p in focus { @@ -2934,9 +3023,10 @@ pub struct PersistentMap< P: SharedPointerKind, F: FnMut(&In) -> Out, Ex: Fn(&In) -> Key, + const CHUNK_SIZE: usize, > { - previous_in: VectorInner, - previous_out: VectorInner, + previous_in: VectorInner, + previous_out: VectorInner, keylookup: std::collections::HashMap, f: F, ex: Ex, @@ -2949,7 +3039,8 @@ impl< P: SharedPointerKind, F: FnMut(&In) -> Out, Ex: Fn(&In) -> Key, - > PersistentMap + const CHUNK_SIZE: usize, + > PersistentMap { /// Initializes a new empty map state pub fn new(f: F, ex: Ex) -> Self { @@ -2999,14 +3090,14 @@ impl< } fn map_chunk( - prev_in: &SharedPointer, P>, - next_in: &SharedPointer, P>, - prev_out: &SharedPointer, P>, + prev_in: &SharedPointer, P>, + next_in: &SharedPointer, P>, + prev_out: &SharedPointer, P>, keylookup: &mut std::collections::HashMap, ex: &impl Fn(&In) -> Key, ma: &mut impl FnMut(&In) -> Out, - ) -> SharedPointer, P> { - if SharedPointer::, P>::ptr_eq(prev_in, next_in) { + ) -> SharedPointer, P> { + if SharedPointer::, P>::ptr_eq(prev_in, next_in) { prev_out.clone() } else { let mut chunk = Chunk::new(); @@ -3019,7 +3110,10 @@ impl< } /// Produces an output vector from the input vector using a map function and a key extractor. - pub fn map(&mut self, from: &GenericVector) -> GenericVector { + pub fn map( + &mut self, + from: &GenericVector, + ) -> GenericVector { match &from.vector { Inline(next_in) => { let mut inline = InlineArray::new(); @@ -3109,7 +3203,10 @@ impl< } } - fn map_with_key_internal(&mut self, next_in: &RRB) -> RRB { + fn map_with_key_internal( + &mut self, + next_in: &RRB, + ) -> RRB { use crate::nodes::rrb::map_subsequence; match &mut self.previous_in { @@ -3213,7 +3310,7 @@ impl< fn test_vector_map_basic() { let a = vector![1, 2, 3, 4]; - let mut map = PersistentMap::::new(|x| *x * *x, |x| *x); + let mut map = PersistentMap::::new(|x| *x * *x, |x| *x); let b = map.map(&a); @@ -3230,7 +3327,7 @@ fn test_vector_map_big() { let mut mutation_count = 0; let len = { - let mut map = PersistentMap::::new( + let mut map = PersistentMap::::new( |x| { mutation_count += 1; *x + 1 diff --git a/src/vector/rayon.rs b/src/vector/rayon.rs index 6663c85..05fde43 100644 --- a/src/vector/rayon.rs +++ b/src/vector/rayon.rs @@ -8,13 +8,14 @@ use ::rayon::iter::{ IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator, }; -impl<'a, A, P: SharedPointerKind> IntoParallelRefIterator<'a> for GenericVector +impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> IntoParallelRefIterator<'a> + for GenericVector where A: Clone + Send + Sync + 'a, P: SharedPointerKind + Send + 'a, { type Item = &'a A; - type Iter = ParIter<'a, A, P>; + type Iter = ParIter<'a, A, P, CHUNK_SIZE>; fn par_iter(&'a self) -> Self::Iter { ParIter { @@ -23,13 +24,14 @@ where } } -impl<'a, A, P> IntoParallelRefMutIterator<'a> for GenericVector +impl<'a, A, P, const CHUNK_SIZE: usize> IntoParallelRefMutIterator<'a> + for GenericVector where A: Clone + Send + Sync + 'a, P: SharedPointerKind + Send + Sync + 'a, { type Item = &'a mut A; - type Iter = ParIterMut<'a, A, P>; + type Iter = ParIterMut<'a, A, P, CHUNK_SIZE>; fn par_iter_mut(&'a mut self) -> Self::Iter { ParIterMut { @@ -41,14 +43,14 @@ where /// A parallel iterator for [`Vector`][Vector]. /// /// [Vector]: ../type.Vector.html -pub struct ParIter<'a, A, P: SharedPointerKind> +pub struct ParIter<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> where A: Clone + Send + Sync, { - focus: Focus<'a, A, P>, + focus: Focus<'a, A, P, CHUNK_SIZE>, } -impl<'a, A, P> ParallelIterator for ParIter<'a, A, P> +impl<'a, A, P, const CHUNK_SIZE: usize> ParallelIterator for ParIter<'a, A, P, CHUNK_SIZE> where A: Clone + Send + Sync + 'a, P: SharedPointerKind + Send + 'a, @@ -63,7 +65,7 @@ where } } -impl<'a, A, P> IndexedParallelIterator for ParIter<'a, A, P> +impl<'a, A, P, const CHUNK_SIZE: usize> IndexedParallelIterator for ParIter<'a, A, P, CHUNK_SIZE> where A: Clone + Send + Sync + 'a, P: SharedPointerKind + Send + 'a, @@ -90,15 +92,15 @@ where /// A mutable parallel iterator for [`Vector`][Vector]. /// /// [Vector]: ../type.Vector.html -pub struct ParIterMut<'a, A, P> +pub struct ParIterMut<'a, A, P, const CHUNK_SIZE: usize> where A: Clone + Send + Sync, P: SharedPointerKind, { - focus: FocusMut<'a, A, P>, + focus: FocusMut<'a, A, P, CHUNK_SIZE>, } -impl<'a, A, P> ParallelIterator for ParIterMut<'a, A, P> +impl<'a, A, P, const CHUNK_SIZE: usize> ParallelIterator for ParIterMut<'a, A, P, CHUNK_SIZE> where A: Clone + Send + Sync + 'a, P: SharedPointerKind + Send + Sync, @@ -113,7 +115,7 @@ where } } -impl<'a, A, P> IndexedParallelIterator for ParIterMut<'a, A, P> +impl<'a, A, P, const CHUNK_SIZE: usize> IndexedParallelIterator for ParIterMut<'a, A, P, CHUNK_SIZE> where A: Clone + Send + Sync + 'a, P: SharedPointerKind + Send + Sync, @@ -137,21 +139,21 @@ where } } -struct VectorProducer<'a, A, P> +struct VectorProducer<'a, A, P, const CHUNK_SIZE: usize> where A: Clone + Send + Sync, P: SharedPointerKind, { - focus: Focus<'a, A, P>, + focus: Focus<'a, A, P, CHUNK_SIZE>, } -impl<'a, A, P> Producer for VectorProducer<'a, A, P> +impl<'a, A, P, const CHUNK_SIZE: usize> Producer for VectorProducer<'a, A, P, CHUNK_SIZE> where A: Clone + Send + Sync + 'a, P: SharedPointerKind + Send + 'a, { type Item = &'a A; - type IntoIter = Iter<'a, A, P>; + type IntoIter = Iter<'a, A, P, CHUNK_SIZE>; fn into_iter(self) -> Self::IntoIter { self.focus.into_iter() @@ -166,21 +168,21 @@ where } } -struct VectorMutProducer<'a, A, P> +struct VectorMutProducer<'a, A, P, const CHUNK_SIZE: usize> where A: Clone + Send + Sync, P: SharedPointerKind, { - focus: FocusMut<'a, A, P>, + focus: FocusMut<'a, A, P, CHUNK_SIZE>, } -impl<'a, A, P> Producer for VectorMutProducer<'a, A, P> +impl<'a, A, P, const CHUNK_SIZE: usize> Producer for VectorMutProducer<'a, A, P, CHUNK_SIZE> where A: Clone + Send + Sync + 'a, P: SharedPointerKind + Send + Sync, { type Item = &'a mut A; - type IntoIter = IterMut<'a, A, P>; + type IntoIter = IterMut<'a, A, P, CHUNK_SIZE>; fn into_iter(self) -> Self::IntoIter { self.focus.into_iter() From 0badd8529b3322289150e1559092d03d232db740 Mon Sep 17 00:00:00 2001 From: Erik McClure Date: Fri, 17 Oct 2025 21:24:18 -0700 Subject: [PATCH 05/12] update version because of breaking change --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 968b986..415148b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -295,7 +295,7 @@ dependencies = [ [[package]] name = "imbl" -version = "6.1.0" +version = "6.2.0" dependencies = [ "arbitrary", "archery", diff --git a/Cargo.toml b/Cargo.toml index d1d5fb0..2f7ac88 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "imbl" -version = "6.1.0" +version = "6.2.0" authors = [ "Bodil Stokke ", "Joe Neeman ", From 77ac0c7b51a2474b792d276f2bfa2b11f4d1285d Mon Sep 17 00:00:00 2001 From: Erik McClure Date: Mon, 20 Oct 2025 17:14:58 -0700 Subject: [PATCH 06/12] Update to 2024 --- Cargo.lock | 16 ++++++------- Cargo.toml | 2 +- benches/utils/mod.rs | 16 ++++++------- benches/vector.rs | 5 ++-- src/hash/map.rs | 10 ++++---- src/nodes/hamt.rs | 34 +++++++++++++--------------- src/nodes/rrb.rs | 54 ++++++++++++++++++++++---------------------- src/ord/map.rs | 28 +++++++++++------------ src/tests/hashset.rs | 4 ++-- src/tests/ordset.rs | 4 ++-- src/tests/vector.rs | 22 ++++++++---------- src/util.rs | 4 ++-- src/vector/mod.rs | 29 ++++++++++++------------ 13 files changed, 109 insertions(+), 119 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 415148b..57cce34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,9 +71,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "bitmaps" @@ -128,18 +128,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.49" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f" +checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.49" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730" +checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" dependencies = [ "anstyle", "clap_lex", @@ -750,9 +750,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "syn" -version = "2.0.106" +version = "2.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 2f7ac88..239a145 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ authors = [ "Joe Neeman ", "Arthur Silva ", ] -edition = "2018" +edition = "2024" license = "MPL-2.0+" rust-version = "1.85" description = "Immutable collection datatypes" diff --git a/benches/utils/mod.rs b/benches/utils/mod.rs index 41df85e..1a6674c 100644 --- a/benches/utils/mod.rs +++ b/benches/utils/mod.rs @@ -2,7 +2,7 @@ use rand::distr::{Distribution, StandardUniform}; use rand::seq::SliceRandom; -use rand::{rngs::SmallRng, Rng, SeedableRng}; +use rand::{Rng, SeedableRng, rngs::SmallRng}; use std::collections::BTreeSet; use std::fmt::Debug; use std::hash::Hash; @@ -23,10 +23,10 @@ pub trait TestData: Clone + Debug + Ord + Eq + Hash { impl TestData for i64 { fn generate(size: usize) -> Vec { - let mut gen = SmallRng::seed_from_u64(1); + let mut rng = SmallRng::seed_from_u64(1); let mut set = BTreeSet::new(); while set.len() < size { - let next = gen.random::(); + let next = rng.random::(); set.insert(next); } set.into_iter().collect() @@ -35,12 +35,12 @@ impl TestData for i64 { impl TestData for String { fn generate(size: usize) -> Vec { - let mut gen = SmallRng::seed_from_u64(1); + let mut rng = SmallRng::seed_from_u64(1); let mut set = BTreeSet::new(); while set.len() < size { - let len = gen.random_range(5..20); + let len = rng.random_range(5..20); let s: String = (0..len) - .map(|_| gen.random_range(b'a'..=b'z') as char) + .map(|_| rng.random_range(b'a'..=b'z') as char) .collect(); set.insert(s); } @@ -58,8 +58,8 @@ where } pub fn reorder(vec: &[A]) -> Vec { - let mut gen = SmallRng::seed_from_u64(1); + let mut rng = SmallRng::seed_from_u64(1); let mut out = vec.to_vec(); - out.shuffle(&mut gen); + out.shuffle(&mut rng); out } diff --git a/benches/vector.rs b/benches/vector.rs index 80d3154..cb4f62b 100644 --- a/benches/vector.rs +++ b/benches/vector.rs @@ -1,7 +1,6 @@ -use criterion::{criterion_group, criterion_main, Bencher, Criterion}; -use imbl::shared_ptr::DefaultSharedPtr; -use imbl::vector::Vector; +use criterion::{Bencher, Criterion, criterion_group, criterion_main}; use imbl::GenericVector; +use imbl::shared_ptr::DefaultSharedPtr; use rand::seq::SliceRandom; use std::collections::VecDeque; use std::hint::black_box; diff --git a/src/hash/map.rs b/src/hash/map.rs index 2bc6f1a..4eb3182 100644 --- a/src/hash/map.rs +++ b/src/hash/map.rs @@ -33,8 +33,8 @@ use std::ops::{Add, Index, IndexMut}; use archery::{SharedPointer, SharedPointerKind}; use crate::nodes::hamt::{ - hash_key, Drain as NodeDrain, HashBits, HashValue, Iter as NodeIter, IterMut as NodeIterMut, - Node, + Drain as NodeDrain, HashBits, HashValue, Iter as NodeIter, IterMut as NodeIterMut, Node, + hash_key, }; use crate::shared_ptr::DefaultSharedPtr; @@ -725,9 +725,7 @@ where BK: Hash + Eq + ?Sized, K: Borrow, { - let Some(root) = self.root.as_mut() else { - return None; - }; + let root = self.root.as_mut()?; match SharedPointer::make_mut(root).get_mut(hash_key(&self.hasher, key), 0, key) { None => None, Some((key, value)) => Some((key, value)), @@ -1576,7 +1574,7 @@ where F: FnOnce(&mut V), { match &mut self { - Entry::Occupied(ref mut entry) => f(entry.get_mut()), + Entry::Occupied(entry) => f(entry.get_mut()), Entry::Vacant(_) => (), } self diff --git a/src/nodes/hamt.rs b/src/nodes/hamt.rs index 002a117..12b9a9a 100644 --- a/src/nodes/hamt.rs +++ b/src/nodes/hamt.rs @@ -133,7 +133,7 @@ where let mut index = Self::mask(hash, shift) as usize; while let Some(entry) = self.data.get(index) { return match entry { - Entry::Value(ref value, value_hash) => { + Entry::Value(value, value_hash) => { if hash_may_eq::(hash, *value_hash) && key == value.extract_key().borrow() { Some(value) } else if !self.linear_probing { @@ -143,21 +143,21 @@ where continue; } } - Entry::Node(ref child) => { + Entry::Node(child) => { assert_eq!( WIDTH, HASH_WIDTH, "SmallNode should not contain Node entries" ); child.get(hash, shift + HASH_SHIFT, key) } - Entry::SmallNode(ref small) => { + Entry::SmallNode(small) => { assert_eq!( WIDTH, HASH_WIDTH, "SmallNode should not contain SmallNode entries" ); small.get(hash, shift + HASH_SHIFT, key) } - Entry::Collision(ref coll) => coll.get(key), + Entry::Collision(coll) => coll.get(key), }; } None @@ -181,7 +181,7 @@ where #[allow(unsafe_code)] let this = unsafe { &mut *this }; return match this.data.get_mut(index) { - Some(Entry::Value(ref mut value, value_hash)) => { + Some(Entry::Value(value, value_hash)) => { if hash_may_eq::(hash, *value_hash) && key == value.extract_key().borrow() { Some(value) } else if !this.linear_probing { @@ -191,23 +191,21 @@ where continue; } } - Some(Entry::Node(ref mut child_ref)) => { + Some(Entry::Node(child_ref)) => { assert_eq!( WIDTH, HASH_WIDTH, "SmallNode should not contain Node entries" ); SharedPointer::make_mut(child_ref).get_mut(hash, shift + HASH_SHIFT, key) } - Some(Entry::SmallNode(ref mut small_ref)) => { + Some(Entry::SmallNode(small_ref)) => { assert_eq!( WIDTH, HASH_WIDTH, "SmallNode should not contain SmallNode entries" ); SharedPointer::make_mut(small_ref).get_mut(hash, shift + HASH_SHIFT, key) } - Some(Entry::Collision(ref mut coll_ref)) => { - SharedPointer::make_mut(coll_ref).get_mut(key) - } + Some(Entry::Collision(coll_ref)) => SharedPointer::make_mut(coll_ref).get_mut(key), None => None, }; } @@ -247,7 +245,7 @@ impl SmallNode { let mut index = Self::mask(hash, shift) as usize; while let Some(entry) = self.data.get_mut(index) { match entry { - Entry::Value(ref mut existing, existing_hash) => { + Entry::Value(existing, existing_hash) => { if hash_may_eq::(hash, *existing_hash) && existing.extract_key() == value.extract_key() { @@ -335,7 +333,7 @@ impl Node { // Value is here match entry { // Update value or create a subtree - Entry::Value(ref mut current, current_hash) => { + Entry::Value(current, current_hash) => { if hash_may_eq::(hash, *current_hash) && current.extract_key() == value.extract_key() { @@ -346,11 +344,11 @@ impl Node { continue; } } - Entry::Node(ref mut child_ref) => { + Entry::Node(child_ref) => { let child = SharedPointer::make_mut(child_ref); return child.insert(hash, shift + HASH_SHIFT, value); } - Entry::SmallNode(ref mut small_ref) => { + Entry::SmallNode(small_ref) => { let small = SharedPointer::make_mut(small_ref); match small.insert(hash, shift + HASH_SHIFT, value) { Ok(result) => return result, @@ -374,7 +372,7 @@ impl Node { } } // There's already a collision here. - Entry::Collision(ref mut collision) => { + Entry::Collision(collision) => { let coll = SharedPointer::make_mut(collision); return coll.insert(value); } @@ -439,7 +437,7 @@ impl Node { let new_node; let removed; match self.data.get_mut(index).unwrap() { - Entry::Node(ref mut child_ref) => { + Entry::Node(child_ref) => { let child = SharedPointer::make_mut(child_ref); match child.remove(hash, shift + HASH_SHIFT, key) { None => return None, @@ -455,7 +453,7 @@ impl Node { } } } - Entry::SmallNode(ref mut small_ref) => { + Entry::SmallNode(small_ref) => { let small = SharedPointer::make_mut(small_ref); match small.remove(hash, shift + HASH_SHIFT, key) { None => return None, @@ -473,7 +471,7 @@ impl Node { new_node = None; removed = self.data.remove(index).map(Entry::unwrap_value); } - Entry::Collision(ref mut coll_ref) => { + Entry::Collision(coll_ref) => { let coll = SharedPointer::make_mut(coll_ref); removed = coll.remove(key); if coll.len() == 1 { diff --git a/src/nodes/rrb.rs b/src/nodes/rrb.rs index 2db05d2..671eb39 100644 --- a/src/nodes/rrb.rs +++ b/src/nodes/rrb.rs @@ -9,8 +9,8 @@ use std::ops::Range; use archery::{SharedPointer, SharedPointerKind}; use crate::nodes::chunk::Chunk; -use crate::util::clone_ref; use crate::util::Side::{self, Left, Right}; +use crate::util::clone_ref; use self::Entry::*; @@ -69,7 +69,7 @@ impl Size { if let Size::Size(size) = self { *self = Size::table_from_size(level, *size); }; - if let Size::Table(ref mut size_ref) = self { + if let Size::Table(size_ref) = self { let size_table = SharedPointer::make_mut(size_ref); debug_assert!(size_table.len() < NODE_SIZE); match side { @@ -92,14 +92,14 @@ impl Size { fn pop(&mut self, side: Side, level: usize, value: usize) { let size = match self { - Size::Size(ref mut size) => match side { + Size::Size(size) => match side { Left => *size, Right => { *size -= value; return; } }, - Size::Table(ref mut size_ref) => { + Size::Table(size_ref) => { let size_table = SharedPointer::make_mut(size_ref); match side { Left => { @@ -124,8 +124,8 @@ impl Size { fn update(&mut self, index: usize, level: usize, value: isize) { let size = match self { - Size::Size(ref size) => *size, - Size::Table(ref mut size_ref) => { + &mut Size::Size(ref size) => *size, + Size::Table(size_ref) => { let size_table = SharedPointer::make_mut(size_ref); for entry in size_table.iter_mut().skip(index) { *entry = (*entry as isize + value) as usize; @@ -177,30 +177,30 @@ impl Clone for Entry Entry { fn len(&self) -> usize { match self { - Nodes(_, ref nodes) => nodes.len(), - Values(ref values) => values.len(), + Nodes(_, nodes) => nodes.len(), + Values(values) => values.len(), Empty => 0, } } fn is_full(&self) -> bool { match self { - Nodes(_, ref nodes) => nodes.is_full(), - Values(ref values) => values.is_full(), + Nodes(_, nodes) => nodes.is_full(), + Values(values) => values.is_full(), Empty => false, } } fn unwrap_values(&self) -> &Chunk { match self { - Values(ref values) => values, + Values(values) => values, _ => panic!("rrb::Entry::unwrap_values: expected values, found nodes"), } } fn unwrap_nodes(&self) -> &Chunk, NODE_SIZE> { match self { - Nodes(_, ref nodes) => nodes, + Nodes(_, nodes) => nodes, _ => panic!("rrb::Entry::unwrap_nodes: expected nodes, found values"), } } @@ -213,14 +213,14 @@ impl Entry { impl Entry { fn unwrap_values_mut(&mut self) -> &mut Chunk { match self { - Values(ref mut values) => SharedPointer::make_mut(values), + Values(values) => SharedPointer::make_mut(values), _ => panic!("rrb::Entry::unwrap_values_mut: expected values, found nodes"), } } fn unwrap_nodes_mut(&mut self) -> &mut Chunk, NODE_SIZE> { match self { - Nodes(_, ref mut nodes) => SharedPointer::make_mut(nodes), + Nodes(_, nodes) => SharedPointer::make_mut(nodes), _ => panic!("rrb::Entry::unwrap_nodes_mut: expected nodes, found values"), } } @@ -438,7 +438,7 @@ impl Node { 0 } else { match size { - Size::Table(ref size_table) => size_table[index - 1], + Size::Table(size_table) => size_table[index - 1], Size::Size(_) => index * NODE_SIZE.pow(level as u32), } } @@ -530,7 +530,7 @@ impl Node { let total: usize = lengths.iter().sum(); assert_eq!(*size, total); } - Size::Table(ref table) => { + Size::Table(table) => { assert_eq!(table.iter().len(), children.len()); for (index, current) in table.iter().enumerate() { let expected: usize = lengths.iter().take(index + 1).sum(); @@ -563,7 +563,7 @@ impl Node { Entry::Nodes(ref size, ref children) => { let label = match size { Size::Size(size) => size.to_string(), - Size::Table(ref table) => { + Size::Table(table) => { format!("\"{:?}\"", table.as_slice()) } }; @@ -607,7 +607,7 @@ impl Node { pub(crate) fn process(&self, f: &mut impl FnMut(&Chunk)) { match &self.children { - Entry::Values(xs) => f(&xs), + Entry::Values(xs) => f(xs), Entry::Nodes(_, children) => { for child in children.iter() { child.process(f); @@ -926,7 +926,7 @@ impl Node Node { + Size::Size(size) if at_last => { *size -= dropped; } - Size::Size(ref mut size) => { + Size::Size(size) => { let size_per_child = NODE_SIZE.pow(level as u32); let remainder = (target_idx + 1) * size_per_child; let new_size = remainder - dropped; @@ -968,7 +968,7 @@ impl Node { + Size::Table(size_ref) => { let size_table = SharedPointer::make_mut(size_ref); let dropped_size = size_table[size_table.len() - 1] - size_table[target_idx]; @@ -1161,11 +1161,11 @@ pub(crate) fn map_subsequence< } else { match &next_in.children { Entry::Values(xs) => { - let result = Node::from_chunk(level, SharedPointer::new(f(&xs, false).unwrap())); + let result = Node::from_chunk(level, SharedPointer::new(f(xs, false).unwrap())); prev_in.process(&mut |chunk| { f(chunk, true); }); - return result; + result } Entry::Nodes(_, children) => { let Entry::Nodes(_, prev_children) = &prev_in.children else { @@ -1183,7 +1183,7 @@ pub(crate) fn map_subsequence< let Entry::Nodes(_, prev_out_children) = &prev_out.children else { panic!("previous out structure doesn't match previous in structure") }; - return Node::parent( + Node::parent( level, Chunk::from_iter( prev_children @@ -1200,7 +1200,7 @@ pub(crate) fn map_subsequence< ) }), ), - ); + ) } Entry::Empty => Node::new(), } @@ -1213,7 +1213,7 @@ fn map_subseq_unpaired( f: &mut impl FnMut(&Chunk) -> Chunk, ) -> Node { match &next_in.children { - Entry::Values(xs) => Node::from_chunk(level, SharedPointer::new(f(&xs))), + Entry::Values(xs) => Node::from_chunk(level, SharedPointer::new(f(xs))), Entry::Nodes(_, children) => Node::parent( level, Chunk::from_iter( diff --git a/src/ord/map.rs b/src/ord/map.rs index ecac628..78c8983 100644 --- a/src/ord/map.rs +++ b/src/ord/map.rs @@ -1548,7 +1548,7 @@ where F: FnOnce(&mut V), { match &mut self { - Entry::Occupied(ref mut entry) => f(entry.get_mut()), + Entry::Occupied(entry) => f(entry.get_mut()), Entry::Vacant(_) => (), } self @@ -2305,12 +2305,12 @@ where } impl< - K: Ord + Hash + Eq + Clone, - V: Clone, - S: BuildHasher + Clone, - P1: SharedPointerKind, - P2: SharedPointerKind, - > From> for GenericOrdMap + K: Ord + Hash + Eq + Clone, + V: Clone, + S: BuildHasher + Clone, + P1: SharedPointerKind, + P2: SharedPointerKind, +> From> for GenericOrdMap { fn from(m: GenericHashMap) -> Self { m.into_iter().collect() @@ -2318,13 +2318,13 @@ impl< } impl< - 'a, - K: Ord + Hash + Eq + Clone, - V: Clone, - S: BuildHasher + Clone, - P1: SharedPointerKind, - P2: SharedPointerKind, - > From<&'a GenericHashMap> for GenericOrdMap + 'a, + K: Ord + Hash + Eq + Clone, + V: Clone, + S: BuildHasher + Clone, + P1: SharedPointerKind, + P2: SharedPointerKind, +> From<&'a GenericHashMap> for GenericOrdMap { fn from(m: &'a GenericHashMap) -> Self { m.iter().map(|(k, v)| (k.clone(), v.clone())).collect() diff --git a/src/tests/hashset.rs b/src/tests/hashset.rs index 01df2be..d2b43f4 100644 --- a/src/tests/hashset.rs +++ b/src/tests/hashset.rs @@ -30,11 +30,11 @@ where writeln!(out, "let mut set = HashSet::new();")?; for action in &self.0 { match action { - Action::Insert(ref value) => { + Action::Insert(value) => { expected.insert(value.clone()); writeln!(out, "set.insert({:?});", value)?; } - Action::Remove(ref value) => { + Action::Remove(value) => { expected.remove(value); writeln!(out, "set.remove({:?});", value)?; } diff --git a/src/tests/ordset.rs b/src/tests/ordset.rs index 80e245e..444067f 100644 --- a/src/tests/ordset.rs +++ b/src/tests/ordset.rs @@ -29,11 +29,11 @@ where writeln!(out, "let mut set = OrdSet::new();")?; for action in &self.0 { match action { - Action::Insert(ref value) => { + Action::Insert(value) => { expected.insert(value.clone()); writeln!(out, "set.insert({:?});", value)?; } - Action::Remove(ref value) => { + Action::Remove(value) => { expected.remove(value); writeln!(out, "set.remove({:?});", value)?; } diff --git a/src/tests/vector.rs b/src/tests/vector.rs index eb95929..570c95c 100644 --- a/src/tests/vector.rs +++ b/src/tests/vector.rs @@ -37,11 +37,11 @@ where writeln!(out, "let mut vec = Vector::new();")?; for action in &self.0 { match action { - Action::PushFront(ref value) => { + Action::PushFront(value) => { expected.insert(0, value.clone()); writeln!(out, "vec.push_front({:?});", value)? } - Action::PushBack(ref value) => { + Action::PushBack(value) => { expected.push(value.clone()); writeln!(out, "vec.push_back({:?});", value)? } @@ -55,12 +55,12 @@ where expected.pop(); writeln!(out, "vec.pop_back();")? } - Action::Insert(ref index, ref value) => { + Action::Insert(index, value) => { let index = cap_index(expected.len(), *index); expected.insert(index, value.clone()); writeln!(out, "vec.insert({:?}, {:?});", index, value)? } - Action::Remove(ref index) => { + Action::Remove(index) => { if !expected.is_empty() { let index = cap_index(expected.len(), *index); expected.remove(index); @@ -69,7 +69,7 @@ where continue; } } - Action::JoinLeft(ref vec) => { + Action::JoinLeft(vec) => { let mut vec_new = vec.clone(); vec_new.append(&mut expected); expected = vec_new; @@ -82,7 +82,7 @@ where writeln!(out, "vec_new.append(vec);")?; writeln!(out, "vec = vec_new;")? } - Action::JoinRight(ref vec) => { + Action::JoinRight(vec) => { expected.append(&mut vec.clone()); writeln!( out, @@ -91,12 +91,12 @@ where vec.len() )? } - Action::SplitLeft(ref index) => { + Action::SplitLeft(index) => { let index = cap_index(expected.len(), *index); expected.truncate(index); writeln!(out, "vec.split_off({:?});", index)? } - Action::SplitRight(ref index) => { + Action::SplitRight(index) => { let index = cap_index(expected.len(), *index); expected = expected.split_off(index); writeln!(out, "vec = vec.split_off({:?});", index)? @@ -111,11 +111,7 @@ where } fn cap_index(len: usize, index: usize) -> usize { - if len == 0 { - 0 - } else { - index % len - } + if len == 0 { 0 } else { index % len } } proptest! { diff --git a/src/util.rs b/src/util.rs index b68cecd..6c7f516 100644 --- a/src/util.rs +++ b/src/util.rs @@ -41,10 +41,10 @@ where #[cfg(test)] macro_rules! assert_covariant { - ($name:ident<$($gen:tt),*> in $param:ident) => { + ($name:ident<$($g:tt),*> in $param:ident) => { #[allow(dead_code, unused_assignments, unused_variables)] const _: () = { - type Tmp<$param> = $name<$($gen),*>; + type Tmp<$param> = $name<$($g),*>; fn assign<'a, 'b: 'a>(src: Tmp<&'b i32>, mut dst: Tmp<&'a i32>) { dst = src; } diff --git a/src/vector/mod.rs b/src/vector/mod.rs index 016d1b3..9964af3 100644 --- a/src/vector/mod.rs +++ b/src/vector/mod.rs @@ -61,7 +61,7 @@ use crate::nodes::chunk::Chunk; use crate::nodes::rrb::{Node, PopResult, PushResult, SplitResult}; use crate::shared_ptr::DefaultSharedPtr; use crate::sort; -use crate::util::{clone_ref, to_range, Side}; +use crate::util::{Side, clone_ref, to_range}; use self::VectorInner::{Full, Inline, Single}; @@ -1013,7 +1013,7 @@ impl GenericVector unreachable!("inline vecs should have been promoted"), // If both are single chunks and left has room for right: directly // memcpy right into left - Single(ref mut right) if total_length <= CHUNK_SIZE => { + Single(right) if total_length <= CHUNK_SIZE => { SharedPointer::make_mut(left).append(SharedPointer::make_mut(right)); return; } @@ -3033,14 +3033,14 @@ pub struct PersistentMap< } impl< - In: Clone, - Out: Clone, - Key: Eq + Hash, - P: SharedPointerKind, - F: FnMut(&In) -> Out, - Ex: Fn(&In) -> Key, - const CHUNK_SIZE: usize, - > PersistentMap + In: Clone, + Out: Clone, + Key: Eq + Hash, + P: SharedPointerKind, + F: FnMut(&In) -> Out, + Ex: Fn(&In) -> Key, + const CHUNK_SIZE: usize, +> PersistentMap { /// Initializes a new empty map state pub fn new(f: F, ex: Ex) -> Self { @@ -3166,9 +3166,9 @@ impl< panic!("invalid internal state"); }; Self::map_chunk( - &prev_in, + prev_in, next_in, - &prev_out, + prev_out, keylookup, &self.ex, &mut self.f, @@ -3192,10 +3192,9 @@ impl< } }; - let out = GenericVector { + GenericVector { vector: VectorInner::Single(inner), - }; - out + } } Full(rrb) => GenericVector { vector: VectorInner::Full(self.map_with_key_internal(rrb)), From 9aac29c74b4e3c5583537b4af84b6e23e3597468 Mon Sep 17 00:00:00 2001 From: Erik McClure Date: Mon, 20 Oct 2025 21:30:27 -0700 Subject: [PATCH 07/12] Working persistent fold --- src/nodes/rrb.rs | 118 ++++++++++++++++++++++++++++++++++++++++++ src/vector/mod.rs | 128 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 245 insertions(+), 1 deletion(-) diff --git a/src/nodes/rrb.rs b/src/nodes/rrb.rs index 671eb39..803dff7 100644 --- a/src/nodes/rrb.rs +++ b/src/nodes/rrb.rs @@ -1225,3 +1225,121 @@ fn map_subseq_unpaired( Entry::Empty => Node::new(), } } + +// not bothering to cache subfolds within a chunk; could be done to speed it up, but adds complexity with not much performance benefit when the chunk size is reasonably small and the zip is reasonably cheap +pub(crate) enum FoldSeqStore { + Values(T, SharedPointer, P>), // result of folding the chunk of leaves, the individual input leaves + Nodes( + T, + SharedPointer, NODE_SIZE>, P>, + SharedPointer, NODE_SIZE>, P>, + ), // result of folding the internal chunk, the original input chunk, and the stored folds of every subchunk of the input chunk + Empty, +} + +impl Clone + for FoldSeqStore +{ + fn clone(&self) -> Self { + match self { + Self::Values(arg0, arg1) => Self::Values(arg0.clone(), arg1.clone()), + Self::Nodes(arg0, arg1, arg2) => Self::Nodes(arg0.clone(), arg1.clone(), arg2.clone()), + Self::Empty => Self::Empty, + } + } +} + +// Fold over a slice that implements a binary tree fold +pub(crate) fn binary_fold(slice: &[T], z: T, f: &mut impl FnMut(T, T) -> T) -> T { + if slice.is_empty() { + z + } else { + binary_fold_inner::(slice, f) + } +} + +fn binary_fold_inner(slice: &[T], f: &mut impl FnMut(T, T) -> T) -> T { + // We just recursively split the slice in half until we have 1 or 2 elements + match slice.len() { + 0 => unreachable!(), + 1 => slice[0].clone(), + 2 => f(slice[0].clone(), slice[1].clone()), + _ => { + let (l, r) = slice.split_at(slice.len() / 2); + let lv = binary_fold_inner::(l, f); + let rv = binary_fold_inner::(r, f); + f(lv, rv) + } + } +} + +// TODO: We can probably remove z completely by allowing this to return Option instead, but this must be carefully done. +pub(crate) fn fold_subsequence( + input: &Node, + prev_out: FoldSeqStore, + f: &mut impl FnMut(T, T) -> T, + z: &T, +) -> (T, FoldSeqStore) { + match (&input.children, prev_out) { + (Entry::Values(xs), y) => { + if let FoldSeqStore::Values(total, ys) = y + && SharedPointer::ptr_eq(&xs, &ys) + { + (total.clone(), FoldSeqStore::Values(total, ys)) + } else if xs.is_empty() { + (z.clone(), FoldSeqStore::Empty) + } else { + let result = binary_fold_inner::(&xs, f); + (result.clone(), FoldSeqStore::Values(result, xs.clone())) + } + } + (Entry::Nodes(_, children), FoldSeqStore::Nodes(total, old_children, total_children)) => { + if SharedPointer::ptr_eq(&children, &old_children) { + ( + total.clone(), + FoldSeqStore::Nodes(total, old_children, total_children), + ) + } else if children.is_empty() { + (z.clone(), FoldSeqStore::Empty) + } else { + let mut outputs: Chunk = Chunk::new(); + let mut nodes = Chunk::new(); + for (input, prev_out) in children.iter().zip(total_children.iter()) { + let (output, next_out) = fold_subsequence(input, prev_out.clone(), f, z); + // Never push an "empty" result, or it will break the fold because we do not have a zero element, only a unit element z. + if !matches!(next_out, FoldSeqStore::Empty) { + outputs.push_back(output); + nodes.push_back(next_out); + } + } + + let total = binary_fold(&outputs, z.clone(), f); + + ( + total.clone(), + FoldSeqStore::Nodes(total, children.clone(), SharedPointer::new(nodes)), + ) + } + } + (Entry::Nodes(_, children), _) => { + let mut outputs: Chunk = Chunk::new(); + let mut nodes = Chunk::new(); + for input in children.iter() { + let (output, next_out) = fold_subsequence(input, FoldSeqStore::Empty, f, z); + // Never push an "empty" result, or it will break the fold because we do not have a zero element, only a unit element z. + if !matches!(next_out, FoldSeqStore::Empty) { + outputs.push_back(output); + nodes.push_back(next_out); + } + } + + let total = binary_fold(&outputs, z.clone(), f); + + ( + total.clone(), + FoldSeqStore::Nodes(total, children.clone(), SharedPointer::new(nodes)), + ) + } + (Entry::Empty, _) => (z.clone(), FoldSeqStore::Empty), + } +} diff --git a/src/vector/mod.rs b/src/vector/mod.rs index 9964af3..0456595 100644 --- a/src/vector/mod.rs +++ b/src/vector/mod.rs @@ -58,7 +58,9 @@ use archery::{SharedPointer, SharedPointerKind}; use imbl_sized_chunks::InlineArray; use crate::nodes::chunk::Chunk; -use crate::nodes::rrb::{Node, PopResult, PushResult, SplitResult}; +use crate::nodes::rrb::{ + FoldSeqStore, Node, PopResult, PushResult, SplitResult, binary_fold, fold_subsequence, +}; use crate::shared_ptr::DefaultSharedPtr; use crate::sort; use crate::util::{Side, clone_ref, to_range}; @@ -3305,6 +3307,86 @@ impl< } } +/// The function must be Associative, meaning `f(f(a, b), c) == f(a, f(b, c))`, but doesn't need to be Commutative. +/// z will only be returned if the slice is empty. Ideally, z should be the identity element (0 for addition, 1 for multiplication). +pub struct PersistentFold T, P: SharedPointerKind, const CHUNK_SIZE: usize> { + outer_f: FoldSeqStore, + inner_f: FoldSeqStore, + middle: FoldSeqStore, + inner_b: FoldSeqStore, + outer_b: FoldSeqStore, + f: F, + z: T, +} + +impl T, P: SharedPointerKind, const CHUNK_SIZE: usize> + PersistentFold +{ + /// Initializes a new empty fold state + pub fn new(f: F, z: T) -> Self { + Self { + outer_f: FoldSeqStore::Empty, + inner_f: FoldSeqStore::Empty, + middle: FoldSeqStore::Empty, + inner_b: FoldSeqStore::Empty, + outer_b: FoldSeqStore::Empty, + f, + z, + } + } + + /// Produces an output vector from the input vector using a map function and a key extractor. + pub fn fold(&mut self, from: &GenericVector) -> T { + match &from.vector { + Inline(chunk) => binary_fold(&chunk, self.z.clone(), &mut self.f), + Single(chunk) => { + if let FoldSeqStore::Values(v, prev) = &self.inner_f + && SharedPointer::ptr_eq(prev, chunk) + { + v.clone() + } else { + let result = binary_fold(&chunk, self.z.clone(), &mut self.f); + self.inner_f = FoldSeqStore::Values(result.clone(), chunk.clone()); + result + } + } + Full(rrb) => { + let mut outer = Chunk::::new(); + for (old_node, chunk) in [ + (&mut self.outer_f, &rrb.outer_f), + (&mut self.inner_f, &rrb.inner_f), + (&mut self.inner_b, &rrb.inner_b), + (&mut self.outer_b, &rrb.outer_b), + ] { + if let &mut FoldSeqStore::Values(ref v, ref old_chunk) = old_node + && SharedPointer::ptr_eq(chunk, old_chunk) + { + if chunk.len() > 0 { + outer.push_back(v.clone()); + } + } else { + let result = binary_fold(&chunk, self.z.clone(), &mut self.f); + *old_node = FoldSeqStore::Values(result.clone(), chunk.clone()); + if chunk.len() > 0 { + outer.push_back(result); + } + } + } + let mut middle = FoldSeqStore::Empty; + std::mem::swap(&mut self.middle, &mut middle); + let (v, mut new_middle) = + fold_subsequence(&rrb.middle, middle, &mut self.f, &self.z); + std::mem::swap(&mut self.middle, &mut new_middle); + if !matches!(self.middle, FoldSeqStore::Empty) { + outer.push_back(v); + } + + binary_fold(&outer, self.z.clone(), &mut self.f) + } + } + } +} + #[test] fn test_vector_map_basic() { let a = vector![1, 2, 3, 4]; @@ -3350,3 +3432,47 @@ fn test_vector_map_big() { assert!(mutation_count < len * 2); } + +#[test] +fn test_vector_fold_basic() { + let a = vector![1, 2, 3, 4]; + + let mut fold = PersistentFold::::new(|l, r| l + r, 0); + + assert_eq!(fold.fold(&a), 1 + 2 + 3 + 4); + assert_eq!(fold.fold(&vector![]), 0); + assert_eq!(fold.fold(&vector![1]), 1); + assert_eq!(fold.fold(&vector![1, 2]), 3); +} + +#[test] +fn test_vector_fold_big() { + const COUNT: usize = 10000; + const BASE: i64 = (COUNT * (COUNT + 1) / 2) as i64; + + let mut a = Vector::from_iter((1..=COUNT).map(|i| i as i64)); + let mut mutation_count = 0; + + let mut fold = PersistentFold::::new( + |l, r| { + mutation_count += 1; + l + r + }, + 0, + ); + + let mut b = fold.fold(&a); + assert_eq!(b, BASE); + + for i in 0..COUNT { + a[i] += 1; + b = fold.fold(&a); + assert_eq!(b, BASE + i as i64 + 1); + } + + // The maximum bound of calls to f() each time we call fold() should be log2(N/NODE_SIZE) * NODE_SIZE. + const MAX_MUTATION_COUNT: usize = COUNT + * ((COUNT / crate::config::VECTOR_CHUNK_SIZE).ilog2() as usize + * crate::config::VECTOR_CHUNK_SIZE); + assert!(mutation_count < MAX_MUTATION_COUNT); +} From 643447ac11d08c31aa3f36c18c77a650556f79e8 Mon Sep 17 00:00:00 2001 From: Erik McClure Date: Tue, 17 Feb 2026 11:33:24 -0800 Subject: [PATCH 08/12] Adjust fold to return an option. --- src/nodes/rrb.rs | 74 ++++++++++++---------- src/vector/mod.rs | 152 ++++++++++++++++++++++++++++++---------------- 2 files changed, 140 insertions(+), 86 deletions(-) diff --git a/src/nodes/rrb.rs b/src/nodes/rrb.rs index 803dff7..0d8935f 100644 --- a/src/nodes/rrb.rs +++ b/src/nodes/rrb.rs @@ -1237,6 +1237,15 @@ pub(crate) enum FoldSeqStore { Empty, } +impl FoldSeqStore { + pub(crate) fn get(&self) -> Option { + match self { + Self::Values(v, _) | Self::Nodes(v, _, _) => Some(v.clone()), + Self::Empty => None, + } + } +} + impl Clone for FoldSeqStore { @@ -1250,12 +1259,9 @@ impl Clone } // Fold over a slice that implements a binary tree fold -pub(crate) fn binary_fold(slice: &[T], z: T, f: &mut impl FnMut(T, T) -> T) -> T { - if slice.is_empty() { - z - } else { - binary_fold_inner::(slice, f) - } +pub(crate) fn binary_fold(slice: &[T], f: &mut impl FnMut(T, T) -> T) -> T { + assert!(!slice.is_empty()); + binary_fold_inner::(slice, f) } fn binary_fold_inner(slice: &[T], f: &mut impl FnMut(T, T) -> T) -> T { @@ -1278,68 +1284,70 @@ pub(crate) fn fold_subsequence, prev_out: FoldSeqStore, f: &mut impl FnMut(T, T) -> T, - z: &T, -) -> (T, FoldSeqStore) { +) -> FoldSeqStore { match (&input.children, prev_out) { (Entry::Values(xs), y) => { if let FoldSeqStore::Values(total, ys) = y && SharedPointer::ptr_eq(&xs, &ys) { - (total.clone(), FoldSeqStore::Values(total, ys)) + FoldSeqStore::Values(total, ys) } else if xs.is_empty() { - (z.clone(), FoldSeqStore::Empty) + FoldSeqStore::Empty } else { let result = binary_fold_inner::(&xs, f); - (result.clone(), FoldSeqStore::Values(result, xs.clone())) + FoldSeqStore::Values(result, xs.clone()) } } (Entry::Nodes(_, children), FoldSeqStore::Nodes(total, old_children, total_children)) => { if SharedPointer::ptr_eq(&children, &old_children) { - ( - total.clone(), - FoldSeqStore::Nodes(total, old_children, total_children), - ) + FoldSeqStore::Nodes(total, old_children, total_children) } else if children.is_empty() { - (z.clone(), FoldSeqStore::Empty) + FoldSeqStore::Empty } else { let mut outputs: Chunk = Chunk::new(); let mut nodes = Chunk::new(); for (input, prev_out) in children.iter().zip(total_children.iter()) { - let (output, next_out) = fold_subsequence(input, prev_out.clone(), f, z); + let next_out = fold_subsequence(input, prev_out.clone(), f); // Never push an "empty" result, or it will break the fold because we do not have a zero element, only a unit element z. - if !matches!(next_out, FoldSeqStore::Empty) { + if let Some(output) = next_out.get() { outputs.push_back(output); nodes.push_back(next_out); } } - let total = binary_fold(&outputs, z.clone(), f); - - ( - total.clone(), - FoldSeqStore::Nodes(total, children.clone(), SharedPointer::new(nodes)), - ) + if outputs.is_empty() { + FoldSeqStore::Empty + } else { + FoldSeqStore::Nodes( + binary_fold(&outputs, f), + children.clone(), + SharedPointer::new(nodes), + ) + } } } (Entry::Nodes(_, children), _) => { let mut outputs: Chunk = Chunk::new(); let mut nodes = Chunk::new(); for input in children.iter() { - let (output, next_out) = fold_subsequence(input, FoldSeqStore::Empty, f, z); + let next_out = fold_subsequence(input, FoldSeqStore::Empty, f); // Never push an "empty" result, or it will break the fold because we do not have a zero element, only a unit element z. - if !matches!(next_out, FoldSeqStore::Empty) { + if let Some(output) = next_out.get() { outputs.push_back(output); nodes.push_back(next_out); } } - let total = binary_fold(&outputs, z.clone(), f); - - ( - total.clone(), - FoldSeqStore::Nodes(total, children.clone(), SharedPointer::new(nodes)), - ) + if outputs.is_empty() { + FoldSeqStore::Empty + } else { + FoldSeqStore::Nodes( + binary_fold(&outputs, f), + children.clone(), + SharedPointer::new(nodes), + ) + } } - (Entry::Empty, _) => (z.clone(), FoldSeqStore::Empty), + (Entry::Empty, _) => FoldSeqStore::Empty, } } diff --git a/src/vector/mod.rs b/src/vector/mod.rs index 0456595..b85883a 100644 --- a/src/vector/mod.rs +++ b/src/vector/mod.rs @@ -49,6 +49,7 @@ use std::borrow::Borrow; use std::cmp::Ordering; use std::fmt::{Debug, Error, Formatter}; use std::hash::{Hash, Hasher}; +use std::io::Chain; use std::iter::Sum; use std::iter::{FromIterator, FusedIterator}; use std::mem::{replace, swap}; @@ -3118,13 +3119,16 @@ impl< ) -> GenericVector { match &from.vector { Inline(next_in) => { - let mut inline = InlineArray::new(); + let mut next = GenericVector { + vector: VectorInner::Inline(InlineArray::new()), + }; + Self::map_next_in( &mut self.keylookup, next_in.iter(), &self.ex, &mut self.f, - |item| inline.push(item.clone()), + |item| next.push_back(item.clone()), ); Self::clear_prev_in( &mut self.keylookup, @@ -3132,70 +3136,70 @@ impl< &self.ex, ); self.previous_in = VectorInner::Inline(next_in.clone()); - GenericVector { - vector: VectorInner::Inline(inline), - } + next } Single(next_in) => { match &mut self.previous_out { Inline(chunk) => self.previous_out = Single(SharedPointer::new(chunk.into())), Single(_) => (), Full(_) => { - let mut chunk = Chunk::new(); + let mut next = GenericVector { + vector: VectorInner::Single(SharedPointer::new(Chunk::new())), + }; Self::map_next_in( &mut self.keylookup, next_in.iter(), &self.ex, &mut self.f, - |v| chunk.push_back(v.clone()), + |v| next.push_back(v.clone()), ); Self::clear_prev_in( &mut self.keylookup, Iter::from_focus(focus::Focus::new_inner(&self.previous_in)), &self.ex, ); - return GenericVector { - vector: VectorInner::Single(SharedPointer::new(chunk)), - }; + return next; } } - let inner = match &self.previous_in { + match &self.previous_in { Single(prev_in) => { let (VectorInner::Single(prev_out), keylookup) = (&self.previous_out, &mut self.keylookup) else { panic!("invalid internal state"); }; - Self::map_chunk( + let inner = Self::map_chunk( prev_in, next_in, prev_out, keylookup, &self.ex, &mut self.f, - ) + ); + + GenericVector { + vector: VectorInner::Single(inner), + } } Inline(_) | Full(_) => { - let mut chunk = Chunk::new(); + let mut next = GenericVector { + vector: VectorInner::Single(SharedPointer::new(Chunk::new())), + }; Self::map_next_in( &mut self.keylookup, next_in.iter(), &self.ex, &mut self.f, - |item| chunk.push_back(item.clone()), + |item| next.push_back(item.clone()), ); Self::clear_prev_in( &mut self.keylookup, Iter::from_focus(focus::Focus::new_inner(&self.previous_in)), &self.ex, ); - SharedPointer::new(chunk) + next } - }; - - GenericVector { - vector: VectorInner::Single(inner), } } Full(rrb) => GenericVector { @@ -3308,7 +3312,6 @@ impl< } /// The function must be Associative, meaning `f(f(a, b), c) == f(a, f(b, c))`, but doesn't need to be Commutative. -/// z will only be returned if the slice is empty. Ideally, z should be the identity element (0 for addition, 1 for multiplication). pub struct PersistentFold T, P: SharedPointerKind, const CHUNK_SIZE: usize> { outer_f: FoldSeqStore, inner_f: FoldSeqStore, @@ -3316,14 +3319,13 @@ pub struct PersistentFold T, P: SharedPointerKind, const CH inner_b: FoldSeqStore, outer_b: FoldSeqStore, f: F, - z: T, } impl T, P: SharedPointerKind, const CHUNK_SIZE: usize> PersistentFold { /// Initializes a new empty fold state - pub fn new(f: F, z: T) -> Self { + pub fn new(f: F) -> Self { Self { outer_f: FoldSeqStore::Empty, inner_f: FoldSeqStore::Empty, @@ -3331,23 +3333,31 @@ impl T, P: SharedPointerKind, const CHUNK_SIZE: usiz inner_b: FoldSeqStore::Empty, outer_b: FoldSeqStore::Empty, f, - z, } } - /// Produces an output vector from the input vector using a map function and a key extractor. - pub fn fold(&mut self, from: &GenericVector) -> T { + /// Produces an output value from the input vector using a fold operation + pub fn fold(&mut self, from: &GenericVector) -> Option { match &from.vector { - Inline(chunk) => binary_fold(&chunk, self.z.clone(), &mut self.f), + Inline(chunk) => { + if chunk.is_empty() { + None + } else { + Some(binary_fold(&chunk, &mut self.f)) + } + } Single(chunk) => { if let FoldSeqStore::Values(v, prev) = &self.inner_f && SharedPointer::ptr_eq(prev, chunk) { - v.clone() + Some(v.clone()) + } else if chunk.is_empty() { + self.inner_f = FoldSeqStore::Empty; + None } else { - let result = binary_fold(&chunk, self.z.clone(), &mut self.f); + let result = binary_fold(&chunk, &mut self.f); self.inner_f = FoldSeqStore::Values(result.clone(), chunk.clone()); - result + Some(result) } } Full(rrb) => { @@ -3361,27 +3371,30 @@ impl T, P: SharedPointerKind, const CHUNK_SIZE: usiz if let &mut FoldSeqStore::Values(ref v, ref old_chunk) = old_node && SharedPointer::ptr_eq(chunk, old_chunk) { - if chunk.len() > 0 { + if !chunk.is_empty() { outer.push_back(v.clone()); } + } else if chunk.is_empty() { + *old_node = FoldSeqStore::Empty; } else { - let result = binary_fold(&chunk, self.z.clone(), &mut self.f); + let result = binary_fold(&chunk, &mut self.f); *old_node = FoldSeqStore::Values(result.clone(), chunk.clone()); - if chunk.len() > 0 { - outer.push_back(result); - } + outer.push_back(result); } } let mut middle = FoldSeqStore::Empty; std::mem::swap(&mut self.middle, &mut middle); - let (v, mut new_middle) = - fold_subsequence(&rrb.middle, middle, &mut self.f, &self.z); + let mut new_middle = fold_subsequence(&rrb.middle, middle, &mut self.f); std::mem::swap(&mut self.middle, &mut new_middle); - if !matches!(self.middle, FoldSeqStore::Empty) { + if let Some(v) = self.middle.get() { outer.push_back(v); } - binary_fold(&outer, self.z.clone(), &mut self.f) + if outer.is_empty() { + None + } else { + Some(binary_fold(&outer, &mut self.f)) + } } } } @@ -3401,6 +3414,42 @@ fn test_vector_map_basic() { assert_eq!(b[3], 16); } +#[test] +fn test_vector_map_ref() { + use std::rc::Rc; + { + let a = vector![Rc::new(1), Rc::new(2), Rc::new(3), Rc::new(4)]; + + let mut map = PersistentMap::, i32, i32, _, _, _, _>::new( + |x| *x.as_ref() * *x.as_ref(), + |x| *x.as_ref(), + ); + + let b = map.map(&a); + + assert_eq!(b[0], 1); + assert_eq!(b[1], 4); + assert_eq!(b[2], 9); + assert_eq!(b[3], 16); + } + + { + let a = vector![Rc::new(1), Rc::new(2), Rc::new(3), Rc::new(4)]; + + let mut map = PersistentMap::, i32, Rc, _, _, _, _>::new( + |x| *x.as_ref() * *x.as_ref(), + |x| x.clone(), + ); + + let b = map.map(&a); + + assert_eq!(b[0], 1); + assert_eq!(b[1], 4); + assert_eq!(b[2], 9); + assert_eq!(b[3], 16); + } +} + #[test] fn test_vector_map_big() { const COUNT: usize = 10000; @@ -3437,12 +3486,12 @@ fn test_vector_map_big() { fn test_vector_fold_basic() { let a = vector![1, 2, 3, 4]; - let mut fold = PersistentFold::::new(|l, r| l + r, 0); + let mut fold = PersistentFold::::new(|l, r| l + r); - assert_eq!(fold.fold(&a), 1 + 2 + 3 + 4); - assert_eq!(fold.fold(&vector![]), 0); - assert_eq!(fold.fold(&vector![1]), 1); - assert_eq!(fold.fold(&vector![1, 2]), 3); + assert_eq!(fold.fold(&a), Some(1 + 2 + 3 + 4)); + assert_eq!(fold.fold(&vector![]), None); + assert_eq!(fold.fold(&vector![1]), Some(1)); + assert_eq!(fold.fold(&vector![1, 2]), Some(3)); } #[test] @@ -3453,21 +3502,18 @@ fn test_vector_fold_big() { let mut a = Vector::from_iter((1..=COUNT).map(|i| i as i64)); let mut mutation_count = 0; - let mut fold = PersistentFold::::new( - |l, r| { - mutation_count += 1; - l + r - }, - 0, - ); + let mut fold = PersistentFold::::new(|l, r| { + mutation_count += 1; + l + r + }); let mut b = fold.fold(&a); - assert_eq!(b, BASE); + assert_eq!(b, Some(BASE)); for i in 0..COUNT { a[i] += 1; b = fold.fold(&a); - assert_eq!(b, BASE + i as i64 + 1); + assert_eq!(b, Some(BASE + i as i64 + 1)); } // The maximum bound of calls to f() each time we call fold() should be log2(N/NODE_SIZE) * NODE_SIZE. From ac6fb624f6cc1dc14dd0a9eb0e1f960da31ca9aa Mon Sep 17 00:00:00 2001 From: Erik McClure Date: Tue, 24 Feb 2026 18:18:43 -0800 Subject: [PATCH 09/12] add default arguments --- src/hash/map.rs | 2 +- src/hash/set.rs | 6 +++--- src/vector/mod.rs | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/hash/map.rs b/src/hash/map.rs index 4eb3182..cedf574 100644 --- a/src/hash/map.rs +++ b/src/hash/map.rs @@ -102,7 +102,7 @@ pub type HashMap = GenericHashMap; /// [std::cmp::Eq]: https://doc.rust-lang.org/std/cmp/trait.Eq.html /// [std::hash::Hash]: https://doc.rust-lang.org/std/hash/trait.Hash.html /// [std::collections::hash_map::RandomState]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html -pub struct GenericHashMap { +pub struct GenericHashMap { size: usize, root: Option, P>>, hasher: S, diff --git a/src/hash/set.rs b/src/hash/set.rs index fa18d19..f73a75e 100644 --- a/src/hash/set.rs +++ b/src/hash/set.rs @@ -31,10 +31,10 @@ use std::ops::{Add, Deref, Mul}; use archery::{SharedPointer, SharedPointerKind}; -use crate::nodes::hamt::{hash_key, Drain as NodeDrain, HashValue, Iter as NodeIter, Node}; +use crate::GenericVector; +use crate::nodes::hamt::{Drain as NodeDrain, HashValue, Iter as NodeIter, Node, hash_key}; use crate::ordset::GenericOrdSet; use crate::shared_ptr::DefaultSharedPtr; -use crate::GenericVector; /// Construct a set from a sequence of values. /// @@ -96,7 +96,7 @@ pub type HashSet = GenericHashSet; /// [std::cmp::Eq]: https://doc.rust-lang.org/std/cmp/trait.Eq.html /// [std::hash::Hash]: https://doc.rust-lang.org/std/hash/trait.Hash.html /// [std::collections::hash_map::RandomState]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html -pub struct GenericHashSet { +pub struct GenericHashSet { hasher: S, root: Option, P>, P>>, size: usize, diff --git a/src/vector/mod.rs b/src/vector/mod.rs index b85883a..1f79a36 100644 --- a/src/vector/mod.rs +++ b/src/vector/mod.rs @@ -49,7 +49,6 @@ use std::borrow::Borrow; use std::cmp::Ordering; use std::fmt::{Debug, Error, Formatter}; use std::hash::{Hash, Hasher}; -use std::io::Chain; use std::iter::Sum; use std::iter::{FromIterator, FusedIterator}; use std::mem::{replace, swap}; From 7dc4f5afde27f259566a36ffc04bf561f16c06e7 Mon Sep 17 00:00:00 2001 From: Erik McClure Date: Sun, 1 Mar 2026 07:42:38 -0800 Subject: [PATCH 10/12] Update rust version after merge --- Cargo.toml | 7 +++++-- src/nodes/hamt.rs | 28 +++++++++++++--------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7842959..5f925de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ authors = [ "Joe Neeman ", "Arthur Silva ", ] -edition = "2018" +edition = "2024" license = "MPL-2.0+" rust-version = "1.85" description = "Immutable collection datatypes" @@ -50,7 +50,10 @@ proptest = { version = "1.0", optional = true } serde_core = { version = "1.0.224", optional = true } rayon = { version = "1", optional = true } arbitrary = { version = "1.0", optional = true } -bincode = {version = "2.0.1", optional = true, default-features=false, features = ["alloc", "std"]} +bincode = { version = "2.0.1", optional = true, default-features = false, features = [ + "alloc", + "std", +] } wide = "0.7" equivalent = "1.0.2" diff --git a/src/nodes/hamt.rs b/src/nodes/hamt.rs index 0679fc1..08140b4 100644 --- a/src/nodes/hamt.rs +++ b/src/nodes/hamt.rs @@ -213,7 +213,7 @@ where while let Some(offset) = bitmap.first_index() { let index = group * GROUP_WIDTH + offset; - let (ref value, value_hash) = self.data.get(index).unwrap(); + let (value, value_hash) = self.data.get(index).unwrap(); if hash_may_eq::(hash, *value_hash) && key.equivalent(value.extract_key()) { return Some(value); } @@ -236,7 +236,7 @@ where let index = group * GROUP_WIDTH + offset; #[allow(unsafe_code)] let this = unsafe { &mut *this }; - let (ref mut value, value_hash) = this.data.get_mut(index).unwrap(); + let (value, value_hash) = this.data.get_mut(index).unwrap(); if hash_may_eq::(hash, *value_hash) && key.equivalent(value.extract_key()) { return Some(value); } @@ -254,7 +254,7 @@ where while let Some(offset) = bitmap.first_index() { let index = group * GROUP_WIDTH + offset; - let (ref value, value_hash) = self.data.get(index).unwrap(); + let (value, value_hash) = self.data.get(index).unwrap(); if hash_may_eq::(hash, *value_hash) && key.equivalent(value.extract_key()) { let mut ctrl_array = self.control[group].to_array(); ctrl_array[offset] = 0; @@ -414,12 +414,12 @@ impl HamtNode { // This is less relevant in other code paths that may include // atomics, memory allocation (e.g. insert, remove) etc.. match entry { - Entry::HamtNode(ref child) => { + Entry::HamtNode(child) => { node = child; shift += HASH_SHIFT; continue; } - Entry::Value(ref value, value_hash) => { + Entry::Value(value, value_hash) => { return if hash_may_eq::(hash, *value_hash) && key.equivalent(value.extract_key()) { @@ -443,9 +443,9 @@ impl HamtNode { Q: Equivalent + ?Sized, { match entry { - Entry::SmallSimdNode(ref small) => small.get(hash, key), - Entry::LargeSimdNode(ref large) => large.get(hash, key), - Entry::Collision(ref coll) => coll.get(key), + Entry::SmallSimdNode(small) => small.get(hash, key), + Entry::LargeSimdNode(large) => large.get(hash, key), + Entry::Collision(coll) => coll.get(key), _ => unreachable!(), } } @@ -457,25 +457,23 @@ impl HamtNode { { let index = Self::mask(hash, shift) as usize; match self.data.get_mut(index) { - Some(Entry::HamtNode(ref mut child_ref)) => { + Some(Entry::HamtNode(child_ref)) => { SharedPointer::make_mut(child_ref).get_mut(hash, shift + HASH_SHIFT, key) } - Some(Entry::SmallSimdNode(ref mut small_ref)) => { + Some(Entry::SmallSimdNode(small_ref)) => { SharedPointer::make_mut(small_ref).get_mut(hash, key) } - Some(Entry::LargeSimdNode(ref mut large_ref)) => { + Some(Entry::LargeSimdNode(large_ref)) => { SharedPointer::make_mut(large_ref).get_mut(hash, key) } - Some(Entry::Value(ref mut value, value_hash)) => { + Some(Entry::Value(value, value_hash)) => { if hash_may_eq::(hash, *value_hash) && key.equivalent(value.extract_key()) { Some(value) } else { None } } - Some(Entry::Collision(ref mut coll_ref)) => { - SharedPointer::make_mut(coll_ref).get_mut(key) - } + Some(Entry::Collision(coll_ref)) => SharedPointer::make_mut(coll_ref).get_mut(key), None => None, } } From abc86a1babdb6ee0e77906b875f10b45f4d02ff2 Mon Sep 17 00:00:00 2001 From: Erik McClure Date: Tue, 3 Mar 2026 16:15:34 -0800 Subject: [PATCH 11/12] Generic Refactor --- Cargo.lock | 647 ++++++++++++++++++++++++------------------- Cargo.toml | 12 +- benches/vector.rs | 10 +- src/arbitrary.rs | 25 +- src/bincode.rs | 34 ++- src/hash/map.rs | 163 ++++++----- src/hash/set.rs | 158 ++++++----- src/lib.rs | 12 +- src/nodes/hamt.rs | 2 +- src/ord/map.rs | 149 +++++----- src/ord/set.rs | 122 ++++---- src/quickcheck.rs | 34 +-- src/ser.rs | 46 +-- src/sort.rs | 6 +- src/tests/hashset.rs | 2 +- src/tests/vector.rs | 12 +- src/vector/focus.rs | 6 +- src/vector/mod.rs | 218 ++++++++------- src/vector/rayon.rs | 4 +- 19 files changed, 871 insertions(+), 791 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72d531c..2ca4c78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -19,9 +19,15 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "arbitrary" @@ -31,9 +37,9 @@ checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" [[package]] name = "archery" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae2ed21cd55021f05707a807a5fc85695dafb98832921f6cfa06db67ca5b869" +checksum = "70e0a5f99dfebb87bb342d0f53bb92c81842e100bbb915223e38349580e5441d" dependencies = [ "triomphe", ] @@ -71,9 +77,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" -version = "2.9.2" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bitmaps" @@ -83,15 +89,15 @@ checksum = "a1d084b0137aaa901caf9f1e8b21daa6aa24d41cd806e111335541eff9683bd6" [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bytemuck" -version = "1.24.0" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" [[package]] name = "cast" @@ -101,9 +107,20 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" -version = "1.0.1" +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 = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core 0.10.0", +] [[package]] name = "ciborium" @@ -134,18 +151,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.45" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.44" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" dependencies = [ "anstyle", "clap_lex", @@ -153,9 +170,18 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.5" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] [[package]] name = "criterion" @@ -234,15 +260,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] -name = "env_logger" -version = "0.8.4" +name = "env_filter" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +checksum = "7a1c3cc8e57274ec99de65301228b537f1e4eedc1b8e0f9411c6caac8ae7308f" dependencies = [ "log", "regex", ] +[[package]] +name = "env_logger" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2daee4ea451f429a58296525ddf28b45a3b64f1acf6587e2067437bb11e218d" +dependencies = [ + "env_filter", + "log", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -251,12 +287,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys", ] [[package]] @@ -271,42 +307,79 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "getrandom" -version = "0.2.16" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "r-efi", + "wasip2", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "rand_core 0.10.0", + "wasip2", + "wasip3", ] [[package]] name = "half" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +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 = "imbl" -version = "7.0.0" +version = "8.0.0" dependencies = [ "arbitrary", "archery", @@ -321,8 +394,8 @@ dependencies = [ "proptest", "proptest-derive", "quickcheck", - "rand 0.9.2", - "rand_core 0.9.3", + "rand 0.10.0", + "rand_core 0.10.0", "rand_xoshiro", "rayon", "rpds", @@ -342,6 +415,18 @@ dependencies = [ "bitmaps", ] +[[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" @@ -353,49 +438,49 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", ] [[package]] -name = "lazy_static" -version = "1.5.0" +name = "leb128fmt" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.175" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "log" -version = "0.4.27" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "memchr" -version = "2.7.5" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "metrohash" @@ -471,25 +556,34 @@ dependencies = [ "yansi", ] +[[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.101" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" +checksum = "37566cb3fdacef14c0737f9546df7cfeadbfbc9fef10991038bf5015d0c80532" dependencies = [ "bit-set", "bit-vec", "bitflags", - "lazy_static", "num-traits", "rand 0.9.2", "rand_chacha", @@ -519,20 +613,20 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quickcheck" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" +checksum = "95c589f335db0f6aaa168a7cd27b1fc6920f5e1470c804f814d9cd6e62a0f70b" dependencies = [ "env_logger", "log", - "rand 0.8.5", + "rand 0.10.0", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -545,21 +639,23 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" -version = "0.8.5" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_core 0.6.4", + "rand_chacha", + "rand_core 0.9.5", ] [[package]] name = "rand" -version = "0.9.2" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" dependencies = [ - "rand_chacha", - "rand_core 0.9.3", + "chacha20", + "getrandom 0.4.1", + "rand_core 0.10.0", ] [[package]] @@ -569,26 +665,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] name = "rand_core" -version = "0.6.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.3.4", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom 0.3.3", -] +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" [[package]] name = "rand_xorshift" @@ -596,16 +689,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] name = "rand_xoshiro" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41" +checksum = "1f0b2cc7bfeef8f0320ca45f88b00157a03c67137022d59393614352d6bf4312" dependencies = [ - "rand_core 0.9.3", + "rand_core 0.10.0", ] [[package]] @@ -630,9 +723,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -642,9 +735,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -653,30 +746,30 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rpds" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0e15515d3ce3313324d842629ea4905c25a13f81953eadb88f85516f59290a4" +checksum = "9e75f485e819d4d3015e6c0d55d02a4fd3db47c1993d9e603e0361fba2bffb34" dependencies = [ "archery", ] [[package]] name = "rustix" -version = "1.0.8" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.60.2", + "windows-sys", ] [[package]] @@ -687,9 +780,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "rusty-fork" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" dependencies = [ "fnv", "quick-error", @@ -697,17 +790,11 @@ dependencies = [ "wait-timeout", ] -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - [[package]] name = "safe_arch" -version = "0.7.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" +checksum = "1f7caad094bd561859bcd467734a720c3c1f5d1f338995351fefe2190c45efed" dependencies = [ "bytemuck", ] @@ -721,11 +808,17 @@ 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.224" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aaeb1e94f53b16384af593c71e20b095e958dab1d26939c1b70645c5cfbcc0b" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -733,18 +826,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.224" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f39390fa6346e24defbcdd3d9544ba8a19985d0af74df8501fbfe9a64341ab" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.224" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ff78ab5e8561c9a675bfc1785cb07ae721f0ee53329a595cefd8c04c2ac4e0" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -753,14 +846,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.142" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", ] [[package]] @@ -771,9 +865,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "syn" -version = "2.0.106" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -782,15 +876,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.20.0" +version = "3.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.4.1", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys", ] [[package]] @@ -805,9 +899,9 @@ dependencies = [ [[package]] name = "triomphe" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8f7726da4807b58ea5c96fdc122f80702030edc33b35aff9190a51148ccc85" +checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39" [[package]] name = "unarray" @@ -817,9 +911,15 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unty" @@ -853,51 +953,41 @@ dependencies = [ ] [[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +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 = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -905,31 +995,65 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" dependencies = [ "unicode-ident", ] +[[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 = "web-sys" -version = "0.3.77" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" dependencies = [ "js-sys", "wasm-bindgen", @@ -937,9 +1061,9 @@ dependencies = [ [[package]] name = "wide" -version = "0.7.33" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03" +checksum = "ac11b009ebeae802ed758530b6496784ebfee7a87b9abfbcaf3bbe25b814eb25" dependencies = [ "bytemuck", "safe_arch", @@ -947,173 +1071,114 @@ dependencies = [ [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys", ] [[package]] name = "windows-link" -version = "0.1.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-targets 0.52.6", + "windows-link", ] [[package]] -name = "windows-sys" -version = "0.60.2" +name = "wit-bindgen" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" dependencies = [ - "windows-targets 0.53.3", + "wit-bindgen-rust-macro", ] [[package]] -name = "windows-targets" -version = "0.52.6" +name = "wit-bindgen-core" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "anyhow", + "heck", + "wit-parser", ] [[package]] -name = "windows-targets" -version = "0.53.3" +name = "wit-bindgen-rust" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" +name = "wit-bindgen-rust-macro" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] [[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" +name = "wit-component" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-parser" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ - "bitflags", + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", ] [[package]] @@ -1124,20 +1189,26 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" dependencies = [ "proc-macro2", "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 5f925de..35f03e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "imbl" -version = "7.0.0" +version = "8.0.0" authors = [ "Bodil Stokke ", "Joe Neeman ", @@ -8,7 +8,7 @@ authors = [ ] edition = "2024" license = "MPL-2.0+" -rust-version = "1.85" +rust-version = "1.89" description = "Immutable collection datatypes" repository = "https://github.com/jneem/imbl" documentation = "https://docs.rs/imbl" @@ -42,8 +42,8 @@ triomphe = ["archery/triomphe"] [dependencies] bitmaps = "3" imbl-sized-chunks = "0.1.3" -rand_core = "0.9" -rand_xoshiro = "0.7" +rand_core = "0.10" +rand_xoshiro = "0.8" archery = "1.2.1" quickcheck = { version = "1.0", optional = true } proptest = { version = "1.0", optional = true } @@ -54,7 +54,7 @@ bincode = { version = "2.0.1", optional = true, default-features = false, featur "alloc", "std", ] } -wide = "0.7" +wide = "1.1" equivalent = "1.0.2" [dev-dependencies] @@ -62,7 +62,7 @@ proptest = "1.0" serde_core = "1" serde_json = "1" rayon = "1" -rand = { version = "0.9", features = ["small_rng"] } +rand = { version = "0.10" } pretty_assertions = "1.0" metrohash = "1" proptest-derive = "0.6" diff --git a/benches/vector.rs b/benches/vector.rs index cb4f62b..0821e66 100644 --- a/benches/vector.rs +++ b/benches/vector.rs @@ -1,5 +1,5 @@ use criterion::{Bencher, Criterion, criterion_group, criterion_main}; -use imbl::GenericVector; +use imbl::Vector; use imbl::shared_ptr::DefaultSharedPtr; use rand::seq::SliceRandom; use std::collections::VecDeque; @@ -67,7 +67,7 @@ impl<'a, T: Clone, const CHUNK_SIZE: usize> VectorFocusMut<'a, T, CHUNK_SIZE> { // Implementation for imbl::Vector impl BenchVector - for GenericVector + for Vector { type Iter<'a> = imbl::vector::Iter<'a, T, imbl::shared_ptr::DefaultSharedPtr, CHUNK_SIZE> @@ -75,7 +75,7 @@ impl BenchVector T: 'a; fn new() -> Self { - GenericVector::new() + Vector::new() } fn push_front(&mut self, value: T) { @@ -405,8 +405,8 @@ fn bench_ops_group>(c: &mut Criterion, grou // Benchmark functions for each vector type fn bench_vector(c: &mut Criterion) { - bench_sort_group::>(c, "vector"); - bench_ops_group::>(c, "vector"); + bench_sort_group::>(c, "vector"); + bench_ops_group::>(c, "vector"); } fn bench_vecdeque(c: &mut Criterion) { diff --git a/src/arbitrary.rs b/src/arbitrary.rs index 498a8f8..1abf479 100644 --- a/src/arbitrary.rs +++ b/src/arbitrary.rs @@ -2,17 +2,12 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use arbitrary::{size_hint, Arbitrary, Result, Unstructured}; +use arbitrary::{Arbitrary, Result, Unstructured, size_hint}; use std::hash::{BuildHasher, Hash}; -use crate::{ - shared_ptr::SharedPointerKind, GenericHashMap, GenericHashSet, GenericOrdMap, GenericOrdSet, - GenericVector, -}; +use crate::{HashMap, HashSet, OrdMap, OrdSet, Vector, shared_ptr::SharedPointerKind}; -impl<'a, A: Arbitrary<'a> + Clone, P: SharedPointerKind + 'static> Arbitrary<'a> - for GenericVector -{ +impl<'a, A: Arbitrary<'a> + Clone, P: SharedPointerKind + 'static> Arbitrary<'a> for Vector { fn arbitrary(u: &mut Unstructured<'a>) -> Result { u.arbitrary_iter()?.collect() } @@ -28,12 +23,8 @@ impl<'a, A: Arbitrary<'a> + Clone, P: SharedPointerKind + 'static> Arbitrary<'a> } } -impl< - 'a, - K: Arbitrary<'a> + Ord + Clone, - V: Arbitrary<'a> + Clone, - P: SharedPointerKind + 'static, - > Arbitrary<'a> for GenericOrdMap +impl<'a, K: Arbitrary<'a> + Ord + Clone, V: Arbitrary<'a> + Clone, P: SharedPointerKind + 'static> + Arbitrary<'a> for OrdMap { fn arbitrary(u: &mut Unstructured<'a>) -> Result { u.arbitrary_iter()?.collect() @@ -51,7 +42,7 @@ impl< } impl<'a, A: Arbitrary<'a> + Ord + Clone, P: SharedPointerKind + 'static> Arbitrary<'a> - for GenericOrdSet + for OrdSet { fn arbitrary(u: &mut Unstructured<'a>) -> Result { u.arbitrary_iter()?.collect() @@ -68,7 +59,7 @@ impl<'a, A: Arbitrary<'a> + Ord + Clone, P: SharedPointerKind + 'static> Arbitra } } -impl<'a, K, V, S, P> Arbitrary<'a> for GenericHashMap +impl<'a, K, V, S, P> Arbitrary<'a> for HashMap where K: Arbitrary<'a> + Hash + Eq + Clone, V: Arbitrary<'a> + Clone, @@ -90,7 +81,7 @@ where } } -impl<'a, A, S, P> Arbitrary<'a> for GenericHashSet +impl<'a, A, S, P> Arbitrary<'a> for HashSet where A: Arbitrary<'a> + Hash + Eq + Clone, S: BuildHasher + Clone + Default + 'static, diff --git a/src/bincode.rs b/src/bincode.rs index 931480a..249230b 100644 --- a/src/bincode.rs +++ b/src/bincode.rs @@ -10,15 +10,15 @@ use bincode::enc::Encoder; use bincode::error::{DecodeError, EncodeError}; use bincode::{Decode, Encode}; -use crate::hashmap::GenericHashMap; -use crate::hashset::GenericHashSet; -use crate::ordmap::GenericOrdMap; -use crate::ordset::GenericOrdSet; -use crate::vector::GenericVector; +use crate::hashmap::HashMap; +use crate::hashset::HashSet; +use crate::ordmap::OrdMap; +use crate::ordset::OrdSet; +use crate::vector::Vector; // Set -impl + Ord + Clone, P: SharedPointerKind> Decode for GenericOrdSet { +impl + Ord + Clone, P: SharedPointerKind> Decode for OrdSet { fn decode>(decoder: &mut D) -> Result { let mut output = Self::new(); let length: usize = Decode::decode(decoder)?; @@ -31,7 +31,7 @@ impl + Ord + Clone, P: SharedPointerKind> Decode for GenericO } } -impl Encode for GenericOrdSet { +impl Encode for OrdSet { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { Encode::encode(&self.len(), encoder)?; for item in self.iter() { @@ -44,7 +44,7 @@ impl Encode for GenericOrdSet { // Map impl + Ord + Clone, V: Decode + Clone, P: SharedPointerKind> Decode - for GenericOrdMap + for OrdMap { fn decode>(decoder: &mut D) -> Result { let len: usize = Decode::decode(decoder)?; @@ -58,9 +58,7 @@ impl + Ord + Clone, V: Decode + Clone, P: SharedPointerKind> } } -impl Encode - for GenericOrdMap -{ +impl Encode for OrdMap { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { Encode::encode(&self.len(), encoder)?; for (k, v) in self.iter() { @@ -72,7 +70,7 @@ impl Encode // HashMap -impl Decode for GenericHashMap +impl Decode for HashMap where K: Decode + Hash + Eq + Clone, V: Decode + Clone, @@ -91,7 +89,7 @@ where } } -impl Encode for GenericHashMap +impl Encode for HashMap where K: Encode + Hash + Eq, V: Encode, @@ -109,7 +107,7 @@ where // HashSet -impl Decode for GenericHashSet +impl Decode for HashSet where A: Decode + Hash + Eq + Clone, S: BuildHasher + Default + Clone, @@ -128,7 +126,7 @@ where } impl Encode - for GenericHashSet + for HashSet { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { Encode::encode(&self.len(), encoder)?; @@ -141,7 +139,7 @@ impl Enco // Vector -impl, P: SharedPointerKind> Decode for GenericVector { +impl, P: SharedPointerKind> Decode for Vector { fn decode>(decoder: &mut D) -> Result { let mut output = Self::new(); let length: usize = Decode::decode(decoder)?; @@ -153,7 +151,7 @@ impl, P: SharedPointerKind> Decode for GenericVector< } } -impl Encode for GenericVector { +impl Encode for Vector { fn encode(&self, encoder: &mut E) -> Result<(), EncodeError> { Encode::encode(&self.len(), encoder)?; for item in self.iter() { @@ -168,8 +166,8 @@ impl Encode for GenericVector { #[cfg(test)] mod test { use crate::{ - proptest::{hash_map, hash_set, ord_map, ord_set, vector}, HashMap, HashSet, OrdMap, OrdSet, Vector, + proptest::{hash_map, hash_set, ord_map, ord_set, vector}, }; use bincode::{decode_from_slice, encode_to_vec}; use proptest::num::i32; diff --git a/src/hash/map.rs b/src/hash/map.rs index 3997fac..462d5ac 100644 --- a/src/hash/map.rs +++ b/src/hash/map.rs @@ -53,7 +53,7 @@ use crate::shared_ptr::DefaultSharedPtr; /// 2 => 22, /// 3 => 33 /// }, -/// HashMap::from(vec![(1, 11), (2, 22), (3, 33)]) +/// HashMap::<_, _>::from(vec![(1, 11), (2, 22), (3, 33)]) /// ); /// # } /// ``` @@ -78,13 +78,6 @@ macro_rules! hashmap { }}; } -/// Type alias for [`GenericHashMap`] that uses [`std::hash::RandomState`] as the default hasher and [`DefaultSharedPtr`] as the pointer type. -/// -/// [GenericHashMap]: ./struct.GenericHashMap.html -/// [`std::hash::RandomState`]: https://doc.rust-lang.org/stable/std/collections/hash_map/struct.RandomState.html -/// [DefaultSharedPtr]: ../shared_ptr/type.DefaultSharedPtr.html -pub type HashMap = GenericHashMap; - /// An unordered map. /// /// An immutable hash map using [hash array mapped tries] [1]. @@ -103,7 +96,7 @@ pub type HashMap = GenericHashMap; /// [std::cmp::Eq]: https://doc.rust-lang.org/std/cmp/trait.Eq.html /// [std::hash::Hash]: https://doc.rust-lang.org/std/hash/trait.Hash.html /// [std::collections::hash_map::RandomState]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html -pub struct GenericHashMap { +pub struct HashMap { size: usize, root: Option, P>>, hasher: S, @@ -124,7 +117,7 @@ where } } -impl GenericHashMap +impl HashMap where K: Hash + Eq + Clone, V: Clone, @@ -137,7 +130,7 @@ where /// ``` /// # #[macro_use] extern crate imbl; /// # use imbl::HashMap; - /// let map = HashMap::unit(123, "onetwothree"); + /// let map = HashMap::<_, _>::unit(123, "onetwothree"); /// assert_eq!( /// map.get(&123), /// Some(&"onetwothree") @@ -145,22 +138,43 @@ where /// ``` #[inline] #[must_use] - pub fn unit(k: K, v: V) -> GenericHashMap { - GenericHashMap::new().update(k, v) + pub fn unit(k: K, v: V) -> HashMap { + HashMap::with_kind().update(k, v) } } -impl GenericHashMap { - /// Construct an empty hash map. +impl HashMap { + /// Construct an empty hash map using the default hasher and shared kind #[inline] #[must_use] - pub fn new() -> Self - where - S: Default, - { + pub fn new() -> Self { Self::default() } +} + +impl HashMap { + /// Construct an empty hash map using a custom shared kind + #[inline] + #[must_use] + pub fn with_kind() -> Self { + Self::default() + } +} + +impl HashMap { + /// Construct an empty hash map using the provided hasher. + #[inline] + #[must_use] + pub fn with_hasher(hasher: S) -> Self { + HashMap { + size: 0, + hasher, + root: None, + } + } +} +impl HashMap { /// Test whether a hash map is empty. /// /// Time: O(1) @@ -221,11 +235,11 @@ impl GenericHashMap { } } - /// Construct an empty hash map using the provided hasher. + /// Construct an empty hash map using a custom shared kind and the provided hasher. #[inline] #[must_use] - pub fn with_hasher(hasher: S) -> Self { - GenericHashMap { + pub fn with_hasher_and_kind(hasher: S) -> Self { + HashMap { size: 0, hasher, root: None, @@ -244,13 +258,13 @@ impl GenericHashMap { /// current hash map. #[inline] #[must_use] - pub fn new_from(&self) -> GenericHashMap + pub fn new_from(&self) -> HashMap where K1: Hash + Eq + Clone, V1: Clone, S: Clone, { - GenericHashMap { + HashMap { size: 0, root: None, hasher: self.hasher.clone(), @@ -474,7 +488,7 @@ impl GenericHashMap { } } -impl GenericHashMap +impl HashMap where K: Hash + Eq, S: BuildHasher + Clone, @@ -482,7 +496,7 @@ where { fn test_eq( &self, - other: &GenericHashMap, + other: &HashMap, ) -> bool where V: PartialEq, @@ -598,7 +612,7 @@ where pub fn is_submap_by(&self, other: RM, mut cmp: F) -> bool where F: FnMut(&V, &B) -> bool, - RM: Borrow>, + RM: Borrow>, { self.iter() .all(|(k, v)| other.borrow().get(k).map(|ov| cmp(v, ov)).unwrap_or(false)) @@ -616,7 +630,7 @@ where pub fn is_proper_submap_by(&self, other: RM, cmp: F) -> bool where F: FnMut(&V, &B) -> bool, - RM: Borrow>, + RM: Borrow>, { self.len() != other.borrow().len() && self.is_submap_by(other, cmp) } @@ -677,7 +691,7 @@ where } } -impl GenericHashMap +impl HashMap where K: Hash + Eq + Clone, V: Clone, @@ -1457,9 +1471,9 @@ where #[must_use] pub fn intersection_with( self, - other: GenericHashMap, + other: HashMap, mut f: F, - ) -> GenericHashMap + ) -> HashMap where B: Clone, C: Clone, @@ -1490,9 +1504,9 @@ where #[must_use] pub fn intersection_with_key( mut self, - other: GenericHashMap, + other: HashMap, mut f: F, - ) -> GenericHashMap + ) -> HashMap where B: Clone, C: Clone, @@ -1605,7 +1619,7 @@ where S: BuildHasher + Clone, P: SharedPointerKind, { - map: &'a mut GenericHashMap, + map: &'a mut HashMap, hash: HashBits, key: K, } @@ -1681,7 +1695,7 @@ where S: BuildHasher + Clone, P: SharedPointerKind, { - map: &'a mut GenericHashMap, + map: &'a mut HashMap, hash: HashBits, key: K, } @@ -1723,7 +1737,7 @@ where // Core traits -impl Clone for GenericHashMap +impl Clone for HashMap where K: Clone, V: Clone, @@ -1735,7 +1749,7 @@ where /// Time: O(1) #[inline] fn clone(&self) -> Self { - GenericHashMap { + HashMap { root: self.root.clone(), size: self.size, hasher: self.hasher.clone(), @@ -1743,7 +1757,7 @@ where } } -impl PartialEq> for GenericHashMap +impl PartialEq> for HashMap where K: Hash + Eq, V: PartialEq, @@ -1752,12 +1766,12 @@ where P1: SharedPointerKind, P2: SharedPointerKind, { - fn eq(&self, other: &GenericHashMap) -> bool { + fn eq(&self, other: &HashMap) -> bool { self.test_eq(other) } } -impl Eq for GenericHashMap +impl Eq for HashMap where K: Hash + Eq, V: Eq, @@ -1766,14 +1780,14 @@ where { } -impl Default for GenericHashMap +impl Default for HashMap where S: Default, P: SharedPointerKind, { #[inline] fn default() -> Self { - GenericHashMap { + HashMap { size: 0, root: None, hasher: Default::default(), @@ -1781,35 +1795,35 @@ where } } -impl Add for GenericHashMap +impl Add for HashMap where K: Hash + Eq + Clone, V: Clone, S: BuildHasher + Clone, P: SharedPointerKind, { - type Output = GenericHashMap; + type Output = HashMap; fn add(self, other: Self) -> Self::Output { self.union(other) } } -impl Add for &GenericHashMap +impl Add for &HashMap where K: Hash + Eq + Clone, V: Clone, S: BuildHasher + Clone, P: SharedPointerKind, { - type Output = GenericHashMap; + type Output = HashMap; fn add(self, other: Self) -> Self::Output { self.clone().union(other.clone()) } } -impl Sum for GenericHashMap +impl Sum for HashMap where K: Hash + Eq + Clone, V: Clone, @@ -1824,7 +1838,7 @@ where } } -impl Extend<(RK, RV)> for GenericHashMap +impl Extend<(RK, RV)> for HashMap where K: Hash + Eq + Clone + From, V: Clone + From, @@ -1841,7 +1855,7 @@ where } } -impl Index<&Q> for GenericHashMap +impl Index<&Q> for HashMap where Q: Hash + Equivalent + ?Sized, K: Hash + Eq, @@ -1858,7 +1872,7 @@ where } } -impl IndexMut<&Q> for GenericHashMap +impl IndexMut<&Q> for HashMap where Q: Hash + Equivalent + ?Sized, K: Hash + Eq + Clone, @@ -1874,7 +1888,7 @@ where } } -impl Debug for GenericHashMap +impl Debug for HashMap where K: Debug, V: Debug, @@ -2040,7 +2054,7 @@ impl<'a, K, V, P: SharedPointerKind> ExactSizeIterator for Values<'a, K, V, P> { impl<'a, K, V, P: SharedPointerKind> FusedIterator for Values<'a, K, V, P> {} -impl<'a, K, V, S, P: SharedPointerKind> IntoIterator for &'a GenericHashMap { +impl<'a, K, V, S, P: SharedPointerKind> IntoIterator for &'a HashMap { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V, P>; @@ -2050,7 +2064,7 @@ impl<'a, K, V, S, P: SharedPointerKind> IntoIterator for &'a GenericHashMap IntoIterator for GenericHashMap +impl IntoIterator for HashMap where K: Hash + Eq + Clone, V: Clone, @@ -2070,7 +2084,7 @@ where // Conversions -impl FromIterator<(K, V)> for GenericHashMap +impl FromIterator<(K, V)> for HashMap where K: Hash + Eq + Clone, V: Clone, @@ -2089,17 +2103,14 @@ where } } -impl AsRef> - for GenericHashMap -{ +impl AsRef> for HashMap { #[inline] fn as_ref(&self) -> &Self { self } } -impl From<&GenericHashMap<&K, &V, SA, P1>> - for GenericHashMap +impl From<&HashMap<&K, &V, SA, P1>> for HashMap where K: Hash + Equivalent + ToOwned + ?Sized, V: ToOwned + ?Sized, @@ -2110,14 +2121,14 @@ where P1: SharedPointerKind, P2: SharedPointerKind, { - fn from(m: &GenericHashMap<&K, &V, SA, P1>) -> Self { + fn from(m: &HashMap<&K, &V, SA, P1>) -> Self { m.iter() .map(|(k, v)| ((*k).to_owned(), (*v).to_owned())) .collect() } } -impl<'a, K, V, S, P> From<&'a [(K, V)]> for GenericHashMap +impl<'a, K, V, S, P> From<&'a [(K, V)]> for HashMap where K: Hash + Eq + Clone, V: Clone, @@ -2129,7 +2140,7 @@ where } } -impl From> for GenericHashMap +impl From> for HashMap where K: Hash + Eq + Clone, V: Clone, @@ -2141,7 +2152,7 @@ where } } -impl<'a, K, V, S, P> From<&'a Vec<(K, V)>> for GenericHashMap +impl<'a, K, V, S, P> From<&'a Vec<(K, V)>> for HashMap where K: Hash + Eq + Clone, V: Clone, @@ -2153,7 +2164,7 @@ where } } -impl From> for GenericHashMap +impl From> for HashMap where K: Hash + Eq + Clone, V: Clone, @@ -2166,7 +2177,7 @@ where } } -impl<'a, K, V, S1, S2, P> From<&'a collections::HashMap> for GenericHashMap +impl<'a, K, V, S1, S2, P> From<&'a collections::HashMap> for HashMap where K: Hash + Eq + Clone, V: Clone, @@ -2179,7 +2190,7 @@ where } } -impl From> for GenericHashMap +impl From> for HashMap where K: Hash + Eq + Clone, V: Clone, @@ -2191,7 +2202,7 @@ where } } -impl<'a, K, V, S, P> From<&'a collections::BTreeMap> for GenericHashMap +impl<'a, K, V, S, P> From<&'a collections::BTreeMap> for HashMap where K: Hash + Eq + Clone, V: Clone, @@ -2251,7 +2262,7 @@ mod test { #[test] fn safe_mutation() { - let v1: HashMap = GenericHashMap::from_iter((0..131_072).map(|i| (i, i))); + let v1: HashMap = HashMap::from_iter((0..131_072).map(|i| (i, i))); let mut v2 = v1.clone(); v2.insert(131_000, 23); assert_eq!(Some(&23), v2.get(&131_000)); @@ -2283,8 +2294,8 @@ mod test { for (k, v) in &pairs { m.insert(*k, *v); } - let mut map: GenericHashMap = - GenericHashMap::with_hasher(BuildHasherDefault::::default()); + let mut map: HashMap = + HashMap::with_hasher(BuildHasherDefault::::default()); for (k, v) in &m { map = map.update(*k, *v); } @@ -2321,7 +2332,7 @@ mod test { #[test] fn remove_top_level_collisions() { let pairs = vec![9, 2569, 27145]; - let mut map: GenericHashMap, DefaultSharedPtr> = + let mut map: HashMap, DefaultSharedPtr> = Default::default(); for k in pairs.clone() { map.insert(k, k); @@ -2412,7 +2423,7 @@ mod test { proptest! { #[test] fn update_and_length(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..1000)) { - let mut map: GenericHashMap, DefaultSharedPtr> = Default::default(); + let mut map: HashMap, DefaultSharedPtr> = Default::default(); for (index, (k, v)) in m.iter().enumerate() { map = map.update(*k, *v); assert_eq!(Some(v), map.get(k)); @@ -2455,7 +2466,7 @@ mod test { for (k, v) in pairs { m.insert(*k, *v); } - let mut map: GenericHashMap = GenericHashMap::with_hasher(BuildHasherDefault::::default()); + let mut map: HashMap = HashMap::with_hasher(BuildHasherDefault::::default()); for (k, v) in &m { map = map.update(*k, *v); } @@ -2470,8 +2481,8 @@ mod test { #[test] fn insert(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..1000)) { - let mut mut_map: GenericHashMap, DefaultSharedPtr> = Default::default(); - let mut map: GenericHashMap, DefaultSharedPtr> = Default::default(); + let mut mut_map: HashMap, DefaultSharedPtr> = Default::default(); + let mut map: HashMap, DefaultSharedPtr> = Default::default(); for (count, (k, v)) in m.iter().enumerate() { map = map.update(*k, *v); mut_map.insert(*k, *v); @@ -2492,7 +2503,7 @@ mod test { for (k, v) in pairs { m.insert(*k, *v); } - let mut map: GenericHashMap = GenericHashMap::with_hasher(BuildHasherDefault::::default()); + let mut map: HashMap = HashMap::with_hasher(BuildHasherDefault::::default()); for (k, v) in &m { map.insert(*k, *v); } diff --git a/src/hash/set.rs b/src/hash/set.rs index 7ecf6a2..3ead37b 100644 --- a/src/hash/set.rs +++ b/src/hash/set.rs @@ -32,9 +32,9 @@ use std::ops::{Add, Deref, Mul}; use archery::{SharedPointer, SharedPointerKind}; use equivalent::Equivalent; -use crate::GenericVector; +use crate::Vector; use crate::nodes::hamt::{Drain as NodeDrain, HashValue, Iter as NodeIter, Node, hash_key}; -use crate::ordset::GenericOrdSet; +use crate::ordset::OrdSet; use crate::shared_ptr::DefaultSharedPtr; /// Construct a set from a sequence of values. @@ -47,7 +47,7 @@ use crate::shared_ptr::DefaultSharedPtr; /// # fn main() { /// assert_eq!( /// hashset![1, 2, 3], -/// HashSet::from(vec![1, 2, 3]) +/// HashSet::<_>::from(vec![1, 2, 3]) /// ); /// # } /// ``` @@ -72,13 +72,6 @@ macro_rules! hashset { }}; } -/// Type alias for [`GenericHashSet`] that uses [`std::hash::RandomState`] as the default hasher and [`DefaultSharedPtr`] as the pointer type. -/// -/// [GenericHashSet]: ./struct.GenericHashSet.html -/// [`std::hash::RandomState`]: https://doc.rust-lang.org/stable/std/collections/hash_map/struct.RandomState.html -/// [DefaultSharedPtr]: ../shared_ptr/type.DefaultSharedPtr.html -pub type HashSet = GenericHashSet; - /// An unordered set. /// /// An immutable hash set using [hash array mapped tries] [1]. @@ -97,7 +90,7 @@ pub type HashSet = GenericHashSet; /// [std::cmp::Eq]: https://doc.rust-lang.org/std/cmp/trait.Eq.html /// [std::hash::Hash]: https://doc.rust-lang.org/std/hash/trait.Hash.html /// [std::collections::hash_map::RandomState]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html -pub struct GenericHashSet { +pub struct HashSet { hasher: S, root: Option, P>, P>>, size: usize, @@ -130,7 +123,7 @@ where } } -impl GenericHashSet +impl HashSet where A: Hash + Eq + Clone, S: BuildHasher + Default + Clone, @@ -144,26 +137,48 @@ where /// # #[macro_use] extern crate imbl; /// # use imbl::hashset::HashSet; /// # use std::sync::Arc; - /// let set = HashSet::unit(123); + /// let set = HashSet::<_>::unit(123); /// assert!(set.contains(&123)); /// ``` #[inline] #[must_use] pub fn unit(a: A) -> Self { - GenericHashSet::new().update(a) + HashSet::with_hasher_and_kind(Default::default()).update(a) } } -impl GenericHashSet { - /// Construct an empty set. +impl HashSet { + /// Construct an empty set using the default hasher and shared kind + #[inline] #[must_use] - pub fn new() -> Self - where - S: Default, - { - Self::default() + pub fn new() -> Self { + Default::default() + } +} + +impl HashSet { + /// Construct an empty set using a custom shared kind + #[inline] + #[must_use] + pub fn with_kind() -> Self { + Default::default() + } +} + +impl HashSet { + /// Construct an empty hash set using the provided hasher. + #[inline] + #[must_use] + pub fn with_hasher(hasher: S) -> Self { + HashSet { + size: 0, + root: None, + hasher, + } } +} +impl HashSet { /// Test whether a set is empty. /// /// Time: O(1) @@ -223,8 +238,8 @@ impl GenericHashSet { /// Construct an empty hash set using the provided hasher. #[inline] #[must_use] - pub fn with_hasher(hasher: S) -> Self { - GenericHashSet { + pub fn with_hasher_and_kind(hasher: S) -> Self { + HashSet { size: 0, root: None, hasher, @@ -242,12 +257,12 @@ impl GenericHashSet { /// Construct an empty hash set using the same hasher as the current hash set. #[inline] #[must_use] - pub fn new_from(&self) -> GenericHashSet + pub fn new_from(&self) -> HashSet where A2: Hash + Eq + Clone, S: Clone, { - GenericHashSet { + HashSet { size: 0, root: None, hasher: self.hasher.clone(), @@ -290,16 +305,13 @@ impl GenericHashSet { } } -impl GenericHashSet +impl HashSet where A: Hash + Eq, S: BuildHasher, P: SharedPointerKind, { - fn test_eq( - &self, - other: &GenericHashSet, - ) -> bool { + fn test_eq(&self, other: &HashSet) -> bool { if self.len() != other.len() { return false; } @@ -360,7 +372,7 @@ where } } -impl GenericHashSet +impl HashSet where A: Hash + Eq + Clone, S: BuildHasher + Clone, @@ -612,7 +624,7 @@ where // Core traits -impl Clone for GenericHashSet +impl Clone for HashSet where A: Clone, S: Clone, @@ -623,7 +635,7 @@ where /// Time: O(1) #[inline] fn clone(&self) -> Self { - GenericHashSet { + HashSet { hasher: self.hasher.clone(), root: self.root.clone(), size: self.size, @@ -631,7 +643,7 @@ where } } -impl PartialEq> for GenericHashSet +impl PartialEq> for HashSet where A: Hash + Eq, S1: BuildHasher, @@ -639,12 +651,12 @@ where P1: SharedPointerKind, P2: SharedPointerKind, { - fn eq(&self, other: &GenericHashSet) -> bool { + fn eq(&self, other: &HashSet) -> bool { self.test_eq(other) } } -impl Eq for GenericHashSet +impl Eq for HashSet where A: Hash + Eq, S: BuildHasher, @@ -652,13 +664,13 @@ where { } -impl Default for GenericHashSet +impl Default for HashSet where S: Default, P: SharedPointerKind, { fn default() -> Self { - GenericHashSet { + HashSet { hasher: Default::default(), root: None, size: 0, @@ -666,59 +678,59 @@ where } } -impl Add for GenericHashSet +impl Add for HashSet where A: Hash + Eq + Clone, S: BuildHasher + Clone, P: SharedPointerKind, { - type Output = GenericHashSet; + type Output = HashSet; fn add(self, other: Self) -> Self::Output { self.union(other) } } -impl Mul for GenericHashSet +impl Mul for HashSet where A: Hash + Eq + Clone, S: BuildHasher + Clone, P: SharedPointerKind, { - type Output = GenericHashSet; + type Output = HashSet; fn mul(self, other: Self) -> Self::Output { self.intersection(other) } } -impl Add for &GenericHashSet +impl Add for &HashSet where A: Hash + Eq + Clone, S: BuildHasher + Clone, P: SharedPointerKind, { - type Output = GenericHashSet; + type Output = HashSet; fn add(self, other: Self) -> Self::Output { self.clone().union(other.clone()) } } -impl Mul for &GenericHashSet +impl Mul for &HashSet where A: Hash + Eq + Clone, S: BuildHasher + Clone, P: SharedPointerKind, { - type Output = GenericHashSet; + type Output = HashSet; fn mul(self, other: Self) -> Self::Output { self.clone().intersection(other.clone()) } } -impl Sum for GenericHashSet +impl Sum for HashSet where A: Hash + Eq + Clone, S: BuildHasher + Default + Clone, @@ -732,7 +744,7 @@ where } } -impl Extend for GenericHashSet +impl Extend for HashSet where A: Hash + Eq + Clone + From, S: BuildHasher + Clone, @@ -747,7 +759,7 @@ where } } -impl Debug for GenericHashSet +impl Debug for HashSet where A: Hash + Eq + Debug, S: BuildHasher, @@ -835,7 +847,7 @@ where // Iterator conversions -impl FromIterator for GenericHashSet +impl FromIterator for HashSet where A: Hash + Eq + Clone + From, S: BuildHasher + Default + Clone, @@ -853,7 +865,7 @@ where } } -impl<'a, A, S, P> IntoIterator for &'a GenericHashSet +impl<'a, A, S, P> IntoIterator for &'a HashSet where A: Hash + Eq, S: BuildHasher, @@ -867,7 +879,7 @@ where } } -impl IntoIterator for GenericHashSet +impl IntoIterator for HashSet where A: Hash + Eq + Clone, S: BuildHasher, @@ -885,7 +897,7 @@ where // Conversions -impl From<&GenericHashSet<&A, SA, P1>> for GenericHashSet +impl From<&HashSet<&A, SA, P1>> for HashSet where A: ToOwned + Hash + Equivalent + ?Sized, OA: Hash + Eq + Clone, @@ -894,12 +906,12 @@ where P1: SharedPointerKind, P2: SharedPointerKind, { - fn from(set: &GenericHashSet<&A, SA, P1>) -> Self { + fn from(set: &HashSet<&A, SA, P1>) -> Self { set.iter().map(|a| (*a).to_owned()).collect() } } -impl From<[A; N]> for GenericHashSet +impl From<[A; N]> for HashSet where A: Hash + Eq + Clone, S: BuildHasher + Default + Clone, @@ -910,7 +922,7 @@ where } } -impl<'a, A, S, P> From<&'a [A]> for GenericHashSet +impl<'a, A, S, P> From<&'a [A]> for HashSet where A: Hash + Eq + Clone, S: BuildHasher + Default + Clone, @@ -921,7 +933,7 @@ where } } -impl From> for GenericHashSet +impl From> for HashSet where A: Hash + Eq + Clone, S: BuildHasher + Default + Clone, @@ -932,7 +944,7 @@ where } } -impl From<&Vec> for GenericHashSet +impl From<&Vec> for HashSet where A: Hash + Eq + Clone, S: BuildHasher + Default + Clone, @@ -943,33 +955,31 @@ where } } -impl From> - for GenericHashSet +impl From> for HashSet where A: Hash + Eq + Clone, S: BuildHasher + Default + Clone, P1: SharedPointerKind, P2: SharedPointerKind, { - fn from(vector: GenericVector) -> Self { + fn from(vector: Vector) -> Self { vector.into_iter().collect() } } -impl From<&GenericVector> - for GenericHashSet +impl From<&Vector> for HashSet where A: Hash + Eq + Clone, S: BuildHasher + Default + Clone, P1: SharedPointerKind, P2: SharedPointerKind, { - fn from(vector: &GenericVector) -> Self { + fn from(vector: &Vector) -> Self { vector.iter().cloned().collect() } } -impl From> for GenericHashSet +impl From> for HashSet where A: Eq + Hash + Clone, S: BuildHasher + Default + Clone, @@ -980,7 +990,7 @@ where } } -impl From<&collections::HashSet> for GenericHashSet +impl From<&collections::HashSet> for HashSet where A: Eq + Hash + Clone, S: BuildHasher + Default + Clone, @@ -991,7 +1001,7 @@ where } } -impl From<&BTreeSet> for GenericHashSet +impl From<&BTreeSet> for HashSet where A: Hash + Eq + Clone, S: BuildHasher + Default + Clone, @@ -1002,26 +1012,26 @@ where } } -impl From> for GenericHashSet +impl From> for HashSet where A: Ord + Hash + Eq + Clone, S: BuildHasher + Default + Clone, P1: SharedPointerKind, P2: SharedPointerKind, { - fn from(ordset: GenericOrdSet) -> Self { + fn from(ordset: OrdSet) -> Self { ordset.into_iter().collect() } } -impl From<&GenericOrdSet> for GenericHashSet +impl From<&OrdSet> for HashSet where A: Ord + Hash + Eq + Clone, S: BuildHasher + Default + Clone, P1: SharedPointerKind, P2: SharedPointerKind, { - fn from(ordset: &GenericOrdSet) -> Self { + fn from(ordset: &OrdSet) -> Self { ordset.into_iter().cloned().collect() } } @@ -1053,7 +1063,7 @@ mod test { #[test] fn insert_failing() { - let mut set: GenericHashSet, DefaultSharedPtr> = + let mut set: HashSet, DefaultSharedPtr> = Default::default(); set.insert(14658); assert_eq!(1, set.len()); @@ -1088,8 +1098,8 @@ mod test { lhs.sort_unstable(); let hasher = MetroHashBuilder::new(i); - let mut iset: GenericHashSet<_, MetroHashBuilder, DefaultSharedPtr> = - GenericHashSet::with_hasher(hasher); + let mut iset: HashSet<_, MetroHashBuilder, DefaultSharedPtr> = + HashSet::with_hasher(hasher); for &i in &lhs { iset.insert(i); } diff --git a/src/lib.rs b/src/lib.rs index a13ccc4..996b6ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -285,7 +285,7 @@ //! [`Arc`](std::sync::Arc). However, `imbl` also supports `Rc` as the pointer //! type through the [`archery`] crate, just like `im-rc` in the original //! `im` crate. If you prioritise speed over thread safety, you can use -//! [`GenericVector`](vector::GenericVector) that uses +//! [`Vector`](vector::Vector) that uses //! non-threadsafe but faster `Rc`, instead of the type alias //! [`Vector`]. You can also create your own type alias for that. //! It can be done on other types too. @@ -369,12 +369,12 @@ pub mod quickcheck; pub mod shared_ptr; -pub use crate::hashmap::{GenericHashMap, HashMap}; -pub use crate::hashset::{GenericHashSet, HashSet}; -pub use crate::ordmap::{GenericOrdMap, OrdMap}; -pub use crate::ordset::{GenericOrdSet, OrdSet}; +pub use crate::hashmap::HashMap; +pub use crate::hashset::HashSet; +pub use crate::ordmap::OrdMap; +pub use crate::ordset::OrdSet; #[doc(inline)] -pub use crate::vector::{GenericVector, Vector}; +pub use crate::vector::Vector; #[cfg(test)] mod test; diff --git a/src/nodes/hamt.rs b/src/nodes/hamt.rs index 08140b4..4e07fdb 100644 --- a/src/nodes/hamt.rs +++ b/src/nodes/hamt.rs @@ -52,7 +52,7 @@ fn group_find_empty(control: &SimdGroup) -> Option { #[inline] fn group_find(control: &SimdGroup, value: u8) -> GroupBitmap { - let mask = control.cmp_eq(SimdGroup::splat(value)).move_mask(); + let mask = control.simd_eq(SimdGroup::splat(value)).to_bitmask(); GroupBitmap::from_value(mask as _) } diff --git a/src/ord/map.rs b/src/ord/map.rs index ec738e6..8d2a387 100644 --- a/src/ord/map.rs +++ b/src/ord/map.rs @@ -29,7 +29,7 @@ use std::ops::{Add, Bound, Index, IndexMut, RangeBounds}; use archery::{SharedPointer, SharedPointerKind}; use equivalent::Comparable; -use crate::hashmap::GenericHashMap; +use crate::hashmap::HashMap; use crate::nodes::btree::{ ConsumingIter as NodeConsumingIter, Cursor, InsertAction, Iter as NodeIter, Node, }; @@ -66,12 +66,6 @@ macro_rules! ordmap { }}; } -/// Type alias for [`GenericOrdMap`] that uses [`DefaultSharedPtr`] as the pointer type. -/// -/// [GenericOrdMap]: ./struct.GenericOrdMap.html -/// [DefaultSharedPtr]: ../shared_ptr/type.DefaultSharedPtr.html -pub type OrdMap = GenericOrdMap; - /// An ordered map. /// /// An immutable ordered map implemented as a B+tree [1]. @@ -86,20 +80,26 @@ pub type OrdMap = GenericOrdMap; /// [1]: https://en.wikipedia.org/wiki/B%2B_tree /// [hashmap::HashMap]: ../hashmap/type.HashMap.html /// [std::cmp::Ord]: https://doc.rust-lang.org/std/cmp/trait.Ord.html -pub struct GenericOrdMap { +pub struct OrdMap { size: usize, root: Option>, } -impl GenericOrdMap { +impl OrdMap { /// Construct an empty map. #[inline] #[must_use] pub fn new() -> Self { - GenericOrdMap { - size: 0, - root: None, - } + Default::default() + } +} + +impl OrdMap { + /// Construct an empty map with a custom shared kind + #[inline] + #[must_use] + pub fn with_kind() -> Self { + Default::default() } /// Construct a map with a single mapping. @@ -206,7 +206,7 @@ impl GenericOrdMap { } } -impl GenericOrdMap +impl OrdMap where K: Ord, P: SharedPointerKind, @@ -447,7 +447,7 @@ where pub fn is_submap_by(&self, other: RM, mut cmp: F) -> bool where F: FnMut(&V, &B) -> bool, - RM: Borrow>, + RM: Borrow>, P2: SharedPointerKind, { self.iter() @@ -466,7 +466,7 @@ where pub fn is_proper_submap_by(&self, other: RM, cmp: F) -> bool where F: FnMut(&V, &B) -> bool, - RM: Borrow>, + RM: Borrow>, P2: SharedPointerKind, { self.len() != other.borrow().len() && self.is_submap_by(other, cmp) @@ -542,7 +542,7 @@ where } } -impl GenericOrdMap +impl OrdMap where K: Ord + Clone, V: Clone, @@ -1296,9 +1296,9 @@ where #[must_use] pub fn intersection_with( self, - other: GenericOrdMap, + other: OrdMap, mut f: F, - ) -> GenericOrdMap + ) -> OrdMap where B: Clone, C: Clone, @@ -1331,9 +1331,9 @@ where #[must_use] pub fn intersection_with_key( mut self, - other: GenericOrdMap, + other: OrdMap, mut f: F, - ) -> GenericOrdMap + ) -> OrdMap where B: Clone, C: Clone, @@ -1341,7 +1341,7 @@ where P2: SharedPointerKind, P3: SharedPointerKind, { - let mut out = GenericOrdMap::::default(); + let mut out = OrdMap::::default(); for (key, right_value) in other { match self.remove(&key) { None => (), @@ -1380,7 +1380,7 @@ where { // TODO this is atrociously slow, got to be a better way self.iter().fold( - (GenericOrdMap::new(), None, GenericOrdMap::new()), + (OrdMap::with_kind(), None, OrdMap::with_kind()), |(l, m, r), (k, v)| match split.compare(k).reverse() { Ordering::Less => (l.update(k.clone(), v.clone()), m, r), Ordering::Equal => (l, Some(v.clone()), r), @@ -1547,7 +1547,7 @@ where V: Clone, P: SharedPointerKind, { - map: &'a mut GenericOrdMap, + map: &'a mut OrdMap, key: K, } @@ -1606,7 +1606,7 @@ where V: Clone, P: SharedPointerKind, { - map: &'a mut GenericOrdMap, + map: &'a mut OrdMap, key: K, } @@ -1638,13 +1638,13 @@ where // Core traits -impl Clone for GenericOrdMap { +impl Clone for OrdMap { /// Clone a map. /// /// Time: O(1) #[inline] fn clone(&self) -> Self { - GenericOrdMap { + OrdMap { size: self.size, root: self.root.clone(), } @@ -1652,32 +1652,32 @@ impl Clone for GenericOrdMap { } // TODO: Support PartialEq for OrdMap that have different P -impl PartialEq for GenericOrdMap +impl PartialEq for OrdMap where K: Ord + PartialEq, V: PartialEq, P: SharedPointerKind, { - fn eq(&self, other: &GenericOrdMap) -> bool { + fn eq(&self, other: &OrdMap) -> bool { self.len() == other.len() && self.diff(other).next().is_none() } } -impl Eq for GenericOrdMap {} +impl Eq for OrdMap {} // TODO: Support PartialOrd for OrdMap that have different P -impl PartialOrd for GenericOrdMap +impl PartialOrd for OrdMap where K: Ord, V: PartialOrd, P: SharedPointerKind, { - fn partial_cmp(&self, other: &GenericOrdMap) -> Option { + fn partial_cmp(&self, other: &OrdMap) -> Option { self.iter().partial_cmp(other.iter()) } } -impl Ord for GenericOrdMap +impl Ord for OrdMap where K: Ord, V: Ord, @@ -1688,7 +1688,7 @@ where } } -impl Hash for GenericOrdMap +impl Hash for OrdMap where K: Ord + Hash, V: Hash, @@ -1704,39 +1704,42 @@ where } } -impl Default for GenericOrdMap { +impl Default for OrdMap { fn default() -> Self { - Self::new() + Self { + size: 0, + root: None, + } } } -impl Add for &GenericOrdMap +impl Add for &OrdMap where K: Ord + Clone, V: Clone, P: SharedPointerKind, { - type Output = GenericOrdMap; + type Output = OrdMap; fn add(self, other: Self) -> Self::Output { self.clone().union(other.clone()) } } -impl Add for GenericOrdMap +impl Add for OrdMap where K: Ord + Clone, V: Clone, P: SharedPointerKind, { - type Output = GenericOrdMap; + type Output = OrdMap; fn add(self, other: Self) -> Self::Output { self.union(other) } } -impl Sum for GenericOrdMap +impl Sum for OrdMap where K: Ord + Clone, V: Clone, @@ -1750,7 +1753,7 @@ where } } -impl Extend<(RK, RV)> for GenericOrdMap +impl Extend<(RK, RV)> for OrdMap where K: Ord + Clone + From, V: Clone + From, @@ -1766,7 +1769,7 @@ where } } -impl Index<&Q> for GenericOrdMap +impl Index<&Q> for OrdMap where Q: Comparable + ?Sized, K: Ord, @@ -1781,7 +1784,7 @@ where } } -impl IndexMut<&Q> for GenericOrdMap +impl IndexMut<&Q> for OrdMap where Q: Comparable + ?Sized, K: Ord + Clone, @@ -1796,7 +1799,7 @@ where } } -impl Debug for GenericOrdMap +impl Debug for OrdMap where K: Ord + Debug, V: Debug, @@ -2075,7 +2078,7 @@ where { } -impl FromIterator<(RK, RV)> for GenericOrdMap +impl FromIterator<(RK, RV)> for OrdMap where K: Ord + Clone + From, V: Clone + From, @@ -2085,7 +2088,7 @@ where where T: IntoIterator, { - let mut m = GenericOrdMap::default(); + let mut m = OrdMap::default(); for (k, v) in i { m.insert(From::from(k), From::from(v)); } @@ -2093,7 +2096,7 @@ where } } -impl<'a, K, V, P> IntoIterator for &'a GenericOrdMap +impl<'a, K, V, P> IntoIterator for &'a OrdMap where K: Ord, P: SharedPointerKind, @@ -2106,7 +2109,7 @@ where } } -impl IntoIterator for GenericOrdMap +impl IntoIterator for OrdMap where K: Clone, V: Clone, @@ -2165,13 +2168,13 @@ where // Conversions -impl AsRef> for GenericOrdMap { +impl AsRef> for OrdMap { fn as_ref(&self) -> &Self { self } } -impl From<&GenericOrdMap<&K, &V, P2>> for GenericOrdMap +impl From<&OrdMap<&K, &V, P2>> for OrdMap where K: Ord + ToOwned + ?Sized, V: ToOwned + ?Sized, @@ -2180,14 +2183,14 @@ where P1: SharedPointerKind, P2: SharedPointerKind, { - fn from(m: &GenericOrdMap<&K, &V, P2>) -> Self { + fn from(m: &OrdMap<&K, &V, P2>) -> Self { m.iter() .map(|(k, v)| ((*k).to_owned(), (*v).to_owned())) .collect() } } -impl<'a, K, V, RK, RV, OK, OV, P> From<&'a [(RK, RV)]> for GenericOrdMap +impl<'a, K, V, RK, RV, OK, OV, P> From<&'a [(RK, RV)]> for OrdMap where K: Ord + Clone + From, V: Clone + From, @@ -2196,25 +2199,25 @@ where RV: ToOwned, P: SharedPointerKind, { - fn from(m: &'a [(RK, RV)]) -> GenericOrdMap { + fn from(m: &'a [(RK, RV)]) -> OrdMap { m.iter() .map(|(k, v)| (k.to_owned(), v.to_owned())) .collect() } } -impl From> for GenericOrdMap +impl From> for OrdMap where K: Ord + Clone + From, V: Clone + From, P: SharedPointerKind, { - fn from(m: Vec<(RK, RV)>) -> GenericOrdMap { + fn from(m: Vec<(RK, RV)>) -> OrdMap { m.into_iter().collect() } } -impl<'a, K, V, RK, RV, OK, OV, P> From<&'a Vec<(RK, RV)>> for GenericOrdMap +impl<'a, K, V, RK, RV, OK, OV, P> From<&'a Vec<(RK, RV)>> for OrdMap where K: Ord + Clone + From, V: Clone + From, @@ -2223,26 +2226,26 @@ where RV: ToOwned, P: SharedPointerKind, { - fn from(m: &'a Vec<(RK, RV)>) -> GenericOrdMap { + fn from(m: &'a Vec<(RK, RV)>) -> OrdMap { m.iter() .map(|(k, v)| (k.to_owned(), v.to_owned())) .collect() } } -impl From> for GenericOrdMap +impl From> for OrdMap where K: Ord + Clone + From, V: Clone + From, P: SharedPointerKind, RK: Eq + Hash, { - fn from(m: collections::HashMap) -> GenericOrdMap { + fn from(m: collections::HashMap) -> OrdMap { m.into_iter().collect() } } -impl<'a, K, V, OK, OV, RK, RV, P> From<&'a collections::HashMap> for GenericOrdMap +impl<'a, K, V, OK, OV, RK, RV, P> From<&'a collections::HashMap> for OrdMap where K: Ord + Clone + From, V: Clone + From, @@ -2251,25 +2254,25 @@ where RV: ToOwned, P: SharedPointerKind, { - fn from(m: &'a collections::HashMap) -> GenericOrdMap { + fn from(m: &'a collections::HashMap) -> OrdMap { m.iter() .map(|(k, v)| (k.to_owned(), v.to_owned())) .collect() } } -impl From> for GenericOrdMap +impl From> for OrdMap where K: Ord + Clone + From, V: Clone + From, P: SharedPointerKind, { - fn from(m: collections::BTreeMap) -> GenericOrdMap { + fn from(m: collections::BTreeMap) -> OrdMap { m.into_iter().collect() } } -impl<'a, K, V, RK, RV, OK, OV, P> From<&'a collections::BTreeMap> for GenericOrdMap +impl<'a, K, V, RK, RV, OK, OV, P> From<&'a collections::BTreeMap> for OrdMap where K: Ord + Clone + From, V: Clone + From, @@ -2278,14 +2281,14 @@ where RV: ToOwned, P: SharedPointerKind, { - fn from(m: &'a collections::BTreeMap) -> GenericOrdMap { + fn from(m: &'a collections::BTreeMap) -> OrdMap { m.iter() .map(|(k, v)| (k.to_owned(), v.to_owned())) .collect() } } -impl From> for GenericOrdMap +impl From> for OrdMap where K: Ord + Hash + Eq + Clone, V: Clone, @@ -2293,12 +2296,12 @@ where P1: SharedPointerKind, P2: SharedPointerKind, { - fn from(m: GenericHashMap) -> Self { + fn from(m: HashMap) -> Self { m.into_iter().collect() } } -impl<'a, K, V, S, P1, P2> From<&'a GenericHashMap> for GenericOrdMap +impl<'a, K, V, S, P1, P2> From<&'a HashMap> for OrdMap where K: Ord + Hash + Eq + Clone, V: Clone, @@ -2306,7 +2309,7 @@ where P1: SharedPointerKind, P2: SharedPointerKind, { - fn from(m: &'a GenericHashMap) -> Self { + fn from(m: &'a HashMap) -> Self { m.iter().map(|(k, v)| (k.clone(), v.clone())).collect() } } @@ -2631,8 +2634,8 @@ mod test { } fn expected_diff<'a, K, V, P>( - a: &'a GenericOrdMap, - b: &'a GenericOrdMap, + a: &'a OrdMap, + b: &'a OrdMap, ) -> Vec> where K: Ord + Clone, @@ -2843,7 +2846,7 @@ mod test { index_rand in usize::ANY ) { let index = *input.keys().nth(index_rand % input.len()).unwrap(); - let map1 = OrdMap::from_iter(input.clone()); + let map1 = OrdMap::::from_iter(input.clone()); let (val, map2): (i16, _) = map1.extract(&index).unwrap(); let map3 = map2.update(index, val); for key in map2.keys() { diff --git a/src/ord/set.rs b/src/ord/set.rs index 40d25f8..1e5cc73 100644 --- a/src/ord/set.rs +++ b/src/ord/set.rs @@ -7,11 +7,11 @@ //! An immutable ordered set implemented as a [B+tree] [1]. //! //! Most operations on this type of set are O(log n). A -//! [`GenericHashSet`] is usually a better choice for +//! [`HashSet`] is usually a better choice for //! performance, but the `OrdSet` has the advantage of only requiring //! an [`Ord`][std::cmp::Ord] constraint on its values, and of being //! ordered, so values always come out from lowest to highest, where a -//! [`GenericHashSet`] has no guaranteed ordering. +//! [`HashSet`] has no guaranteed ordering. //! //! [1]: https://en.wikipedia.org/wiki/B%2B_tree @@ -27,9 +27,9 @@ use archery::SharedPointerKind; use equivalent::Comparable; use super::map; -use crate::hashset::GenericHashSet; +use crate::OrdMap; +use crate::hashset::HashSet; use crate::shared_ptr::DefaultSharedPtr; -use crate::GenericOrdMap; /// Construct a set from a sequence of values. /// @@ -58,36 +58,36 @@ macro_rules! ordset { }}; } -/// Type alias for [`GenericOrdSet`] that uses [`DefaultSharedPtr`] as the pointer type. -/// -/// [GenericOrdSet]: ./struct.GenericOrdSet.html -/// [DefaultSharedPtr]: ../shared_ptr/type.DefaultSharedPtr.html -pub type OrdSet = GenericOrdSet; - /// An ordered set. /// /// An immutable ordered map implemented as a B+tree [1]. /// /// Most operations on this type of set are O(log n). A -/// [`GenericHashSet`] is usually a better choice for +/// [`HashSet`] is usually a better choice for /// performance, but the `OrdSet` has the advantage of only requiring /// an [`Ord`][std::cmp::Ord] constraint on its values, and of being /// ordered, so values always come out from lowest to highest, where a -/// [`GenericHashSet`] has no guaranteed ordering. +/// [`HashSet`] has no guaranteed ordering. /// /// [1]: https://en.wikipedia.org/wiki/B%2B_tree -pub struct GenericOrdSet { - map: GenericOrdMap, +pub struct OrdSet { + map: OrdMap, } -impl GenericOrdSet { +impl OrdSet { /// Construct an empty set. #[inline] #[must_use] pub fn new() -> Self { - GenericOrdSet { - map: GenericOrdMap::new(), - } + Default::default() + } +} +impl OrdSet { + /// Construct an empty set with a custom shared kind + #[inline] + #[must_use] + pub fn with_kind() -> Self { + Default::default() } /// Construct a set with a single value. @@ -103,8 +103,8 @@ impl GenericOrdSet { #[inline] #[must_use] pub fn unit(a: A) -> Self { - GenericOrdSet { - map: GenericOrdMap::unit(a, ()), + OrdSet { + map: OrdMap::unit(a, ()), } } @@ -181,7 +181,7 @@ impl GenericOrdSet { } } -impl GenericOrdSet +impl OrdSet where A: Ord, P: SharedPointerKind, @@ -392,7 +392,7 @@ where } } -impl GenericOrdSet +impl OrdSet where A: Ord + Clone, P: SharedPointerKind, @@ -717,40 +717,40 @@ where // Core traits -impl Clone for GenericOrdSet { +impl Clone for OrdSet { /// Clone a set. /// /// Time: O(1) #[inline] fn clone(&self) -> Self { - GenericOrdSet { + OrdSet { map: self.map.clone(), } } } // TODO: Support PartialEq for OrdSet that have different P -impl PartialEq for GenericOrdSet { +impl PartialEq for OrdSet { fn eq(&self, other: &Self) -> bool { self.map.eq(&other.map) } } -impl Eq for GenericOrdSet {} +impl Eq for OrdSet {} -impl PartialOrd for GenericOrdSet { +impl PartialOrd for OrdSet { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for GenericOrdSet { +impl Ord for OrdSet { fn cmp(&self, other: &Self) -> Ordering { self.iter().cmp(other.iter()) } } -impl Hash for GenericOrdSet { +impl Hash for OrdSet { fn hash(&self, state: &mut H) where H: Hasher, @@ -761,54 +761,56 @@ impl Hash for GenericOrdSet { } } -impl Default for GenericOrdSet { +impl Default for OrdSet { fn default() -> Self { - GenericOrdSet::new() + OrdSet { + map: OrdMap::with_kind(), + } } } -impl Add for GenericOrdSet { - type Output = GenericOrdSet; +impl Add for OrdSet { + type Output = OrdSet; fn add(self, other: Self) -> Self::Output { self.union(other) } } -impl Add for &GenericOrdSet { - type Output = GenericOrdSet; +impl Add for &OrdSet { + type Output = OrdSet; fn add(self, other: Self) -> Self::Output { self.clone().union(other.clone()) } } -impl Mul for GenericOrdSet { - type Output = GenericOrdSet; +impl Mul for OrdSet { + type Output = OrdSet; fn mul(self, other: Self) -> Self::Output { self.intersection(other) } } -impl Mul for &GenericOrdSet { - type Output = GenericOrdSet; +impl Mul for &OrdSet { + type Output = OrdSet; fn mul(self, other: Self) -> Self::Output { self.clone().intersection(other.clone()) } } -impl Sum for GenericOrdSet { +impl Sum for OrdSet { fn sum(it: I) -> Self where I: Iterator, { - it.fold(Self::new(), |a, b| a + b) + it.fold(Self::with_kind(), |a, b| a + b) } } -impl Extend for GenericOrdSet +impl Extend for OrdSet where A: Ord + Clone + From, P: SharedPointerKind, @@ -823,7 +825,7 @@ where } } -impl Debug for GenericOrdSet { +impl Debug for OrdSet { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { f.debug_set().entries(self.iter()).finish() } @@ -1011,7 +1013,7 @@ where { } -impl FromIterator for GenericOrdSet +impl FromIterator for OrdSet where A: Ord + Clone + From, P: SharedPointerKind, @@ -1020,7 +1022,7 @@ where where T: IntoIterator, { - let mut out = Self::new(); + let mut out = Self::with_kind(); for item in i { out.insert(From::from(item)); } @@ -1028,7 +1030,7 @@ where } } -impl<'a, A, P> IntoIterator for &'a GenericOrdSet +impl<'a, A, P> IntoIterator for &'a OrdSet where A: 'a + Ord, P: SharedPointerKind, @@ -1041,7 +1043,7 @@ where } } -impl IntoIterator for GenericOrdSet +impl IntoIterator for OrdSet where A: Ord + Clone, P: SharedPointerKind, @@ -1058,19 +1060,19 @@ where // Conversions -impl From<&GenericOrdSet<&A, P2>> for GenericOrdSet +impl From<&OrdSet<&A, P2>> for OrdSet where A: ToOwned + Ord + ?Sized, OA: Ord + Clone, P1: SharedPointerKind, P2: SharedPointerKind, { - fn from(set: &GenericOrdSet<&A, P2>) -> Self { + fn from(set: &OrdSet<&A, P2>) -> Self { set.iter().map(|a| (*a).to_owned()).collect() } } -impl<'a, A, P> From<&'a [A]> for GenericOrdSet +impl<'a, A, P> From<&'a [A]> for OrdSet where A: Ord + Clone, P: SharedPointerKind, @@ -1080,20 +1082,20 @@ where } } -impl From> for GenericOrdSet { +impl From> for OrdSet { fn from(vec: Vec) -> Self { vec.into_iter().collect() } } -impl From<&Vec> for GenericOrdSet { +impl From<&Vec> for OrdSet { fn from(vec: &Vec) -> Self { vec.iter().cloned().collect() } } impl From> - for GenericOrdSet + for OrdSet { fn from(hash_set: collections::HashSet) -> Self { hash_set.into_iter().collect() @@ -1101,37 +1103,37 @@ impl From From<&collections::HashSet> - for GenericOrdSet + for OrdSet { fn from(hash_set: &collections::HashSet) -> Self { hash_set.iter().cloned().collect() } } -impl From> for GenericOrdSet { +impl From> for OrdSet { fn from(btree_set: collections::BTreeSet) -> Self { btree_set.into_iter().collect() } } -impl From<&collections::BTreeSet> for GenericOrdSet { +impl From<&collections::BTreeSet> for OrdSet { fn from(btree_set: &collections::BTreeSet) -> Self { btree_set.iter().cloned().collect() } } impl - From> for GenericOrdSet + From> for OrdSet { - fn from(hashset: GenericHashSet) -> Self { + fn from(hashset: HashSet) -> Self { hashset.into_iter().collect() } } impl - From<&GenericHashSet> for GenericOrdSet + From<&HashSet> for OrdSet { - fn from(hashset: &GenericHashSet) -> Self { + fn from(hashset: &HashSet) -> Self { hashset.into_iter().cloned().collect() } } diff --git a/src/quickcheck.rs b/src/quickcheck.rs index c03335d..963bf15 100644 --- a/src/quickcheck.rs +++ b/src/quickcheck.rs @@ -1,50 +1,40 @@ -use crate::{ - shared_ptr::SharedPointerKind, GenericHashMap, GenericHashSet, GenericOrdMap, GenericOrdSet, - GenericVector, -}; +use crate::{HashMap, HashSet, OrdMap, OrdSet, Vector, shared_ptr::SharedPointerKind}; use ::quickcheck::{Arbitrary, Gen}; use std::hash::{BuildHasher, Hash}; use std::iter::FromIterator; -impl Arbitrary - for GenericVector -{ +impl Arbitrary for Vector { fn arbitrary(g: &mut Gen) -> Self { - GenericVector::from_iter(Vec::::arbitrary(g)) + Vector::from_iter(Vec::::arbitrary(g)) } } -impl< - K: Ord + Clone + Arbitrary + Sync, - V: Clone + Arbitrary + Sync, - P: SharedPointerKind + 'static, - > Arbitrary for GenericOrdMap +impl + Arbitrary for OrdMap { fn arbitrary(g: &mut Gen) -> Self { - GenericOrdMap::from_iter(Vec::<(K, V)>::arbitrary(g)) + OrdMap::from_iter(Vec::<(K, V)>::arbitrary(g)) } } -impl Arbitrary - for GenericOrdSet -{ +impl Arbitrary for OrdSet { fn arbitrary(g: &mut Gen) -> Self { - GenericOrdSet::from_iter(Vec::::arbitrary(g)) + OrdSet::from_iter(Vec::::arbitrary(g)) } } -impl Arbitrary for GenericHashSet +impl Arbitrary for HashSet where A: Hash + Eq + Arbitrary + Sync, S: BuildHasher + Clone + Default + Send + Sync + 'static, P: SharedPointerKind + 'static, { fn arbitrary(g: &mut Gen) -> Self { - GenericHashSet::from_iter(Vec::::arbitrary(g)) + HashSet::from_iter(Vec::::arbitrary(g)) } } -impl Arbitrary for GenericHashMap +impl Arbitrary for HashMap where K: Hash + Eq + Arbitrary + Sync, V: Arbitrary + Sync, @@ -52,6 +42,6 @@ where P: SharedPointerKind + 'static, { fn arbitrary(g: &mut Gen) -> Self { - GenericHashMap::from(Vec::<(K, V)>::arbitrary(g)) + HashMap::from(Vec::<(K, V)>::arbitrary(g)) } } diff --git a/src/ser.rs b/src/ser.rs index 21664d6..b8b0e1a 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -9,11 +9,11 @@ use std::fmt; use std::hash::{BuildHasher, Hash}; use std::marker::PhantomData; -use crate::hashmap::GenericHashMap; -use crate::hashset::GenericHashSet; -use crate::ordmap::GenericOrdMap; -use crate::ordset::GenericOrdSet; -use crate::vector::GenericVector; +use crate::hashmap::HashMap; +use crate::hashset::HashSet; +use crate::ordmap::OrdMap; +use crate::ordset::OrdSet; +use crate::vector::Vector; struct SeqVisitor<'de, S, A> { phantom_s: PhantomData, @@ -105,7 +105,7 @@ where // Set impl<'de, A: Deserialize<'de> + Ord + Clone, P: SharedPointerKind> Deserialize<'de> - for GenericOrdSet + for OrdSet { fn deserialize(des: D) -> Result where @@ -115,7 +115,7 @@ impl<'de, A: Deserialize<'de> + Ord + Clone, P: SharedPointerKind> Deserialize<' } } -impl Serialize for GenericOrdSet { +impl Serialize for OrdSet { fn serialize(&self, ser: S) -> Result where S: Serializer, @@ -131,17 +131,17 @@ impl Serialize for GenericOrdSet // Map impl<'de, K: Deserialize<'de> + Ord + Clone, V: Deserialize<'de> + Clone, P: SharedPointerKind> - Deserialize<'de> for GenericOrdMap + Deserialize<'de> for OrdMap { fn deserialize(des: D) -> Result where D: Deserializer<'de>, { - des.deserialize_map(MapVisitor::<'de, GenericOrdMap, K, V>::new()) + des.deserialize_map(MapVisitor::<'de, OrdMap, K, V>::new()) } } -impl Serialize for GenericOrdMap { +impl Serialize for OrdMap { fn serialize(&self, ser: S) -> Result where S: Serializer, @@ -156,7 +156,7 @@ impl Serialize for Gener // HashMap -impl<'de, K, V, S, P: SharedPointerKind> Deserialize<'de> for GenericHashMap +impl<'de, K, V, S, P: SharedPointerKind> Deserialize<'de> for HashMap where K: Deserialize<'de> + Hash + Eq + Clone, V: Deserialize<'de> + Clone, @@ -167,11 +167,11 @@ where where D: Deserializer<'de>, { - des.deserialize_map(MapVisitor::<'de, GenericHashMap, K, V>::new()) + des.deserialize_map(MapVisitor::<'de, HashMap, K, V>::new()) } } -impl Serialize for GenericHashMap +impl Serialize for HashMap where K: Serialize + Hash + Eq, V: Serialize, @@ -193,11 +193,11 @@ where // HashSet impl< - 'de, - A: Deserialize<'de> + Hash + Eq + Clone, - S: BuildHasher + Default + Clone, - P: SharedPointerKind, - > Deserialize<'de> for GenericHashSet + 'de, + A: Deserialize<'de> + Hash + Eq + Clone, + S: BuildHasher + Default + Clone, + P: SharedPointerKind, +> Deserialize<'de> for HashSet { fn deserialize(des: D) -> Result where @@ -208,7 +208,7 @@ impl< } impl Serialize - for GenericHashSet + for HashSet { fn serialize(&self, ser: Ser) -> Result where @@ -225,18 +225,18 @@ impl S // Vector impl<'de, A: Clone + Deserialize<'de>, P: SharedPointerKind, const CHUNK_SIZE: usize> - Deserialize<'de> for GenericVector + Deserialize<'de> for Vector { fn deserialize(des: D) -> Result where D: Deserializer<'de>, { - des.deserialize_seq(SeqVisitor::<'de, GenericVector, A>::new()) + des.deserialize_seq(SeqVisitor::<'de, Vector, A>::new()) } } impl Serialize - for GenericVector + for Vector { fn serialize(&self, ser: S) -> Result where @@ -255,8 +255,8 @@ impl Serialize #[cfg(test)] mod test { use crate::{ - proptest::{hash_map, hash_set, ord_map, ord_set, vector}, HashMap, HashSet, OrdMap, OrdSet, Vector, + proptest::{hash_map, hash_set, ord_map, ord_set, vector}, }; use proptest::num::i32; use proptest::proptest; diff --git a/src/sort.rs b/src/sort.rs index 19f5e00..eb2cb89 100644 --- a/src/sort.rs +++ b/src/sort.rs @@ -4,11 +4,11 @@ use crate::vector::FocusMut; use archery::SharedPointerKind; -use rand_core::{RngCore, SeedableRng}; +use rand_core::{Rng, SeedableRng}; use std::cmp::Ordering; use std::mem; -fn gen_range(rng: &mut R, min: usize, max: usize) -> usize { +fn gen_range(rng: &mut R, min: usize, max: usize) -> usize { let range = max - min; min + (rng.next_u64() as usize % range) } @@ -27,7 +27,7 @@ fn do_quicksort( ) where A: Clone, F: Fn(&A, &A) -> Ordering, - R: RngCore, + R: Rng, P: SharedPointerKind, { if vector.len() <= 1 { diff --git a/src/tests/hashset.rs b/src/tests/hashset.rs index d2b43f4..9a98809 100644 --- a/src/tests/hashset.rs +++ b/src/tests/hashset.rs @@ -79,7 +79,7 @@ proptest! { } } assert_eq!(nat.len(), set.len()); - assert_eq!(HashSet::from(nat.clone()), set); + assert_eq!(HashSet::::from(nat.clone()), set); } } } diff --git a/src/tests/vector.rs b/src/tests/vector.rs index 570c95c..3c87f26 100644 --- a/src/tests/vector.rs +++ b/src/tests/vector.rs @@ -3,7 +3,7 @@ use std::fmt::{Debug, Error, Formatter, Write}; use std::iter::FromIterator; -use crate::{GenericVector, Vector}; +use crate::Vector; use proptest::proptest; use proptest_derive::Arbitrary; @@ -170,7 +170,7 @@ proptest! { assert_eq!(len - 1, vec.len()); } Action::JoinLeft(mut new_nat) => { - let mut new_vec = GenericVector::from_iter(new_nat.iter().cloned()); + let mut new_vec = Vector::from_iter(new_nat.iter().cloned()); let add_len = new_nat.len(); let len = vec.len(); new_vec.append(vec); @@ -180,7 +180,7 @@ proptest! { assert_eq!(len + add_len, vec.len()); } Action::JoinRight(mut new_nat) => { - let new_vec = GenericVector::from_iter(new_nat.iter().cloned()); + let new_vec = Vector::from_iter(new_nat.iter().cloned()); let add_len = new_nat.len(); let len = vec.len(); vec.append(new_vec); @@ -194,7 +194,7 @@ proptest! { let nat_right = nat.split_off(index); assert_eq!(index, vec.len()); assert_eq!(len - index, vec_right.len()); - assert_eq!(GenericVector::from_iter(nat_right.iter().cloned()), vec_right); + assert_eq!(Vector::from_iter(nat_right.iter().cloned()), vec_right); } Action::SplitRight(index) => { let index = cap_index(vec.len(), index); @@ -203,7 +203,7 @@ proptest! { let nat_right = nat.split_off(index); assert_eq!(index, vec.len()); assert_eq!(len - index, vec_right.len()); - assert_eq!(GenericVector::from_iter(nat.iter().cloned()), vec); + assert_eq!(Vector::from_iter(nat.iter().cloned()), vec); vec = vec_right; nat = nat_right; } @@ -225,5 +225,5 @@ fn test_inserts() { let mut rv: Vec = Vec::new(); rv.extend((0..N).skip(1).step_by(2)); rv.extend((0..N).step_by(2).rev()); - assert_eq!(GenericVector::from_iter(rv.iter().cloned()), v); + assert_eq!(Vector::from_iter(rv.iter().cloned()), v); } diff --git a/src/vector/focus.rs b/src/vector/focus.rs index b37c4cd..6cb73e1 100644 --- a/src/vector/focus.rs +++ b/src/vector/focus.rs @@ -13,7 +13,7 @@ use crate::nodes::chunk::Chunk; use crate::sync::Lock; use crate::util::to_range; use crate::vector::{ - GenericVector, Iter, IterMut, + Vector, Iter, IterMut, VectorInner::{Full, Inline, Single}, RRB, }; @@ -113,7 +113,7 @@ where /// Construct a `Focus` for a [`Vector`][Vector]. /// /// [Vector]: type.Vector.html - pub fn new(vector: &'a GenericVector) -> Self { + pub fn new(vector: &'a Vector) -> Self { Self::new_inner(&vector.vector) } @@ -637,7 +637,7 @@ where A: Clone + 'a, { /// Construct a `FocusMut` for a `Vector`. - pub fn new(vector: &'a mut GenericVector) -> Self { + pub fn new(vector: &'a mut Vector) -> Self { match &mut vector.vector { Inline(chunk) => FocusMut::Single(chunk), Single(chunk) => FocusMut::Single(SharedPointer::make_mut(chunk).as_mut_slice()), diff --git a/src/vector/mod.rs b/src/vector/mod.rs index 1f79a36..a05934d 100644 --- a/src/vector/mod.rs +++ b/src/vector/mod.rs @@ -109,12 +109,6 @@ macro_rules! vector { }}; } -/// Type alias for [`GenericVector`] that uses [`DefaultSharedPtr`] as the pointer type. -/// -/// [GenericVector]: ./struct.GenericVector.html -/// [DefaultSharedPtr]: ../shared_ptr/type.DefaultSharedPtr.html -pub type Vector = GenericVector; - /// A persistent vector. /// /// This is a sequence of elements in insertion order - if you need a list of @@ -151,7 +145,11 @@ pub type Vector = GenericVector { +pub struct Vector< + A, + P: SharedPointerKind = DefaultSharedPtr, + const CHUNK_SIZE: usize = { crate::config::VECTOR_CHUNK_SIZE }, +> { vector: VectorInner, } @@ -200,7 +198,31 @@ impl Clone for RRB GenericVector { +impl Vector { + /// Construct an empty vector using [`DefaultSharedPtr`] and [`crate::config::VECTOR_CHUNK_SIZE`] + #[must_use] + pub fn new() -> Self { + Default::default() + } +} + +impl Vector { + /// Construct an empty vector using a custom shared kind + #[must_use] + pub fn with_kind() -> Self { + Default::default() + } +} + +impl Vector { + /// Construct an empty vector using a custom chunk size + #[must_use] + pub fn with_size() -> Self { + Default::default() + } +} + +impl Vector { /// True if a vector is a full inline or single chunk, ie. must be promoted /// to grow further. fn needs_promotion(&self) -> bool { @@ -256,9 +278,8 @@ impl GenericVector Self { + /// Construct an empty vector using a custom chunk size and shared kind + pub fn with_kind_and_size() -> Self { Self { vector: Inline(InlineArray::new()), } @@ -308,7 +329,7 @@ impl GenericVector>()` bytes are stored inline on + /// the space of `std::mem::size_of::>()` bytes are stored inline on /// the stack instead of allocating any chunks. This method returns `true` if /// this vector is currently inlined, or `false` if it currently has chunks allocated /// on the heap. @@ -657,7 +678,7 @@ impl GenericVector::unit(1337); /// assert_eq!(1, vec.len()); /// assert_eq!( /// vec.get(0), @@ -708,7 +729,7 @@ impl GenericVector GenericVector { +impl Vector { /// Get a mutable reference to the value at index `index` in a /// vector. /// @@ -1308,7 +1329,7 @@ impl GenericVector Self { match count { 0 => self.clone(), - count if count >= self.len() => Self::new(), + count if count >= self.len() => Self::with_kind_and_size(), count => { // FIXME can be made more efficient by dropping the unwanted side without constructing it self.clone().split_off(count) @@ -1355,7 +1376,7 @@ impl GenericVector= r.end || r.start >= self.len() { - return GenericVector::new(); + return Vector::with_kind_and_size(); } let mut middle = self.split_off(r.start); let right = middle.split_off(r.end - r.start); @@ -1756,15 +1777,15 @@ fn replace_shared_pointer( // Core traits -impl Default for GenericVector { +impl Default for Vector { fn default() -> Self { - Self::new() + Self { + vector: Inline(InlineArray::new()), + } } } -impl Clone - for GenericVector -{ +impl Clone for Vector { /// Clone a vector. /// /// Time: O(1), or O(n) with a very small, bounded *n* for an inline vector. @@ -1779,9 +1800,7 @@ impl Clone } } -impl Debug - for GenericVector -{ +impl Debug for Vector { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { f.debug_list().entries(self.iter()).finish() // match self { @@ -1796,34 +1815,30 @@ impl Debug } impl PartialEq - for GenericVector + for Vector { fn eq(&self, other: &Self) -> bool { self.len() == other.len() && self.iter().eq(other.iter()) } } -impl Eq for GenericVector {} +impl Eq for Vector {} impl PartialOrd - for GenericVector + for Vector { fn partial_cmp(&self, other: &Self) -> Option { self.iter().partial_cmp(other.iter()) } } -impl Ord - for GenericVector -{ +impl Ord for Vector { fn cmp(&self, other: &Self) -> Ordering { self.iter().cmp(other.iter()) } } -impl Hash - for GenericVector -{ +impl Hash for Vector { fn hash(&self, state: &mut H) { for i in self { i.hash(state) @@ -1831,21 +1846,17 @@ impl Hash } } -impl Sum - for GenericVector -{ +impl Sum for Vector { fn sum(it: I) -> Self where I: Iterator, { - it.fold(Self::new(), |a, b| a + b) + it.fold(Self::with_kind_and_size(), |a, b| a + b) } } -impl Add - for GenericVector -{ - type Output = GenericVector; +impl Add for Vector { + type Output = Vector; /// Concatenate two vectors. /// @@ -1856,10 +1867,8 @@ impl Add } } -impl Add - for &GenericVector -{ - type Output = GenericVector; +impl Add for &Vector { + type Output = Vector; /// Concatenate two vectors. /// @@ -1872,7 +1881,7 @@ impl Add } impl Extend - for GenericVector + for Vector { /// Add values to the end of a vector by consuming an iterator. /// @@ -1887,9 +1896,7 @@ impl Extend } } -impl Index - for GenericVector -{ +impl Index for Vector { type Output = A; /// Get a reference to the value at index `index` in the vector. /// @@ -1907,7 +1914,7 @@ impl Index } impl IndexMut - for GenericVector + for Vector { /// Get a mutable reference to the value at index `index` in the /// vector. @@ -1924,7 +1931,7 @@ impl IndexMut // Conversions impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> IntoIterator - for &'a GenericVector + for &'a Vector { type Item = &'a A; type IntoIter = Iter<'a, A, P, CHUNK_SIZE>; @@ -1934,7 +1941,7 @@ impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> IntoIterator } impl<'a, A: Clone, P: SharedPointerKind, const CHUNK_SIZE: usize> IntoIterator - for &'a mut GenericVector + for &'a mut Vector { type Item = &'a mut A; type IntoIter = IterMut<'a, A, P, CHUNK_SIZE>; @@ -1944,7 +1951,7 @@ impl<'a, A: Clone, P: SharedPointerKind, const CHUNK_SIZE: usize> IntoIterator } impl IntoIterator - for GenericVector + for Vector { type Item = A; type IntoIter = ConsumingIter; @@ -1954,7 +1961,7 @@ impl IntoIterator } impl FromIterator - for GenericVector + for Vector { /// Create a vector from an iterator. /// @@ -1963,7 +1970,7 @@ impl FromIterator where I: IntoIterator, { - let mut seq = Self::new(); + let mut seq = Self::with_kind_and_size(); for item in iter { seq.push_back(item) } @@ -1971,21 +1978,21 @@ impl FromIterator } } -impl From<&GenericVector<&A, P2, CHUNK_SIZE>> - for GenericVector +impl From<&Vector<&A, P2, CHUNK_SIZE>> + for Vector where A: ToOwned, OA: Borrow + Clone, P1: SharedPointerKind, P2: SharedPointerKind, { - fn from(vec: &GenericVector<&A, P2, CHUNK_SIZE>) -> Self { + fn from(vec: &Vector<&A, P2, CHUNK_SIZE>) -> Self { vec.iter().map(|a| (*a).to_owned()).collect() } } impl From<[A; N]> - for GenericVector + for Vector where A: Clone, { @@ -1995,7 +2002,7 @@ where } impl From<&[A]> - for GenericVector + for Vector { fn from(slice: &[A]) -> Self { slice.iter().cloned().collect() @@ -2003,7 +2010,7 @@ impl From<&[A]> } impl From> - for GenericVector + for Vector { /// Create a vector from a [`std::vec::Vec`][vec]. /// @@ -2016,7 +2023,7 @@ impl From> } impl From<&Vec> - for GenericVector + for Vector { /// Create a vector from a [`std::vec::Vec`][vec]. /// @@ -2044,7 +2051,7 @@ pub struct Iter<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> { } impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> Iter<'a, A, P, CHUNK_SIZE> { - fn new(seq: &'a GenericVector) -> Self { + fn new(seq: &'a Vector) -> Self { Iter { focus: seq.focus(), front_index: 0, @@ -2153,7 +2160,7 @@ impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> IterMut<'a, A, P, CHU } impl<'a, A: Clone, P: SharedPointerKind, const CHUNK_SIZE: usize> IterMut<'a, A, P, CHUNK_SIZE> { - fn new(seq: &'a mut GenericVector) -> Self { + fn new(seq: &'a mut Vector) -> Self { let focus = seq.focus_mut(); let len = focus.len(); IterMut { @@ -2222,11 +2229,11 @@ impl<'a, A: Clone, P: SharedPointerKind, const CHUNK_SIZE: usize> FusedIterator /// A consuming iterator over vectors with values of type `A`. pub struct ConsumingIter { - vector: GenericVector, + vector: Vector, } impl ConsumingIter { - fn new(vector: GenericVector) -> Self { + fn new(vector: Vector) -> Self { Self { vector } } } @@ -2282,7 +2289,7 @@ pub struct Chunks<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> { } impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> Chunks<'a, A, P, CHUNK_SIZE> { - fn new(seq: &'a GenericVector) -> Self { + fn new(seq: &'a Vector) -> Self { Chunks { focus: seq.focus(), front_index: 0, @@ -2347,7 +2354,7 @@ pub struct ChunksMut<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> { } impl<'a, A: Clone, P: SharedPointerKind, const CHUNK_SIZE: usize> ChunksMut<'a, A, P, CHUNK_SIZE> { - fn new(seq: &'a mut GenericVector) -> Self { + fn new(seq: &'a mut Vector) -> Self { let len = seq.len(); ChunksMut { focus: seq.focus_mut(), @@ -2451,7 +2458,7 @@ mod test { #[cfg(not(miri))] (0..100_000, vec![0, 1, 50_000, 99_999, 100_000]), ] { - let imbl_vec = Vector::from_iter(data.clone()); + let imbl_vec = Vector::::from_iter(data.clone()); let vec = Vec::from_iter(data); let focus = imbl_vec.focus(); for split_point in split_points { @@ -2472,7 +2479,7 @@ mod test { #[test] #[should_panic(expected = "range out of bounds")] fn test_vector_focus_narrow_out_of_range() { - let vec = Vector::from_iter(0..100); + let vec = Vector::::from_iter(0..100); _ = vec.focus().narrow(..1000); } @@ -2509,7 +2516,7 @@ mod test { #[cfg_attr(miri, ignore)] #[test] fn large_vector_focus() { - let input = Vector::from_iter(0..100_000); + let input = Vector::::from_iter(0..100_000); let vec = input.clone(); let mut sum: i64 = 0; let mut focus = vec.focus(); @@ -2523,7 +2530,7 @@ mod test { #[cfg_attr(miri, ignore)] #[test] fn large_vector_focus_mut() { - let input = Vector::from_iter(0..100_000); + let input = Vector::::from_iter(0..100_000); let mut vec = input.clone(); { let mut focus = vec.focus_mut(); @@ -2541,9 +2548,9 @@ mod test { fn issue_55_fwd() { let mut l = Vector::new(); for i in 0..4098 { - l.append(GenericVector::unit(i)); + l.append(Vector::unit(i)); } - l.append(GenericVector::unit(4098)); + l.append(Vector::unit(4098)); assert_eq!(Some(&4097), l.get(4097)); assert_eq!(Some(&4096), l.get(4096)); } @@ -2551,9 +2558,9 @@ mod test { #[cfg_attr(miri, ignore)] #[test] fn issue_55_back() { - let mut l = Vector::unit(0); + let mut l = Vector::::unit(0); for i in 0..4099 { - let mut tmp = GenericVector::unit(i + 1); + let mut tmp = Vector::unit(i + 1); tmp.append(l); l = tmp; } @@ -2565,15 +2572,15 @@ mod test { #[test] fn issue_55_append() { - let mut vec1 = Vector::from_iter(0..92); - let vec2 = GenericVector::from_iter(0..165); + let mut vec1 = Vector::::from_iter(0..92); + let vec2 = Vector::::from_iter(0..165); vec1.append(vec2); } #[test] fn issue_70() { // This tests assumes a chunk size of 64 - let mut x = GenericVector::::new(); + let mut x = Vector::::new(); for _ in 0..262 { x.push_back(0); } @@ -2613,9 +2620,9 @@ mod test { #[cfg_attr(miri, ignore)] #[test] fn issue_67() { - let mut l = Vector::unit(4100); + let mut l = Vector::::unit(4100); for i in (0..4099).rev() { - let mut tmp = GenericVector::unit(i); + let mut tmp = Vector::unit(i); tmp.append(l); l = tmp; } @@ -2631,7 +2638,7 @@ mod test { #[test] fn issue_74_simple_size() { const CHUNK_SIZE: usize = 64; - let mut x = GenericVector::::new(); + let mut x = Vector::::new(); for _ in 0..(CHUNK_SIZE * ( 1 // inner_f @@ -2706,7 +2713,7 @@ mod test { #[cfg_attr(miri, ignore)] #[test] fn issue_107_split_off_causes_overflow() { - let mut vec = Vector::from_iter(0..4289); + let mut vec = Vector::::from_iter(0..4289); let mut control = Vec::from_iter(0..4289); let chunk = 64; @@ -2727,7 +2734,7 @@ mod test { #[test] fn issue_116() { - let vec = Vector::from_iter(0..300); + let vec = Vector::::from_iter(0..300); let rev_vec: Vector<_> = vec.clone().into_iter().rev().collect(); assert_eq!(vec.len(), rev_vec.len()); } @@ -2762,7 +2769,7 @@ mod test { #[test] fn full_retain() { - let mut a = Vector::from_iter(0..128); + let mut a = Vector::::from_iter(0..128); let b = Vector::from_iter(128..256); a.append(b); assert!(matches!(a.vector, Full(_))); @@ -2777,7 +2784,7 @@ mod test { #[cfg_attr(miri, ignore)] #[test] fn iter(ref vec in vec(i32::ANY, 0..1000)) { - let seq = Vector::from_iter(vec.iter().cloned()); + let seq = Vector::::from_iter(vec.iter().cloned()); for (index, item) in seq.iter().enumerate() { assert_eq!(&vec[index], item); } @@ -2793,8 +2800,8 @@ mod test { vector.push_front(value); assert_eq!(count + 1, vector.len()); } - let input2 = Vec::from_iter(input.iter().rev().cloned()); - assert_eq!(input2, Vec::from_iter(vector.iter().cloned())); + let input2 = Vec::::from_iter(input.iter().rev().cloned()); + assert_eq!(input2, Vec::::from_iter(vector.iter().cloned())); } #[cfg_attr(miri, ignore)] @@ -2806,13 +2813,13 @@ mod test { vector.push_back(value); assert_eq!(count + 1, vector.len()); } - assert_eq!(input, &Vec::from_iter(vector.iter().cloned())); + assert_eq!(input, &Vec::::from_iter(vector.iter().cloned())); } #[cfg_attr(miri, ignore)] #[test] fn pop_back_mut(ref input in vec(i32::ANY, 0..1000)) { - let mut vector = Vector::from_iter(input.iter().cloned()); + let mut vector = Vector::::from_iter(input.iter().cloned()); assert_eq!(input.len(), vector.len()); for (index, value) in input.iter().cloned().enumerate().rev() { match vector.pop_back() { @@ -2829,7 +2836,7 @@ mod test { #[cfg_attr(miri, ignore)] #[test] fn pop_front_mut(ref input in vec(i32::ANY, 0..1000)) { - let mut vector = Vector::from_iter(input.iter().cloned()); + let mut vector = Vector::::from_iter(input.iter().cloned()); assert_eq!(input.len(), vector.len()); for (index, value) in input.iter().cloned().rev().enumerate().rev() { match vector.pop_front() { @@ -2867,7 +2874,7 @@ mod test { #[test] fn skip(ref vec in vec(i32::ANY, 1..2000), count in usize::ANY) { let count = count % (vec.len() + 1); - let old = Vector::from_iter(vec.iter().cloned()); + let old = Vector::::from_iter(vec.iter().cloned()); let new = old.skip(count); assert_eq!(old.len(), vec.len()); assert_eq!(new.len(), vec.len() - count); @@ -2883,7 +2890,7 @@ mod test { #[test] fn split_off(ref vec in vec(i32::ANY, 1..2000), split_pos in usize::ANY) { let split_index = split_pos % (vec.len() + 1); - let mut left = Vector::from_iter(vec.iter().cloned()); + let mut left = Vector::::from_iter(vec.iter().cloned()); let right = left.split_off(split_index); assert_eq!(left.len(), split_index); assert_eq!(right.len(), vec.len() - split_index); @@ -2898,8 +2905,8 @@ mod test { #[cfg_attr(miri, ignore)] #[test] fn append(ref vec1 in vec(i32::ANY, 0..1000), ref vec2 in vec(i32::ANY, 0..1000)) { - let mut seq1 = Vector::from_iter(vec1.iter().cloned()); - let seq2 = Vector::from_iter(vec2.iter().cloned()); + let mut seq1 = Vector::::from_iter(vec1.iter().cloned()); + let seq2 = Vector::::from_iter(vec2.iter().cloned()); assert_eq!(seq1.len(), vec1.len()); assert_eq!(seq2.len(), vec2.len()); seq1.append(seq2); @@ -3112,13 +3119,10 @@ impl< } /// Produces an output vector from the input vector using a map function and a key extractor. - pub fn map( - &mut self, - from: &GenericVector, - ) -> GenericVector { + pub fn map(&mut self, from: &Vector) -> Vector { match &from.vector { Inline(next_in) => { - let mut next = GenericVector { + let mut next = Vector { vector: VectorInner::Inline(InlineArray::new()), }; @@ -3142,7 +3146,7 @@ impl< Inline(chunk) => self.previous_out = Single(SharedPointer::new(chunk.into())), Single(_) => (), Full(_) => { - let mut next = GenericVector { + let mut next = Vector { vector: VectorInner::Single(SharedPointer::new(Chunk::new())), }; Self::map_next_in( @@ -3177,12 +3181,12 @@ impl< &mut self.f, ); - GenericVector { + Vector { vector: VectorInner::Single(inner), } } Inline(_) | Full(_) => { - let mut next = GenericVector { + let mut next = Vector { vector: VectorInner::Single(SharedPointer::new(Chunk::new())), }; Self::map_next_in( @@ -3201,7 +3205,7 @@ impl< } } } - Full(rrb) => GenericVector { + Full(rrb) => Vector { vector: VectorInner::Full(self.map_with_key_internal(rrb)), }, } @@ -3336,7 +3340,7 @@ impl T, P: SharedPointerKind, const CHUNK_SIZE: usiz } /// Produces an output value from the input vector using a fold operation - pub fn fold(&mut self, from: &GenericVector) -> Option { + pub fn fold(&mut self, from: &Vector) -> Option { match &from.vector { Inline(chunk) => { if chunk.is_empty() { @@ -3452,7 +3456,7 @@ fn test_vector_map_ref() { #[test] fn test_vector_map_big() { const COUNT: usize = 10000; - let mut a = Vector::from_iter((0..COUNT).map(|i| i as i64)); + let mut a = Vector::::from_iter((0..COUNT).map(|i| i as i64)); let mut mutation_count = 0; let len = { @@ -3498,7 +3502,7 @@ fn test_vector_fold_big() { const COUNT: usize = 10000; const BASE: i64 = (COUNT * (COUNT + 1) / 2) as i64; - let mut a = Vector::from_iter((1..=COUNT).map(|i| i as i64)); + let mut a = Vector::::from_iter((1..=COUNT).map(|i| i as i64)); let mut mutation_count = 0; let mut fold = PersistentFold::::new(|l, r| { diff --git a/src/vector/rayon.rs b/src/vector/rayon.rs index 05fde43..3a4c59c 100644 --- a/src/vector/rayon.rs +++ b/src/vector/rayon.rs @@ -9,7 +9,7 @@ use ::rayon::iter::{ }; impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> IntoParallelRefIterator<'a> - for GenericVector + for Vector where A: Clone + Send + Sync + 'a, P: SharedPointerKind + Send + 'a, @@ -25,7 +25,7 @@ where } impl<'a, A, P, const CHUNK_SIZE: usize> IntoParallelRefMutIterator<'a> - for GenericVector + for Vector where A: Clone + Send + Sync + 'a, P: SharedPointerKind + Send + Sync + 'a, From a38dcb3acb09ba307b00cd813289b290d74843ce Mon Sep 17 00:00:00 2001 From: Erik McClure Date: Wed, 4 Mar 2026 07:09:45 -0800 Subject: [PATCH 12/12] clippy + fmt fixes --- .github/workflows/ci.yml | 4 ++-- benches/hashmap.rs | 2 +- benches/ordmap.rs | 2 +- src/nodes/btree.rs | 43 ++++++++++++++++++++-------------------- src/nodes/hamt.rs | 3 ++- src/nodes/rrb.rs | 30 ++++++++++++++-------------- src/ord/map.rs | 17 ++++++++-------- src/vector/focus.rs | 3 +-- src/vector/mod.rs | 6 +++--- src/vector/rayon.rs | 5 ++--- 10 files changed, 57 insertions(+), 58 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4527d69..d7d9404 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: strategy: fail-fast: false matrix: - rust: [stable, beta, nightly, 1.85] + rust: [stable, beta, nightly, 1.89] os: [ubuntu-latest, windows-latest, macOS-latest] steps: @@ -52,7 +52,7 @@ jobs: strategy: fail-fast: false matrix: - rust: [stable, beta, nightly, 1.85] + rust: [stable, beta, nightly, 1.89] os: [ubuntu-latest] steps: diff --git a/benches/hashmap.rs b/benches/hashmap.rs index 8cca49e..dd2d603 100644 --- a/benches/hashmap.rs +++ b/benches/hashmap.rs @@ -1,4 +1,4 @@ -use criterion::{criterion_group, criterion_main, Bencher, Criterion}; +use criterion::{Bencher, Criterion, criterion_group, criterion_main}; use imbl::hashmap::HashMap; use std::borrow::Borrow; use std::collections::HashMap as StdHashMap; diff --git a/benches/ordmap.rs b/benches/ordmap.rs index f126811..3ff8431 100644 --- a/benches/ordmap.rs +++ b/benches/ordmap.rs @@ -1,4 +1,4 @@ -use criterion::{criterion_group, criterion_main, Bencher, Criterion}; +use criterion::{Bencher, Criterion, criterion_group, criterion_main}; use equivalent::Comparable; use imbl::ordmap::OrdMap; use std::borrow::Borrow; diff --git a/src/nodes/btree.rs b/src/nodes/btree.rs index 0cfa07f..99c00fc 100644 --- a/src/nodes/btree.rs +++ b/src/nodes/btree.rs @@ -973,11 +973,12 @@ impl<'a, K, V, P: SharedPointerKind> Iter<'a, K, V, P> { // Check if the cursors are exhausted by checking their leaves // This is valid even if the cursors are empty due to not being initialized yet. // If they were empty because exhaustion we would not be in this function. - if let (Some((fi, f)), Some((bi, b))) = (self.fwd.leaf, self.bwd.leaf) { - if std::ptr::eq(f, b) && fi >= bi { - self.exhausted = true; - return fi == bi && other_side_yielded; - } + if let (Some((fi, f)), Some((bi, b))) = (self.fwd.leaf, self.bwd.leaf) + && std::ptr::eq(f, b) + && fi >= bi + { + self.exhausted = true; + return fi == bi && other_side_yielded; } false } @@ -1192,22 +1193,22 @@ impl<'a, K, V, P: SharedPointerKind> Cursor<'a, K, V, P> { let mut skipped_any = false; debug_assert!(self.leaf.is_some()); debug_assert!(other.leaf.is_some()); - if let (Some(this), Some(that)) = (self.leaf, other.leaf) { - if std::ptr::eq(this.1, that.1) { - self.leaf = None; - other.leaf = None; - skipped_any = true; - let shared_levels = self - .stack - .iter() - .rev() - .zip(other.stack.iter().rev()) - .take_while(|(this, that)| std::ptr::eq(this.1, that.1)) - .count(); - if shared_levels != 0 { - self.stack.drain(self.stack.len() - shared_levels..); - other.stack.drain(other.stack.len() - shared_levels..); - } + if let (Some(this), Some(that)) = (self.leaf, other.leaf) + && std::ptr::eq(this.1, that.1) + { + self.leaf = None; + other.leaf = None; + skipped_any = true; + let shared_levels = self + .stack + .iter() + .rev() + .zip(other.stack.iter().rev()) + .take_while(|(this, that)| std::ptr::eq(this.1, that.1)) + .count(); + if shared_levels != 0 { + self.stack.drain(self.stack.len() - shared_levels..); + other.stack.drain(other.stack.len() - shared_levels..); } } self.next(); diff --git a/src/nodes/hamt.rs b/src/nodes/hamt.rs index 4e07fdb..c441295 100644 --- a/src/nodes/hamt.rs +++ b/src/nodes/hamt.rs @@ -739,6 +739,7 @@ impl Node { /// An allocation-free stack for iterators. type InlineStack = InlineArray; +#[allow(clippy::enum_variant_names)] enum IterItem<'a, A, P: SharedPointerKind> { SmallSimdNode(ChunkIter<'a, (A, HashBits), SMALL_NODE_WIDTH>), LargeSimdNode(ChunkIter<'a, (A, HashBits), HASH_WIDTH>), @@ -859,7 +860,7 @@ impl<'a, A, P: SharedPointerKind> ExactSizeIterator for Iter<'a, A, P> where A: impl<'a, A, P: SharedPointerKind> FusedIterator for Iter<'a, A, P> where A: 'a {} // Mut ref iterator - +#[allow(clippy::enum_variant_names)] enum IterMutItem<'a, A, P: SharedPointerKind> { SmallSimdNode(ChunkIterMut<'a, (A, HashBits), SMALL_NODE_WIDTH>), LargeSimdNode(ChunkIterMut<'a, (A, HashBits), HASH_WIDTH>), diff --git a/src/nodes/rrb.rs b/src/nodes/rrb.rs index 0d8935f..5ea8bd7 100644 --- a/src/nodes/rrb.rs +++ b/src/nodes/rrb.rs @@ -738,12 +738,12 @@ impl Node Node { - if side == Left && chunk_size < NODE_SIZE { - if let Entry::Nodes(ref mut size, _) = self.children { - if let Size::Size(value) = *size { - *size = Size::table_from_size(level, value); - } - } + if side == Left + && chunk_size < NODE_SIZE + && let Entry::Nodes(ref mut size, _) = self.children + && let Size::Size(value) = *size + { + *size = Size::table_from_size(level, value); } self.push_size(side, level, child.len()); self.push_child_node(side, child); @@ -1288,18 +1288,18 @@ pub(crate) fn fold_subsequence { if let FoldSeqStore::Values(total, ys) = y - && SharedPointer::ptr_eq(&xs, &ys) + && SharedPointer::ptr_eq(xs, &ys) { FoldSeqStore::Values(total, ys) } else if xs.is_empty() { FoldSeqStore::Empty } else { - let result = binary_fold_inner::(&xs, f); + let result = binary_fold_inner::(xs, f); FoldSeqStore::Values(result, xs.clone()) } } (Entry::Nodes(_, children), FoldSeqStore::Nodes(total, old_children, total_children)) => { - if SharedPointer::ptr_eq(&children, &old_children) { + if SharedPointer::ptr_eq(children, &old_children) { FoldSeqStore::Nodes(total, old_children, total_children) } else if children.is_empty() { FoldSeqStore::Empty diff --git a/src/ord/map.rs b/src/ord/map.rs index 8d2a387..a1724b1 100644 --- a/src/ord/map.rs +++ b/src/ord/map.rs @@ -744,15 +744,14 @@ where { let root = self.root.as_mut()?; let mut removed = None; - if root.remove(k, &mut removed) { - if let Node::Branch(branch) = root { - if let Some(child) = SharedPointer::make_mut(branch).pop_single_child() { - self.root = Some(child); - } - } - // Note that even if the root leaf is empty, we don't - // drop it, but retain the allocation for future use. - } + if root.remove(k, &mut removed) + && let Node::Branch(branch) = root + && let Some(child) = SharedPointer::make_mut(branch).pop_single_child() + { + self.root = Some(child); + } + // Note that even if the root leaf is empty, we don't + // drop it, but retain the allocation for future use. self.size -= removed.is_some() as usize; removed } diff --git a/src/vector/focus.rs b/src/vector/focus.rs index 6cb73e1..1ad505a 100644 --- a/src/vector/focus.rs +++ b/src/vector/focus.rs @@ -13,9 +13,8 @@ use crate::nodes::chunk::Chunk; use crate::sync::Lock; use crate::util::to_range; use crate::vector::{ - Vector, Iter, IterMut, + Iter, IterMut, RRB, Vector, VectorInner::{Full, Inline, Single}, - RRB, }; fn check_indices(len: usize, indices: &[usize; N]) -> Option<()> { diff --git a/src/vector/mod.rs b/src/vector/mod.rs index a05934d..f414dd3 100644 --- a/src/vector/mod.rs +++ b/src/vector/mod.rs @@ -3346,7 +3346,7 @@ impl T, P: SharedPointerKind, const CHUNK_SIZE: usiz if chunk.is_empty() { None } else { - Some(binary_fold(&chunk, &mut self.f)) + Some(binary_fold(chunk, &mut self.f)) } } Single(chunk) => { @@ -3358,7 +3358,7 @@ impl T, P: SharedPointerKind, const CHUNK_SIZE: usiz self.inner_f = FoldSeqStore::Empty; None } else { - let result = binary_fold(&chunk, &mut self.f); + let result = binary_fold(chunk, &mut self.f); self.inner_f = FoldSeqStore::Values(result.clone(), chunk.clone()); Some(result) } @@ -3380,7 +3380,7 @@ impl T, P: SharedPointerKind, const CHUNK_SIZE: usiz } else if chunk.is_empty() { *old_node = FoldSeqStore::Empty; } else { - let result = binary_fold(&chunk, &mut self.f); + let result = binary_fold(chunk, &mut self.f); *old_node = FoldSeqStore::Values(result.clone(), chunk.clone()); outer.push_back(result); } diff --git a/src/vector/rayon.rs b/src/vector/rayon.rs index 3a4c59c..e96b9e7 100644 --- a/src/vector/rayon.rs +++ b/src/vector/rayon.rs @@ -3,7 +3,7 @@ //! These are only available when using the `rayon` feature flag. use super::*; -use ::rayon::iter::plumbing::{bridge, Consumer, Producer, ProducerCallback, UnindexedConsumer}; +use ::rayon::iter::plumbing::{Consumer, Producer, ProducerCallback, UnindexedConsumer, bridge}; use ::rayon::iter::{ IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator, }; @@ -24,8 +24,7 @@ where } } -impl<'a, A, P, const CHUNK_SIZE: usize> IntoParallelRefMutIterator<'a> - for Vector +impl<'a, A, P, const CHUNK_SIZE: usize> IntoParallelRefMutIterator<'a> for Vector where A: Clone + Send + Sync + 'a, P: SharedPointerKind + Send + Sync + 'a,