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/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 7842959..35f03e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "imbl" -version = "7.0.0" +version = "8.0.0" authors = [ "Bodil Stokke ", "Joe Neeman ", "Arthur Silva ", ] -edition = "2018" +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,16 +42,19 @@ 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 } 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"]} -wide = "0.7" +bincode = { version = "2.0.1", optional = true, default-features = false, features = [ + "alloc", + "std", +] } +wide = "1.1" equivalent = "1.0.2" [dev-dependencies] @@ -59,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/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/benches/utils/mod.rs b/benches/utils/mod.rs index 7a41939..e4ef379 100644 --- a/benches/utils/mod.rs +++ b/benches/utils/mod.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] 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; @@ -13,10 +13,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() @@ -25,12 +25,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); } @@ -48,8 +48,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 f3bfeb4..0821e66 100644 --- a/benches/vector.rs +++ b/benches/vector.rs @@ -1,14 +1,14 @@ -use criterion::{criterion_group, criterion_main, Bencher, Criterion}; -use imbl::vector::Vector; +use criterion::{Bencher, Criterion, criterion_group, criterion_main}; +use imbl::Vector; +use imbl::shared_ptr::DefaultSharedPtr; 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,39 +36,41 @@ 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 Vector +{ 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; @@ -119,13 +121,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 +135,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 +185,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 +196,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 +204,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 +215,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 +225,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 +235,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 +246,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 +257,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 +265,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 +275,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 +284,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 +293,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 +307,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 +322,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 +349,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 +377,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 +405,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/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 f5c4873..462d5ac 100644 --- a/src/hash/map.rs +++ b/src/hash/map.rs @@ -34,8 +34,8 @@ use archery::{SharedPointer, SharedPointerKind}; use equivalent::Equivalent; 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; @@ -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, @@ -1590,7 +1604,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 @@ -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 e24085b..3ead37b 100644 --- a/src/hash/set.rs +++ b/src/hash/set.rs @@ -32,10 +32,10 @@ use std::ops::{Add, Deref, Mul}; use archery::{SharedPointer, SharedPointerKind}; use equivalent::Equivalent; -use crate::nodes::hamt::{hash_key, Drain as NodeDrain, HashValue, Iter as NodeIter, Node}; -use crate::ordset::GenericOrdSet; +use crate::Vector; +use crate::nodes::hamt::{Drain as NodeDrain, HashValue, Iter as NodeIter, Node, hash_key}; +use crate::ordset::OrdSet; use crate::shared_ptr::DefaultSharedPtr; -use crate::GenericVector; /// Construct a set from a sequence of values. /// @@ -47,7 +47,7 @@ use crate::GenericVector; /// # 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,31 +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, @@ -978,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, @@ -989,7 +1001,7 @@ where } } -impl From<&BTreeSet> for GenericHashSet +impl From<&BTreeSet> for HashSet where A: Hash + Eq + Clone, S: BuildHasher + Default + Clone, @@ -1000,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() } } @@ -1051,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()); @@ -1086,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 c7fcb6f..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. @@ -331,6 +331,7 @@ mod config; mod nodes; mod sort; mod sync; +pub use archery; #[macro_use] mod ord; @@ -368,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/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 0679fc1..c441295 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 _) } @@ -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, } } @@ -741,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>), @@ -861,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/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 b2befe1..5ea8bd7 100644 --- a/src/nodes/rrb.rs +++ b/src/nodes/rrb.rs @@ -2,26 +2,25 @@ // 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; use archery::{SharedPointer, SharedPointerKind}; -use crate::nodes::chunk::{Chunk, CHUNK_SIZE}; -use crate::util::clone_ref; +use crate::nodes::chunk::Chunk; use crate::util::Side::{self, Left, Right}; +use crate::util::clone_ref; 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), @@ -30,7 +29,7 @@ impl Clone for Size

{ } } -impl Size

