Bug 2060165 - chore(rust): audit-shim-upgrade itertools 0.14.0 → 0.15.0 r=glandium,supply-chain-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D315997
This commit is contained in:
committed by
egubler@mozilla.com
parent
f6a45b81e4
commit
6c3cf2c215
Generated
+18
-11
@@ -584,7 +584,7 @@ dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools 0.14.0",
|
||||
"itertools 0.14.999",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
@@ -3976,14 +3976,21 @@ dependencies = [
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
dependencies = [
|
||||
"itertools 0.14.0",
|
||||
"itertools 0.14.999",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.14.0"
|
||||
version = "0.14.999"
|
||||
dependencies = [
|
||||
"itertools 0.15.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
||||
checksum = "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
@@ -4928,7 +4935,7 @@ dependencies = [
|
||||
"futures",
|
||||
"getrandom 0.2.999",
|
||||
"hex",
|
||||
"itertools 0.14.0",
|
||||
"itertools 0.14.999",
|
||||
"maybe-async",
|
||||
"mls-rs-codec",
|
||||
"mls-rs-core",
|
||||
@@ -4950,7 +4957,7 @@ version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45bd834f164dc06c1fed805540ae307a460b7ed7c2769a35a376f1de577a0dc1"
|
||||
dependencies = [
|
||||
"itertools 0.14.0",
|
||||
"itertools 0.14.999",
|
||||
"mls-rs-codec-derive",
|
||||
"thiserror 2.0.12",
|
||||
"wasm-bindgen",
|
||||
@@ -5228,7 +5235,7 @@ dependencies = [
|
||||
"icu_properties",
|
||||
"idna",
|
||||
"indexmap",
|
||||
"itertools 0.14.0",
|
||||
"itertools 0.15.0",
|
||||
"libc",
|
||||
"log",
|
||||
"memchr",
|
||||
@@ -5590,7 +5597,7 @@ dependencies = [
|
||||
"glob",
|
||||
"heck",
|
||||
"icu_segmenter",
|
||||
"itertools 0.14.0",
|
||||
"itertools 0.14.999",
|
||||
"lazy_static",
|
||||
"mozilla-central-workspace-hack",
|
||||
"regex",
|
||||
@@ -6548,7 +6555,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.14.0",
|
||||
"itertools 0.14.999",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
@@ -7727,7 +7734,7 @@ dependencies = [
|
||||
"gecko-profiler",
|
||||
"icu_segmenter",
|
||||
"indexmap",
|
||||
"itertools 0.14.0",
|
||||
"itertools 0.14.999",
|
||||
"itoa",
|
||||
"log",
|
||||
"malloc_size_of",
|
||||
@@ -7823,7 +7830,7 @@ dependencies = [
|
||||
"icu_normalizer",
|
||||
"icu_properties",
|
||||
"interrupt-support",
|
||||
"itertools 0.14.0",
|
||||
"itertools 0.14.999",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"rc_crypto",
|
||||
|
||||
+5
-2
@@ -266,8 +266,11 @@ base64_21 = { package = "base64", path = "build/rust/base64" }
|
||||
# Patch wasi 0.11 to 0.14
|
||||
wasi_0_11 = { package = "wasi", path = "build/rust/wasi" }
|
||||
|
||||
# Patch itertools 0.13 to 0.14
|
||||
itertools = { path = "build/rust/itertools" }
|
||||
# Patch itertools 0.13 to 0.15
|
||||
itertools_0_13 = { package = "itertools", path = "build/rust/itertools-0.13" }
|
||||
|
||||
# Patch itertools 0.14 to 0.15
|
||||
itertools_0_14 = { package = "itertools", path = "build/rust/itertools" }
|
||||
|
||||
# tokio 0.29.0 includes an experimental "tracing" feature which requires
|
||||
# backtrace ^0.3.58 and the `tokio_unstable` flag. We don't use it, and nothing
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
edition = "2018"
|
||||
license = "MPL2.0"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies.itertools]
|
||||
version = "0.14"
|
||||
@@ -0,0 +1,5 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
pub use itertools::*;
|
||||
@@ -1,11 +1,17 @@
|
||||
[package]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
version = "0.14.999"
|
||||
edition = "2018"
|
||||
license = "MPL2.0"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[features]
|
||||
default = ["itertools/default"]
|
||||
use_alloc = ["itertools/use_alloc"]
|
||||
use_std = ["itertools/use_std"]
|
||||
|
||||
[dependencies.itertools]
|
||||
version = "0.14"
|
||||
version = "0.15"
|
||||
default-features = false
|
||||
|
||||
@@ -87,7 +87,7 @@ scopeguard = { version = "1", optional = true }
|
||||
[build-dependencies]
|
||||
bindgen = { version = "0.69", default-features = false, features = ["runtime"], optional = true }
|
||||
cc = { version = "1.0", features = ["parallel"], optional = true }
|
||||
itertools = { version = "0.14", default-features = false, features = ["use_alloc"], optional = true }
|
||||
itertools = { version = "0.15", default-features = false, features = ["use_alloc"], optional = true }
|
||||
libc = "0.2"
|
||||
log = { version = "0.4", features = ["std"], optional = true }
|
||||
memchr = { version = "2", optional = true }
|
||||
|
||||
@@ -4105,6 +4105,11 @@ who = "Mike Hommey <mh+mozilla@glandium.org>"
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "0.10.3 -> 0.10.5"
|
||||
|
||||
[[audits.itertools]]
|
||||
who = "Erich Gubler <erichdongubler@gmail.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "0.14.0 -> 0.15.0"
|
||||
|
||||
[[audits.itoa]]
|
||||
who = "Mike Hommey <mh+mozilla@glandium.org>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"git": {
|
||||
"sha1": "a015a6831525ee1637df747d3f530a627d9741bf"
|
||||
"sha1": "37bd72aa6d58e594711d127b52418ca5e58b6091"
|
||||
},
|
||||
"path_in_vcs": ""
|
||||
}
|
||||
+26
@@ -1,5 +1,31 @@
|
||||
# Changelog
|
||||
|
||||
## 0.15.0
|
||||
|
||||
### Breaking
|
||||
- Restructure `Position` as struct instead of enum (#1042, #1043)
|
||||
- Canonicalize `all_equal_value`'s error type (#1032)
|
||||
|
||||
### Added
|
||||
- Add `*_with_hasher` adaptors (#1007)
|
||||
- Add strip_prefix and strip_prefix_by methods (#1104)
|
||||
|
||||
### Changed
|
||||
- Remove `Clone` bounds from `tuple_combinations` and `array_combinations`(#1011)
|
||||
- `must_use` for `collect_vec` (#1009)
|
||||
- Make `izip!` temporary friendly (#1021)
|
||||
- Add `array_combinations_with_replacement` (#1033)
|
||||
- Implement `Debug` for remaining public types (#1038)
|
||||
- Specialize `ExactlyOneError::count` (#1046)
|
||||
- Implement `PeekingNext` for more types, in particular `vec::IntoIter` (#1059, #1073)
|
||||
- Fix `PadUsing::next_back` (#1082)
|
||||
- Introduce `[circular_]array_windows`, deprecate `tuple_windows` (#1086)
|
||||
- Deprecate `tuple_combinations` (replaced by `array_combinations`) (#1085)
|
||||
|
||||
### Notable Internal Changes
|
||||
- Make `into_group_map` code more idiomatic (#1027)
|
||||
- Fix clippy lints (#1017, #1029, #1076, #1099)
|
||||
|
||||
## 0.14.0
|
||||
|
||||
### Breaking
|
||||
|
||||
+169
-162
@@ -4,9 +4,9 @@ version = 3
|
||||
|
||||
[[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",
|
||||
]
|
||||
@@ -30,9 +30,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.3.0"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
@@ -42,9 +42,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
version = "3.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
@@ -54,9 +54,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "ciborium"
|
||||
@@ -144,9 +144,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.5"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
@@ -163,21 +163,45 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.19"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.2"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.11.0"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
|
||||
checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
@@ -192,12 +216,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.4.1"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
|
||||
checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crunchy",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -236,7 +261,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.14.0"
|
||||
version = "0.15.0"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"either",
|
||||
@@ -248,42 +273,38 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.69"
|
||||
version = "0.3.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
||||
checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-util",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.154"
|
||||
version = "0.2.186"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.2"
|
||||
version = "2.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
||||
checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
@@ -296,15 +317,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
version = "1.21.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
version = "11.1.3"
|
||||
version = "11.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
|
||||
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
@@ -325,10 +346,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c"
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.5"
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45"
|
||||
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"plotters-backend",
|
||||
@@ -339,30 +366,33 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "plotters-backend"
|
||||
version = "0.3.5"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609"
|
||||
checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a"
|
||||
|
||||
[[package]]
|
||||
name = "plotters-svg"
|
||||
version = "0.3.5"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab"
|
||||
checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670"
|
||||
dependencies = [
|
||||
"plotters-backend",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.82"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -379,9 +409,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -429,9 +459,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.10.0"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||
checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
@@ -439,9 +469,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.12.1"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
||||
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
@@ -449,9 +479,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.4"
|
||||
version = "1.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
|
||||
checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -461,9 +491,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.6"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
||||
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -472,15 +502,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.3"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
|
||||
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
name = "rustversion"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
@@ -493,18 +523,28 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.202"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.202"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -513,20 +553,28 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.117"
|
||||
version = "1.0.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
||||
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.63"
|
||||
name = "slab"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704"
|
||||
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -535,9 +583,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.16.1"
|
||||
version = "0.16.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
|
||||
checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
|
||||
|
||||
[[package]]
|
||||
name = "tinytemplate"
|
||||
@@ -551,9 +599,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
@@ -573,34 +621,22 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.92"
|
||||
version = "0.2.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
||||
checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.92"
|
||||
version = "0.2.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
|
||||
checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -608,28 +644,31 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.92"
|
||||
version = "0.2.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||
checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.92"
|
||||
version = "0.2.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
||||
checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.69"
|
||||
version = "0.3.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
|
||||
checksum = "a6430a72df5eb332242960fe84b3002a241163998241eb596d4f739b9757061d"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@@ -653,9 +692,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.8"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
@@ -666,75 +705,43 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.5"
|
||||
name = "zerocopy"
|
||||
version = "0.8.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||
checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.5"
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||
checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.5"
|
||||
name = "zmij"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||
|
||||
+5
-1
@@ -13,7 +13,7 @@
|
||||
edition = "2018"
|
||||
rust-version = "1.63.0"
|
||||
name = "itertools"
|
||||
version = "0.14.0"
|
||||
version = "0.15.0"
|
||||
authors = ["bluss"]
|
||||
build = false
|
||||
autolib = false
|
||||
@@ -61,6 +61,10 @@ path = "examples/iris.rs"
|
||||
name = "adaptors_no_collect"
|
||||
path = "tests/adaptors_no_collect.rs"
|
||||
|
||||
[[test]]
|
||||
name = "arrays"
|
||||
path = "tests/arrays.rs"
|
||||
|
||||
[[test]]
|
||||
name = "flatten_ok"
|
||||
path = "tests/flatten_ok.rs"
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "itertools"
|
||||
version = "0.14.0"
|
||||
version = "0.15.0"
|
||||
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/rust-itertools/itertools"
|
||||
|
||||
Vendored
+1
-1
@@ -8,7 +8,7 @@ How to use with Cargo:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
itertools = "0.14.0"
|
||||
itertools = "0.15.0"
|
||||
```
|
||||
|
||||
How to use in your crate:
|
||||
|
||||
@@ -30,11 +30,42 @@ fn comb_replacement_n10_k10(c: &mut Criterion) {
|
||||
})
|
||||
});
|
||||
}
|
||||
fn array_comb_replacement_n10_k5(c: &mut Criterion) {
|
||||
c.bench_function("array comb replacement n10k5", move |b| {
|
||||
b.iter(|| {
|
||||
for i in (0..10).array_combinations_with_replacement::<5>() {
|
||||
black_box(i);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn array_comb_replacement_n5_k10(c: &mut Criterion) {
|
||||
c.bench_function("array comb replacement n5 k10", move |b| {
|
||||
b.iter(|| {
|
||||
for i in (0..5).array_combinations_with_replacement::<10>() {
|
||||
black_box(i);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn array_comb_replacement_n10_k10(c: &mut Criterion) {
|
||||
c.bench_function("array comb replacement n10 k10", move |b| {
|
||||
b.iter(|| {
|
||||
for i in (0..10).array_combinations_with_replacement::<10>() {
|
||||
black_box(i);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
criterion_group!(
|
||||
benches,
|
||||
comb_replacement_n10_k5,
|
||||
comb_replacement_n5_k10,
|
||||
comb_replacement_n10_k10,
|
||||
array_comb_replacement_n10_k5,
|
||||
array_comb_replacement_n5_k10,
|
||||
array_comb_replacement_n10_k10,
|
||||
);
|
||||
criterion_main!(benches);
|
||||
|
||||
+2
-2
@@ -8,7 +8,7 @@ const fn calc_iters(n: usize) -> usize {
|
||||
}
|
||||
|
||||
fn powerset_n(c: &mut Criterion, n: usize) {
|
||||
let id = format!("powerset {}", n);
|
||||
let id = format!("powerset {n}");
|
||||
c.bench_function(id.as_str(), move |b| {
|
||||
b.iter(|| {
|
||||
for _ in 0..calc_iters(n) {
|
||||
@@ -21,7 +21,7 @@ fn powerset_n(c: &mut Criterion, n: usize) {
|
||||
}
|
||||
|
||||
fn powerset_n_fold(c: &mut Criterion, n: usize) {
|
||||
let id = format!("powerset {} fold", n);
|
||||
let id = format!("powerset {n} fold");
|
||||
c.bench_function(id.as_str(), move |b| {
|
||||
b.iter(|| {
|
||||
for _ in 0..calc_iters(n) {
|
||||
|
||||
+32
-8
@@ -355,29 +355,29 @@ bench_specializations! {
|
||||
}
|
||||
v.iter().copied().update(|x| *x *= 7)
|
||||
}
|
||||
tuple_combinations1 {
|
||||
array_combinations1 {
|
||||
{
|
||||
let v = black_box(vec![0; 1024]);
|
||||
}
|
||||
v.iter().tuple_combinations::<(_,)>()
|
||||
v.iter().array_combinations::<1>()
|
||||
}
|
||||
tuple_combinations2 {
|
||||
array_combinations2 {
|
||||
{
|
||||
let v = black_box(vec![0; 64]);
|
||||
}
|
||||
v.iter().tuple_combinations::<(_, _)>()
|
||||
v.iter().array_combinations::<2>()
|
||||
}
|
||||
tuple_combinations3 {
|
||||
array_combinations3 {
|
||||
{
|
||||
let v = black_box(vec![0; 64]);
|
||||
}
|
||||
v.iter().tuple_combinations::<(_, _, _)>()
|
||||
v.iter().array_combinations::<3>()
|
||||
}
|
||||
tuple_combinations4 {
|
||||
array_combinations4 {
|
||||
{
|
||||
let v = black_box(vec![0; 64]);
|
||||
}
|
||||
v.iter().tuple_combinations::<(_, _, _, _)>()
|
||||
v.iter().array_combinations::<4>()
|
||||
}
|
||||
intersperse {
|
||||
{
|
||||
@@ -441,6 +441,30 @@ bench_specializations! {
|
||||
}
|
||||
v.iter().combinations_with_replacement(4)
|
||||
}
|
||||
array_combinations_with_replacement1 {
|
||||
{
|
||||
let v = black_box(vec![0; 4096]);
|
||||
}
|
||||
v.iter().array_combinations_with_replacement::<1>()
|
||||
}
|
||||
array_combinations_with_replacement2 {
|
||||
{
|
||||
let v = black_box(vec![0; 90]);
|
||||
}
|
||||
v.iter().array_combinations_with_replacement::<2>()
|
||||
}
|
||||
array_combinations_with_replacement3 {
|
||||
{
|
||||
let v = black_box(vec![0; 28]);
|
||||
}
|
||||
v.iter().array_combinations_with_replacement::<3>()
|
||||
}
|
||||
array_combinations_with_replacement4 {
|
||||
{
|
||||
let v = black_box(vec![0; 16]);
|
||||
}
|
||||
v.iter().array_combinations_with_replacement::<4>()
|
||||
}
|
||||
permutations1 {
|
||||
{
|
||||
let v = black_box(vec![0; 1024]);
|
||||
|
||||
+2
-2
@@ -12,8 +12,8 @@ trait IterEx: Iterator {
|
||||
Self: Sized,
|
||||
{
|
||||
let hint = self.size_hint().0;
|
||||
let cap = std::mem::size_of::<usize>() * 8 - hint.leading_zeros() as usize;
|
||||
let mut stack = Vec::with_capacity(cap);
|
||||
let capacity = usize::BITS - hint.leading_zeros();
|
||||
let mut stack = Vec::with_capacity(capacity as usize);
|
||||
self.enumerate().for_each(|(mut i, mut x)| {
|
||||
while (i & 1) != 0 {
|
||||
x = f(stack.pop().unwrap(), x);
|
||||
|
||||
+28
-28
@@ -7,8 +7,8 @@ const N2: usize = 448;
|
||||
const N3: usize = 86;
|
||||
const N4: usize = 41;
|
||||
|
||||
fn tuple_comb_for1(c: &mut Criterion) {
|
||||
c.bench_function("tuple comb for1", move |b| {
|
||||
fn array_comb_for1(c: &mut Criterion) {
|
||||
c.bench_function("array comb for1", move |b| {
|
||||
b.iter(|| {
|
||||
for i in 0..N1 {
|
||||
black_box(i);
|
||||
@@ -17,8 +17,8 @@ fn tuple_comb_for1(c: &mut Criterion) {
|
||||
});
|
||||
}
|
||||
|
||||
fn tuple_comb_for2(c: &mut Criterion) {
|
||||
c.bench_function("tuple comb for2", move |b| {
|
||||
fn array_comb_for2(c: &mut Criterion) {
|
||||
c.bench_function("array comb for2", move |b| {
|
||||
b.iter(|| {
|
||||
for i in 0..N2 {
|
||||
for j in (i + 1)..N2 {
|
||||
@@ -29,8 +29,8 @@ fn tuple_comb_for2(c: &mut Criterion) {
|
||||
});
|
||||
}
|
||||
|
||||
fn tuple_comb_for3(c: &mut Criterion) {
|
||||
c.bench_function("tuple comb for3", move |b| {
|
||||
fn array_comb_for3(c: &mut Criterion) {
|
||||
c.bench_function("array comb for3", move |b| {
|
||||
b.iter(|| {
|
||||
for i in 0..N3 {
|
||||
for j in (i + 1)..N3 {
|
||||
@@ -43,8 +43,8 @@ fn tuple_comb_for3(c: &mut Criterion) {
|
||||
});
|
||||
}
|
||||
|
||||
fn tuple_comb_for4(c: &mut Criterion) {
|
||||
c.bench_function("tuple comb for4", move |b| {
|
||||
fn array_comb_for4(c: &mut Criterion) {
|
||||
c.bench_function("array comb for4", move |b| {
|
||||
b.iter(|| {
|
||||
for i in 0..N4 {
|
||||
for j in (i + 1)..N4 {
|
||||
@@ -59,40 +59,40 @@ fn tuple_comb_for4(c: &mut Criterion) {
|
||||
});
|
||||
}
|
||||
|
||||
fn tuple_comb_c1(c: &mut Criterion) {
|
||||
c.bench_function("tuple comb c1", move |b| {
|
||||
fn array_comb_c1(c: &mut Criterion) {
|
||||
c.bench_function("array comb c1", move |b| {
|
||||
b.iter(|| {
|
||||
for (i,) in (0..N1).tuple_combinations() {
|
||||
for [i] in (0..N1).array_combinations() {
|
||||
black_box(i);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn tuple_comb_c2(c: &mut Criterion) {
|
||||
c.bench_function("tuple comb c2", move |b| {
|
||||
fn array_comb_c2(c: &mut Criterion) {
|
||||
c.bench_function("array comb c2", move |b| {
|
||||
b.iter(|| {
|
||||
for (i, j) in (0..N2).tuple_combinations() {
|
||||
for [i, j] in (0..N2).array_combinations() {
|
||||
black_box(i + j);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn tuple_comb_c3(c: &mut Criterion) {
|
||||
c.bench_function("tuple comb c3", move |b| {
|
||||
fn array_comb_c3(c: &mut Criterion) {
|
||||
c.bench_function("array comb c3", move |b| {
|
||||
b.iter(|| {
|
||||
for (i, j, k) in (0..N3).tuple_combinations() {
|
||||
for [i, j, k] in (0..N3).array_combinations() {
|
||||
black_box(i + j + k);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn tuple_comb_c4(c: &mut Criterion) {
|
||||
c.bench_function("tuple comb c4", move |b| {
|
||||
fn array_comb_c4(c: &mut Criterion) {
|
||||
c.bench_function("array comb c4", move |b| {
|
||||
b.iter(|| {
|
||||
for (i, j, k, l) in (0..N4).tuple_combinations() {
|
||||
for [i, j, k, l] in (0..N4).array_combinations() {
|
||||
black_box(i + j + k + l);
|
||||
}
|
||||
})
|
||||
@@ -101,13 +101,13 @@ fn tuple_comb_c4(c: &mut Criterion) {
|
||||
|
||||
criterion_group!(
|
||||
benches,
|
||||
tuple_comb_for1,
|
||||
tuple_comb_for2,
|
||||
tuple_comb_for3,
|
||||
tuple_comb_for4,
|
||||
tuple_comb_c1,
|
||||
tuple_comb_c2,
|
||||
tuple_comb_c3,
|
||||
tuple_comb_c4,
|
||||
array_comb_for1,
|
||||
array_comb_for2,
|
||||
array_comb_for3,
|
||||
array_comb_for4,
|
||||
array_comb_c1,
|
||||
array_comb_c2,
|
||||
array_comb_c3,
|
||||
array_comb_c4,
|
||||
);
|
||||
criterion_main!(benches);
|
||||
|
||||
+4
-4
@@ -65,7 +65,7 @@ fn main() {
|
||||
});
|
||||
let mut irises = match irises {
|
||||
Err(e) => {
|
||||
println!("Error parsing: {:?}", e);
|
||||
println!("Error parsing: {e:?}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
Ok(data) => data,
|
||||
@@ -99,9 +99,9 @@ fn main() {
|
||||
let n = 30; // plot size
|
||||
let mut plot = vec![' '; n * n];
|
||||
|
||||
// using Itertools::tuple_combinations
|
||||
for (a, b) in (0..4).tuple_combinations() {
|
||||
println!("Column {} vs {}:", a, b);
|
||||
// using Itertools::array_combinations
|
||||
for [a, b] in (0..4).array_combinations() {
|
||||
println!("Column {a} vs {b}:");
|
||||
|
||||
// Clear plot
|
||||
//
|
||||
|
||||
+4
-2
@@ -74,9 +74,9 @@ where
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (low, hi) = size_hint::add_scalar(
|
||||
self.iter.size_hint(),
|
||||
matches!(self.last, Some(Some(_))) as usize,
|
||||
usize::from(matches!(self.last, Some(Some(_)))),
|
||||
);
|
||||
((low > 0) as usize, hi)
|
||||
(usize::from(low > 0), hi)
|
||||
}
|
||||
|
||||
fn fold<Acc, FnAcc>(self, acc: Acc, mut fn_acc: FnAcc) -> Acc
|
||||
@@ -110,8 +110,10 @@ where
|
||||
{
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NoCount;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WithCount;
|
||||
|
||||
pub trait CountItem<T> {
|
||||
|
||||
+7
-7
@@ -300,11 +300,11 @@ where
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
// Not ExactSizeIterator because size may be larger than usize
|
||||
size_hint::add_scalar(self.iter.size_hint(), self.top.is_some() as usize)
|
||||
size_hint::add_scalar(self.iter.size_hint(), usize::from(self.top.is_some()))
|
||||
}
|
||||
|
||||
fn count(self) -> usize {
|
||||
self.iter.count() + (self.top.is_some() as usize)
|
||||
self.iter.count() + usize::from(self.top.is_some())
|
||||
}
|
||||
|
||||
fn last(self) -> Option<Self::Item> {
|
||||
@@ -522,8 +522,8 @@ where
|
||||
debug_fmt_fields!(TakeWhileRef, iter);
|
||||
}
|
||||
|
||||
/// Create a new `TakeWhileRef` from a reference to clonable iterator.
|
||||
pub fn take_while_ref<I, F>(iter: &mut I, f: F) -> TakeWhileRef<I, F>
|
||||
/// Create a new `TakeWhileRef` from a reference to cloneable iterator.
|
||||
pub fn take_while_ref<I, F>(iter: &mut I, f: F) -> TakeWhileRef<'_, I, F>
|
||||
where
|
||||
I: Iterator + Clone,
|
||||
{
|
||||
@@ -626,10 +626,10 @@ pub trait HasCombination<I>: Sized {
|
||||
type Combination: From<I> + Iterator<Item = Self>;
|
||||
}
|
||||
|
||||
/// Create a new `TupleCombinations` from a clonable iterator.
|
||||
/// Create a new `TupleCombinations` from a cloneable iterator.
|
||||
pub fn tuple_combinations<T, I>(iter: I) -> TupleCombinations<I, T>
|
||||
where
|
||||
I: Iterator + Clone,
|
||||
I: Iterator,
|
||||
I::Item: Clone,
|
||||
T: HasCombination<I>,
|
||||
{
|
||||
@@ -992,7 +992,7 @@ fn transpose_result<T, E>(result: Result<Option<T>, E>) -> Option<Result<T, E>>
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `FilterOk` iterator.
|
||||
/// Create a new `FilterMapOk` iterator.
|
||||
pub fn filter_map_ok<I, F, T, U, E>(iter: I, f: F) -> FilterMapOk<I, F>
|
||||
where
|
||||
I: Iterator<Item = Result<T, E>>,
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#[cfg(doc)]
|
||||
use crate::Itertools;
|
||||
#[cfg(feature = "use_std")]
|
||||
use std::error::Error;
|
||||
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
|
||||
|
||||
/// Value returned for the error case of [`Itertools::all_equal_value`].
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct AllEqualValueError<Item>(pub Option<[Item; 2]>);
|
||||
|
||||
impl<Item> Display for AllEqualValueError<Item> {
|
||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||
match self.0 {
|
||||
None => {
|
||||
write!(
|
||||
f,
|
||||
"got zero elements when all elements were expected to be equal"
|
||||
)
|
||||
}
|
||||
Some([_, _]) => {
|
||||
write!(
|
||||
f,
|
||||
"got different elements when all elements were expected to be equal"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "use_std")]
|
||||
impl<Item> Error for AllEqualValueError<Item> where Item: Debug {}
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
use crate::Itertools;
|
||||
use std::iter::Fuse;
|
||||
|
||||
/// An iterator over all contiguous windows of the input iterator,
|
||||
/// producing arrays of a specific size.
|
||||
///
|
||||
/// See [`.array_windows()`](crate::Itertools::array_windows) for more
|
||||
/// information.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ArrayWindows<I, const N: usize>
|
||||
where
|
||||
I: Iterator + Sized,
|
||||
I::Item: Clone,
|
||||
{
|
||||
iter: Fuse<I>,
|
||||
inner: Option<ArrayWindowsInner<I::Item, N>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct ArrayWindowsInner<T: Clone, const N: usize> {
|
||||
// `window` stores the `N` items delivered in the most
|
||||
// recent output window. It is stored in the form of a ring
|
||||
// buffer, with `window_start` identifying the element
|
||||
// that logically comes first.
|
||||
window: [T; N],
|
||||
window_start: usize,
|
||||
}
|
||||
|
||||
impl<T: Clone, const N: usize> ArrayWindowsInner<T, N> {
|
||||
/// Replace the least recent item in `window` with a new
|
||||
/// item.
|
||||
fn add_to_buffer(&mut self, item: T) {
|
||||
if N > 0 {
|
||||
self.window[self.window_start] = item;
|
||||
self.window_start = (self.window_start + 1) % N;
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct an array window to return.
|
||||
fn make_window(&self) -> [T; N] {
|
||||
std::array::from_fn(|i| self.window[(i + self.window_start) % N].clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, const N: usize> Iterator for ArrayWindows<I, N>
|
||||
where
|
||||
I: Iterator + Sized,
|
||||
I::Item: Clone,
|
||||
{
|
||||
type Item = [I::Item; N];
|
||||
|
||||
fn next(&mut self) -> Option<[I::Item; N]> {
|
||||
match &mut self.inner {
|
||||
// Initialisation code, when next() is called for the first time
|
||||
None => match self.iter.next_array() {
|
||||
None => {
|
||||
// The input iterator was completely empty
|
||||
None
|
||||
}
|
||||
Some(buf) => {
|
||||
let inner = ArrayWindowsInner {
|
||||
window: buf,
|
||||
window_start: 0,
|
||||
};
|
||||
let window = inner.make_window();
|
||||
self.inner = Some(inner);
|
||||
Some(window)
|
||||
}
|
||||
},
|
||||
Some(inner) => match self.iter.next() {
|
||||
Some(item) => {
|
||||
inner.add_to_buffer(item);
|
||||
Some(inner.make_window())
|
||||
}
|
||||
None => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn array_windows<I, const N: usize>(iter: I) -> ArrayWindows<I, N>
|
||||
where
|
||||
I: Iterator + Sized,
|
||||
I::Item: Clone,
|
||||
{
|
||||
ArrayWindows {
|
||||
iter: iter.fuse(),
|
||||
inner: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over all windows, wrapping back to the first elements when the
|
||||
/// window would otherwise exceed the length of the iterator, producing arrays
|
||||
/// of a specific size.
|
||||
///
|
||||
/// See [`.circular_array_windows()`](crate::Itertools::circular_array_windows)
|
||||
/// for more information.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CircularArrayWindows<I, const N: usize>
|
||||
where
|
||||
I: Iterator + Sized,
|
||||
I::Item: Clone,
|
||||
{
|
||||
iter: Fuse<I>,
|
||||
inner: Option<CircularArrayWindowsInner<I::Item, N>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct CircularArrayWindowsInner<T: Clone, const N: usize> {
|
||||
// `prefix` stores the first `N` items output from this iterator.
|
||||
// If the input contained fewer than `N` items, then it is filled
|
||||
// with clones of the previous items in a cycle.
|
||||
//
|
||||
// `prefix_pos` tracks the number of items that have been _used_
|
||||
// from `prefix`. It begins counting up from 0 once the input runs
|
||||
// out. (So in the case where the input iterator is shorter than
|
||||
// `N`, it will begin counting up before `prefix` has even been
|
||||
// populated during setup.)
|
||||
prefix: [T; N],
|
||||
prefix_pos: usize,
|
||||
|
||||
// For delivering the output arrays, we reuse `ArrayWindowsInner`
|
||||
// unchanged.
|
||||
arraywin: ArrayWindowsInner<T, N>,
|
||||
}
|
||||
|
||||
impl<I, const N: usize> Iterator for CircularArrayWindows<I, N>
|
||||
where
|
||||
I: Iterator + Sized,
|
||||
I::Item: Clone,
|
||||
{
|
||||
type Item = [I::Item; N];
|
||||
|
||||
fn next(&mut self) -> Option<[I::Item; N]> {
|
||||
match &mut self.inner {
|
||||
// Initialisation code, when next() is called for the first time
|
||||
None => match self.iter.next() {
|
||||
None => {
|
||||
// The input iterator was completely empty
|
||||
None
|
||||
}
|
||||
Some(first) => {
|
||||
// We have at least one item, so we can definitely
|
||||
// populate `prefix` (even if we have to make N
|
||||
// copies of this element).
|
||||
|
||||
// Construct [Option<T>; N] and convert to [T; N]
|
||||
// once it's full. TODO: can this be improved?
|
||||
let mut items = std::array::from_fn(|_| None);
|
||||
let mut prefix_pos = 0;
|
||||
if N > 0 {
|
||||
// The first item stored is the one passed to
|
||||
// us from our caller.
|
||||
items[0] = Some(first);
|
||||
}
|
||||
for i in 1..N {
|
||||
// Populate the remaining slots in `items`
|
||||
// from the input iterator.
|
||||
items[i] = self.iter.next();
|
||||
if items[i].is_none() {
|
||||
// If the input iterator runs out early,
|
||||
// populate the rest of `items` by
|
||||
// recycling from the beginning, and set
|
||||
// `prefix_pos` to indicate that we have
|
||||
// already consumed those items.
|
||||
for j in i..N {
|
||||
items[j] = items[j - i].clone();
|
||||
}
|
||||
prefix_pos = N - i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
let items = items.map(Option::unwrap);
|
||||
|
||||
let inner = CircularArrayWindowsInner {
|
||||
prefix: items.clone(),
|
||||
prefix_pos,
|
||||
arraywin: ArrayWindowsInner {
|
||||
window: items,
|
||||
window_start: 0,
|
||||
},
|
||||
};
|
||||
|
||||
let window = inner.arraywin.make_window();
|
||||
self.inner = Some(inner);
|
||||
Some(window)
|
||||
}
|
||||
},
|
||||
Some(inner) => {
|
||||
// Normal case. Read the next item in the logical
|
||||
// input sequence (consisting of the contents of the
|
||||
// input iterator followed by N-1 items recycling from
|
||||
// the beginning), and add it to the ring buffer.
|
||||
let item = if let Some(item) = self.iter.next() {
|
||||
// Read from the input iterator.
|
||||
item
|
||||
} else {
|
||||
assert!(N == 0 || inner.prefix_pos < N);
|
||||
if N == 0 || inner.prefix_pos + 1 == N {
|
||||
// The input iterator has run out, and we've
|
||||
// emitted as many windows as we read items,
|
||||
// so we've finished.
|
||||
return None;
|
||||
}
|
||||
let item = inner.prefix[inner.prefix_pos].clone();
|
||||
inner.prefix_pos += 1;
|
||||
item
|
||||
};
|
||||
|
||||
inner.arraywin.add_to_buffer(item);
|
||||
Some(inner.arraywin.make_window())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn circular_array_windows<I, const N: usize>(iter: I) -> CircularArrayWindows<I, N>
|
||||
where
|
||||
I: Iterator + Sized,
|
||||
I::Item: Clone,
|
||||
{
|
||||
CircularArrayWindows {
|
||||
iter: iter.fuse(),
|
||||
inner: None,
|
||||
}
|
||||
}
|
||||
+12
-2
@@ -1,3 +1,4 @@
|
||||
use alloc::boxed::Box;
|
||||
use core::array;
|
||||
use core::borrow::BorrowMut;
|
||||
use std::fmt;
|
||||
@@ -13,7 +14,7 @@ pub type Combinations<I> = CombinationsGeneric<I, Vec<usize>>;
|
||||
/// Iterator for const generic combinations returned by [`.array_combinations()`](crate::Itertools::array_combinations)
|
||||
pub type ArrayCombinations<I, const K: usize> = CombinationsGeneric<I, [usize; K]>;
|
||||
|
||||
/// Create a new `Combinations` from a clonable iterator.
|
||||
/// Create a new `Combinations` from a cloneable iterator.
|
||||
pub fn combinations<I: Iterator>(iter: I, k: usize) -> Combinations<I>
|
||||
where
|
||||
I::Item: Clone,
|
||||
@@ -21,7 +22,7 @@ where
|
||||
Combinations::new(iter, (0..k).collect())
|
||||
}
|
||||
|
||||
/// Create a new `ArrayCombinations` from a clonable iterator.
|
||||
/// Create a new `ArrayCombinations` from a cloneable iterator.
|
||||
pub fn array_combinations<I: Iterator, const K: usize>(iter: I) -> ArrayCombinations<I, K>
|
||||
where
|
||||
I::Item: Clone,
|
||||
@@ -52,7 +53,16 @@ pub trait PoolIndex<T>: BorrowMut<[usize]> {
|
||||
self.borrow().len()
|
||||
}
|
||||
}
|
||||
impl<T> PoolIndex<T> for Box<[usize]> {
|
||||
type Item = Vec<T>;
|
||||
|
||||
fn extract_item<I: Iterator<Item = T>>(&self, pool: &LazyBuffer<I>) -> Vec<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
pool.get_at(self)
|
||||
}
|
||||
}
|
||||
impl<T> PoolIndex<T> for Vec<usize> {
|
||||
type Item = Vec<T>;
|
||||
|
||||
|
||||
+47
-26
@@ -1,52 +1,62 @@
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use std::fmt;
|
||||
use std::iter::FusedIterator;
|
||||
|
||||
use super::lazy_buffer::LazyBuffer;
|
||||
use crate::adaptors::checked_binomial;
|
||||
|
||||
use crate::combinations::PoolIndex;
|
||||
/// An iterator to iterate through all the `n`-length combinations in an iterator, with replacement.
|
||||
///
|
||||
/// See [`.combinations_with_replacement()`](crate::Itertools::combinations_with_replacement)
|
||||
/// for more information.
|
||||
#[derive(Clone)]
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct CombinationsWithReplacement<I>
|
||||
pub struct CombinationsWithReplacementGeneric<I, Idx>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Clone,
|
||||
{
|
||||
indices: Box<[usize]>,
|
||||
indices: Idx,
|
||||
pool: LazyBuffer<I>,
|
||||
first: bool,
|
||||
}
|
||||
|
||||
impl<I> fmt::Debug for CombinationsWithReplacement<I>
|
||||
/// Iterator for `Box<[I]>` valued combinations_with_replacement returned by [`.combinations_with_replacement()`](crate::Itertools::combinations_with_replacement)
|
||||
pub type CombinationsWithReplacement<I> = CombinationsWithReplacementGeneric<I, Box<[usize]>>;
|
||||
/// Iterator for const generic combinations_with_replacement returned by [`.array_combinations_with_replacement()`](crate::Itertools::array_combinations_with_replacement)
|
||||
pub type ArrayCombinationsWithReplacement<I, const K: usize> =
|
||||
CombinationsWithReplacementGeneric<I, [usize; K]>;
|
||||
|
||||
impl<I, Idx> fmt::Debug for CombinationsWithReplacementGeneric<I, Idx>
|
||||
where
|
||||
I: Iterator + fmt::Debug,
|
||||
I::Item: fmt::Debug + Clone,
|
||||
Idx: fmt::Debug,
|
||||
{
|
||||
debug_fmt_fields!(CombinationsWithReplacement, indices, pool, first);
|
||||
debug_fmt_fields!(CombinationsWithReplacementGeneric, indices, pool, first);
|
||||
}
|
||||
|
||||
/// Create a new `CombinationsWithReplacement` from a clonable iterator.
|
||||
/// Create a new `ArrayCombinationsWithReplacement`` from a cloneable iterator.
|
||||
pub fn array_combinations_with_replacement<I: Iterator, const K: usize>(
|
||||
iter: I,
|
||||
) -> ArrayCombinationsWithReplacement<I, K>
|
||||
where
|
||||
I::Item: Clone,
|
||||
{
|
||||
ArrayCombinationsWithReplacement::new(iter, [0; K])
|
||||
}
|
||||
/// Create a new `CombinationsWithReplacement` from a cloneable iterator.
|
||||
pub fn combinations_with_replacement<I>(iter: I, k: usize) -> CombinationsWithReplacement<I>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Clone,
|
||||
{
|
||||
let indices = alloc::vec![0; k].into_boxed_slice();
|
||||
let pool: LazyBuffer<I> = LazyBuffer::new(iter);
|
||||
|
||||
CombinationsWithReplacement {
|
||||
indices,
|
||||
pool,
|
||||
first: true,
|
||||
}
|
||||
CombinationsWithReplacementGeneric::new(iter, indices)
|
||||
}
|
||||
|
||||
impl<I> CombinationsWithReplacement<I>
|
||||
impl<I: Iterator, Idx: PoolIndex<I::Item>> CombinationsWithReplacementGeneric<I, Idx>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Clone,
|
||||
@@ -62,7 +72,8 @@ where
|
||||
|
||||
// Work out where we need to update our indices
|
||||
let mut increment = None;
|
||||
for (i, indices_int) in self.indices.iter().enumerate().rev() {
|
||||
let indices: &mut [usize] = self.indices.borrow_mut();
|
||||
for (i, indices_int) in indices.iter().enumerate().rev() {
|
||||
if *indices_int < self.pool.len() - 1 {
|
||||
increment = Some((i, indices_int + 1));
|
||||
break;
|
||||
@@ -73,39 +84,48 @@ where
|
||||
Some((increment_from, increment_value)) => {
|
||||
// We need to update the rightmost non-max value
|
||||
// and all those to the right
|
||||
self.indices[increment_from..].fill(increment_value);
|
||||
indices[increment_from..].fill(increment_value);
|
||||
false
|
||||
}
|
||||
// Otherwise, we're done
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
/// Constructor with arguments the inner iterator and the initial state for the indices.
|
||||
fn new(iter: I, indices: Idx) -> Self {
|
||||
Self {
|
||||
indices,
|
||||
pool: LazyBuffer::new(iter),
|
||||
first: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> Iterator for CombinationsWithReplacement<I>
|
||||
impl<I, Idx> Iterator for CombinationsWithReplacementGeneric<I, Idx>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Clone,
|
||||
Idx: PoolIndex<I::Item>,
|
||||
{
|
||||
type Item = Vec<I::Item>;
|
||||
type Item = Idx::Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.first {
|
||||
// In empty edge cases, stop iterating immediately
|
||||
if !(self.indices.is_empty() || self.pool.get_next()) {
|
||||
if !(self.indices.borrow().is_empty() || self.pool.get_next()) {
|
||||
return None;
|
||||
}
|
||||
self.first = false;
|
||||
} else if self.increment_indices() {
|
||||
return None;
|
||||
}
|
||||
Some(self.pool.get_at(&self.indices))
|
||||
Some(self.indices.extract_item(&self.pool))
|
||||
}
|
||||
|
||||
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
||||
if self.first {
|
||||
// In empty edge cases, stop iterating immediately
|
||||
if !(self.indices.is_empty() || self.pool.get_next()) {
|
||||
if !(self.indices.borrow().is_empty() || self.pool.get_next()) {
|
||||
return None;
|
||||
}
|
||||
self.first = false;
|
||||
@@ -117,13 +137,13 @@ where
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(self.pool.get_at(&self.indices))
|
||||
Some(self.indices.extract_item(&self.pool))
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (mut low, mut upp) = self.pool.size_hint();
|
||||
low = remaining_for(low, self.first, &self.indices).unwrap_or(usize::MAX);
|
||||
upp = upp.and_then(|upp| remaining_for(upp, self.first, &self.indices));
|
||||
low = remaining_for(low, self.first, self.indices.borrow()).unwrap_or(usize::MAX);
|
||||
upp = upp.and_then(|upp| remaining_for(upp, self.first, self.indices.borrow()));
|
||||
(low, upp)
|
||||
}
|
||||
|
||||
@@ -134,14 +154,15 @@ where
|
||||
first,
|
||||
} = self;
|
||||
let n = pool.count();
|
||||
remaining_for(n, first, &indices).unwrap()
|
||||
remaining_for(n, first, indices.borrow()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> FusedIterator for CombinationsWithReplacement<I>
|
||||
impl<I, Idx> FusedIterator for CombinationsWithReplacementGeneric<I, Idx>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Clone,
|
||||
Idx: PoolIndex<I::Item>,
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
+37
-19
@@ -1,31 +1,39 @@
|
||||
use core::hash::BuildHasher;
|
||||
use std::collections::hash_map::RandomState;
|
||||
use std::hash::Hash;
|
||||
|
||||
mod private {
|
||||
use core::hash::BuildHasher;
|
||||
use std::collections::hash_map::RandomState;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct DuplicatesBy<I: Iterator, Key, F> {
|
||||
pub struct DuplicatesBy<I: Iterator, Key, F, S = RandomState>
|
||||
where
|
||||
S: BuildHasher,
|
||||
{
|
||||
pub(crate) iter: I,
|
||||
pub(crate) meta: Meta<Key, F>,
|
||||
pub(crate) meta: Meta<Key, F, S>,
|
||||
}
|
||||
|
||||
impl<I, V, F> fmt::Debug for DuplicatesBy<I, V, F>
|
||||
impl<I, V, F, S> fmt::Debug for DuplicatesBy<I, V, F, S>
|
||||
where
|
||||
I: Iterator + fmt::Debug,
|
||||
V: fmt::Debug + Hash + Eq,
|
||||
S: BuildHasher,
|
||||
{
|
||||
debug_fmt_fields!(DuplicatesBy, iter, meta.used);
|
||||
}
|
||||
|
||||
impl<I: Iterator, Key: Eq + Hash, F> DuplicatesBy<I, Key, F> {
|
||||
pub(crate) fn new(iter: I, key_method: F) -> Self {
|
||||
impl<I: Iterator, Key: Eq + Hash, F, S: BuildHasher> DuplicatesBy<I, Key, F, S> {
|
||||
pub(crate) fn new(iter: I, key_method: F, hash_builder: S) -> Self {
|
||||
Self {
|
||||
iter,
|
||||
meta: Meta {
|
||||
used: HashMap::new(),
|
||||
used: HashMap::with_hasher(hash_builder),
|
||||
pending: 0,
|
||||
key_method,
|
||||
},
|
||||
@@ -34,15 +42,16 @@ mod private {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Meta<Key, F> {
|
||||
used: HashMap<Key, bool>,
|
||||
pub struct Meta<Key, F, S> {
|
||||
used: HashMap<Key, bool, S>,
|
||||
pending: usize,
|
||||
key_method: F,
|
||||
}
|
||||
|
||||
impl<Key, F> Meta<Key, F>
|
||||
impl<Key, F, S> Meta<Key, F, S>
|
||||
where
|
||||
Key: Eq + Hash,
|
||||
S: BuildHasher,
|
||||
{
|
||||
/// Takes an item and returns it back to the caller if it's the second time we see it.
|
||||
/// Otherwise the item is consumed and None is returned
|
||||
@@ -68,11 +77,12 @@ mod private {
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, Key, F> Iterator for DuplicatesBy<I, Key, F>
|
||||
impl<I, Key, F, S> Iterator for DuplicatesBy<I, Key, F, S>
|
||||
where
|
||||
I: Iterator,
|
||||
Key: Eq + Hash,
|
||||
F: KeyMethod<Key, I::Item>,
|
||||
S: BuildHasher,
|
||||
{
|
||||
type Item = I::Item;
|
||||
|
||||
@@ -102,11 +112,12 @@ mod private {
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, Key, F> DoubleEndedIterator for DuplicatesBy<I, Key, F>
|
||||
impl<I, Key, F, S> DoubleEndedIterator for DuplicatesBy<I, Key, F, S>
|
||||
where
|
||||
I: DoubleEndedIterator,
|
||||
Key: Eq + Hash,
|
||||
F: KeyMethod<Key, I::Item>,
|
||||
S: BuildHasher,
|
||||
{
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
let Self { iter, meta } = self;
|
||||
@@ -189,28 +200,35 @@ mod private {
|
||||
/// An iterator adapter to filter for duplicate elements.
|
||||
///
|
||||
/// See [`.duplicates_by()`](crate::Itertools::duplicates_by) for more information.
|
||||
pub type DuplicatesBy<I, V, F> = private::DuplicatesBy<I, V, private::ByFn<F>>;
|
||||
pub type DuplicatesBy<I, V, F, S = RandomState> = private::DuplicatesBy<I, V, private::ByFn<F>, S>;
|
||||
|
||||
/// Create a new `DuplicatesBy` iterator.
|
||||
pub fn duplicates_by<I, Key, F>(iter: I, f: F) -> DuplicatesBy<I, Key, F>
|
||||
/// Create a new `DuplicatesBy` iterator with a specified hash builder.
|
||||
pub fn duplicates_by_with_hasher<I, Key, F, S>(
|
||||
iter: I,
|
||||
f: F,
|
||||
hash_builder: S,
|
||||
) -> DuplicatesBy<I, Key, F, S>
|
||||
where
|
||||
Key: Eq + Hash,
|
||||
F: FnMut(&I::Item) -> Key,
|
||||
I: Iterator,
|
||||
S: BuildHasher,
|
||||
{
|
||||
DuplicatesBy::new(iter, private::ByFn(f))
|
||||
DuplicatesBy::new(iter, private::ByFn(f), hash_builder)
|
||||
}
|
||||
|
||||
/// An iterator adapter to filter out duplicate elements.
|
||||
///
|
||||
/// See [`.duplicates()`](crate::Itertools::duplicates) for more information.
|
||||
pub type Duplicates<I> = private::DuplicatesBy<I, <I as Iterator>::Item, private::ById>;
|
||||
pub type Duplicates<I, S = RandomState> =
|
||||
private::DuplicatesBy<I, <I as Iterator>::Item, private::ById, S>;
|
||||
|
||||
/// Create a new `Duplicates` iterator.
|
||||
pub fn duplicates<I>(iter: I) -> Duplicates<I>
|
||||
/// Create a new `Duplicates` iterator with a specified hash builder.
|
||||
pub fn duplicates_with_hasher<I, S>(iter: I, hash_builder: S) -> Duplicates<I, S>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Eq + Hash,
|
||||
S: BuildHasher,
|
||||
{
|
||||
Duplicates::new(iter, private::ById)
|
||||
Duplicates::new(iter, private::ById, hash_builder)
|
||||
}
|
||||
|
||||
+2
-2
@@ -421,7 +421,7 @@ impl<A, B> EitherOrBoth<A, B> {
|
||||
/// // Inserting a second value.
|
||||
/// let mut either = Left("what's");
|
||||
/// assert_eq!(*either.insert_right(9 + 10), 21 - 2);
|
||||
/// assert_eq!(either, Both("what's", 9+10));
|
||||
/// assert_eq!(either, Both("what's", 9 + 10));
|
||||
/// ```
|
||||
pub fn insert_right(&mut self, val: B) -> &mut B {
|
||||
match self {
|
||||
@@ -467,7 +467,7 @@ impl<T> EitherOrBoth<T, T> {
|
||||
/// Return either value of left, right, or apply a function `f` to both values if both are present.
|
||||
/// The input function has to return the same type as both Right and Left carry.
|
||||
///
|
||||
/// This function can be used to preferrably extract the left resp. right value,
|
||||
/// This function can be used to preferably extract the left resp. right value,
|
||||
/// but fall back to the other (i.e. right resp. left) if the preferred one is not present.
|
||||
///
|
||||
/// # Examples
|
||||
|
||||
+10
-1
@@ -8,7 +8,9 @@ use either::Either;
|
||||
|
||||
use crate::size_hint;
|
||||
|
||||
/// Iterator returned for the error case of `Itertools::exactly_one()`
|
||||
/// Iterator returned for the error case of `Itertools`
|
||||
/// [`exactly_one()`](crate::Itertools::exactly_one) and
|
||||
/// [`at_most_one()`](crate::Itertools::at_most_one).
|
||||
/// This iterator yields exactly the same elements as the input iterator.
|
||||
///
|
||||
/// During the execution of `exactly_one` the iterator must be mutated. This wrapper
|
||||
@@ -64,6 +66,13 @@ where
|
||||
size_hint::add_scalar(self.inner.size_hint(), self.additional_len())
|
||||
}
|
||||
|
||||
fn count(self) -> usize
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.additional_len() + self.inner.count()
|
||||
}
|
||||
|
||||
fn fold<B, F>(self, mut init: B, mut f: F) -> B
|
||||
where
|
||||
F: FnMut(B, Self::Item) -> B,
|
||||
|
||||
+4
-4
@@ -119,7 +119,7 @@ where
|
||||
/// for (a, b) in zip(&[1, 2, 3, 4, 5], &['a', 'b', 'c']) {
|
||||
/// result.push((*a, *b));
|
||||
/// }
|
||||
/// assert_eq!(result, vec![(1, 'a'),(2, 'b'),(3, 'c')]);
|
||||
/// assert_eq!(result, vec![(1, 'a'), (2, 'b'), (3, 'c')]);
|
||||
/// ```
|
||||
#[deprecated(
|
||||
note = "Use [std::iter::zip](https://doc.rust-lang.org/std/iter/fn.zip.html) instead",
|
||||
@@ -141,7 +141,7 @@ where
|
||||
/// ```
|
||||
/// use itertools::chain;
|
||||
///
|
||||
/// let mut result:Vec<i32> = Vec::new();
|
||||
/// let mut result: Vec<i32> = Vec::new();
|
||||
///
|
||||
/// for element in chain(&[1, 2, 3], &[4]) {
|
||||
/// result.push(*element);
|
||||
@@ -284,8 +284,8 @@ where
|
||||
/// [`IntoIterator`] enabled version of [`Itertools::sorted`].
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::sorted;
|
||||
/// use itertools::assert_equal;
|
||||
/// use itertools::sorted;
|
||||
///
|
||||
/// assert_equal(sorted("rust".chars()), "rstu".chars());
|
||||
/// ```
|
||||
@@ -304,8 +304,8 @@ where
|
||||
/// [`IntoIterator`] enabled version of [`Itertools::sorted_unstable`].
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::sorted_unstable;
|
||||
/// use itertools::assert_equal;
|
||||
/// use itertools::sorted_unstable;
|
||||
///
|
||||
/// assert_equal(sorted_unstable("rust".chars()), "rstu".chars());
|
||||
/// ```
|
||||
|
||||
+12
-5
@@ -1,5 +1,6 @@
|
||||
#![cfg(feature = "use_std")]
|
||||
|
||||
use core::hash::BuildHasher;
|
||||
use std::collections::HashMap;
|
||||
use std::hash::Hash;
|
||||
use std::iter::Iterator;
|
||||
@@ -8,25 +9,31 @@ use std::iter::Iterator;
|
||||
///
|
||||
/// See [`.into_group_map()`](crate::Itertools::into_group_map)
|
||||
/// for more information.
|
||||
pub fn into_group_map<I, K, V>(iter: I) -> HashMap<K, Vec<V>>
|
||||
pub fn into_group_map_with_hasher<I, K, V, S>(iter: I, hash_builder: S) -> HashMap<K, Vec<V>, S>
|
||||
where
|
||||
I: Iterator<Item = (K, V)>,
|
||||
K: Hash + Eq,
|
||||
S: BuildHasher,
|
||||
{
|
||||
let mut lookup = HashMap::new();
|
||||
let mut lookup = HashMap::<K, Vec<V>, S>::with_hasher(hash_builder);
|
||||
|
||||
iter.for_each(|(key, val)| {
|
||||
lookup.entry(key).or_insert_with(Vec::new).push(val);
|
||||
lookup.entry(key).or_default().push(val);
|
||||
});
|
||||
|
||||
lookup
|
||||
}
|
||||
|
||||
pub fn into_group_map_by<I, K, V, F>(iter: I, mut f: F) -> HashMap<K, Vec<V>>
|
||||
pub fn into_group_map_by_with_hasher<I, K, V, F, S>(
|
||||
iter: I,
|
||||
mut f: F,
|
||||
hash_builder: S,
|
||||
) -> HashMap<K, Vec<V>, S>
|
||||
where
|
||||
I: Iterator<Item = V>,
|
||||
K: Hash + Eq,
|
||||
F: FnMut(&V) -> K,
|
||||
S: BuildHasher,
|
||||
{
|
||||
into_group_map(iter.map(|v| (f(&v), v)))
|
||||
into_group_map_with_hasher(iter.map(|v| (f(&v), v)), hash_builder)
|
||||
}
|
||||
|
||||
+78
-18
@@ -1,5 +1,6 @@
|
||||
use alloc::vec::{self, Vec};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// A trait to unify `FnMut` for `ChunkBy` with the chunk key in `IntoChunks`
|
||||
trait KeyFunction<A> {
|
||||
@@ -76,6 +77,27 @@ where
|
||||
dropped_group: usize,
|
||||
}
|
||||
|
||||
impl<K, I, F> Debug for GroupInner<K, I, F>
|
||||
where
|
||||
K: Debug,
|
||||
I: Iterator + Debug,
|
||||
I::Item: Debug,
|
||||
{
|
||||
debug_fmt_fields!(
|
||||
GroupInner,
|
||||
// key, omitted because functions are almost never Debug
|
||||
iter,
|
||||
current_key,
|
||||
current_elt,
|
||||
done,
|
||||
top_group,
|
||||
oldest_buffered_group,
|
||||
bottom_group,
|
||||
buffer,
|
||||
dropped_group
|
||||
);
|
||||
}
|
||||
|
||||
impl<K, I, F> GroupInner<K, I, F>
|
||||
where
|
||||
I: Iterator,
|
||||
@@ -175,14 +197,11 @@ where
|
||||
|
||||
while let Some(elt) = self.next_element() {
|
||||
let key = self.key.call_mut(&elt);
|
||||
match self.current_key.take() {
|
||||
None => {}
|
||||
Some(old_key) => {
|
||||
if old_key != key {
|
||||
self.current_key = Some(key);
|
||||
first_elt = Some(elt);
|
||||
break;
|
||||
}
|
||||
if let Some(old_key) = self.current_key.take() {
|
||||
if old_key != key {
|
||||
self.current_key = Some(key);
|
||||
first_elt = Some(elt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.current_key = Some(key);
|
||||
@@ -226,15 +245,12 @@ where
|
||||
None => None,
|
||||
Some(elt) => {
|
||||
let key = self.key.call_mut(&elt);
|
||||
match self.current_key.take() {
|
||||
None => {}
|
||||
Some(old_key) => {
|
||||
if old_key != key {
|
||||
self.current_key = Some(key);
|
||||
self.current_elt = Some(elt);
|
||||
self.top_group += 1;
|
||||
return None;
|
||||
}
|
||||
if let Some(old_key) = self.current_key.take() {
|
||||
if old_key != key {
|
||||
self.current_key = Some(key);
|
||||
self.current_elt = Some(elt);
|
||||
self.top_group += 1;
|
||||
return None;
|
||||
}
|
||||
}
|
||||
self.current_key = Some(key);
|
||||
@@ -311,6 +327,15 @@ where
|
||||
index: Cell<usize>,
|
||||
}
|
||||
|
||||
impl<K, I, F> Debug for ChunkBy<K, I, F>
|
||||
where
|
||||
K: Debug,
|
||||
I: Iterator + Debug,
|
||||
I::Item: Debug,
|
||||
{
|
||||
debug_fmt_fields!(ChunkBy, inner, index);
|
||||
}
|
||||
|
||||
/// Create a new
|
||||
pub fn new<K, J, F>(iter: J, f: F) -> ChunkBy<K, J::IntoIter, F>
|
||||
where
|
||||
@@ -385,6 +410,15 @@ where
|
||||
parent: &'a ChunkBy<K, I, F>,
|
||||
}
|
||||
|
||||
impl<'a, K, I, F> Debug for Groups<'a, K, I, F>
|
||||
where
|
||||
K: Debug,
|
||||
I: Iterator + Debug,
|
||||
I::Item: Debug,
|
||||
{
|
||||
debug_fmt_fields!(Groups, parent);
|
||||
}
|
||||
|
||||
impl<'a, K, I, F> Iterator for Groups<'a, K, I, F>
|
||||
where
|
||||
I: Iterator,
|
||||
@@ -438,6 +472,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, I, F> Debug for Group<'a, K, I, F>
|
||||
where
|
||||
K: Debug,
|
||||
I: Iterator + Debug,
|
||||
I::Item: Debug,
|
||||
{
|
||||
debug_fmt_fields!(Group, parent, index, first);
|
||||
}
|
||||
|
||||
impl<'a, K, I, F> Iterator for Group<'a, K, I, F>
|
||||
where
|
||||
I: Iterator,
|
||||
@@ -479,7 +522,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// `ChunkLazy` is the storage for a lazy chunking operation.
|
||||
/// `IntoChunks` is the storage for a lazy chunking operation.
|
||||
///
|
||||
/// `IntoChunks` behaves just like `ChunkBy`: it is iterable, and
|
||||
/// it only buffers if several chunk iterators are alive at the same time.
|
||||
@@ -503,6 +546,14 @@ where
|
||||
index: Cell<usize>,
|
||||
}
|
||||
|
||||
impl<I> Debug for IntoChunks<I>
|
||||
where
|
||||
I: Iterator + Debug,
|
||||
I::Item: Debug,
|
||||
{
|
||||
debug_fmt_fields!(IntoChunks, inner, index);
|
||||
}
|
||||
|
||||
impl<I> Clone for IntoChunks<I>
|
||||
where
|
||||
I: Clone + Iterator,
|
||||
@@ -554,6 +605,14 @@ where
|
||||
parent: &'a IntoChunks<I>,
|
||||
}
|
||||
|
||||
impl<'a, I> Debug for Chunks<'a, I>
|
||||
where
|
||||
I: Iterator + Debug,
|
||||
I::Item: Debug,
|
||||
{
|
||||
debug_fmt_fields!(Chunks, parent);
|
||||
}
|
||||
|
||||
impl<'a, I> Iterator for Chunks<'a, I>
|
||||
where
|
||||
I: Iterator,
|
||||
@@ -577,6 +636,7 @@ where
|
||||
/// An iterator for the elements in a single chunk.
|
||||
///
|
||||
/// Iterator element type is `I::Item`.
|
||||
#[derive(Debug)]
|
||||
pub struct Chunk<'a, I>
|
||||
where
|
||||
I: Iterator + 'a,
|
||||
|
||||
+37
-30
@@ -2,11 +2,12 @@ use crate::{
|
||||
adaptors::map::{MapSpecialCase, MapSpecialCaseFn},
|
||||
MinMaxResult,
|
||||
};
|
||||
use std::cmp::Ordering;
|
||||
use core::hash::BuildHasher;
|
||||
use std::collections::HashMap;
|
||||
use std::hash::Hash;
|
||||
use std::iter::Iterator;
|
||||
use std::ops::{Add, Mul};
|
||||
use std::{cmp::Ordering, collections::hash_map::RandomState};
|
||||
|
||||
/// A wrapper to allow for an easy [`into_grouping_map_by`](crate::Itertools::into_grouping_map_by)
|
||||
pub type MapForGrouping<I, F> = MapSpecialCase<I, GroupingMapFn<F>>;
|
||||
@@ -36,18 +37,19 @@ pub(crate) fn new_map_for_grouping<K, I: Iterator, F: FnMut(&I::Item) -> K>(
|
||||
}
|
||||
|
||||
/// Creates a new `GroupingMap` from `iter`
|
||||
pub fn new<I, K, V>(iter: I) -> GroupingMap<I>
|
||||
pub fn new<I, K, V, S>(iter: I, hash_builder: S) -> GroupingMap<I, S>
|
||||
where
|
||||
I: Iterator<Item = (K, V)>,
|
||||
K: Hash + Eq,
|
||||
S: BuildHasher,
|
||||
{
|
||||
GroupingMap { iter }
|
||||
GroupingMap { iter, hash_builder }
|
||||
}
|
||||
|
||||
/// `GroupingMapBy` is an intermediate struct for efficient group-and-fold operations.
|
||||
///
|
||||
/// See [`GroupingMap`] for more informations.
|
||||
pub type GroupingMapBy<I, F> = GroupingMap<MapForGrouping<I, F>>;
|
||||
/// See [`GroupingMap`] for more information.
|
||||
pub type GroupingMapBy<I, F, S = RandomState> = GroupingMap<MapForGrouping<I, F>, S>;
|
||||
|
||||
/// `GroupingMap` is an intermediate struct for efficient group-and-fold operations.
|
||||
/// It groups elements by their key and at the same time fold each group
|
||||
@@ -56,14 +58,19 @@ pub type GroupingMapBy<I, F> = GroupingMap<MapForGrouping<I, F>>;
|
||||
/// No method on this struct performs temporary allocations.
|
||||
#[derive(Clone, Debug)]
|
||||
#[must_use = "GroupingMap is lazy and do nothing unless consumed"]
|
||||
pub struct GroupingMap<I> {
|
||||
pub struct GroupingMap<I, S = RandomState>
|
||||
where
|
||||
S: BuildHasher,
|
||||
{
|
||||
iter: I,
|
||||
hash_builder: S,
|
||||
}
|
||||
|
||||
impl<I, K, V> GroupingMap<I>
|
||||
impl<I, K, V, S> GroupingMap<I, S>
|
||||
where
|
||||
I: Iterator<Item = (K, V)>,
|
||||
K: Hash + Eq,
|
||||
S: BuildHasher,
|
||||
{
|
||||
/// This is the generic way to perform any operation on a `GroupingMap`.
|
||||
/// It's suggested to use this method only to implement custom operations
|
||||
@@ -105,11 +112,11 @@ where
|
||||
/// assert_eq!(lookup[&3], 7);
|
||||
/// assert_eq!(lookup.len(), 3); // The final keys are only 0, 1 and 2
|
||||
/// ```
|
||||
pub fn aggregate<FO, R>(self, mut operation: FO) -> HashMap<K, R>
|
||||
pub fn aggregate<FO, R>(self, mut operation: FO) -> HashMap<K, R, S>
|
||||
where
|
||||
FO: FnMut(Option<R>, &K, V) -> Option<R>,
|
||||
{
|
||||
let mut destination_map = HashMap::new();
|
||||
let mut destination_map = HashMap::with_hasher(self.hash_builder);
|
||||
|
||||
self.iter.for_each(|(key, val)| {
|
||||
let acc = destination_map.remove(&key);
|
||||
@@ -139,7 +146,7 @@ where
|
||||
///
|
||||
/// #[derive(Debug, Default)]
|
||||
/// struct Accumulator {
|
||||
/// acc: usize,
|
||||
/// acc: usize,
|
||||
/// }
|
||||
///
|
||||
/// let lookup = (1..=7)
|
||||
@@ -154,7 +161,7 @@ where
|
||||
/// assert_eq!(lookup[&2].acc, 2 + 5);
|
||||
/// assert_eq!(lookup.len(), 3);
|
||||
/// ```
|
||||
pub fn fold_with<FI, FO, R>(self, mut init: FI, mut operation: FO) -> HashMap<K, R>
|
||||
pub fn fold_with<FI, FO, R>(self, mut init: FI, mut operation: FO) -> HashMap<K, R, S>
|
||||
where
|
||||
FI: FnMut(&K, &V) -> R,
|
||||
FO: FnMut(R, &K, V) -> R,
|
||||
@@ -190,7 +197,7 @@ where
|
||||
/// assert_eq!(lookup[&2], 2 + 5);
|
||||
/// assert_eq!(lookup.len(), 3);
|
||||
/// ```
|
||||
pub fn fold<FO, R>(self, init: R, operation: FO) -> HashMap<K, R>
|
||||
pub fn fold<FO, R>(self, init: R, operation: FO) -> HashMap<K, R, S>
|
||||
where
|
||||
R: Clone,
|
||||
FO: FnMut(R, &K, V) -> R,
|
||||
@@ -225,7 +232,7 @@ where
|
||||
/// assert_eq!(lookup[&2], 2 + 5);
|
||||
/// assert_eq!(lookup.len(), 3);
|
||||
/// ```
|
||||
pub fn reduce<FO>(self, mut operation: FO) -> HashMap<K, V>
|
||||
pub fn reduce<FO>(self, mut operation: FO) -> HashMap<K, V, S>
|
||||
where
|
||||
FO: FnMut(V, &K, V) -> V,
|
||||
{
|
||||
@@ -239,7 +246,7 @@ where
|
||||
|
||||
/// See [`.reduce()`](GroupingMap::reduce).
|
||||
#[deprecated(note = "Use .reduce() instead", since = "0.13.0")]
|
||||
pub fn fold_first<FO>(self, operation: FO) -> HashMap<K, V>
|
||||
pub fn fold_first<FO>(self, operation: FO) -> HashMap<K, V, S>
|
||||
where
|
||||
FO: FnMut(V, &K, V) -> V,
|
||||
{
|
||||
@@ -264,11 +271,11 @@ where
|
||||
/// assert_eq!(lookup[&2], vec![2, 5].into_iter().collect::<HashSet<_>>());
|
||||
/// assert_eq!(lookup.len(), 3);
|
||||
/// ```
|
||||
pub fn collect<C>(self) -> HashMap<K, C>
|
||||
pub fn collect<C>(self) -> HashMap<K, C, S>
|
||||
where
|
||||
C: Default + Extend<V>,
|
||||
{
|
||||
let mut destination_map = HashMap::new();
|
||||
let mut destination_map = HashMap::with_hasher(self.hash_builder);
|
||||
|
||||
self.iter.for_each(|(key, val)| {
|
||||
destination_map
|
||||
@@ -298,7 +305,7 @@ where
|
||||
/// assert_eq!(lookup[&2], 8);
|
||||
/// assert_eq!(lookup.len(), 3);
|
||||
/// ```
|
||||
pub fn max(self) -> HashMap<K, V>
|
||||
pub fn max(self) -> HashMap<K, V, S>
|
||||
where
|
||||
V: Ord,
|
||||
{
|
||||
@@ -324,7 +331,7 @@ where
|
||||
/// assert_eq!(lookup[&2], 5);
|
||||
/// assert_eq!(lookup.len(), 3);
|
||||
/// ```
|
||||
pub fn max_by<F>(self, mut compare: F) -> HashMap<K, V>
|
||||
pub fn max_by<F>(self, mut compare: F) -> HashMap<K, V, S>
|
||||
where
|
||||
F: FnMut(&K, &V, &V) -> Ordering,
|
||||
{
|
||||
@@ -353,7 +360,7 @@ where
|
||||
/// assert_eq!(lookup[&2], 5);
|
||||
/// assert_eq!(lookup.len(), 3);
|
||||
/// ```
|
||||
pub fn max_by_key<F, CK>(self, mut f: F) -> HashMap<K, V>
|
||||
pub fn max_by_key<F, CK>(self, mut f: F) -> HashMap<K, V, S>
|
||||
where
|
||||
F: FnMut(&K, &V) -> CK,
|
||||
CK: Ord,
|
||||
@@ -379,7 +386,7 @@ where
|
||||
/// assert_eq!(lookup[&2], 5);
|
||||
/// assert_eq!(lookup.len(), 3);
|
||||
/// ```
|
||||
pub fn min(self) -> HashMap<K, V>
|
||||
pub fn min(self) -> HashMap<K, V, S>
|
||||
where
|
||||
V: Ord,
|
||||
{
|
||||
@@ -405,7 +412,7 @@ where
|
||||
/// assert_eq!(lookup[&2], 8);
|
||||
/// assert_eq!(lookup.len(), 3);
|
||||
/// ```
|
||||
pub fn min_by<F>(self, mut compare: F) -> HashMap<K, V>
|
||||
pub fn min_by<F>(self, mut compare: F) -> HashMap<K, V, S>
|
||||
where
|
||||
F: FnMut(&K, &V, &V) -> Ordering,
|
||||
{
|
||||
@@ -434,7 +441,7 @@ where
|
||||
/// assert_eq!(lookup[&2], 8);
|
||||
/// assert_eq!(lookup.len(), 3);
|
||||
/// ```
|
||||
pub fn min_by_key<F, CK>(self, mut f: F) -> HashMap<K, V>
|
||||
pub fn min_by_key<F, CK>(self, mut f: F) -> HashMap<K, V, S>
|
||||
where
|
||||
F: FnMut(&K, &V) -> CK,
|
||||
CK: Ord,
|
||||
@@ -458,7 +465,7 @@ where
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::Itertools;
|
||||
/// use itertools::MinMaxResult::{OneElement, MinMax};
|
||||
/// use itertools::MinMaxResult::{MinMax, OneElement};
|
||||
///
|
||||
/// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter()
|
||||
/// .into_grouping_map_by(|&n| n % 3)
|
||||
@@ -469,7 +476,7 @@ where
|
||||
/// assert_eq!(lookup[&2], OneElement(5));
|
||||
/// assert_eq!(lookup.len(), 3);
|
||||
/// ```
|
||||
pub fn minmax(self) -> HashMap<K, MinMaxResult<V>>
|
||||
pub fn minmax(self) -> HashMap<K, MinMaxResult<V>, S>
|
||||
where
|
||||
V: Ord,
|
||||
{
|
||||
@@ -488,7 +495,7 @@ where
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::Itertools;
|
||||
/// use itertools::MinMaxResult::{OneElement, MinMax};
|
||||
/// use itertools::MinMaxResult::{MinMax, OneElement};
|
||||
///
|
||||
/// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter()
|
||||
/// .into_grouping_map_by(|&n| n % 3)
|
||||
@@ -499,7 +506,7 @@ where
|
||||
/// assert_eq!(lookup[&2], OneElement(5));
|
||||
/// assert_eq!(lookup.len(), 3);
|
||||
/// ```
|
||||
pub fn minmax_by<F>(self, mut compare: F) -> HashMap<K, MinMaxResult<V>>
|
||||
pub fn minmax_by<F>(self, mut compare: F) -> HashMap<K, MinMaxResult<V>, S>
|
||||
where
|
||||
F: FnMut(&K, &V, &V) -> Ordering,
|
||||
{
|
||||
@@ -539,7 +546,7 @@ where
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::Itertools;
|
||||
/// use itertools::MinMaxResult::{OneElement, MinMax};
|
||||
/// use itertools::MinMaxResult::{MinMax, OneElement};
|
||||
///
|
||||
/// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter()
|
||||
/// .into_grouping_map_by(|&n| n % 3)
|
||||
@@ -550,7 +557,7 @@ where
|
||||
/// assert_eq!(lookup[&2], OneElement(5));
|
||||
/// assert_eq!(lookup.len(), 3);
|
||||
/// ```
|
||||
pub fn minmax_by_key<F, CK>(self, mut f: F) -> HashMap<K, MinMaxResult<V>>
|
||||
pub fn minmax_by_key<F, CK>(self, mut f: F) -> HashMap<K, MinMaxResult<V>, S>
|
||||
where
|
||||
F: FnMut(&K, &V) -> CK,
|
||||
CK: Ord,
|
||||
@@ -577,7 +584,7 @@ where
|
||||
/// assert_eq!(lookup[&2], 5 + 8);
|
||||
/// assert_eq!(lookup.len(), 3);
|
||||
/// ```
|
||||
pub fn sum(self) -> HashMap<K, V>
|
||||
pub fn sum(self) -> HashMap<K, V, S>
|
||||
where
|
||||
V: Add<V, Output = V>,
|
||||
{
|
||||
@@ -603,7 +610,7 @@ where
|
||||
/// assert_eq!(lookup[&2], 5 * 8);
|
||||
/// assert_eq!(lookup.len(), 3);
|
||||
/// ```
|
||||
pub fn product(self) -> HashMap<K, V>
|
||||
pub fn product(self) -> HashMap<K, V, S>
|
||||
where
|
||||
V: Mul<V, Output = V>,
|
||||
{
|
||||
|
||||
+3
-3
@@ -80,7 +80,7 @@ where
|
||||
while child + 1 < heap.len() {
|
||||
// pick the smaller of the two children
|
||||
// use arithmetic to avoid an unpredictable branch
|
||||
child += less_than(&heap[child + 1], &heap[child]) as usize;
|
||||
child += usize::from(less_than(&heap[child + 1], &heap[child]));
|
||||
|
||||
// sift down is done if we are already in order
|
||||
if !less_than(&heap[child], &heap[pos]) {
|
||||
@@ -97,7 +97,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator adaptor that merges an abitrary number of base iterators in ascending order.
|
||||
/// An iterator adaptor that merges an arbitrary number of base iterators in ascending order.
|
||||
/// If all base iterators are sorted (ascending), the result is sorted.
|
||||
///
|
||||
/// Iterator element type is `I::Item`.
|
||||
@@ -146,7 +146,7 @@ where
|
||||
kmerge_by(iterable, KMergeByLt)
|
||||
}
|
||||
|
||||
/// An iterator adaptor that merges an abitrary number of base iterators
|
||||
/// An iterator adaptor that merges an arbitrary number of base iterators
|
||||
/// according to an ordering function.
|
||||
///
|
||||
/// Iterator element type is `I::Item`.
|
||||
|
||||
+730
-100
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -24,7 +24,7 @@ impl<T: Clone> MinMaxResult<T> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::MinMaxResult::{self, NoElements, OneElement, MinMax};
|
||||
/// use itertools::MinMaxResult::{self, MinMax, NoElements, OneElement};
|
||||
///
|
||||
/// let r: MinMaxResult<i32> = NoElements;
|
||||
/// assert_eq!(r.into_option(), None);
|
||||
|
||||
+54
-52
@@ -1,4 +1,3 @@
|
||||
use crate::size_hint;
|
||||
use std::iter::{Fuse, FusedIterator};
|
||||
|
||||
/// An iterator adaptor that pads a sequence to a minimum length by filling
|
||||
@@ -11,8 +10,9 @@ use std::iter::{Fuse, FusedIterator};
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct PadUsing<I, F> {
|
||||
iter: Fuse<I>,
|
||||
min: usize,
|
||||
pos: usize,
|
||||
elements_from_next: usize,
|
||||
elements_from_next_back: usize,
|
||||
elements_required: usize,
|
||||
filler: F,
|
||||
}
|
||||
|
||||
@@ -20,19 +20,26 @@ impl<I, F> std::fmt::Debug for PadUsing<I, F>
|
||||
where
|
||||
I: std::fmt::Debug,
|
||||
{
|
||||
debug_fmt_fields!(PadUsing, iter, min, pos);
|
||||
debug_fmt_fields!(
|
||||
PadUsing,
|
||||
iter,
|
||||
elements_from_next,
|
||||
elements_from_next_back,
|
||||
elements_required
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a new `PadUsing` iterator.
|
||||
pub fn pad_using<I, F>(iter: I, min: usize, filler: F) -> PadUsing<I, F>
|
||||
pub fn pad_using<I, F>(iter: I, elements_required: usize, filler: F) -> PadUsing<I, F>
|
||||
where
|
||||
I: Iterator,
|
||||
F: FnMut(usize) -> I::Item,
|
||||
{
|
||||
PadUsing {
|
||||
iter: iter.fuse(),
|
||||
min,
|
||||
pos: 0,
|
||||
elements_from_next: 0,
|
||||
elements_from_next_back: 0,
|
||||
elements_required,
|
||||
filler,
|
||||
}
|
||||
}
|
||||
@@ -46,38 +53,34 @@ where
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.iter.next() {
|
||||
None => {
|
||||
if self.pos < self.min {
|
||||
let e = Some((self.filler)(self.pos));
|
||||
self.pos += 1;
|
||||
e
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
e => {
|
||||
self.pos += 1;
|
||||
e
|
||||
}
|
||||
let total_consumed = self.elements_from_next + self.elements_from_next_back;
|
||||
|
||||
if total_consumed >= self.elements_required {
|
||||
self.iter.next()
|
||||
} else if let Some(e) = self.iter.next() {
|
||||
self.elements_from_next += 1;
|
||||
Some(e)
|
||||
} else {
|
||||
let e = (self.filler)(self.elements_from_next);
|
||||
self.elements_from_next += 1;
|
||||
Some(e)
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let tail = self.min.saturating_sub(self.pos);
|
||||
size_hint::max(self.iter.size_hint(), (tail, Some(tail)))
|
||||
}
|
||||
let total_consumed = self.elements_from_next + self.elements_from_next_back;
|
||||
|
||||
fn fold<B, G>(self, mut init: B, mut f: G) -> B
|
||||
where
|
||||
G: FnMut(B, Self::Item) -> B,
|
||||
{
|
||||
let mut pos = self.pos;
|
||||
init = self.iter.fold(init, |acc, item| {
|
||||
pos += 1;
|
||||
f(acc, item)
|
||||
});
|
||||
(pos..self.min).map(self.filler).fold(init, f)
|
||||
if total_consumed >= self.elements_required {
|
||||
return self.iter.size_hint();
|
||||
}
|
||||
|
||||
let elements_remaining = self.elements_required - total_consumed;
|
||||
let (low, high) = self.iter.size_hint();
|
||||
|
||||
let lower_bound = low.max(elements_remaining);
|
||||
let upper_bound = high.map(|h| h.max(elements_remaining));
|
||||
|
||||
(lower_bound, upper_bound)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,25 +90,24 @@ where
|
||||
F: FnMut(usize) -> I::Item,
|
||||
{
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
if self.min == 0 {
|
||||
self.iter.next_back()
|
||||
} else if self.iter.len() >= self.min {
|
||||
self.min -= 1;
|
||||
self.iter.next_back()
|
||||
} else {
|
||||
self.min -= 1;
|
||||
Some((self.filler)(self.min))
|
||||
}
|
||||
}
|
||||
let total_consumed = self.elements_from_next + self.elements_from_next_back;
|
||||
|
||||
fn rfold<B, G>(self, mut init: B, mut f: G) -> B
|
||||
where
|
||||
G: FnMut(B, Self::Item) -> B,
|
||||
{
|
||||
init = (self.iter.len()..self.min)
|
||||
.map(self.filler)
|
||||
.rfold(init, &mut f);
|
||||
self.iter.rfold(init, f)
|
||||
if total_consumed >= self.elements_required {
|
||||
return self.iter.next_back();
|
||||
}
|
||||
|
||||
let elements_remaining = self.elements_required - total_consumed;
|
||||
self.elements_from_next_back += 1;
|
||||
|
||||
if self.iter.len() < elements_remaining {
|
||||
Some((self.filler)(
|
||||
self.elements_required - self.elements_from_next_back,
|
||||
))
|
||||
} else {
|
||||
let item = self.iter.next_back();
|
||||
debug_assert!(item.is_some()); // If this triggers, we should not have incremented elements_from_next_back, and the input iterator mistakenly reported that it would be able to produce at least elements_remaining items.
|
||||
item
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+74
-1
@@ -92,6 +92,57 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "use_alloc")]
|
||||
impl<T> PeekingNext for ::alloc::vec::IntoIter<T> {
|
||||
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||
where
|
||||
F: FnOnce(&Self::Item) -> bool,
|
||||
{
|
||||
match accept(self.as_slice().first()?) {
|
||||
true => self.next(),
|
||||
false => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "use_alloc")]
|
||||
impl<'a, T> PeekingNext for ::alloc::vec::Drain<'a, T> {
|
||||
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||
where
|
||||
F: FnOnce(&Self::Item) -> bool,
|
||||
{
|
||||
match accept(self.as_slice().first()?) {
|
||||
true => self.next(),
|
||||
false => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "use_alloc")]
|
||||
impl<'a> PeekingNext for ::alloc::string::Drain<'a> {
|
||||
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||
where
|
||||
F: FnOnce(&Self::Item) -> bool,
|
||||
{
|
||||
match accept(&self.as_str().chars().next()?) {
|
||||
true => self.next(),
|
||||
false => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const N: usize> PeekingNext for ::core::array::IntoIter<T, N> {
|
||||
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||
where
|
||||
F: FnOnce(&Self::Item) -> bool,
|
||||
{
|
||||
match accept(self.as_slice().first()?) {
|
||||
true => self.next(),
|
||||
false => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> PeekingNext for RepeatN<T> {
|
||||
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||
where
|
||||
@@ -126,7 +177,7 @@ where
|
||||
}
|
||||
|
||||
/// Create a `PeekingTakeWhile`
|
||||
pub fn peeking_take_while<I, F>(iter: &mut I, f: F) -> PeekingTakeWhile<I, F>
|
||||
pub fn peeking_take_while<I, F>(iter: &mut I, f: F) -> PeekingTakeWhile<'_, I, F>
|
||||
where
|
||||
I: Iterator,
|
||||
{
|
||||
@@ -191,11 +242,33 @@ peeking_next_by_clone! { ['a] ::std::str::Bytes<'a> }
|
||||
peeking_next_by_clone! { ['a, T] ::std::option::Iter<'a, T> }
|
||||
peeking_next_by_clone! { ['a, T] ::std::result::Iter<'a, T> }
|
||||
peeking_next_by_clone! { [T] ::std::iter::Empty<T> }
|
||||
|
||||
#[cfg(feature = "use_alloc")]
|
||||
peeking_next_by_clone! { ['a, T] alloc::collections::linked_list::Iter<'a, T> }
|
||||
#[cfg(feature = "use_alloc")]
|
||||
peeking_next_by_clone! { ['a, T] alloc::collections::vec_deque::Iter<'a, T> }
|
||||
|
||||
#[cfg(feature = "use_alloc")]
|
||||
peeking_next_by_clone! { ['a, K, V] alloc::collections::btree_map::Iter<'a, K, V> }
|
||||
#[cfg(feature = "use_alloc")]
|
||||
peeking_next_by_clone! { ['a, K, V] alloc::collections::btree_map::Keys<'a, K, V> }
|
||||
#[cfg(feature = "use_alloc")]
|
||||
peeking_next_by_clone! { ['a, K, V] alloc::collections::btree_map::Values<'a, K, V> }
|
||||
|
||||
#[cfg(feature = "use_alloc")]
|
||||
peeking_next_by_clone! { ['a, T] alloc::collections::btree_set::Iter<'a, T> }
|
||||
#[cfg(feature = "use_alloc")]
|
||||
peeking_next_by_clone! { ['a, T] alloc::collections::binary_heap::Iter<'a, T> }
|
||||
|
||||
#[cfg(feature = "use_std")]
|
||||
peeking_next_by_clone! { ['a, K, V] std::collections::hash_map::Iter<'a, K, V> }
|
||||
#[cfg(feature = "use_std")]
|
||||
peeking_next_by_clone! { ['a, K, V] std::collections::hash_map::Keys<'a, K, V> }
|
||||
#[cfg(feature = "use_std")]
|
||||
peeking_next_by_clone! { ['a, K, V] std::collections::hash_map::Values<'a, K, V> }
|
||||
#[cfg(feature = "use_std")]
|
||||
peeking_next_by_clone! { ['a, T] std::collections::hash_set::Iter<'a, T> }
|
||||
|
||||
// cloning a Rev has no extra overhead; peekable and put backs are never DEI.
|
||||
peeking_next_by_clone! { [I: Clone + PeekingNext + DoubleEndedIterator]
|
||||
::std::iter::Rev<I> }
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ where
|
||||
debug_fmt_fields!(Powerset, combs);
|
||||
}
|
||||
|
||||
/// Create a new `Powerset` from a clonable iterator.
|
||||
/// Create a new `Powerset` from a cloneable iterator.
|
||||
pub fn powerset<I>(src: I) -> Powerset<I>
|
||||
where
|
||||
I: Iterator,
|
||||
|
||||
+1
-1
@@ -1,5 +1,4 @@
|
||||
//! Arithmetic on `Iterator.size_hint()` values.
|
||||
//!
|
||||
|
||||
use std::cmp;
|
||||
|
||||
@@ -86,6 +85,7 @@ pub fn min(a: SizeHint, b: SizeHint) -> SizeHint {
|
||||
(lower, upper)
|
||||
}
|
||||
|
||||
/// Test multiplication of size hints.
|
||||
#[test]
|
||||
fn mul_size_hints() {
|
||||
assert_eq!(mul((3, Some(4)), (3, Some(4))), (9, Some(16)));
|
||||
|
||||
@@ -385,6 +385,7 @@ macro_rules! impl_tuple_collect {
|
||||
count_ident!($($Y)*)
|
||||
}
|
||||
|
||||
/// Shift all elements one position to the left and push the new item to the end.
|
||||
fn left_shift_push(&mut self, mut item: A) {
|
||||
use std::mem::replace;
|
||||
|
||||
|
||||
+36
-19
@@ -1,4 +1,6 @@
|
||||
use core::hash::BuildHasher;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::hash_map::RandomState;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
@@ -9,42 +11,48 @@ use std::iter::FusedIterator;
|
||||
/// See [`.unique_by()`](crate::Itertools::unique) for more information.
|
||||
#[derive(Clone)]
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct UniqueBy<I: Iterator, V, F> {
|
||||
pub struct UniqueBy<I: Iterator, V, F, S = RandomState>
|
||||
where
|
||||
S: BuildHasher,
|
||||
{
|
||||
iter: I,
|
||||
// Use a Hashmap for the Entry API in order to prevent hashing twice.
|
||||
// This can maybe be replaced with a HashSet once `get_or_insert_with`
|
||||
// or a proper Entry API for Hashset is stable and meets this msrv
|
||||
used: HashMap<V, ()>,
|
||||
used: HashMap<V, (), S>,
|
||||
f: F,
|
||||
}
|
||||
|
||||
impl<I, V, F> fmt::Debug for UniqueBy<I, V, F>
|
||||
impl<I, V, F, S> fmt::Debug for UniqueBy<I, V, F, S>
|
||||
where
|
||||
I: Iterator + fmt::Debug,
|
||||
V: fmt::Debug + Hash + Eq,
|
||||
S: BuildHasher,
|
||||
{
|
||||
debug_fmt_fields!(UniqueBy, iter, used);
|
||||
}
|
||||
|
||||
/// Create a new `UniqueBy` iterator.
|
||||
pub fn unique_by<I, V, F>(iter: I, f: F) -> UniqueBy<I, V, F>
|
||||
pub fn unique_by_with_hasher<I, V, F, S>(iter: I, f: F, hash_builder: S) -> UniqueBy<I, V, F, S>
|
||||
where
|
||||
V: Eq + Hash,
|
||||
F: FnMut(&I::Item) -> V,
|
||||
I: Iterator,
|
||||
S: BuildHasher,
|
||||
{
|
||||
UniqueBy {
|
||||
iter,
|
||||
used: HashMap::new(),
|
||||
used: HashMap::with_hasher(hash_builder),
|
||||
f,
|
||||
}
|
||||
}
|
||||
|
||||
// count the number of new unique keys in iterable (`used` is the set already seen)
|
||||
fn count_new_keys<I, K>(mut used: HashMap<K, ()>, iterable: I) -> usize
|
||||
fn count_new_keys<I, K, S>(mut used: HashMap<K, (), S>, iterable: I) -> usize
|
||||
where
|
||||
I: IntoIterator<Item = K>,
|
||||
K: Hash + Eq,
|
||||
S: BuildHasher,
|
||||
{
|
||||
let iter = iterable.into_iter();
|
||||
let current_used = used.len();
|
||||
@@ -52,11 +60,12 @@ where
|
||||
used.len() - current_used
|
||||
}
|
||||
|
||||
impl<I, V, F> Iterator for UniqueBy<I, V, F>
|
||||
impl<I, V, F, S> Iterator for UniqueBy<I, V, F, S>
|
||||
where
|
||||
I: Iterator,
|
||||
V: Eq + Hash,
|
||||
F: FnMut(&I::Item) -> V,
|
||||
S: BuildHasher,
|
||||
{
|
||||
type Item = I::Item;
|
||||
|
||||
@@ -68,7 +77,7 @@ where
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (low, hi) = self.iter.size_hint();
|
||||
((low > 0 && self.used.is_empty()) as usize, hi)
|
||||
(usize::from(low > 0 && self.used.is_empty()), hi)
|
||||
}
|
||||
|
||||
fn count(self) -> usize {
|
||||
@@ -77,11 +86,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, V, F> DoubleEndedIterator for UniqueBy<I, V, F>
|
||||
impl<I, V, F, S> DoubleEndedIterator for UniqueBy<I, V, F, S>
|
||||
where
|
||||
I: DoubleEndedIterator,
|
||||
V: Eq + Hash,
|
||||
F: FnMut(&I::Item) -> V,
|
||||
S: BuildHasher,
|
||||
{
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
let Self { iter, used, f } = self;
|
||||
@@ -89,18 +99,20 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, V, F> FusedIterator for UniqueBy<I, V, F>
|
||||
impl<I, V, F, S> FusedIterator for UniqueBy<I, V, F, S>
|
||||
where
|
||||
I: FusedIterator,
|
||||
V: Eq + Hash,
|
||||
F: FnMut(&I::Item) -> V,
|
||||
S: BuildHasher,
|
||||
{
|
||||
}
|
||||
|
||||
impl<I> Iterator for Unique<I>
|
||||
impl<I, S> Iterator for Unique<I, S>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Eq + Hash + Clone,
|
||||
S: BuildHasher,
|
||||
{
|
||||
type Item = I::Item;
|
||||
|
||||
@@ -119,7 +131,7 @@ where
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (low, hi) = self.iter.iter.size_hint();
|
||||
((low > 0 && self.iter.used.is_empty()) as usize, hi)
|
||||
(usize::from(low > 0 && self.iter.used.is_empty()), hi)
|
||||
}
|
||||
|
||||
fn count(self) -> usize {
|
||||
@@ -127,10 +139,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> DoubleEndedIterator for Unique<I>
|
||||
impl<I, S> DoubleEndedIterator for Unique<I, S>
|
||||
where
|
||||
I: DoubleEndedIterator,
|
||||
I::Item: Eq + Hash + Clone,
|
||||
S: BuildHasher,
|
||||
{
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
let UniqueBy { iter, used, .. } = &mut self.iter;
|
||||
@@ -145,10 +158,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> FusedIterator for Unique<I>
|
||||
impl<I, S> FusedIterator for Unique<I, S>
|
||||
where
|
||||
I: FusedIterator,
|
||||
I::Item: Eq + Hash + Clone,
|
||||
S: BuildHasher,
|
||||
{
|
||||
}
|
||||
|
||||
@@ -157,31 +171,34 @@ where
|
||||
/// See [`.unique()`](crate::Itertools::unique) for more information.
|
||||
#[derive(Clone)]
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct Unique<I>
|
||||
pub struct Unique<I, S = RandomState>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Eq + Hash + Clone,
|
||||
S: BuildHasher,
|
||||
{
|
||||
iter: UniqueBy<I, I::Item, ()>,
|
||||
iter: UniqueBy<I, I::Item, (), S>,
|
||||
}
|
||||
|
||||
impl<I> fmt::Debug for Unique<I>
|
||||
impl<I, S> fmt::Debug for Unique<I, S>
|
||||
where
|
||||
I: Iterator + fmt::Debug,
|
||||
I::Item: Hash + Eq + fmt::Debug + Clone,
|
||||
S: BuildHasher,
|
||||
{
|
||||
debug_fmt_fields!(Unique, iter);
|
||||
}
|
||||
|
||||
pub fn unique<I>(iter: I) -> Unique<I>
|
||||
pub fn unique_with_hasher<I, S>(iter: I, hash_builder: S) -> Unique<I, S>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Eq + Hash + Clone,
|
||||
S: BuildHasher,
|
||||
{
|
||||
Unique {
|
||||
iter: UniqueBy {
|
||||
iter,
|
||||
used: HashMap::new(),
|
||||
used: HashMap::with_hasher(hash_builder),
|
||||
f: (),
|
||||
},
|
||||
}
|
||||
|
||||
+56
-36
@@ -47,44 +47,46 @@ where
|
||||
///
|
||||
/// See [`.with_position()`](crate::Itertools::with_position) for more information.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Position {
|
||||
/// This is the first element.
|
||||
First,
|
||||
/// This is neither the first nor the last element.
|
||||
Middle,
|
||||
/// This is the last element.
|
||||
Last,
|
||||
/// This is the only element.
|
||||
Only,
|
||||
pub struct Position {
|
||||
/// This is the initial element (also true if there's exactly one element)
|
||||
pub is_first: bool,
|
||||
/// This is the final element (also true if there's exactly one element)
|
||||
pub is_last: bool,
|
||||
}
|
||||
|
||||
impl Position {
|
||||
/// This is the first and the last element at the same time, and there are no more elements
|
||||
pub fn is_exactly_one(self) -> bool {
|
||||
self.is_first && self.is_last
|
||||
}
|
||||
|
||||
/// This is neither first nor last element, and there will be more elements
|
||||
pub fn is_middle(self) -> bool {
|
||||
!self.is_first && !self.is_last
|
||||
}
|
||||
|
||||
/// This is the initial element (also true if there's exactly one element)
|
||||
pub fn is_first(self) -> bool {
|
||||
self.is_first
|
||||
}
|
||||
|
||||
/// This is the final element (also true if there's exactly one element)
|
||||
pub fn is_last(self) -> bool {
|
||||
self.is_last
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Iterator> Iterator for WithPosition<I> {
|
||||
type Item = (Position, I::Item);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.peekable.next() {
|
||||
Some(item) => {
|
||||
if !self.handled_first {
|
||||
// Haven't seen the first item yet, and there is one to give.
|
||||
self.handled_first = true;
|
||||
// Peek to see if this is also the last item,
|
||||
// in which case tag it as `Only`.
|
||||
match self.peekable.peek() {
|
||||
Some(_) => Some((Position::First, item)),
|
||||
None => Some((Position::Only, item)),
|
||||
}
|
||||
} else {
|
||||
// Have seen the first item, and there's something left.
|
||||
// Peek to see if this is the last item.
|
||||
match self.peekable.peek() {
|
||||
Some(_) => Some((Position::Middle, item)),
|
||||
None => Some((Position::Last, item)),
|
||||
}
|
||||
}
|
||||
}
|
||||
// Iterator is finished.
|
||||
None => None,
|
||||
}
|
||||
let item = self.peekable.next()?;
|
||||
|
||||
let is_last = self.peekable.peek().is_none();
|
||||
let is_first = !self.handled_first;
|
||||
self.handled_first = true;
|
||||
|
||||
Some((Position { is_first, is_last }, item))
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
@@ -102,18 +104,36 @@ impl<I: Iterator> Iterator for WithPosition<I> {
|
||||
match self.peekable.next() {
|
||||
Some(second) => {
|
||||
let first = std::mem::replace(&mut head, second);
|
||||
init = f(init, (Position::First, first));
|
||||
let position = Position {
|
||||
is_first: true,
|
||||
is_last: false,
|
||||
};
|
||||
init = f(init, (position, first));
|
||||
}
|
||||
None => {
|
||||
let position = Position {
|
||||
is_first: true,
|
||||
is_last: true,
|
||||
};
|
||||
return f(init, (position, head));
|
||||
}
|
||||
None => return f(init, (Position::Only, head)),
|
||||
}
|
||||
}
|
||||
// Have seen the first item, and there's something left.
|
||||
init = self.peekable.fold(init, |acc, mut item| {
|
||||
std::mem::swap(&mut head, &mut item);
|
||||
f(acc, (Position::Middle, item))
|
||||
let position = Position {
|
||||
is_first: false,
|
||||
is_last: false,
|
||||
};
|
||||
f(acc, (position, item))
|
||||
});
|
||||
let position = Position {
|
||||
is_first: false,
|
||||
is_last: true,
|
||||
};
|
||||
// The "head" is now the last item.
|
||||
init = f(init, (Position::Last, head));
|
||||
init = f(init, (position, head));
|
||||
}
|
||||
init
|
||||
}
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ pub struct Zip<T> {
|
||||
/// implement [`IntoIterator`]) and yields elements
|
||||
/// until any of the subiterators yields `None`.
|
||||
///
|
||||
/// The iterator element type is a tuple like like `(A, B, ..., E)` where `A` to `E` are the
|
||||
/// The iterator element type is a tuple like `(A, B, ..., E)` where `A` to `E` are the
|
||||
/// element types of the subiterator.
|
||||
///
|
||||
/// **Note:** The result of this function is a value of a named type (`Zip<(I, J,
|
||||
|
||||
@@ -49,3 +49,7 @@ fn combinations_no_collect() {
|
||||
fn combinations_with_replacement_no_collect() {
|
||||
no_collect_test(|iter| iter.combinations_with_replacement(5))
|
||||
}
|
||||
#[test]
|
||||
fn array_combinations_with_replacement_no_collect() {
|
||||
no_collect_test(|iter| iter.array_combinations_with_replacement::<5>())
|
||||
}
|
||||
|
||||
+483
@@ -0,0 +1,483 @@
|
||||
use itertools::Itertools;
|
||||
|
||||
#[test]
|
||||
fn array_windows() {
|
||||
let [vec0, vec1, vec2, vec4, vec10] = [
|
||||
vec![],
|
||||
vec![1],
|
||||
vec![1, 2],
|
||||
vec![1, 2, 3, 4],
|
||||
vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
vec10
|
||||
.iter()
|
||||
.copied()
|
||||
.array_windows::<2>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
[1, 2],
|
||||
[2, 3],
|
||||
[3, 4],
|
||||
[4, 5],
|
||||
[5, 6],
|
||||
[6, 7],
|
||||
[7, 8],
|
||||
[8, 9],
|
||||
[9, 10],
|
||||
]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec4.iter()
|
||||
.copied()
|
||||
.array_windows::<2>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![[1, 2], [2, 3], [3, 4]]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec2.iter()
|
||||
.copied()
|
||||
.array_windows::<2>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![[1, 2]]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec1.iter()
|
||||
.copied()
|
||||
.array_windows::<2>()
|
||||
.collect::<Vec<_>>(),
|
||||
Vec::<[i32; 2]>::new()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec0.iter()
|
||||
.copied()
|
||||
.array_windows::<2>()
|
||||
.collect::<Vec<_>>(),
|
||||
Vec::<[i32; 2]>::new()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec10
|
||||
.iter()
|
||||
.copied()
|
||||
.array_windows::<4>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
[1, 2, 3, 4],
|
||||
[2, 3, 4, 5],
|
||||
[3, 4, 5, 6],
|
||||
[4, 5, 6, 7],
|
||||
[5, 6, 7, 8],
|
||||
[6, 7, 8, 9],
|
||||
[7, 8, 9, 10],
|
||||
]
|
||||
);
|
||||
|
||||
// For zero-length output windows, the equation
|
||||
//
|
||||
// output length = input length + N - 1
|
||||
//
|
||||
// implies that we return one _more_ zero-length window than there
|
||||
// are input items, as if we were returning a zero-length window
|
||||
// for each position between elements of the input list, including
|
||||
// the positions at the start and end.
|
||||
assert_eq!(
|
||||
vec0.iter()
|
||||
.copied()
|
||||
.array_windows::<0>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![[]]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec1.iter()
|
||||
.copied()
|
||||
.array_windows::<0>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![[], []]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec2.iter()
|
||||
.copied()
|
||||
.array_windows::<0>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![[], [], []]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec0.iter()
|
||||
.copied()
|
||||
.array_windows::<1>()
|
||||
.collect::<Vec<_>>(),
|
||||
Vec::<[i32; 1]>::new()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec1.iter()
|
||||
.copied()
|
||||
.array_windows::<1>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![[1]]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec2.iter()
|
||||
.copied()
|
||||
.array_windows::<1>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![[1], [2]]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec1.iter()
|
||||
.copied()
|
||||
.array_windows::<7>()
|
||||
.collect::<Vec<_>>(),
|
||||
Vec::<[i32; 7]>::new()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec2.iter()
|
||||
.copied()
|
||||
.array_windows::<7>()
|
||||
.collect::<Vec<_>>(),
|
||||
Vec::<[i32; 7]>::new()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec4.iter()
|
||||
.copied()
|
||||
.array_windows::<7>()
|
||||
.collect::<Vec<_>>(),
|
||||
Vec::<[i32; 7]>::new()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_windows_equal_tuple_windows() {
|
||||
fn internal(slice: &[usize]) {
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.tuple_windows::<(_,)>()
|
||||
.map(Into::<[_; 1]>::into),
|
||||
slice.iter().array_windows::<1>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.tuple_windows::<(_, _)>()
|
||||
.map(Into::<[_; 2]>::into),
|
||||
slice.iter().array_windows::<2>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.tuple_windows::<(_, _, _)>()
|
||||
.map(Into::<[_; 3]>::into),
|
||||
slice.iter().array_windows::<3>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.tuple_windows::<(_, _, _, _)>()
|
||||
.map(Into::<[_; 4]>::into),
|
||||
slice.iter().array_windows::<4>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.tuple_windows::<(_, _, _, _, _)>()
|
||||
.map(Into::<[_; 5]>::into),
|
||||
slice.iter().array_windows::<5>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.tuple_windows::<(_, _, _, _, _, _)>()
|
||||
.map(Into::<[_; 6]>::into),
|
||||
slice.iter().array_windows::<6>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.tuple_windows::<(_, _, _, _, _, _, _)>()
|
||||
.map(Into::<[_; 7]>::into),
|
||||
slice.iter().array_windows::<7>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.tuple_windows::<(_, _, _, _, _, _, _, _)>()
|
||||
.map(Into::<[_; 8]>::into),
|
||||
slice.iter().array_windows::<8>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.tuple_windows::<(_, _, _, _, _, _, _, _, _)>()
|
||||
.map(Into::<[_; 9]>::into),
|
||||
slice.iter().array_windows::<9>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.tuple_windows::<(_, _, _, _, _, _, _, _, _, _)>()
|
||||
.map(Into::<[_; 10]>::into),
|
||||
slice.iter().array_windows::<10>(),
|
||||
);
|
||||
}
|
||||
for i in 0..100 {
|
||||
internal(&(0..i).collect::<Vec<_>>());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn circular_array_windows() {
|
||||
let [vec0, vec1, vec2, vec4, vec10] = [
|
||||
vec![],
|
||||
vec![1],
|
||||
vec![1, 2],
|
||||
vec![1, 2, 3, 4],
|
||||
vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
vec10
|
||||
.iter()
|
||||
.copied()
|
||||
.circular_array_windows::<2>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
[1, 2],
|
||||
[2, 3],
|
||||
[3, 4],
|
||||
[4, 5],
|
||||
[5, 6],
|
||||
[6, 7],
|
||||
[7, 8],
|
||||
[8, 9],
|
||||
[9, 10],
|
||||
[10, 1]
|
||||
]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec4.iter()
|
||||
.copied()
|
||||
.circular_array_windows::<2>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![[1, 2], [2, 3], [3, 4], [4, 1]]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec2.iter()
|
||||
.copied()
|
||||
.circular_array_windows::<2>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![[1, 2], [2, 1]]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec1.iter()
|
||||
.copied()
|
||||
.circular_array_windows::<2>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![[1, 1]]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec0.iter()
|
||||
.copied()
|
||||
.circular_array_windows::<2>()
|
||||
.collect::<Vec<_>>(),
|
||||
Vec::<[i32; 2]>::new()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec10
|
||||
.iter()
|
||||
.copied()
|
||||
.circular_array_windows::<4>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
[1, 2, 3, 4],
|
||||
[2, 3, 4, 5],
|
||||
[3, 4, 5, 6],
|
||||
[4, 5, 6, 7],
|
||||
[5, 6, 7, 8],
|
||||
[6, 7, 8, 9],
|
||||
[7, 8, 9, 10],
|
||||
[8, 9, 10, 1],
|
||||
[9, 10, 1, 2],
|
||||
[10, 1, 2, 3],
|
||||
]
|
||||
);
|
||||
|
||||
// For zero-length output windows, we preserve the invariant that
|
||||
// output length = input length, and return the same number of
|
||||
// zero-length windows as there were input items, as if we were
|
||||
// returning a zero-length window for every possible starting
|
||||
// position in the cyclic input list.
|
||||
assert_eq!(
|
||||
vec0.iter()
|
||||
.copied()
|
||||
.circular_array_windows::<0>()
|
||||
.collect::<Vec<_>>(),
|
||||
Vec::<[i32; 0]>::new()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec1.iter()
|
||||
.copied()
|
||||
.circular_array_windows::<0>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![[]]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec2.iter()
|
||||
.copied()
|
||||
.circular_array_windows::<0>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![[], []]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec0.iter()
|
||||
.copied()
|
||||
.circular_array_windows::<1>()
|
||||
.collect::<Vec<_>>(),
|
||||
Vec::<[i32; 1]>::new()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec1.iter()
|
||||
.copied()
|
||||
.circular_array_windows::<1>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![[1]]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec2.iter()
|
||||
.copied()
|
||||
.circular_array_windows::<1>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![[1], [2]]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec1.iter()
|
||||
.copied()
|
||||
.circular_array_windows::<7>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![[1, 1, 1, 1, 1, 1, 1]]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec2.iter()
|
||||
.copied()
|
||||
.circular_array_windows::<7>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![[1, 2, 1, 2, 1, 2, 1], [2, 1, 2, 1, 2, 1, 2]]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec4.iter()
|
||||
.copied()
|
||||
.circular_array_windows::<7>()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
[1, 2, 3, 4, 1, 2, 3],
|
||||
[2, 3, 4, 1, 2, 3, 4],
|
||||
[3, 4, 1, 2, 3, 4, 1],
|
||||
[4, 1, 2, 3, 4, 1, 2],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn circular_array_windows_equal_circular_tuple_windows() {
|
||||
fn internal(slice: &[usize]) {
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.circular_tuple_windows::<(_,)>()
|
||||
.map(Into::<[_; 1]>::into),
|
||||
slice.iter().circular_array_windows::<1>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.circular_tuple_windows::<(_, _)>()
|
||||
.map(Into::<[_; 2]>::into),
|
||||
slice.iter().circular_array_windows::<2>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.circular_tuple_windows::<(_, _, _)>()
|
||||
.map(Into::<[_; 3]>::into),
|
||||
slice.iter().circular_array_windows::<3>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.circular_tuple_windows::<(_, _, _, _)>()
|
||||
.map(Into::<[_; 4]>::into),
|
||||
slice.iter().circular_array_windows::<4>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.circular_tuple_windows::<(_, _, _, _, _)>()
|
||||
.map(Into::<[_; 5]>::into),
|
||||
slice.iter().circular_array_windows::<5>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.circular_tuple_windows::<(_, _, _, _, _, _)>()
|
||||
.map(Into::<[_; 6]>::into),
|
||||
slice.iter().circular_array_windows::<6>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.circular_tuple_windows::<(_, _, _, _, _, _, _)>()
|
||||
.map(Into::<[_; 7]>::into),
|
||||
slice.iter().circular_array_windows::<7>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.circular_tuple_windows::<(_, _, _, _, _, _, _, _)>()
|
||||
.map(Into::<[_; 8]>::into),
|
||||
slice.iter().circular_array_windows::<8>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.circular_tuple_windows::<(_, _, _, _, _, _, _, _, _)>()
|
||||
.map(Into::<[_; 9]>::into),
|
||||
slice.iter().circular_array_windows::<9>(),
|
||||
);
|
||||
itertools::assert_equal(
|
||||
slice
|
||||
.iter()
|
||||
.circular_tuple_windows::<(_, _, _, _, _, _, _, _, _, _)>()
|
||||
.map(Into::<[_; 10]>::into),
|
||||
slice.iter().circular_array_windows::<10>(),
|
||||
);
|
||||
}
|
||||
for i in 0..100 {
|
||||
internal(&(0..i).collect::<Vec<_>>());
|
||||
}
|
||||
}
|
||||
+29
@@ -104,6 +104,18 @@ must_use_tests! {
|
||||
let _ = Panicking.circular_tuple_windows::<(_, _)>();
|
||||
let _ = Panicking.circular_tuple_windows::<(_, _, _)>();
|
||||
}
|
||||
array_windows {
|
||||
let _ = Panicking.array_windows::<0>();
|
||||
let _ = Panicking.array_windows::<1>();
|
||||
let _ = Panicking.array_windows::<2>();
|
||||
let _ = Panicking.array_windows::<3>();
|
||||
}
|
||||
circular_array_windows {
|
||||
let _ = Panicking.circular_array_windows::<0>();
|
||||
let _ = Panicking.circular_array_windows::<1>();
|
||||
let _ = Panicking.circular_array_windows::<2>();
|
||||
let _ = Panicking.circular_array_windows::<3>();
|
||||
}
|
||||
tuples {
|
||||
let _ = Panicking.tuples::<(_,)>();
|
||||
let _ = Panicking.tuples::<(_, _)>();
|
||||
@@ -196,17 +208,29 @@ must_use_tests! {
|
||||
while_some {
|
||||
let _ = Panicking.map(Some).while_some();
|
||||
}
|
||||
#[allow(deprecated)]
|
||||
tuple_combinations1 {
|
||||
let _ = Panicking.tuple_combinations::<(_,)>();
|
||||
}
|
||||
#[allow(deprecated)]
|
||||
#[should_panic]
|
||||
tuple_combinations2 {
|
||||
let _ = Panicking.tuple_combinations::<(_, _)>();
|
||||
}
|
||||
#[allow(deprecated)]
|
||||
#[should_panic]
|
||||
tuple_combinations3 {
|
||||
let _ = Panicking.tuple_combinations::<(_, _, _)>();
|
||||
}
|
||||
array_combinations1 {
|
||||
let _ = Panicking.array_combinations::<1>();
|
||||
}
|
||||
array_combinations2 {
|
||||
let _ = Panicking.array_combinations::<2>();
|
||||
}
|
||||
array_combinations3 {
|
||||
let _ = Panicking.array_combinations::<3>();
|
||||
}
|
||||
combinations {
|
||||
let _ = Panicking.combinations(0);
|
||||
let _ = Panicking.combinations(1);
|
||||
@@ -217,6 +241,11 @@ must_use_tests! {
|
||||
let _ = Panicking.combinations_with_replacement(1);
|
||||
let _ = Panicking.combinations_with_replacement(2);
|
||||
}
|
||||
array_combinations_with_replacement {
|
||||
let _ = Panicking.array_combinations_with_replacement::<0>();
|
||||
let _ = Panicking.array_combinations_with_replacement::<1>();
|
||||
let _ = Panicking.array_combinations_with_replacement::<2>();
|
||||
}
|
||||
permutations {
|
||||
let _ = Panicking.permutations(0);
|
||||
let _ = Panicking.permutations(1);
|
||||
|
||||
+198
-28
@@ -275,8 +275,7 @@ where
|
||||
let actual_count = total_actual_count - i;
|
||||
if actual_count != returned_count {
|
||||
println!(
|
||||
"Total iterations: {} True count: {} returned count: {}",
|
||||
i, actual_count, returned_count
|
||||
"Total iterations: {i} True count: {actual_count} returned count: {returned_count}"
|
||||
);
|
||||
|
||||
return false;
|
||||
@@ -450,7 +449,13 @@ quickcheck! {
|
||||
}
|
||||
assert_eq!(answer, actual);
|
||||
|
||||
assert_eq!(answer.into_iter().last(), a.multi_cartesian_product().last());
|
||||
assert_eq!(
|
||||
{
|
||||
#[allow(clippy::double_ended_iterator_last)]
|
||||
answer.into_iter().last()
|
||||
},
|
||||
a.multi_cartesian_product().last()
|
||||
);
|
||||
}
|
||||
|
||||
fn correct_empty_multi_product() -> () {
|
||||
@@ -993,6 +998,45 @@ quickcheck! {
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn pad_using_next_next_back(v: Vec<i8>) -> () {
|
||||
let only_oks = v.into_iter().map(Ok).collect::<Vec<_>>();
|
||||
for elements_required in 0..128 {
|
||||
let mut oks_then_errs_vector = only_oks.clone();
|
||||
while oks_then_errs_vector.len() < elements_required {
|
||||
oks_then_errs_vector.push(Err(oks_then_errs_vector.len()));
|
||||
}
|
||||
let oks_then_errs_pad_using = only_oks.iter().copied().pad_using(elements_required, Err);
|
||||
assert_eq!(
|
||||
oks_then_errs_pad_using.clone().collect::<Vec<_>>(),
|
||||
oks_then_errs_vector
|
||||
);
|
||||
// Check next, next_back (https://github.com/rust-itertools/itertools/issues/1065)
|
||||
let mut iter_check = oks_then_errs_vector.into_iter();
|
||||
let mut iter_real = oks_then_errs_pad_using;
|
||||
let mut rng = rand::thread_rng();
|
||||
loop {
|
||||
let next_or_next_back = if rng.gen_bool(0.5) {
|
||||
let element_next_check = iter_check.next();
|
||||
let element_next_real = iter_real.next();
|
||||
assert_eq!(element_next_check, element_next_real);
|
||||
element_next_real
|
||||
} else {
|
||||
let element_next_back_check = iter_check.next_back();
|
||||
let element_next_back_real = iter_real.next_back();
|
||||
assert_eq!(element_next_back_check, element_next_back_real);
|
||||
element_next_back_real
|
||||
};
|
||||
if next_or_next_back.is_none() {
|
||||
assert!(iter_real.next().is_none());
|
||||
assert!(iter_real.next_back().is_none());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn size_powerset(it: Iter<u8, Exact>) -> bool {
|
||||
// Powerset cardinality gets large very quickly, limit input to keep test fast.
|
||||
@@ -1059,7 +1103,7 @@ quickcheck! {
|
||||
|
||||
let tup1 = |(_, b)| b;
|
||||
for &(ord, consume_now) in &order {
|
||||
let iter = &mut [&mut chunks1, &mut chunks2][ord as usize];
|
||||
let iter = &mut [&mut chunks1, &mut chunks2][usize::from(ord)];
|
||||
match iter.next() {
|
||||
Some((_, gr)) => if consume_now {
|
||||
for og in old_chunks.drain(..) {
|
||||
@@ -1256,6 +1300,79 @@ quickcheck! {
|
||||
}
|
||||
}
|
||||
|
||||
// array iterators
|
||||
quickcheck! {
|
||||
fn equal_array_windows_0(a: Vec<u8>) -> bool {
|
||||
let x = (0..=a.len()).map(|_| [&0u8; 0] );
|
||||
let y = a.iter().array_windows::<0>();
|
||||
itertools::assert_equal(x,y);
|
||||
true
|
||||
}
|
||||
|
||||
fn equal_array_windows_1(a: Vec<u8>) -> bool {
|
||||
let x = a.iter().map(|e| [e] );
|
||||
let y = a.iter().array_windows::<1>();
|
||||
itertools::assert_equal(x,y);
|
||||
true
|
||||
}
|
||||
|
||||
fn equal_array_windows_2(a: Vec<u8>) -> bool {
|
||||
let x = (0..a.len().saturating_sub(1)).map(|start_idx| [
|
||||
&a[start_idx],
|
||||
&a[start_idx + 1],
|
||||
]);
|
||||
let y = a.iter().array_windows::<2>();
|
||||
itertools::assert_equal(x,y);
|
||||
true
|
||||
}
|
||||
|
||||
fn equal_array_windows_3(a: Vec<u8>) -> bool {
|
||||
let x = (0..a.len().saturating_sub(2)).map(|start_idx| [
|
||||
&a[start_idx],
|
||||
&a[start_idx + 1],
|
||||
&a[start_idx + 2],
|
||||
]);
|
||||
let y = a.iter().array_windows::<3>();
|
||||
itertools::assert_equal(x,y);
|
||||
true
|
||||
}
|
||||
|
||||
fn equal_circular_array_windows_0(a: Vec<u8>) -> bool {
|
||||
let x = a.iter().map(|_| [&0u8; 0] );
|
||||
let y = a.iter().circular_array_windows::<0>();
|
||||
itertools::assert_equal(x,y);
|
||||
true
|
||||
}
|
||||
|
||||
fn equal_circular_array_windows_1(a: Vec<u8>) -> bool {
|
||||
let x = a.iter().map(|e| [e] );
|
||||
let y = a.iter().circular_array_windows::<1>();
|
||||
itertools::assert_equal(x,y);
|
||||
true
|
||||
}
|
||||
|
||||
fn equal_circular_array_windows_2(a: Vec<u8>) -> bool {
|
||||
let x = (0..a.len()).map(|start_idx| [
|
||||
&a[start_idx],
|
||||
&a[(start_idx + 1) % a.len()],
|
||||
]);
|
||||
let y = a.iter().circular_array_windows::<2>();
|
||||
itertools::assert_equal(x,y);
|
||||
true
|
||||
}
|
||||
|
||||
fn equal_circular_array_windows_3(a: Vec<u8>) -> bool {
|
||||
let x = (0..a.len()).map(|start_idx| [
|
||||
&a[start_idx],
|
||||
&a[(start_idx + 1) % a.len()],
|
||||
&a[(start_idx + 2) % a.len()],
|
||||
]);
|
||||
let y = a.iter().circular_array_windows::<3>();
|
||||
itertools::assert_equal(x,y);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
// with_position
|
||||
quickcheck! {
|
||||
fn with_position_exact_size_1(a: Vec<u8>) -> bool {
|
||||
@@ -1385,6 +1502,16 @@ quickcheck! {
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn exactly_one_count(a: Vec<i32>) -> TestResult {
|
||||
let ret = a.iter().cloned().exactly_one();
|
||||
match a.len() {
|
||||
1 => TestResult::passed(),
|
||||
len => TestResult::from_bool(len == ret.unwrap_err().count()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn at_most_one_i32(a: Vec<i32>) -> TestResult {
|
||||
let ret = a.iter().cloned().at_most_one();
|
||||
@@ -1407,9 +1534,9 @@ quickcheck! {
|
||||
}
|
||||
|
||||
fn correct_grouping_map_by_aggregate_modulo_key(a: Vec<u8>, modulo: u8) -> () {
|
||||
let modulo = if modulo < 2 { 2 } else { modulo } as u64; // Avoid `% 0`
|
||||
let modulo = u64::from(if modulo < 2 { 2 } else { modulo }); // Avoid `% 0`
|
||||
let lookup = a.iter()
|
||||
.map(|&b| b as u64) // Avoid overflows
|
||||
.map(|&b| u64::from(b)) // Avoid overflows
|
||||
.into_grouping_map_by(|i| i % modulo)
|
||||
.aggregate(|acc, &key, val| {
|
||||
assert!(val % modulo == key);
|
||||
@@ -1421,7 +1548,7 @@ quickcheck! {
|
||||
});
|
||||
|
||||
let group_map_lookup = a.iter()
|
||||
.map(|&b| b as u64)
|
||||
.map(|&b| u64::from(b))
|
||||
.map(|i| (i % modulo, i))
|
||||
.into_group_map()
|
||||
.into_iter()
|
||||
@@ -1441,7 +1568,7 @@ quickcheck! {
|
||||
assert_eq!(
|
||||
lookup.get(&m).copied(),
|
||||
a.iter()
|
||||
.map(|&b| b as u64)
|
||||
.map(|&b| u64::from(b))
|
||||
.filter(|&val| val % modulo == m)
|
||||
.fold(None, |acc, val| {
|
||||
if val % (modulo - 1) == 0 {
|
||||
@@ -1460,8 +1587,8 @@ quickcheck! {
|
||||
acc: u64,
|
||||
}
|
||||
|
||||
let modulo = if modulo == 0 { 1 } else { modulo } as u64; // Avoid `% 0`
|
||||
let lookup = a.iter().map(|&b| b as u64) // Avoid overflows
|
||||
let modulo = u64::from(if modulo == 0 { 1 } else { modulo }); // Avoid `% 0`
|
||||
let lookup = a.iter().map(|&b| u64::from(b)) // Avoid overflows
|
||||
.into_grouping_map_by(|i| i % modulo)
|
||||
.fold_with(|_key, _val| Default::default(), |Accumulator { acc }, &key, val| {
|
||||
assert!(val % modulo == key);
|
||||
@@ -1470,7 +1597,7 @@ quickcheck! {
|
||||
});
|
||||
|
||||
let group_map_lookup = a.iter()
|
||||
.map(|&b| b as u64)
|
||||
.map(|&b| u64::from(b))
|
||||
.map(|i| (i % modulo, i))
|
||||
.into_group_map()
|
||||
.into_iter()
|
||||
@@ -1479,13 +1606,13 @@ quickcheck! {
|
||||
assert_eq!(lookup, group_map_lookup);
|
||||
|
||||
for (&key, &Accumulator { acc: sum }) in lookup.iter() {
|
||||
assert_eq!(sum, a.iter().map(|&b| b as u64).filter(|&val| val % modulo == key).sum::<u64>());
|
||||
assert_eq!(sum, a.iter().map(|&b| u64::from(b)).filter(|&val| val % modulo == key).sum::<u64>());
|
||||
}
|
||||
}
|
||||
|
||||
fn correct_grouping_map_by_fold_modulo_key(a: Vec<u8>, modulo: u8) -> () {
|
||||
let modulo = if modulo == 0 { 1 } else { modulo } as u64; // Avoid `% 0`
|
||||
let lookup = a.iter().map(|&b| b as u64) // Avoid overflows
|
||||
let modulo = u64::from(if modulo == 0 { 1 } else { modulo }); // Avoid `% 0`
|
||||
let lookup = a.iter().map(|&b| u64::from(b)) // Avoid overflows
|
||||
.into_grouping_map_by(|i| i % modulo)
|
||||
.fold(0u64, |acc, &key, val| {
|
||||
assert!(val % modulo == key);
|
||||
@@ -1493,7 +1620,7 @@ quickcheck! {
|
||||
});
|
||||
|
||||
let group_map_lookup = a.iter()
|
||||
.map(|&b| b as u64)
|
||||
.map(|&b| u64::from(b))
|
||||
.map(|i| (i % modulo, i))
|
||||
.into_group_map()
|
||||
.into_iter()
|
||||
@@ -1502,13 +1629,13 @@ quickcheck! {
|
||||
assert_eq!(lookup, group_map_lookup);
|
||||
|
||||
for (&key, &sum) in lookup.iter() {
|
||||
assert_eq!(sum, a.iter().map(|&b| b as u64).filter(|&val| val % modulo == key).sum::<u64>());
|
||||
assert_eq!(sum, a.iter().map(|&b| u64::from(b)).filter(|&val| val % modulo == key).sum::<u64>());
|
||||
}
|
||||
}
|
||||
|
||||
fn correct_grouping_map_by_reduce_modulo_key(a: Vec<u8>, modulo: u8) -> () {
|
||||
let modulo = if modulo == 0 { 1 } else { modulo } as u64; // Avoid `% 0`
|
||||
let lookup = a.iter().map(|&b| b as u64) // Avoid overflows
|
||||
let modulo = u64::from(if modulo == 0 { 1 } else { modulo }); // Avoid `% 0`
|
||||
let lookup = a.iter().map(|&b| u64::from(b)) // Avoid overflows
|
||||
.into_grouping_map_by(|i| i % modulo)
|
||||
.reduce(|acc, &key, val| {
|
||||
assert!(val % modulo == key);
|
||||
@@ -1516,7 +1643,7 @@ quickcheck! {
|
||||
});
|
||||
|
||||
let group_map_lookup = a.iter()
|
||||
.map(|&b| b as u64)
|
||||
.map(|&b| u64::from(b))
|
||||
.map(|i| (i % modulo, i))
|
||||
.into_group_map()
|
||||
.into_iter()
|
||||
@@ -1525,7 +1652,7 @@ quickcheck! {
|
||||
assert_eq!(lookup, group_map_lookup);
|
||||
|
||||
for (&key, &sum) in lookup.iter() {
|
||||
assert_eq!(sum, a.iter().map(|&b| b as u64).filter(|&val| val % modulo == key).sum::<u64>());
|
||||
assert_eq!(sum, a.iter().map(|&b| u64::from(b)).filter(|&val| val % modulo == key).sum::<u64>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1691,12 +1818,12 @@ quickcheck! {
|
||||
}
|
||||
|
||||
fn correct_grouping_map_by_sum_modulo_key(a: Vec<u8>, modulo: u8) -> () {
|
||||
let modulo = if modulo == 0 { 1 } else { modulo } as u64; // Avoid `% 0`
|
||||
let lookup = a.iter().map(|&b| b as u64) // Avoid overflows
|
||||
let modulo = u64::from(if modulo == 0 { 1 } else { modulo }); // Avoid `% 0`
|
||||
let lookup = a.iter().map(|&b| u64::from(b)) // Avoid overflows
|
||||
.into_grouping_map_by(|i| i % modulo)
|
||||
.sum();
|
||||
|
||||
let group_map_lookup = a.iter().map(|&b| b as u64)
|
||||
let group_map_lookup = a.iter().map(|&b| u64::from(b))
|
||||
.map(|i| (i % modulo, i))
|
||||
.into_group_map()
|
||||
.into_iter()
|
||||
@@ -1705,17 +1832,17 @@ quickcheck! {
|
||||
assert_eq!(lookup, group_map_lookup);
|
||||
|
||||
for (&key, &sum) in lookup.iter() {
|
||||
assert_eq!(sum, a.iter().map(|&b| b as u64).filter(|&val| val % modulo == key).sum::<u64>());
|
||||
assert_eq!(sum, a.iter().map(|&b| u64::from(b)).filter(|&val| val % modulo == key).sum::<u64>());
|
||||
}
|
||||
}
|
||||
|
||||
fn correct_grouping_map_by_product_modulo_key(a: Vec<u8>, modulo: u8) -> () {
|
||||
let modulo = Wrapping(if modulo == 0 { 1 } else { modulo } as u64); // Avoid `% 0`
|
||||
let lookup = a.iter().map(|&b| Wrapping(b as u64)) // Avoid overflows
|
||||
let modulo = Wrapping(u64::from(if modulo == 0 { 1 } else { modulo })); // Avoid `% 0`
|
||||
let lookup = a.iter().map(|&b| Wrapping(u64::from(b))) // Avoid overflows
|
||||
.into_grouping_map_by(|i| i % modulo)
|
||||
.product();
|
||||
|
||||
let group_map_lookup = a.iter().map(|&b| Wrapping(b as u64))
|
||||
let group_map_lookup = a.iter().map(|&b| Wrapping(u64::from(b)))
|
||||
.map(|i| (i % modulo, i))
|
||||
.into_group_map()
|
||||
.into_iter()
|
||||
@@ -1727,7 +1854,7 @@ quickcheck! {
|
||||
assert_eq!(
|
||||
prod,
|
||||
a.iter()
|
||||
.map(|&b| Wrapping(b as u64))
|
||||
.map(|&b| Wrapping(u64::from(b)))
|
||||
.filter(|&val| val % modulo == key)
|
||||
.product::<Wrapping<u64>>()
|
||||
);
|
||||
@@ -1832,6 +1959,11 @@ quickcheck! {
|
||||
is_fused(a.combinations_with_replacement(3))
|
||||
}
|
||||
|
||||
fn fused_array_combination_with_replacement(a: Iter<i16>) -> bool
|
||||
{
|
||||
is_fused(a.clone().array_combinations_with_replacement::<1>()) &&
|
||||
is_fused(a.array_combinations_with_replacement::<3>())
|
||||
}
|
||||
fn fused_tuple_combination(a: Iter<i16>) -> bool
|
||||
{
|
||||
is_fused(a.clone().fuse().tuple_combinations::<(_,)>()) &&
|
||||
@@ -1966,4 +2098,42 @@ quickcheck! {
|
||||
itertools::equal(v.iter().tail(n), result)
|
||||
&& itertools::equal(v.iter().filter(|_| true).tail(n), result)
|
||||
}
|
||||
|
||||
fn strip_prefix_matches_str(haystack: String, needle: String) -> bool {
|
||||
let expected = haystack.strip_prefix(&needle);
|
||||
let got: Option<String> = haystack
|
||||
.chars()
|
||||
.strip_prefix(needle.chars())
|
||||
.ok()
|
||||
.map(Iterator::collect);
|
||||
got.as_deref() == expected
|
||||
}
|
||||
|
||||
fn strip_prefix_by_matches_strip_prefix(v: Vec<i32>, n: u8) -> bool {
|
||||
let prefix: Vec<i32> = v.iter().take(n as usize).copied().collect();
|
||||
let by_eq = v.iter().strip_prefix_by(&prefix, |a, b| **a == **b).ok();
|
||||
let plain = v.iter().strip_prefix(prefix.iter()).ok();
|
||||
match (by_eq, plain) {
|
||||
(Some(a), Some(b)) => itertools::equal(a, b),
|
||||
(None, None) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn strip_prefix_error_exposes_mismatch_and_remainders() {
|
||||
let err = (1..6)
|
||||
.strip_prefix([1, 2, 9, 4])
|
||||
.expect_err("third item mismatches");
|
||||
assert_eq!(err.mismatch, (Some(3), 9));
|
||||
assert_eq!(err.prefix.collect_vec(), vec![4]);
|
||||
assert_eq!(err.iterator.collect_vec(), vec![4, 5]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn strip_prefix_error_signals_self_exhausted() {
|
||||
let err = (1..3).strip_prefix([1, 2, 3]).expect_err("self exhausted");
|
||||
assert_eq!(err.mismatch, (None, 3));
|
||||
assert!(err.iterator.collect_vec().is_empty());
|
||||
}
|
||||
|
||||
+15
-1
@@ -255,6 +255,7 @@ quickcheck! {
|
||||
test_double_ended_specializations(&it);
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
fn tuple_combinations(v: Vec<u8>) -> TestResult {
|
||||
if v.len() > 10 {
|
||||
return TestResult::discard();
|
||||
@@ -299,6 +300,16 @@ quickcheck! {
|
||||
TestResult::passed()
|
||||
}
|
||||
|
||||
fn array_combinations_with_replacement(a: Vec<u8>) -> TestResult {
|
||||
if a.len() > 10 {
|
||||
return TestResult::discard();
|
||||
}
|
||||
test_specializations(&a.iter().array_combinations_with_replacement::<1>());
|
||||
test_specializations(&a.iter().array_combinations_with_replacement::<2>());
|
||||
test_specializations(&a.iter().array_combinations_with_replacement::<3>());
|
||||
|
||||
TestResult::passed()
|
||||
}
|
||||
fn permutations(a: Vec<u8>, n: u8) -> TestResult {
|
||||
if n > 3 || a.len() > 8 {
|
||||
return TestResult::discard();
|
||||
@@ -503,7 +514,10 @@ quickcheck! {
|
||||
}
|
||||
|
||||
check_results_specialized!(it, |i| i.count());
|
||||
check_results_specialized!(it, |i| i.last());
|
||||
check_results_specialized!(it, |i| {
|
||||
#[allow(clippy::double_ended_iterator_last)]
|
||||
i.last()
|
||||
});
|
||||
check_results_specialized!(it, |i| i.collect::<Vec<_>>());
|
||||
check_results_specialized!(it, |i| i.rev().collect::<Vec<_>>());
|
||||
check_results_specialized!(it, |i| {
|
||||
|
||||
+2
-1
@@ -226,7 +226,7 @@ fn batching() {
|
||||
let pit = xs
|
||||
.iter()
|
||||
.cloned()
|
||||
.batching(|it| it.next().and_then(|x| it.next().map(|y| (x, y))));
|
||||
.batching(|it| it.next_array::<2>().map(|[a, b]| (a, b)));
|
||||
it::assert_equal(pit, ys.iter().cloned());
|
||||
}
|
||||
|
||||
@@ -281,6 +281,7 @@ fn count_clones() {
|
||||
let f = Foo { n: Cell::new(0) };
|
||||
let it = it::repeat_n(f, n);
|
||||
// drain it
|
||||
#[allow(clippy::double_ended_iterator_last)]
|
||||
let last = it.last();
|
||||
if n == 0 {
|
||||
assert_eq!(last, None);
|
||||
|
||||
+119
-11
@@ -9,6 +9,7 @@ use crate::it::multipeek;
|
||||
use crate::it::multizip;
|
||||
use crate::it::peek_nth;
|
||||
use crate::it::repeat_n;
|
||||
use crate::it::AllEqualValueError;
|
||||
use crate::it::ExactlyOneError;
|
||||
use crate::it::FoldWhile;
|
||||
use crate::it::Itertools;
|
||||
@@ -20,8 +21,31 @@ use rand::{
|
||||
Rng, SeedableRng,
|
||||
};
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
use std::collections::HashMap;
|
||||
use std::hash::BuildHasher;
|
||||
use std::hash::RandomState;
|
||||
use std::iter::empty;
|
||||
use std::{cmp::min, fmt::Debug, marker::PhantomData};
|
||||
|
||||
// A Hasher which forwards it's calls to RandomState to make sure different hashers
|
||||
// are accepted in the various *_with_hasher methods.
|
||||
#[derive(Default)]
|
||||
struct TestHasher(RandomState);
|
||||
|
||||
impl TestHasher {
|
||||
fn new() -> Self {
|
||||
TestHasher(RandomState::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildHasher for TestHasher {
|
||||
type Hasher = <RandomState as BuildHasher>::Hasher;
|
||||
|
||||
fn build_hasher(&self) -> Self::Hasher {
|
||||
self.0.build_hasher()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn product3() {
|
||||
let prod = iproduct!(0..3, 0..2, 0..2);
|
||||
@@ -76,6 +100,10 @@ fn duplicates_by() {
|
||||
ys_rev.iter(),
|
||||
xs.iter().duplicates_by(|x| x[..2].to_string()).rev(),
|
||||
);
|
||||
|
||||
let _ = empty::<u8>()
|
||||
.duplicates_by_with_hasher(|x| *x, TestHasher::new())
|
||||
.next();
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -103,6 +131,10 @@ fn duplicates() {
|
||||
);
|
||||
let ys_rev = vec![2, 1];
|
||||
assert_eq!(ys_rev, xs.iter().duplicates().rev().cloned().collect_vec());
|
||||
|
||||
let _ = empty::<u8>()
|
||||
.duplicates_with_hasher(TestHasher::new())
|
||||
.next();
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -119,6 +151,8 @@ fn unique_by() {
|
||||
ys_rev.iter(),
|
||||
xs.iter().unique_by(|x| x[..2].to_string()).rev(),
|
||||
);
|
||||
|
||||
let _ = empty::<u8>().unique_by_with_hasher(|x| *x, TestHasher::new());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -136,6 +170,8 @@ fn unique() {
|
||||
it::assert_equal(ys.iter(), xs.iter().rev().unique().rev());
|
||||
let ys_rev = [1, 0];
|
||||
it::assert_equal(ys_rev.iter(), xs.iter().unique().rev());
|
||||
|
||||
let _ = empty::<u8>().unique_with_hasher(TestHasher::new());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -282,14 +318,17 @@ fn all_equal() {
|
||||
|
||||
#[test]
|
||||
fn all_equal_value() {
|
||||
assert_eq!("".chars().all_equal_value(), Err(None));
|
||||
assert_eq!("".chars().all_equal_value(), Err(AllEqualValueError(None)));
|
||||
assert_eq!("A".chars().all_equal_value(), Ok('A'));
|
||||
assert_eq!("AABBCCC".chars().all_equal_value(), Err(Some(('A', 'B'))));
|
||||
assert_eq!(
|
||||
"AABBCCC".chars().all_equal_value(),
|
||||
Err(AllEqualValueError(Some(['A', 'B'])))
|
||||
);
|
||||
assert_eq!("AAAAAAA".chars().all_equal_value(), Ok('A'));
|
||||
{
|
||||
let mut it = [1, 2, 3].iter().copied();
|
||||
let result = it.all_equal_value();
|
||||
assert_eq!(result, Err(Some((1, 2))));
|
||||
assert_eq!(result, Err(AllEqualValueError(Some([1, 2]))));
|
||||
let remaining = it.next();
|
||||
assert_eq!(remaining, Some(3));
|
||||
assert!(it.next().is_none());
|
||||
@@ -301,6 +340,8 @@ fn all_unique() {
|
||||
assert!("ABCDEFGH".chars().all_unique());
|
||||
assert!(!"ABCDEFGA".chars().all_unique());
|
||||
assert!(::std::iter::empty::<usize>().all_unique());
|
||||
|
||||
let _ = empty::<u8>().all_unique_with_hasher(TestHasher::new());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -443,13 +484,13 @@ fn kmerge_empty() {
|
||||
|
||||
#[test]
|
||||
fn kmerge_size_hint() {
|
||||
let its = (0..5).map(|_| (0..10));
|
||||
let its = (0..5).map(|_| 0..10);
|
||||
assert_eq!(its.kmerge().size_hint(), (50, Some(50)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kmerge_empty_size_hint() {
|
||||
let its = (0..5).map(|_| (0..0));
|
||||
let its = (0..5).map(|_| 0..0);
|
||||
assert_eq!(its.kmerge().size_hint(), (0, Some(0)));
|
||||
}
|
||||
|
||||
@@ -496,7 +537,7 @@ qc::quickcheck! {
|
||||
fn k_smallest_range(n: i64, m: u16, k: u16) -> () {
|
||||
// u16 is used to constrain k and m to 0..2¹⁶,
|
||||
// otherwise the test could use too much memory.
|
||||
let (k, m) = (k as usize, m as u64);
|
||||
let (k, m) = (k as usize, u64::from(m));
|
||||
|
||||
let mut v: Vec<_> = (n..n.saturating_add(m as _)).collect();
|
||||
// Generate a random permutation of n..n+m
|
||||
@@ -532,7 +573,7 @@ qc::quickcheck! {
|
||||
fn k_smallest_relaxed_range(n: i64, m: u16, k: u16) -> () {
|
||||
// u16 is used to constrain k and m to 0..2¹⁶,
|
||||
// otherwise the test could use too much memory.
|
||||
let (k, m) = (k as usize, m as u64);
|
||||
let (k, m) = (k as usize, u64::from(m));
|
||||
|
||||
let mut v: Vec<_> = (n..n.saturating_add(m as _)).collect();
|
||||
// Generate a random permutation of n..n+m
|
||||
@@ -1066,9 +1107,15 @@ fn combinations() {
|
||||
],
|
||||
);
|
||||
|
||||
it::assert_equal((0..0).tuple_combinations::<(_, _)>(), <Vec<_>>::new());
|
||||
it::assert_equal((0..1).tuple_combinations::<(_, _)>(), <Vec<_>>::new());
|
||||
it::assert_equal((0..2).tuple_combinations::<(_, _)>(), vec![(0, 1)]);
|
||||
#[allow(deprecated)]
|
||||
{
|
||||
it::assert_equal((0..0).tuple_combinations::<(_, _)>(), <Vec<_>>::new());
|
||||
it::assert_equal((0..1).tuple_combinations::<(_, _)>(), <Vec<_>>::new());
|
||||
it::assert_equal((0..2).tuple_combinations::<(_, _)>(), vec![(0, 1)]);
|
||||
}
|
||||
it::assert_equal((0..0).array_combinations::<2>(), <Vec<[isize; 2]>>::new());
|
||||
it::assert_equal((0..1).array_combinations::<2>(), <Vec<[isize; 2]>>::new());
|
||||
it::assert_equal((0..2).array_combinations::<2>(), vec![[0, 1]]);
|
||||
|
||||
it::assert_equal((0..0).combinations(2), <Vec<Vec<_>>>::new());
|
||||
it::assert_equal((0..1).combinations(1), vec![vec![0]]);
|
||||
@@ -1256,6 +1303,30 @@ fn combinations_with_replacement_range_count() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))]
|
||||
fn array_combinations_with_replacement() {
|
||||
// Pool smaller than n
|
||||
it::assert_equal(
|
||||
(0..1).array_combinations_with_replacement::<2>(),
|
||||
vec![[0, 0]],
|
||||
);
|
||||
// Pool larger than n
|
||||
it::assert_equal(
|
||||
(0..3).array_combinations_with_replacement::<2>(),
|
||||
vec![[0, 0], [0, 1], [0, 2], [1, 1], [1, 2], [2, 2]],
|
||||
);
|
||||
// Zero size
|
||||
it::assert_equal((0..3).array_combinations_with_replacement::<0>(), vec![[]]);
|
||||
// Zero size on empty pool
|
||||
it::assert_equal((0..0).array_combinations_with_replacement::<0>(), vec![[]]);
|
||||
// Empty pool
|
||||
it::assert_equal(
|
||||
(0..0).array_combinations_with_replacement::<2>(),
|
||||
vec![] as Vec<[_; 2]>,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn powerset() {
|
||||
it::assert_equal((0..0).powerset(), vec![vec![]]);
|
||||
@@ -1507,7 +1578,7 @@ fn tree_reduce() {
|
||||
Some(s.to_string())
|
||||
};
|
||||
let num_strings = (0..i).map(|x| x.to_string());
|
||||
let actual = num_strings.tree_reduce(|a, b| format!("{} {} x", a, b));
|
||||
let actual = num_strings.tree_reduce(|a, b| format!("{a} {b} x"));
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
@@ -1567,3 +1638,40 @@ fn multiunzip() {
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_group_map_with_hasher() {
|
||||
let _: HashMap<_, _, TestHasher> =
|
||||
empty::<(u8, u8)>().into_group_map_with_hasher(TestHasher::new());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_group_map_by_with_hasher() {
|
||||
let _: HashMap<_, _, TestHasher> =
|
||||
empty::<(u8, u8)>().into_group_map_by_with_hasher(|x| *x, TestHasher::new());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_grouping_map_with_hasher() {
|
||||
let _: HashMap<_, Vec<_>, TestHasher> = empty::<(u8, u8)>()
|
||||
.into_grouping_map_with_hasher(TestHasher::new())
|
||||
.collect();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_grouping_map_by_with_hasher() {
|
||||
let _: HashMap<_, Vec<_>, TestHasher> = empty::<(u8, u8)>()
|
||||
.into_grouping_map_by_with_hasher(|x| *x, TestHasher::new())
|
||||
.collect();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn counts_with_hasher() {
|
||||
let _: HashMap<_, _, TestHasher> = empty::<u8>().counts_with_hasher(TestHasher::new());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn counts_by_with_hasher() {
|
||||
let _: HashMap<_, _, TestHasher> =
|
||||
empty::<u8>().counts_by_with_hasher(|x| x, TestHasher::new());
|
||||
}
|
||||
|
||||
+46
@@ -54,3 +54,49 @@ fn test_double_ended_zip() {
|
||||
assert_eq!(it.next_back(), Some((1, 1)));
|
||||
assert_eq!(it.next_back(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// The purpose of this test is not really to test the iterator mechanics itself, rather that it
|
||||
/// compiles and accepts temporary values as inputs, as those would be valid when not used with the
|
||||
/// izip! macro and zipped manually via .zip calls
|
||||
fn test_izip_with_temporaries() {
|
||||
struct Owned {
|
||||
data: Vec<i32>,
|
||||
}
|
||||
|
||||
impl Owned {
|
||||
fn new(val: i32) -> Self {
|
||||
Self {
|
||||
data: vec![val; 10],
|
||||
}
|
||||
}
|
||||
|
||||
fn as_view(&self) -> View<'_> {
|
||||
View {
|
||||
data: self.data.as_slice(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct View<'a> {
|
||||
data: &'a [i32],
|
||||
}
|
||||
|
||||
impl View<'_> {
|
||||
fn iter(&self) -> impl Iterator<Item = &i32> {
|
||||
self.data.iter()
|
||||
}
|
||||
}
|
||||
|
||||
let a = Owned::new(0);
|
||||
let b = Owned::new(1);
|
||||
let c = Owned::new(2);
|
||||
|
||||
let mut sum = 0;
|
||||
|
||||
for (x, y, z) in itertools::izip!(a.as_view().iter(), b.as_view().iter(), c.as_view().iter()) {
|
||||
sum += x + y + z;
|
||||
}
|
||||
|
||||
assert_eq!(sum, 30);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user