{ +impl Size { fn size(&self) -> usize { match self { Size::Size(s) => *s, @@ -70,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 { @@ -93,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 => { @@ -125,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; @@ -156,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()), @@ -172,33 +174,33 @@ impl Clone for Entry { } } -impl Entry { +impl 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 { + 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> { + 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"), } } @@ -208,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), + Values(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), + Nodes(_, 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"), @@ -240,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(), @@ -252,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; @@ -291,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), }; @@ -436,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), } } @@ -480,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(); @@ -528,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(); @@ -561,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()) } }; @@ -602,9 +604,21 @@ 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 { +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] @@ -621,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(); @@ -637,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), @@ -645,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(), @@ -657,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; } @@ -724,12 +738,12 @@ impl Node { } else if is_full { PushResult::Full(chunk, num_drained) } else { - if side == Left && chunk.len() < 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.len() < 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, chunk.len()); self.push_child_node(side, Node::from_chunk(0, chunk)); @@ -780,12 +794,12 @@ impl Node { PushResult::Done } Some(child) => { - 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); @@ -799,7 +813,7 @@ impl Node { &mut self, level: usize, side: Side, - ) -> PopResult, P>> { + ) -> PopResult, P>> { if self.is_empty() { return PopResult::Empty; } @@ -912,7 +926,7 @@ impl Node { if let Size::Size(value) = *size { *size = Size::table_from_size(level, value); } - let size_table = if let Size::Table(ref mut size_ref) = size { + let size_table = if let Size::Table(size_ref) = size { SharedPointer::make_mut(size_ref) } else { unreachable!() @@ -938,10 +952,10 @@ impl Node { children.drop_right(drop_from); } match size { - Size::Size(ref mut size) if at_last => { + 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; @@ -954,7 +968,7 @@ impl Node { ); } } - Size::Table(ref mut size_ref) => { + 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]; @@ -1104,6 +1118,20 @@ impl Node { Self::merge_rebalance(level, left, merged, right) } } + + pub(crate) fn ptr_eq(&self, rhs: &Self) -> bool { + match (&self.children, &rhs.children) { + (Nodes(lsize, l), Nodes(rsize, r)) => { + SharedPointer::, _>, 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 +1143,211 @@ impl Node { // } // Ok(()) // } + +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 { + if prev_in.ptr_eq(next_in) { + prev_out.clone() + } else { + match &next_in.children { + Entry::Values(xs) => { + let result = Node::from_chunk(level, SharedPointer::new(f(xs, false).unwrap())); + prev_in.process(&mut |chunk| { + f(chunk, true); + }); + result + } + Entry::Nodes(_, children) => { + let Entry::Nodes(_, prev_children) = &prev_in.children else { + let result = Node::parent( + level, + 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") + }; + Node::parent( + level, + Chunk::from_iter( + 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, + ) + }), + ), + ) + } + Entry::Empty => Node::new(), + } + } +} + +fn map_subseq_unpaired( + next_in: &Node, + level: usize, + 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( + level, + Chunk::from_iter( + children + .iter() + .map(|x| map_subseq_unpaired(x, level - 1, f)), + ), + ), + 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 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 +{ + 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], 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 { + // 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, +) -> FoldSeqStore { + match (&input.children, prev_out) { + (Entry::Values(xs), y) => { + if let FoldSeqStore::Values(total, ys) = y + && SharedPointer::ptr_eq(xs, &ys) + { + FoldSeqStore::Values(total, ys) + } else if xs.is_empty() { + FoldSeqStore::Empty + } else { + 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) { + FoldSeqStore::Nodes(total, old_children, total_children) + } else if children.is_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 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 let Some(output) = next_out.get() { + outputs.push_back(output); + nodes.push_back(next_out); + } + } + + 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 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 let Some(output) = next_out.get() { + outputs.push_back(output); + nodes.push_back(next_out); + } + } + + if outputs.is_empty() { + FoldSeqStore::Empty + } else { + FoldSeqStore::Nodes( + binary_fold(&outputs, f), + children.clone(), + SharedPointer::new(nodes), + ) + } + } + (Entry::Empty, _) => FoldSeqStore::Empty, + } +} diff --git a/src/ord/map.rs b/src/ord/map.rs index 807a105..a1724b1 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, @@ -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 } @@ -1296,9 +1295,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 +1330,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 +1340,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 +1379,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), @@ -1533,7 +1532,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 @@ -1547,7 +1546,7 @@ where V: Clone, P: SharedPointerKind, { - map: &'a mut GenericOrdMap, + map: &'a mut OrdMap, key: K, } @@ -1606,7 +1605,7 @@ where V: Clone, P: SharedPointerKind, { - map: &'a mut GenericOrdMap, + map: &'a mut OrdMap, key: K, } @@ -1638,13 +1637,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 +1651,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 +1687,7 @@ where } } -impl Hash for GenericOrdMap +impl Hash for OrdMap where K: Ord + Hash, V: Hash, @@ -1704,39 +1703,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 +1752,7 @@ where } } -impl Extend<(RK, RV)> for GenericOrdMap +impl Extend<(RK, RV)> for OrdMap where K: Ord + Clone + From, V: Clone + From, @@ -1766,7 +1768,7 @@ where } } -impl Index<&Q> for GenericOrdMap +impl Index<&Q> for OrdMap where Q: Comparable + ?Sized, K: Ord, @@ -1781,7 +1783,7 @@ where } } -impl IndexMut<&Q> for GenericOrdMap +impl IndexMut<&Q> for OrdMap where Q: Comparable + ?Sized, K: Ord + Clone, @@ -1796,7 +1798,7 @@ where } } -impl Debug for GenericOrdMap +impl Debug for OrdMap where K: Ord + Debug, V: Debug, @@ -2075,7 +2077,7 @@ where { } -impl FromIterator<(RK, RV)> for GenericOrdMap +impl FromIterator<(RK, RV)> for OrdMap where K: Ord + Clone + From, V: Clone + From, @@ -2085,7 +2087,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 +2095,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 +2108,7 @@ where } } -impl IntoIterator for GenericOrdMap +impl IntoIterator for OrdMap where K: Clone, V: Clone, @@ -2165,13 +2167,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 +2182,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 +2198,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 +2225,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 +2253,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 +2280,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 +2295,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 +2308,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 +2633,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 +2845,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 d8ba69d..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 @@ -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 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 { +impl Serialize + for Vector +{ fn serialize(&self, ser: S) -> Result where S: Serializer, @@ -253,8 +255,8 @@ impl Serialize 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 proptest::num::i32; use proptest::proptest; diff --git a/src/sort.rs b/src/sort.rs index e500ad6..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) } @@ -20,11 +20,14 @@ 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, + R: Rng, P: SharedPointerKind, { if vector.len() <= 1 { @@ -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/tests/hashset.rs b/src/tests/hashset.rs index 01df2be..9a98809 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)?; } @@ -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/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..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; @@ -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! { @@ -174,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); @@ -184,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); @@ -198,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); @@ -207,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; } @@ -229,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/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/focus.rs b/src/vector/focus.rs index cf577d0..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::{ - GenericVector, Iter, IterMut, + Iter, IterMut, RRB, Vector, VectorInner::{Full, Inline, Single}, - RRB, }; fn check_indices(len: usize, indices: &[usize; N]) -> Option<()> { @@ -97,24 +96,28 @@ 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 { - match &vector.vector { + pub fn new(vector: &'a Vector) -> Self { + 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)), @@ -249,19 +252,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, { @@ -273,10 +277,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, @@ -287,10 +291,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 { @@ -303,17 +307,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 { @@ -396,7 +406,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 } } @@ -489,16 +499,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, { @@ -604,7 +614,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 { @@ -621,12 +631,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 Vector) -> Self { match &mut vector.vector { Inline(chunk) => FocusMut::Single(chunk), Single(chunk) => FocusMut::Single(SharedPointer::make_mut(chunk).as_mut_slice()), @@ -782,34 +792,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, @@ -822,15 +834,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 { @@ -894,16 +906,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 8c15725..f414dd3 100644 --- a/src/vector/mod.rs +++ b/src/vector/mod.rs @@ -57,11 +57,13 @@ 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::rrb::{Node, PopResult, PushResult, SplitResult}; +use crate::nodes::chunk::Chunk; +use crate::nodes::rrb::{ + FoldSeqStore, Node, PopResult, PushResult, SplitResult, binary_fold, fold_subsequence, +}; 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}; @@ -107,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 @@ -149,28 +145,46 @@ 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 Vector< + A, + P: SharedPointerKind = DefaultSharedPtr, + const CHUNK_SIZE: usize = { crate::config::VECTOR_CHUNK_SIZE }, +> { + 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>, } -impl Clone for RRB { +fn rrb_from_chunk( + chunk: SharedPointer, P>, +) -> 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 { length: self.length, @@ -184,7 +198,31 @@ impl Clone for RRB { } } -impl 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 { @@ -213,15 +251,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, } @@ -248,9 +278,8 @@ impl GenericVector { } } - /// Construct an empty vector. - #[must_use] - pub fn new() -> 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()), } @@ -300,7 +329,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. @@ -334,9 +363,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) } @@ -364,7 +393,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) } @@ -379,7 +408,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) } @@ -390,8 +419,8 @@ impl GenericVector { /// [Focus]: enum.Focus.html #[inline] #[must_use] - pub fn focus(&self) -> Focus<'_, A, P> { - Focus::new(self) + pub fn focus(&self) -> Focus<'_, A, P, CHUNK_SIZE> { + Focus::new_inner(&self.vector) } /// Get a reference to the value at index `index` in a vector. @@ -649,7 +678,7 @@ impl GenericVector { /// ``` /// # #[macro_use] extern crate imbl; /// # use imbl::Vector; - /// let vec = Vector::unit(1337); + /// let vec = Vector::<_>::unit(1337); /// assert_eq!(1, vec.len()); /// assert_eq!( /// vec.get(0), @@ -659,7 +688,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 { @@ -700,7 +729,7 @@ impl GenericVector { } } -impl GenericVector { +impl Vector { /// Get a mutable reference to the value at index `index` in a /// vector. /// @@ -795,7 +824,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) } @@ -804,7 +833,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) } @@ -819,7 +848,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) } @@ -1007,7 +1036,7 @@ impl GenericVector { Inline(_) => 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; } @@ -1300,7 +1329,7 @@ impl GenericVector { pub fn skip(&self, count: usize) -> 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) @@ -1347,7 +1376,7 @@ impl GenericVector { { let r = to_range(&range, self.len()); if r.start >= 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); @@ -1585,7 +1614,7 @@ impl GenericVector { // Implementation details -impl RRB { +impl RRB { fn new() -> Self { RRB { length: 0, @@ -1608,7 +1637,7 @@ impl RRB { } } -impl RRB { +impl RRB { fn prune(&mut self) { if self.middle.is_empty() { self.middle = SharedPointer::new(Node::new()); @@ -1698,7 +1727,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; } @@ -1722,7 +1751,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) { @@ -1748,13 +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. @@ -1769,7 +1800,7 @@ impl Clone for GenericVector { } } -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 { @@ -1783,27 +1814,31 @@ impl Debug for GenericVector { } } -impl PartialEq for GenericVector { +impl PartialEq + 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 { +impl PartialOrd + 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) @@ -1811,17 +1846,17 @@ impl Hash for GenericVector { } } -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. /// @@ -1832,8 +1867,8 @@ impl Add for GenericVector { } } -impl Add for &GenericVector { - type Output = GenericVector; +impl Add for &Vector { + type Output = Vector; /// Concatenate two vectors. /// @@ -1845,7 +1880,9 @@ impl Add for &GenericVector { } } -impl Extend for GenericVector { +impl Extend + for Vector +{ /// Add values to the end of a vector by consuming an iterator. /// /// Time: O(n) @@ -1859,7 +1896,7 @@ impl Extend for GenericVector { } } -impl Index for GenericVector { +impl Index for Vector { type Output = A; /// Get a reference to the value at index `index` in the vector. /// @@ -1876,7 +1913,9 @@ impl Index for GenericVector { } } -impl IndexMut for GenericVector { +impl IndexMut + for Vector +{ /// Get a mutable reference to the value at index `index` in the /// vector. /// @@ -1891,31 +1930,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 Vector +{ 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 Vector +{ 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 Vector +{ 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 Vector +{ /// Create a vector from an iterator. /// /// Time: O(n) @@ -1923,7 +1970,7 @@ impl FromIterator for GenericVector { where I: IntoIterator, { - let mut seq = Self::new(); + let mut seq = Self::with_kind_and_size(); for item in iter { seq.push_back(item) } @@ -1931,19 +1978,21 @@ impl FromIterator for GenericVector { } } -impl From<&GenericVector<&A, P2>> 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>) -> Self { + fn from(vec: &Vector<&A, P2, CHUNK_SIZE>) -> Self { vec.iter().map(|a| (*a).to_owned()).collect() } } -impl From<[A; N]> for GenericVector +impl From<[A; N]> + for Vector where A: Clone, { @@ -1952,13 +2001,17 @@ where } } -impl From<&[A]> for GenericVector { +impl From<&[A]> + for Vector +{ fn from(slice: &[A]) -> Self { slice.iter().cloned().collect() } } -impl From> for GenericVector { +impl From> + for Vector +{ /// Create a vector from a [`std::vec::Vec`][vec]. /// /// Time: O(n) @@ -1969,7 +2022,9 @@ impl From> for GenericVector { } } -impl From<&Vec> for GenericVector { +impl From<&Vec> + for Vector +{ /// Create a vector from a [`std::vec::Vec`][vec]. /// /// Time: O(n) @@ -1989,14 +2044,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 Vector) -> Self { Iter { focus: seq.focus(), front_index: 0, @@ -2004,7 +2059,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(), @@ -2013,7 +2068,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(), @@ -2023,7 +2078,17 @@ impl Clone for Iter<'_, A, P> { } } -impl<'a, A, P: SharedPointerKind + 'a> Iterator for Iter<'a, 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, const CHUNK_SIZE: usize> Iterator + for Iter<'a, A, P, CHUNK_SIZE> +{ type Item = &'a A; /// Advance the iterator and return the next value. @@ -2033,7 +2098,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 @@ -2045,7 +2111,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)* @@ -2054,28 +2122,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(), @@ -2084,8 +2159,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 Vector) -> Self { let focus = seq.focus_mut(); let len = focus.len(); IterMut { @@ -2096,7 +2171,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, { @@ -2109,7 +2185,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 @@ -2121,7 +2198,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, { @@ -2133,27 +2211,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: Vector, } -impl ConsumingIter { - fn new(vector: GenericVector) -> Self { +impl ConsumingIter { + fn new(vector: Vector) -> Self { Self { vector } } } -impl Iterator for ConsumingIter { +impl Iterator + for ConsumingIter +{ type Item = A; /// Advance the iterator and return the next value. @@ -2169,7 +2256,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)* @@ -2178,23 +2267,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 Vector) -> Self { Chunks { focus: seq.focus(), front_index: 0, @@ -2203,7 +2298,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. @@ -2213,14 +2310,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)* @@ -2229,28 +2329,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 Vector) -> Self { let len = seq.len(); ChunksMut { focus: seq.focus_mut(), @@ -2260,7 +2364,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. @@ -2270,14 +2376,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)* @@ -2286,14 +2395,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"))] @@ -2345,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 { @@ -2366,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); } @@ -2403,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(); @@ -2417,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(); @@ -2435,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)); } @@ -2445,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; } @@ -2459,18 +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 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 = Vector::::new(); for _ in 0..262 { x.push_back(0); } @@ -2510,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; } @@ -2527,12 +2637,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 = Vector::::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 @@ -2541,7 +2651,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 @@ -2550,11 +2660,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() ); } @@ -2605,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; @@ -2626,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()); } @@ -2661,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(_))); @@ -2676,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); } @@ -2692,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)] @@ -2705,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() { @@ -2728,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() { @@ -2766,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); @@ -2782,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); @@ -2797,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); @@ -2843,7 +2951,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 { @@ -2914,3 +3022,506 @@ 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< + In, + Out, + Key: Eq + Hash, + P: SharedPointerKind, + F: FnMut(&In) -> Out, + Ex: Fn(&In) -> Key, + const CHUNK_SIZE: usize, +> { + previous_in: VectorInner, + previous_out: VectorInner, + keylookup: std::collections::HashMap, + f: F, + ex: Ex, +} + +impl< + 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 { + Self { + previous_in: Inline(InlineArray::new()), + previous_out: Inline(InlineArray::new()), + keylookup: std::collections::HashMap::new(), + f, + ex, + } + } + + 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; + } + } + } + } + + 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, from: &Vector) -> Vector { + match &from.vector { + Inline(next_in) => { + let mut next = Vector { + vector: VectorInner::Inline(InlineArray::new()), + }; + + Self::map_next_in( + &mut self.keylookup, + next_in.iter(), + &self.ex, + &mut self.f, + |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, + ); + self.previous_in = VectorInner::Inline(next_in.clone()); + next + } + Single(next_in) => { + match &mut self.previous_out { + Inline(chunk) => self.previous_out = Single(SharedPointer::new(chunk.into())), + Single(_) => (), + Full(_) => { + let mut next = Vector { + vector: VectorInner::Single(SharedPointer::new(Chunk::new())), + }; + Self::map_next_in( + &mut self.keylookup, + next_in.iter(), + &self.ex, + &mut self.f, + |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 next; + } + } + + match &self.previous_in { + Single(prev_in) => { + let (VectorInner::Single(prev_out), keylookup) = + (&self.previous_out, &mut self.keylookup) + else { + panic!("invalid internal state"); + }; + let inner = Self::map_chunk( + prev_in, + next_in, + prev_out, + keylookup, + &self.ex, + &mut self.f, + ); + + Vector { + vector: VectorInner::Single(inner), + } + } + Inline(_) | Full(_) => { + let mut next = Vector { + vector: VectorInner::Single(SharedPointer::new(Chunk::new())), + }; + Self::map_next_in( + &mut self.keylookup, + next_in.iter(), + &self.ex, + &mut self.f, + |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, + ); + next + } + } + } + Full(rrb) => Vector { + vector: VectorInner::Full(self.map_with_key_internal(rrb)), + }, + } + } + + fn map_with_key_internal( + &mut self, + next_in: &RRB, + ) -> RRB { + use crate::nodes::rrb::map_subsequence; + + match &mut self.previous_in { + Inline(chunk) => { + self.previous_in = + VectorInner::Full(rrb_from_chunk(SharedPointer::new(chunk.into()))) + } + Single(chunk) => self.previous_in = VectorInner::Full(rrb_from_chunk(chunk.clone())), + Full(_) => (), + } + + match &mut self.previous_out { + Inline(chunk) => { + self.previous_out = + VectorInner::Full(rrb_from_chunk(SharedPointer::new(chunk.into()))) + } + Single(chunk) => self.previous_out = VectorInner::Full(rrb_from_chunk(chunk.clone())), + Full(_) => (), + } + + 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"); + }; + + let outer_f = Self::map_chunk( + &prev_in.outer_f, + &next_in.outer_f, + &prev_out.outer_f, + keylookup, + ex, + ma, + ); + let inner_f = Self::map_chunk( + &prev_in.inner_f, + &next_in.inner_f, + &prev_out.inner_f, + keylookup, + ex, + ma, + ); + let inner_b = Self::map_chunk( + &prev_in.inner_b, + &next_in.inner_b, + &prev_out.inner_b, + keylookup, + ex, + ma, + ); + let outer_b = Self::map_chunk( + &prev_in.outer_b, + &next_in.outer_b, + &prev_out.outer_b, + keylookup, + ex, + ma, + ); + + let middle = map_subsequence( + &prev_in.middle, + &next_in.middle, + next_in.middle_level, + &prev_out.middle, + &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, ma, |item| { + chunk.push_back(item.clone()) + }); + Some(chunk) + } + }, + ); + + 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, + }; + + self.previous_in = VectorInner::Full(next_in.clone()); + self.previous_out = VectorInner::Full(next_out.clone()); + + next_out + } +} + +/// The function must be Associative, meaning `f(f(a, b), c) == f(a, f(b, c))`, but doesn't need to be Commutative. +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, +} + +impl T, P: SharedPointerKind, const CHUNK_SIZE: usize> + PersistentFold +{ + /// Initializes a new empty fold state + pub fn new(f: F) -> Self { + Self { + outer_f: FoldSeqStore::Empty, + inner_f: FoldSeqStore::Empty, + middle: FoldSeqStore::Empty, + inner_b: FoldSeqStore::Empty, + outer_b: FoldSeqStore::Empty, + f, + } + } + + /// Produces an output value from the input vector using a fold operation + pub fn fold(&mut self, from: &Vector) -> Option { + match &from.vector { + 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) + { + Some(v.clone()) + } else if chunk.is_empty() { + self.inner_f = FoldSeqStore::Empty; + None + } else { + let result = binary_fold(chunk, &mut self.f); + self.inner_f = FoldSeqStore::Values(result.clone(), chunk.clone()); + Some(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.is_empty() { + outer.push_back(v.clone()); + } + } else if chunk.is_empty() { + *old_node = FoldSeqStore::Empty; + } else { + let result = binary_fold(chunk, &mut self.f); + *old_node = FoldSeqStore::Values(result.clone(), chunk.clone()); + outer.push_back(result); + } + } + let mut middle = FoldSeqStore::Empty; + std::mem::swap(&mut self.middle, &mut middle); + let mut new_middle = fold_subsequence(&rrb.middle, middle, &mut self.f); + std::mem::swap(&mut self.middle, &mut new_middle); + if let Some(v) = self.middle.get() { + outer.push_back(v); + } + + if outer.is_empty() { + None + } else { + Some(binary_fold(&outer, &mut self.f)) + } + } + } + } +} + +#[test] +fn test_vector_map_basic() { + let a = vector![1, 2, 3, 4]; + + let mut map = PersistentMap::::new(|x| *x * *x, |x| *x); + + 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_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; + let mut a = Vector::::from_iter((0..COUNT).map(|i| i as i64)); + let mut mutation_count = 0; + + let len = { + let mut map = PersistentMap::::new( + |x| { + mutation_count += 1; + *x + 1 + }, + |x| *x as usize, + ); + + 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); +} + +#[test] +fn test_vector_fold_basic() { + let a = vector![1, 2, 3, 4]; + + let mut fold = PersistentFold::::new(|l, r| l + r); + + 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] +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 + }); + + let mut b = fold.fold(&a); + assert_eq!(b, Some(BASE)); + + for i in 0..COUNT { + a[i] += 1; + b = fold.fold(&a); + 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. + 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); +} diff --git a/src/vector/rayon.rs b/src/vector/rayon.rs index 6663c85..e96b9e7 100644 --- a/src/vector/rayon.rs +++ b/src/vector/rayon.rs @@ -3,18 +3,19 @@ //! 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, }; -impl<'a, A, P: SharedPointerKind> IntoParallelRefIterator<'a> for GenericVector +impl<'a, A, P: SharedPointerKind, const CHUNK_SIZE: usize> IntoParallelRefIterator<'a> + for Vector 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,13 @@ where } } -impl<'a, A, P> IntoParallelRefMutIterator<'a> for GenericVector +impl<'a, A, P, const CHUNK_SIZE: usize> IntoParallelRefMutIterator<'a> for Vector 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 +42,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 +64,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 +91,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 +114,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 +138,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 +167,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()