Bug 1961207 - build(rust): shim-upgrade itertools 0.10.0 → 0.14.0 r=supply-chain-reviewers,glandium
Differential Revision: https://phabricator.services.mozilla.com/D245935
This commit is contained in:
21
Cargo.lock
generated
21
Cargo.lock
generated
@@ -423,7 +423,7 @@ dependencies = [
|
|||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
"cexpr",
|
"cexpr",
|
||||||
"clang-sys",
|
"clang-sys",
|
||||||
"itertools",
|
"itertools 0.10.999",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"lazycell",
|
"lazycell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -3393,9 +3393,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.10.5"
|
version = "0.10.999"
|
||||||
|
dependencies = [
|
||||||
|
"itertools 0.14.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
@@ -4176,7 +4183,7 @@ dependencies = [
|
|||||||
"futures",
|
"futures",
|
||||||
"getrandom 0.2.999",
|
"getrandom 0.2.999",
|
||||||
"hex",
|
"hex",
|
||||||
"itertools",
|
"itertools 0.10.999",
|
||||||
"maybe-async",
|
"maybe-async",
|
||||||
"mls-rs-codec",
|
"mls-rs-codec",
|
||||||
"mls-rs-core",
|
"mls-rs-core",
|
||||||
@@ -4423,7 +4430,7 @@ dependencies = [
|
|||||||
"icu_properties",
|
"icu_properties",
|
||||||
"idna",
|
"idna",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"itertools",
|
"itertools 0.14.0",
|
||||||
"libc",
|
"libc",
|
||||||
"lmdb-rkv-sys",
|
"lmdb-rkv-sys",
|
||||||
"log",
|
"log",
|
||||||
@@ -5338,7 +5345,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32"
|
checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"itertools",
|
"itertools 0.10.999",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
@@ -6316,7 +6323,7 @@ dependencies = [
|
|||||||
"gecko-profiler",
|
"gecko-profiler",
|
||||||
"icu_segmenter",
|
"icu_segmenter",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"itertools",
|
"itertools 0.14.0",
|
||||||
"itoa",
|
"itoa",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
|
|||||||
@@ -220,6 +220,9 @@ ron = { path = "build/rust/ron" }
|
|||||||
# Patch `strum` 0.26.* to 0.27.
|
# Patch `strum` 0.26.* to 0.27.
|
||||||
strum = { path = "build/rust/strum" }
|
strum = { path = "build/rust/strum" }
|
||||||
|
|
||||||
|
# Patch `itertools` 0.10.* to 0.14.
|
||||||
|
itertools = { path = "build/rust/itertools" }
|
||||||
|
|
||||||
# Overrides to allow easier use of common internal crates.
|
# Overrides to allow easier use of common internal crates.
|
||||||
moz_asserts = { path = "mozglue/static/rust/moz_asserts" }
|
moz_asserts = { path = "mozglue/static/rust/moz_asserts" }
|
||||||
|
|
||||||
|
|||||||
17
build/rust/itertools/Cargo.toml
Normal file
17
build/rust/itertools/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
[package]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.10.999"
|
||||||
|
edition = "2018"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "lib.rs"
|
||||||
|
|
||||||
|
[dependencies.itertools]
|
||||||
|
version = "0.14.0"
|
||||||
|
default-features = false
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["itertools/default"]
|
||||||
|
use_alloc = ["itertools/use_alloc"]
|
||||||
|
use_std = ["itertools/use_std"]
|
||||||
5
build/rust/itertools/lib.rs
Normal file
5
build/rust/itertools/lib.rs
Normal file
@@ -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::*;
|
||||||
@@ -88,7 +88,7 @@ scopeguard = { version = "1", optional = true }
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
bindgen = { version = "0.69", default-features = false, features = ["runtime"], optional = true }
|
bindgen = { version = "0.69", default-features = false, features = ["runtime"], optional = true }
|
||||||
cc = { version = "1.0", features = ["parallel"], optional = true }
|
cc = { version = "1.0", features = ["parallel"], optional = true }
|
||||||
itertools = { version = "0.10", default-features = false, features = ["use_alloc"], optional = true }
|
itertools = { version = "0.14", default-features = false, features = ["use_alloc"], optional = true }
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
log = { version = "0.4", features = ["std"], optional = true }
|
log = { version = "0.4", features = ["std"], optional = true }
|
||||||
memchr = { version = "2", optional = true }
|
memchr = { version = "2", optional = true }
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ euclid = "0.22"
|
|||||||
fxhash = "0.2"
|
fxhash = "0.2"
|
||||||
icu_segmenter = { version = "1.5", default-features = false, features = ["auto", "compiled_data"] }
|
icu_segmenter = { version = "1.5", default-features = false, features = ["auto", "compiled_data"] }
|
||||||
indexmap = {version = "2", features = ["std"]}
|
indexmap = {version = "2", features = ["std"]}
|
||||||
itertools = "0.10"
|
itertools = "0.14"
|
||||||
itoa = "1.0"
|
itoa = "1.0"
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|||||||
@@ -1210,6 +1210,24 @@ crate is broadly used throughout the ecosystem and does not contain anything
|
|||||||
suspicious.
|
suspicious.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
[[audits.bytecode-alliance.audits.itertools]]
|
||||||
|
who = "Nick Fitzgerald <fitzgen@gmail.com>"
|
||||||
|
criteria = "safe-to-deploy"
|
||||||
|
delta = "0.10.5 -> 0.12.1"
|
||||||
|
notes = """
|
||||||
|
Minimal `unsafe` usage. Few blocks that existed looked reasonable. Does what it
|
||||||
|
says on the tin: lots of iterators.
|
||||||
|
"""
|
||||||
|
|
||||||
|
[[audits.bytecode-alliance.audits.itertools]]
|
||||||
|
who = "Alex Crichton <alex@alexcrichton.com>"
|
||||||
|
criteria = "safe-to-deploy"
|
||||||
|
delta = "0.12.1 -> 0.14.0"
|
||||||
|
notes = """
|
||||||
|
Lots of new iterators and shuffling some things around. Some new unsafe code but
|
||||||
|
it's well-documented and well-tested. Nothing suspicious.
|
||||||
|
"""
|
||||||
|
|
||||||
[[audits.bytecode-alliance.audits.itoa]]
|
[[audits.bytecode-alliance.audits.itoa]]
|
||||||
who = "Dan Gohman <dev@sunfishcode.online>"
|
who = "Dan Gohman <dev@sunfishcode.online>"
|
||||||
criteria = "safe-to-deploy"
|
criteria = "safe-to-deploy"
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
190
third_party/rust/itertools/CHANGELOG.md
vendored
190
third_party/rust/itertools/CHANGELOG.md
vendored
@@ -1,5 +1,192 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.14.0
|
||||||
|
|
||||||
|
### Breaking
|
||||||
|
- Increased MSRV to 1.63.0 (#960)
|
||||||
|
- Removed generic parameter from `cons_tuples` (#988)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Added `array_combinations` (#991)
|
||||||
|
- Added `k_smallest_relaxed` and variants (#925)
|
||||||
|
- Added `next_array` and `collect_array` (#560)
|
||||||
|
- Implemented `DoubleEndedIterator` for `FilterOk` (#948)
|
||||||
|
- Implemented `DoubleEndedIterator` for `FilterMapOk` (#950)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Allow `Q: ?Sized` in `Itertools::contains` (#971)
|
||||||
|
- Improved hygiene of `chain!` (#943)
|
||||||
|
- Improved `into_group_map_by` documentation (#1000)
|
||||||
|
- Improved `tree_reduce` documentation (#955)
|
||||||
|
- Improved discoverability of `merge_join_by` (#966)
|
||||||
|
- Improved discoverability of `take_while_inclusive` (#972)
|
||||||
|
- Improved documentation of `find_or_last` and `find_or_first` (#984)
|
||||||
|
- Prevented exponentially large type sizes in `tuple_combinations` (#945)
|
||||||
|
- Added `track_caller` attr for `asser_equal` (#976)
|
||||||
|
|
||||||
|
### Notable Internal Changes
|
||||||
|
- Fixed clippy lints (#956, #987, #1008)
|
||||||
|
- Addressed warnings within doctests (#964)
|
||||||
|
- CI: Run most tests with miri (#961)
|
||||||
|
- CI: Speed up "cargo-semver-checks" action (#938)
|
||||||
|
- Changed an instance of `default_features` in `Cargo.toml` to `default-features` (#985)
|
||||||
|
|
||||||
|
## 0.13.0
|
||||||
|
|
||||||
|
### Breaking
|
||||||
|
- Removed implementation of `DoubleEndedIterator` for `ConsTuples` (#853)
|
||||||
|
- Made `MultiProduct` fused and fixed on an empty iterator (#835, #834)
|
||||||
|
- Changed `iproduct!` to return tuples for maxi one iterator too (#870)
|
||||||
|
- Changed `PutBack::put_back` to return the old value (#880)
|
||||||
|
- Removed deprecated `repeat_call, Itertools::{foreach, step, map_results, fold_results}` (#878)
|
||||||
|
- Removed `TakeWhileInclusive::new` (#912)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Added `Itertools::{smallest_by, smallest_by_key, largest, largest_by, largest_by_key}` (#654, #885)
|
||||||
|
- Added `Itertools::tail` (#899)
|
||||||
|
- Implemented `DoubleEndedIterator` for `ProcessResults` (#910)
|
||||||
|
- Implemented `Debug` for `FormatWith` (#931)
|
||||||
|
- Added `Itertools::get` (#891)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Deprecated `Itertools::group_by` (renamed `chunk_by`) (#866, #879)
|
||||||
|
- Deprecated `unfold` (use `std::iter::from_fn` instead) (#871)
|
||||||
|
- Optimized `GroupingMapBy` (#873, #876)
|
||||||
|
- Relaxed `Fn` bounds to `FnMut` in `diff_with, Itertools::into_group_map_by` (#886)
|
||||||
|
- Relaxed `Debug/Clone` bounds for `MapInto` (#889)
|
||||||
|
- Documented the `use_alloc` feature (#887)
|
||||||
|
- Optimized `Itertools::set_from` (#888)
|
||||||
|
- Removed badges in `README.md` (#890)
|
||||||
|
- Added "no-std" categories in `Cargo.toml` (#894)
|
||||||
|
- Fixed `Itertools::k_smallest` on short unfused iterators (#900)
|
||||||
|
- Deprecated `Itertools::tree_fold1` (renamed `tree_reduce`) (#895)
|
||||||
|
- Deprecated `GroupingMap::fold_first` (renamed `reduce`) (#902)
|
||||||
|
- Fixed `Itertools::k_smallest(0)` to consume the iterator, optimized `Itertools::k_smallest(1)` (#909)
|
||||||
|
- Specialized `Combinations::nth` (#914)
|
||||||
|
- Specialized `MergeBy::fold` (#920)
|
||||||
|
- Specialized `CombinationsWithReplacement::nth` (#923)
|
||||||
|
- Specialized `FlattenOk::{fold, rfold}` (#927)
|
||||||
|
- Specialized `Powerset::nth` (#924)
|
||||||
|
- Documentation fixes (#882, #936)
|
||||||
|
- Fixed `assert_equal` for iterators longer than `i32::MAX` (#932)
|
||||||
|
- Updated the `must_use` message of non-lazy `KMergeBy` and `TupleCombinations` (#939)
|
||||||
|
|
||||||
|
### Notable Internal Changes
|
||||||
|
- Tested iterator laziness (#792)
|
||||||
|
- Created `CONTRIBUTING.md` (#767)
|
||||||
|
|
||||||
|
## 0.12.1
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Documented iteration order guarantee for `Itertools::[tuple_]combinations` (#822)
|
||||||
|
- Documented possible panic in `iterate` (#842)
|
||||||
|
- Implemented `Clone` and `Debug` for `Diff` (#845)
|
||||||
|
- Implemented `Debug` for `WithPosition` (#859)
|
||||||
|
- Implemented `Eq` for `MinMaxResult` (#838)
|
||||||
|
- Implemented `From<EitherOrBoth<A, B>>` for `Option<Either<A, B>>` (#843)
|
||||||
|
- Implemented `PeekingNext` for `RepeatN` (#855)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Made `CoalesceBy` lazy (#801)
|
||||||
|
- Optimized `Filter[Map]Ok::next`, `Itertools::partition`, `Unique[By]::next[_back]` (#818)
|
||||||
|
- Optimized `Itertools::find_position` (#837)
|
||||||
|
- Optimized `Positions::next[_back]` (#816)
|
||||||
|
- Optimized `ZipLongest::fold` (#854)
|
||||||
|
- Relaxed `Debug` bounds for `GroupingMapBy` (#860)
|
||||||
|
- Specialized `ExactlyOneError::fold` (#826)
|
||||||
|
- Specialized `Interleave[Shortest]::fold` (#849)
|
||||||
|
- Specialized `MultiPeek::fold` (#820)
|
||||||
|
- Specialized `PadUsing::[r]fold` (#825)
|
||||||
|
- Specialized `PeekNth::fold` (#824)
|
||||||
|
- Specialized `Positions::[r]fold` (#813)
|
||||||
|
- Specialized `PutBackN::fold` (#823)
|
||||||
|
- Specialized `RepeatN::[r]fold` (#821)
|
||||||
|
- Specialized `TakeWhileInclusive::fold` (#851)
|
||||||
|
- Specialized `ZipLongest::rfold` (#848)
|
||||||
|
|
||||||
|
### Notable Internal Changes
|
||||||
|
- Added test coverage in CI (#847, #856)
|
||||||
|
- Added semver check in CI (#784)
|
||||||
|
- Enforced `clippy` in CI (#740)
|
||||||
|
- Enforced `rustdoc` in CI (#840)
|
||||||
|
- Improved specialization tests (#807)
|
||||||
|
- More specialization benchmarks (#806)
|
||||||
|
|
||||||
|
## 0.12.0
|
||||||
|
|
||||||
|
### Breaking
|
||||||
|
- Made `take_while_inclusive` consume iterator by value (#709)
|
||||||
|
- Added `Clone` bound to `Unique` (#777)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Added `Itertools::try_len` (#723)
|
||||||
|
- Added free function `sort_unstable` (#796)
|
||||||
|
- Added `GroupMap::fold_with` (#778, #785)
|
||||||
|
- Added `PeekNth::{peek_mut, peek_nth_mut}` (#716)
|
||||||
|
- Added `PeekNth::{next_if, next_if_eq}` (#734)
|
||||||
|
- Added conversion into `(Option<A>,Option<B>)` to `EitherOrBoth` (#713)
|
||||||
|
- Added conversion from `Either<A, B>` to `EitherOrBoth<A, B>` (#715)
|
||||||
|
- Implemented `ExactSizeIterator` for `Tuples` (#761)
|
||||||
|
- Implemented `ExactSizeIterator` for `(Circular)TupleWindows` (#752)
|
||||||
|
- Made `EitherOrBoth<T>` a shorthand for `EitherOrBoth<T, T>` (#719)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Added missing `#[must_use]` annotations on iterator adaptors (#794)
|
||||||
|
- Made `Combinations` lazy (#795)
|
||||||
|
- Made `Intersperse(With)` lazy (#797)
|
||||||
|
- Made `Permutations` lazy (#793)
|
||||||
|
- Made `Product` lazy (#800)
|
||||||
|
- Made `TupleWindows` lazy (#602)
|
||||||
|
- Specialized `Combinations::{count, size_hint}` (#729)
|
||||||
|
- Specialized `CombinationsWithReplacement::{count, size_hint}` (#737)
|
||||||
|
- Specialized `Powerset::fold` (#765)
|
||||||
|
- Specialized `Powerset::count` (#735)
|
||||||
|
- Specialized `TupleCombinations::{count, size_hint}` (#763)
|
||||||
|
- Specialized `TupleCombinations::fold` (#775)
|
||||||
|
- Specialized `WhileSome::fold` (#780)
|
||||||
|
- Specialized `WithPosition::fold` (#772)
|
||||||
|
- Specialized `ZipLongest::fold` (#774)
|
||||||
|
- Changed `{min, max}_set*` operations require `alloc` feature, instead of `std` (#760)
|
||||||
|
- Improved documentation of `tree_fold1` (#787)
|
||||||
|
- Improved documentation of `permutations` (#724)
|
||||||
|
- Fixed typo in documentation of `multiunzip` (#770)
|
||||||
|
|
||||||
|
### Notable Internal Changes
|
||||||
|
- Improved specialization tests (#799, #786, #782)
|
||||||
|
- Simplified implementation of `Permutations` (#739, #748, #790)
|
||||||
|
- Combined `Merge`/`MergeBy`/`MergeJoinBy` implementations (#736)
|
||||||
|
- Simplified `Permutations::size_hint` (#739)
|
||||||
|
- Fix wrapping arithmetic in benchmarks (#770)
|
||||||
|
- Enforced `rustfmt` in CI (#751)
|
||||||
|
- Disallowed compile warnings in CI (#720)
|
||||||
|
- Used `cargo hack` to check MSRV (#754)
|
||||||
|
|
||||||
|
## 0.11.0
|
||||||
|
|
||||||
|
### Breaking
|
||||||
|
- Make `Itertools::merge_join_by` also accept functions returning bool (#704)
|
||||||
|
- Implement `PeekingNext` transitively over mutable references (#643)
|
||||||
|
- Change `with_position` to yield `(Position, Item)` instead of `Position<Item>` (#699)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Add `Itertools::take_while_inclusive` (#616)
|
||||||
|
- Implement `PeekingNext` for `PeekingTakeWhile` (#644)
|
||||||
|
- Add `EitherOrBoth::{just_left, just_right, into_left, into_right, as_deref, as_deref_mut, left_or_insert, right_or_insert, left_or_insert_with, right_or_insert_with, insert_left, insert_right, insert_both}` (#629)
|
||||||
|
- Implement `Clone` for `CircularTupleWindows` (#686)
|
||||||
|
- Implement `Clone` for `Chunks` (#683)
|
||||||
|
- Add `Itertools::process_results` (#680)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Use `Cell` instead of `RefCell` in `Format` and `FormatWith` (#608)
|
||||||
|
- CI tweaks (#674, #675)
|
||||||
|
- Document and test the difference between stable and unstable sorts (#653)
|
||||||
|
- Fix documentation error on `Itertools::max_set_by_key` (#692)
|
||||||
|
- Move MSRV metadata to `Cargo.toml` (#672)
|
||||||
|
- Implement `equal` with `Iterator::eq` (#591)
|
||||||
|
|
||||||
|
## 0.10.5
|
||||||
|
- Maintenance
|
||||||
|
|
||||||
## 0.10.4
|
## 0.10.4
|
||||||
- Add `EitherOrBoth::or` and `EitherOrBoth::or_else` (#593)
|
- Add `EitherOrBoth::or` and `EitherOrBoth::or_else` (#593)
|
||||||
- Add `min_set`, `max_set` et al. (#613, #323)
|
- Add `min_set`, `max_set` et al. (#613, #323)
|
||||||
@@ -7,6 +194,9 @@
|
|||||||
- Documentation fixes (#612, #625, #632, #633, #634, #638)
|
- Documentation fixes (#612, #625, #632, #633, #634, #638)
|
||||||
- Code maintenance (#623, #624, #627, #630)
|
- Code maintenance (#623, #624, #627, #630)
|
||||||
|
|
||||||
|
## 0.10.3
|
||||||
|
- Maintenance
|
||||||
|
|
||||||
## 0.10.2
|
## 0.10.2
|
||||||
- Add `Itertools::multiunzip` (#362, #565)
|
- Add `Itertools::multiunzip` (#362, #565)
|
||||||
- Add `intersperse` and `intersperse_with` free functions (#555)
|
- Add `intersperse` and `intersperse_with` free functions (#555)
|
||||||
|
|||||||
189
third_party/rust/itertools/CONTRIBUTING.md
vendored
Normal file
189
third_party/rust/itertools/CONTRIBUTING.md
vendored
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
# Contributing to itertools
|
||||||
|
|
||||||
|
We use stable Rust only.
|
||||||
|
Please check the minimum version of Rust we use in `Cargo.toml`.
|
||||||
|
|
||||||
|
_If you are proposing a major change to CI or a new iterator adaptor for this crate,
|
||||||
|
then **please first file an issue** describing your proposal._
|
||||||
|
[Usual concerns about new methods](https://github.com/rust-itertools/itertools/issues/413#issuecomment-657670781).
|
||||||
|
|
||||||
|
To pass CI tests successfully, your code must be free of "compiler warnings" and "clippy warnings" and be "rustfmt" formatted.
|
||||||
|
|
||||||
|
Note that small PRs are easier to review and therefore are more easily merged.
|
||||||
|
|
||||||
|
## Write a new method/adaptor for `Itertools` trait
|
||||||
|
In general, the code logic should be tested with [quickcheck](https://crates.io/crates/quickcheck) tests in `tests/quick.rs`
|
||||||
|
which allow us to test properties about the code with randomly generated inputs.
|
||||||
|
|
||||||
|
### Behind `use_std`/`use_alloc` feature?
|
||||||
|
If it needs the "std" (such as using hashes) then it should be behind the `use_std` feature,
|
||||||
|
or if it requires heap allocation (such as using vectors) then it should be behind the `use_alloc` feature.
|
||||||
|
Otherwise it should be able to run in `no_std` context.
|
||||||
|
|
||||||
|
This mostly applies to your new module, each import from it, and to your new `Itertools` method.
|
||||||
|
|
||||||
|
### Pick the right receiver
|
||||||
|
`self`, `&mut self` or `&self`? From [#710](https://github.com/rust-itertools/itertools/pull/710):
|
||||||
|
|
||||||
|
- Take by value when:
|
||||||
|
- It transfers ownership to another iterator type, such as `filter`, `map`...
|
||||||
|
- It consumes the iterator completely, such as `count`, `last`, `max`...
|
||||||
|
- Mutably borrow when it consumes only part of the iterator, such as `find`, `all`, `try_collect`...
|
||||||
|
- Immutably borrow when there is no change, such as `size_hint`.
|
||||||
|
|
||||||
|
### Laziness
|
||||||
|
Iterators are [lazy](https://doc.rust-lang.org/std/iter/index.html#laziness):
|
||||||
|
|
||||||
|
- structs of iterator adaptors should have `#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]` ;
|
||||||
|
- structs of iterators should have `#[must_use = "iterators are lazy and do nothing unless consumed"]`.
|
||||||
|
|
||||||
|
Those behaviors are **tested** in `tests/laziness.rs`.
|
||||||
|
|
||||||
|
## Specialize `Iterator` methods
|
||||||
|
It might be more performant to specialize some methods.
|
||||||
|
However, each specialization should be thoroughly tested.
|
||||||
|
|
||||||
|
Correctly specializing methods can be difficult, and _we do not require that you do it on your initial PR_.
|
||||||
|
|
||||||
|
Most of the time, we want specializations of:
|
||||||
|
|
||||||
|
- [`size_hint`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.size_hint):
|
||||||
|
It mostly allows allocation optimizations.
|
||||||
|
When always exact, it also enables to implement `ExactSizeIterator`.
|
||||||
|
See our private module `src/size_hint.rs` for helpers.
|
||||||
|
- [`fold`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.fold)
|
||||||
|
might make iteration faster than calling `next` repeatedly.
|
||||||
|
- [`count`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.count),
|
||||||
|
[`last`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.last),
|
||||||
|
[`nth`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.nth)
|
||||||
|
as we might be able to avoid iterating on every item with `next`.
|
||||||
|
|
||||||
|
Additionally,
|
||||||
|
|
||||||
|
- `for_each`, `reduce`, `max/min[_by[_key]]` and `partition` all rely on `fold` so you should specialize it instead.
|
||||||
|
- `all`, `any`, `find`, `find_map`, `cmp`, `partial_cmp`, `eq`, `ne`, `lt`, `le`, `gt`, `ge` and `position` all rely (by default) on `try_fold`
|
||||||
|
which we can not specialize on stable rust, so you might want to wait it stabilizes
|
||||||
|
or specialize each of them.
|
||||||
|
- `DoubleEndedIterator::{nth_back, rfold, rfind}`: similar reasoning.
|
||||||
|
|
||||||
|
An adaptor might use the inner iterator specializations for its own specializations.
|
||||||
|
|
||||||
|
They are **tested** in `tests/specializations.rs` and **benchmarked** in `benches/specializations.rs`
|
||||||
|
(build those benchmarks is slow so you might want to temporarily remove the ones you do not want to measure).
|
||||||
|
|
||||||
|
## Additional implementations
|
||||||
|
### The [`Debug`](https://doc.rust-lang.org/std/fmt/trait.Debug.html) implementation
|
||||||
|
All our iterators should implement `Debug`.
|
||||||
|
|
||||||
|
When one of the field is not debuggable (such as _functions_), you must not derive `Debug`.
|
||||||
|
Instead, manually implement it and _ignore this field_ in our helper macro `debug_fmt_fields`.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>4 examples (click to expand)</summary>
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/* ===== Simple derive. ===== */
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Name1<I> {
|
||||||
|
iter: I,
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== With an unclonable field. ===== */
|
||||||
|
struct Name2<I, F> {
|
||||||
|
iter: I,
|
||||||
|
func: F,
|
||||||
|
}
|
||||||
|
|
||||||
|
// No `F: Debug` bound and the field `func` is ignored.
|
||||||
|
impl<I: fmt::Debug, F> fmt::Debug for Name2<I, F> {
|
||||||
|
// it defines the `fmt` function from a struct name and the fields you want to debug.
|
||||||
|
debug_fmt_fields!(Name2, iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== With an unclonable field, but another bound to add. ===== */
|
||||||
|
struct Name3<I: Iterator, F> {
|
||||||
|
iter: I,
|
||||||
|
item: Option<I::Item>,
|
||||||
|
func: F,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same about `F` and `func`, similar about `I` but we must add the `I::Item: Debug` bound.
|
||||||
|
impl<I: Iterator + fmt::Debug, F> fmt::Debug for Name3<I, F>
|
||||||
|
where
|
||||||
|
I::Item: fmt::Debug,
|
||||||
|
{
|
||||||
|
debug_fmt_fields!(Name3, iter, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== With an unclonable field for which we can provide some information. ===== */
|
||||||
|
struct Name4<I, F> {
|
||||||
|
iter: I,
|
||||||
|
func: Option<F>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// If ignore a field is not good enough, implement Debug fully manually.
|
||||||
|
impl<I: fmt::Debug, F> fmt::Debug for Name4<I, F> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let func = if self.func.is_some() { "Some(_)" } else { "None" };
|
||||||
|
f.debug_struct("Name4")
|
||||||
|
.field("iter", &self.iter)
|
||||||
|
.field("func", &func)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### When/How to implement [`Clone`](https://doc.rust-lang.org/std/clone/trait.Clone.html)
|
||||||
|
All our iterators should implement `Clone` when possible.
|
||||||
|
|
||||||
|
Note that a mutable reference is never clonable so `struct Name<'a, I: 'a> { iter: &'a mut I }` can not implement `Clone`.
|
||||||
|
|
||||||
|
Derive `Clone` on a generic struct adds the bound `Clone` on each generic parameter.
|
||||||
|
It might be an issue in which case you should manually implement it with our helper macro `clone_fields` (it defines the `clone` function calling `clone` on each field) and be careful about the bounds.
|
||||||
|
|
||||||
|
### When to implement [`std::iter::FusedIterator`](https://doc.rust-lang.org/std/iter/trait.FusedIterator.html)
|
||||||
|
This trait should be implemented _by all iterators that always return `None` after returning `None` once_, because it allows to optimize `Iterator::fuse()`.
|
||||||
|
|
||||||
|
The conditions on which it should be implemented are usually the ones from the `Iterator` implementation, eventually refined to ensure it behaves in a fused way.
|
||||||
|
|
||||||
|
### When to implement [`ExactSizeIterator`](https://doc.rust-lang.org/std/iter/trait.ExactSizeIterator.html)
|
||||||
|
_When we are always able to return an exact non-overflowing length._
|
||||||
|
|
||||||
|
Therefore, we do not implement it on adaptors that makes the iterator longer as the resulting length could overflow.
|
||||||
|
|
||||||
|
One should not override `ExactSizeIterator::len` method but rely on an exact `Iterator::size_hint` implementation, meaning it returns `(length, Some(length))` (unless you could make `len` more performant than the default).
|
||||||
|
|
||||||
|
The conditions on which it should be implemented are usually the ones from the `Iterator` implementation, probably refined to ensure the size hint is exact.
|
||||||
|
|
||||||
|
### When to implement [`DoubleEndedIterator`](https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html)
|
||||||
|
When the iterator structure allows to handle _iterating on both fronts simultaneously_.
|
||||||
|
The iteration might stop in the middle when both fronts meet.
|
||||||
|
|
||||||
|
The conditions on which it should be implemented are usually the ones from the `Iterator` implementation, probably refined to ensure we can iterate on both fronts simultaneously.
|
||||||
|
|
||||||
|
### When to implement [`itertools::PeekingNext`](https://docs.rs/itertools/latest/itertools/trait.PeekingNext.html)
|
||||||
|
TODO
|
||||||
|
|
||||||
|
This is currently **tested** in `tests/test_std.rs`.
|
||||||
|
|
||||||
|
## About lending iterators
|
||||||
|
TODO
|
||||||
|
|
||||||
|
|
||||||
|
## Other notes
|
||||||
|
No guideline about using `#[inline]` yet.
|
||||||
|
|
||||||
|
### `.fold` / `.for_each` / `.try_fold` / `.try_for_each`
|
||||||
|
In the Rust standard library, it's quite common for `fold` to be implemented in terms of `try_fold`. But it's not something we do yet because we can not specialize `try_fold` methods yet (it uses the unstable `Try`).
|
||||||
|
|
||||||
|
From [#781](https://github.com/rust-itertools/itertools/pull/781), the general rule to follow is something like this:
|
||||||
|
|
||||||
|
- If you need to completely consume an iterator:
|
||||||
|
- Use `fold` if you need an _owned_ access to an accumulator.
|
||||||
|
- Use `for_each` otherwise.
|
||||||
|
- If you need to partly consume an iterator, the same applies with `try_` versions:
|
||||||
|
- Use `try_fold` if you need an _owned_ access to an accumulator.
|
||||||
|
- Use `try_for_each` otherwise.
|
||||||
740
third_party/rust/itertools/Cargo.lock
generated
vendored
Normal file
740
third_party/rust/itertools/Cargo.lock
generated
vendored
Normal file
@@ -0,0 +1,740 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anes"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atty"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bumpalo"
|
||||||
|
version = "3.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cast"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
|
||||||
|
dependencies = [
|
||||||
|
"ciborium-io",
|
||||||
|
"ciborium-ll",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium-io"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium-ll"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
|
||||||
|
dependencies = [
|
||||||
|
"ciborium-io",
|
||||||
|
"half",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "3.2.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"clap_lex",
|
||||||
|
"indexmap",
|
||||||
|
"textwrap",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||||
|
dependencies = [
|
||||||
|
"os_str_bytes",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "criterion"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb"
|
||||||
|
dependencies = [
|
||||||
|
"anes",
|
||||||
|
"atty",
|
||||||
|
"cast",
|
||||||
|
"ciborium",
|
||||||
|
"clap",
|
||||||
|
"criterion-plot",
|
||||||
|
"itertools 0.10.5",
|
||||||
|
"lazy_static",
|
||||||
|
"num-traits",
|
||||||
|
"oorandom",
|
||||||
|
"plotters",
|
||||||
|
"rayon",
|
||||||
|
"regex",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"tinytemplate",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "criterion-plot"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
|
||||||
|
dependencies = [
|
||||||
|
"cast",
|
||||||
|
"itertools 0.10.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-deque"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-epoch"
|
||||||
|
version = "0.9.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crunchy"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.1.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "half"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crunchy",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.10.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.14.0"
|
||||||
|
dependencies = [
|
||||||
|
"criterion",
|
||||||
|
"either",
|
||||||
|
"paste",
|
||||||
|
"permutohedron",
|
||||||
|
"quickcheck",
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "js-sys"
|
||||||
|
version = "0.3.69"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
||||||
|
dependencies = [
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.154"
|
||||||
|
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"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "oorandom"
|
||||||
|
version = "11.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_str_bytes"
|
||||||
|
version = "6.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "permutohedron"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plotters"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
"plotters-backend",
|
||||||
|
"plotters-svg",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plotters-backend"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plotters-svg"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab"
|
||||||
|
dependencies = [
|
||||||
|
"plotters-backend",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.82"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quickcheck"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a44883e74aa97ad63db83c4bf8ca490f02b2fc02f92575e720c8551e843c945f"
|
||||||
|
dependencies = [
|
||||||
|
"rand",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.36"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
"rand_hc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_hc"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"rayon-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon-core"
|
||||||
|
version = "1.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-deque",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "same-file"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.202"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.202"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.117"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.63"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "textwrap"
|
||||||
|
version = "0.16.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinytemplate"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "walkdir"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||||
|
dependencies = [
|
||||||
|
"same-file",
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.9.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen"
|
||||||
|
version = "0.2.92"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
||||||
|
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",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro"
|
||||||
|
version = "0.2.92"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"wasm-bindgen-macro-support",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro-support"
|
||||||
|
version = "0.2.92"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-backend",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-shared"
|
||||||
|
version = "0.2.92"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "web-sys"
|
||||||
|
version = "0.3.69"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||||
|
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",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.5"
|
||||||
|
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"
|
||||||
162
third_party/rust/itertools/Cargo.toml
vendored
162
third_party/rust/itertools/Cargo.toml
vendored
@@ -3,71 +3,165 @@
|
|||||||
# When uploading crates to the registry Cargo will automatically
|
# When uploading crates to the registry Cargo will automatically
|
||||||
# "normalize" Cargo.toml files for maximal compatibility
|
# "normalize" Cargo.toml files for maximal compatibility
|
||||||
# with all versions of Cargo and also rewrite `path` dependencies
|
# with all versions of Cargo and also rewrite `path` dependencies
|
||||||
# to registry (e.g., crates.io) dependencies
|
# to registry (e.g., crates.io) dependencies.
|
||||||
#
|
#
|
||||||
# If you believe there's an error in this file please file an
|
# If you are reading this file be aware that the original Cargo.toml
|
||||||
# issue against the rust-lang/cargo repository. If you're
|
# will likely look very different (and much more reasonable).
|
||||||
# editing this file be aware that the upstream Cargo.toml
|
# See Cargo.toml.orig for the original contents.
|
||||||
# will likely look very different (and much more reasonable)
|
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
rust-version = "1.63.0"
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.10.5"
|
version = "0.14.0"
|
||||||
authors = ["bluss"]
|
authors = ["bluss"]
|
||||||
exclude = ["/bors.toml"]
|
build = false
|
||||||
|
autolib = false
|
||||||
|
autobins = false
|
||||||
|
autoexamples = false
|
||||||
|
autotests = false
|
||||||
|
autobenches = false
|
||||||
description = "Extra iterator adaptors, iterator methods, free functions, and macros."
|
description = "Extra iterator adaptors, iterator methods, free functions, and macros."
|
||||||
documentation = "https://docs.rs/itertools/"
|
documentation = "https://docs.rs/itertools/"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["iterator", "data-structure", "zip", "product", "group-by"]
|
keywords = [
|
||||||
categories = ["algorithms", "rust-patterns"]
|
"iterator",
|
||||||
license = "MIT/Apache-2.0"
|
"data-structure",
|
||||||
|
"zip",
|
||||||
|
"product",
|
||||||
|
]
|
||||||
|
categories = [
|
||||||
|
"algorithms",
|
||||||
|
"rust-patterns",
|
||||||
|
"no-std",
|
||||||
|
"no-std::no-alloc",
|
||||||
|
]
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://github.com/rust-itertools/itertools"
|
repository = "https://github.com/rust-itertools/itertools"
|
||||||
[package.metadata.release]
|
|
||||||
no-dev-version = true
|
[features]
|
||||||
[profile.bench]
|
default = ["use_std"]
|
||||||
debug = true
|
use_alloc = []
|
||||||
|
use_std = [
|
||||||
|
"use_alloc",
|
||||||
|
"either/use_std",
|
||||||
|
]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
name = "itertools"
|
||||||
|
path = "src/lib.rs"
|
||||||
test = false
|
test = false
|
||||||
bench = false
|
bench = false
|
||||||
|
|
||||||
[[bench]]
|
[[example]]
|
||||||
name = "tuple_combinations"
|
name = "iris"
|
||||||
harness = false
|
path = "examples/iris.rs"
|
||||||
|
|
||||||
[[bench]]
|
[[test]]
|
||||||
|
name = "adaptors_no_collect"
|
||||||
|
path = "tests/adaptors_no_collect.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "flatten_ok"
|
||||||
|
path = "tests/flatten_ok.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "laziness"
|
||||||
|
path = "tests/laziness.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "macros_hygiene"
|
||||||
|
path = "tests/macros_hygiene.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "merge_join"
|
||||||
|
path = "tests/merge_join.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "peeking_take_while"
|
||||||
|
path = "tests/peeking_take_while.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "quick"
|
||||||
|
path = "tests/quick.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "specializations"
|
||||||
|
path = "tests/specializations.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "test_core"
|
||||||
|
path = "tests/test_core.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "test_std"
|
||||||
|
path = "tests/test_std.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
name = "tuples"
|
name = "tuples"
|
||||||
harness = false
|
path = "tests/tuples.rs"
|
||||||
|
|
||||||
[[bench]]
|
[[test]]
|
||||||
name = "fold_specialization"
|
name = "zip"
|
||||||
harness = false
|
path = "tests/zip.rs"
|
||||||
|
|
||||||
[[bench]]
|
|
||||||
name = "combinations_with_replacement"
|
|
||||||
harness = false
|
|
||||||
|
|
||||||
[[bench]]
|
|
||||||
name = "tree_fold1"
|
|
||||||
harness = false
|
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "bench1"
|
name = "bench1"
|
||||||
|
path = "benches/bench1.rs"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "combinations"
|
name = "combinations"
|
||||||
|
path = "benches/combinations.rs"
|
||||||
|
harness = false
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "combinations_with_replacement"
|
||||||
|
path = "benches/combinations_with_replacement.rs"
|
||||||
|
harness = false
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "fold_specialization"
|
||||||
|
path = "benches/fold_specialization.rs"
|
||||||
|
harness = false
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "k_smallest"
|
||||||
|
path = "benches/k_smallest.rs"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "powerset"
|
name = "powerset"
|
||||||
|
path = "benches/powerset.rs"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "specializations"
|
||||||
|
path = "benches/specializations.rs"
|
||||||
|
harness = false
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "tree_reduce"
|
||||||
|
path = "benches/tree_reduce.rs"
|
||||||
|
harness = false
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "tuple_combinations"
|
||||||
|
path = "benches/tuple_combinations.rs"
|
||||||
|
harness = false
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "tuples"
|
||||||
|
path = "benches/tuples.rs"
|
||||||
|
harness = false
|
||||||
|
|
||||||
[dependencies.either]
|
[dependencies.either]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[dev-dependencies.criterion]
|
[dev-dependencies.criterion]
|
||||||
version = "=0"
|
version = "0.4.0"
|
||||||
|
features = ["html_reports"]
|
||||||
|
|
||||||
[dev-dependencies.paste]
|
[dev-dependencies.paste]
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@@ -82,7 +176,5 @@ default-features = false
|
|||||||
[dev-dependencies.rand]
|
[dev-dependencies.rand]
|
||||||
version = "0.7"
|
version = "0.7"
|
||||||
|
|
||||||
[features]
|
[profile.bench]
|
||||||
default = ["use_std"]
|
debug = 2
|
||||||
use_alloc = []
|
|
||||||
use_std = ["use_alloc", "either/use_std"]
|
|
||||||
|
|||||||
17
third_party/rust/itertools/README.md
vendored
17
third_party/rust/itertools/README.md
vendored
@@ -4,14 +4,11 @@ Extra iterator adaptors, functions and macros.
|
|||||||
|
|
||||||
Please read the [API documentation here](https://docs.rs/itertools/).
|
Please read the [API documentation here](https://docs.rs/itertools/).
|
||||||
|
|
||||||
[](https://github.com/rust-itertools/itertools/actions)
|
|
||||||
[](https://crates.io/crates/itertools)
|
|
||||||
|
|
||||||
How to use with Cargo:
|
How to use with Cargo:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
itertools = "0.10.5"
|
itertools = "0.14.0"
|
||||||
```
|
```
|
||||||
|
|
||||||
How to use in your crate:
|
How to use in your crate:
|
||||||
@@ -21,17 +18,9 @@ use itertools::Itertools;
|
|||||||
```
|
```
|
||||||
|
|
||||||
## How to contribute
|
## How to contribute
|
||||||
|
If you're not sure what to work on, try checking the [help wanted](https://github.com/rust-itertools/itertools/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) label.
|
||||||
|
|
||||||
- Fix a bug or implement a new thing
|
See our [CONTRIBUTING.md](https://github.com/rust-itertools/itertools/blob/master/CONTRIBUTING.md) for a detailed guide.
|
||||||
- Include tests for your new feature, preferably a QuickCheck test
|
|
||||||
- Make a Pull Request
|
|
||||||
|
|
||||||
For new features, please first consider filing a PR to [rust-lang/rust](https://github.com/rust-lang/rust),
|
|
||||||
adding your new feature to the `Iterator` trait of the standard library, if you believe it is reasonable.
|
|
||||||
If it isn't accepted there, proposing it for inclusion in ``itertools`` is a good idea.
|
|
||||||
The reason for doing is this is so that we avoid future breakage as with ``.flatten()``.
|
|
||||||
However, if your feature involves heap allocation, such as storing elements in a ``Vec<T>``,
|
|
||||||
then it can't be accepted into ``libcore``, and you should propose it for ``itertools`` directly instead.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
290
third_party/rust/itertools/benches/bench1.rs
vendored
290
third_party/rust/itertools/benches/bench1.rs
vendored
@@ -1,22 +1,20 @@
|
|||||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion};
|
||||||
use itertools::Itertools;
|
|
||||||
use itertools::free::cloned;
|
use itertools::free::cloned;
|
||||||
use itertools::iproduct;
|
use itertools::iproduct;
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
use std::iter::repeat;
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
use std::iter::repeat;
|
||||||
use std::ops::{Add, Range};
|
use std::ops::{Add, Range};
|
||||||
|
|
||||||
mod extra;
|
|
||||||
|
|
||||||
use crate::extra::ZipSlices;
|
|
||||||
|
|
||||||
fn slice_iter(c: &mut Criterion) {
|
fn slice_iter(c: &mut Criterion) {
|
||||||
let xs: Vec<_> = repeat(1i32).take(20).collect();
|
let xs: Vec<_> = repeat(1i32).take(20).collect();
|
||||||
|
|
||||||
c.bench_function("slice iter", move |b| {
|
c.bench_function("slice iter", move |b| {
|
||||||
b.iter(|| for elt in xs.iter() {
|
b.iter(|| {
|
||||||
black_box(elt);
|
for elt in xs.iter() {
|
||||||
|
black_box(elt);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -25,8 +23,10 @@ fn slice_iter_rev(c: &mut Criterion) {
|
|||||||
let xs: Vec<_> = repeat(1i32).take(20).collect();
|
let xs: Vec<_> = repeat(1i32).take(20).collect();
|
||||||
|
|
||||||
c.bench_function("slice iter rev", move |b| {
|
c.bench_function("slice iter rev", move |b| {
|
||||||
b.iter(|| for elt in xs.iter().rev() {
|
b.iter(|| {
|
||||||
black_box(elt);
|
for elt in xs.iter().rev() {
|
||||||
|
black_box(elt);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -116,72 +116,6 @@ fn zip_slices_ziptuple(c: &mut Criterion) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zipslices(c: &mut Criterion) {
|
|
||||||
let xs = vec![0; 1024];
|
|
||||||
let ys = vec![0; 768];
|
|
||||||
let xs = black_box(xs);
|
|
||||||
let ys = black_box(ys);
|
|
||||||
|
|
||||||
c.bench_function("zipslices", move |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
for (&x, &y) in ZipSlices::new(&xs, &ys) {
|
|
||||||
black_box(x);
|
|
||||||
black_box(y);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn zipslices_mut(c: &mut Criterion) {
|
|
||||||
let xs = vec![0; 1024];
|
|
||||||
let ys = vec![0; 768];
|
|
||||||
let xs = black_box(xs);
|
|
||||||
let mut ys = black_box(ys);
|
|
||||||
|
|
||||||
c.bench_function("zipslices mut", move |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
for (&x, &mut y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) {
|
|
||||||
black_box(x);
|
|
||||||
black_box(y);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn zipdot_i32_zipslices(c: &mut Criterion) {
|
|
||||||
let xs = vec![2; 1024];
|
|
||||||
let ys = vec![2; 768];
|
|
||||||
let xs = black_box(xs);
|
|
||||||
let ys = black_box(ys);
|
|
||||||
|
|
||||||
c.bench_function("zipdot i32 zipslices", move |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut s = 0i32;
|
|
||||||
for (&x, &y) in ZipSlices::new(&xs, &ys) {
|
|
||||||
s += x * y;
|
|
||||||
}
|
|
||||||
s
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn zipdot_f32_zipslices(c: &mut Criterion) {
|
|
||||||
let xs = vec![2f32; 1024];
|
|
||||||
let ys = vec![2f32; 768];
|
|
||||||
let xs = black_box(xs);
|
|
||||||
let ys = black_box(ys);
|
|
||||||
|
|
||||||
c.bench_function("zipdot f32 zipslices", move |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut s = 0.;
|
|
||||||
for (&x, &y) in ZipSlices::new(&xs, &ys) {
|
|
||||||
s += x * y;
|
|
||||||
}
|
|
||||||
s
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn zip_checked_counted_loop(c: &mut Criterion) {
|
fn zip_checked_counted_loop(c: &mut Criterion) {
|
||||||
let xs = vec![0; 1024];
|
let xs = vec![0; 1024];
|
||||||
let ys = vec![0; 768];
|
let ys = vec![0; 768];
|
||||||
@@ -307,10 +241,10 @@ fn zip_unchecked_counted_loop(c: &mut Criterion) {
|
|||||||
let len = cmp::min(xs.len(), ys.len());
|
let len = cmp::min(xs.len(), ys.len());
|
||||||
for i in 0..len {
|
for i in 0..len {
|
||||||
unsafe {
|
unsafe {
|
||||||
let x = *xs.get_unchecked(i);
|
let x = *xs.get_unchecked(i);
|
||||||
let y = *ys.get_unchecked(i);
|
let y = *ys.get_unchecked(i);
|
||||||
black_box(x);
|
black_box(x);
|
||||||
black_box(y);
|
black_box(y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -329,9 +263,9 @@ fn zipdot_i32_unchecked_counted_loop(c: &mut Criterion) {
|
|||||||
let mut s = 0i32;
|
let mut s = 0i32;
|
||||||
for i in 0..len {
|
for i in 0..len {
|
||||||
unsafe {
|
unsafe {
|
||||||
let x = *xs.get_unchecked(i);
|
let x = *xs.get_unchecked(i);
|
||||||
let y = *ys.get_unchecked(i);
|
let y = *ys.get_unchecked(i);
|
||||||
s += x * y;
|
s += x * y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s
|
s
|
||||||
@@ -351,9 +285,9 @@ fn zipdot_f32_unchecked_counted_loop(c: &mut Criterion) {
|
|||||||
let mut s = 0f32;
|
let mut s = 0f32;
|
||||||
for i in 0..len {
|
for i in 0..len {
|
||||||
unsafe {
|
unsafe {
|
||||||
let x = *xs.get_unchecked(i);
|
let x = *xs.get_unchecked(i);
|
||||||
let y = *ys.get_unchecked(i);
|
let y = *ys.get_unchecked(i);
|
||||||
s += x * y;
|
s += x * y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s
|
s
|
||||||
@@ -374,19 +308,19 @@ fn zip_unchecked_counted_loop3(c: &mut Criterion) {
|
|||||||
let len = cmp::min(xs.len(), cmp::min(ys.len(), zs.len()));
|
let len = cmp::min(xs.len(), cmp::min(ys.len(), zs.len()));
|
||||||
for i in 0..len {
|
for i in 0..len {
|
||||||
unsafe {
|
unsafe {
|
||||||
let x = *xs.get_unchecked(i);
|
let x = *xs.get_unchecked(i);
|
||||||
let y = *ys.get_unchecked(i);
|
let y = *ys.get_unchecked(i);
|
||||||
let z = *zs.get_unchecked(i);
|
let z = *zs.get_unchecked(i);
|
||||||
black_box(x);
|
black_box(x);
|
||||||
black_box(y);
|
black_box(y);
|
||||||
black_box(z);
|
black_box(z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn group_by_lazy_1(c: &mut Criterion) {
|
fn chunk_by_lazy_1(c: &mut Criterion) {
|
||||||
let mut data = vec![0; 1024];
|
let mut data = vec![0; 1024];
|
||||||
for (index, elt) in data.iter_mut().enumerate() {
|
for (index, elt) in data.iter_mut().enumerate() {
|
||||||
*elt = index / 10;
|
*elt = index / 10;
|
||||||
@@ -394,10 +328,10 @@ fn group_by_lazy_1(c: &mut Criterion) {
|
|||||||
|
|
||||||
let data = black_box(data);
|
let data = black_box(data);
|
||||||
|
|
||||||
c.bench_function("group by lazy 1", move |b| {
|
c.bench_function("chunk by lazy 1", move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
for (_key, group) in &data.iter().group_by(|elt| **elt) {
|
for (_key, chunk) in &data.iter().chunk_by(|elt| **elt) {
|
||||||
for elt in group {
|
for elt in chunk {
|
||||||
black_box(elt);
|
black_box(elt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -405,7 +339,7 @@ fn group_by_lazy_1(c: &mut Criterion) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn group_by_lazy_2(c: &mut Criterion) {
|
fn chunk_by_lazy_2(c: &mut Criterion) {
|
||||||
let mut data = vec![0; 1024];
|
let mut data = vec![0; 1024];
|
||||||
for (index, elt) in data.iter_mut().enumerate() {
|
for (index, elt) in data.iter_mut().enumerate() {
|
||||||
*elt = index / 2;
|
*elt = index / 2;
|
||||||
@@ -413,10 +347,10 @@ fn group_by_lazy_2(c: &mut Criterion) {
|
|||||||
|
|
||||||
let data = black_box(data);
|
let data = black_box(data);
|
||||||
|
|
||||||
c.bench_function("group by lazy 2", move |b| {
|
c.bench_function("chunk by lazy 2", move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
for (_key, group) in &data.iter().group_by(|elt| **elt) {
|
for (_key, chunk) in &data.iter().chunk_by(|elt| **elt) {
|
||||||
for elt in group {
|
for elt in chunk {
|
||||||
black_box(elt);
|
black_box(elt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -432,8 +366,8 @@ fn slice_chunks(c: &mut Criterion) {
|
|||||||
|
|
||||||
c.bench_function("slice chunks", move |b| {
|
c.bench_function("slice chunks", move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
for group in data.chunks(sz) {
|
for chunk in data.chunks(sz) {
|
||||||
for elt in group {
|
for elt in chunk {
|
||||||
black_box(elt);
|
black_box(elt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -449,8 +383,8 @@ fn chunks_lazy_1(c: &mut Criterion) {
|
|||||||
|
|
||||||
c.bench_function("chunks lazy 1", move |b| {
|
c.bench_function("chunks lazy 1", move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
for group in &data.iter().chunks(sz) {
|
for chunk in &data.iter().chunks(sz) {
|
||||||
for elt in group {
|
for elt in chunk {
|
||||||
black_box(elt);
|
black_box(elt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -464,17 +398,15 @@ fn equal(c: &mut Criterion) {
|
|||||||
let alpha = black_box(&data[1..]);
|
let alpha = black_box(&data[1..]);
|
||||||
let beta = black_box(&data[..l - 1]);
|
let beta = black_box(&data[..l - 1]);
|
||||||
|
|
||||||
c.bench_function("equal", move |b| {
|
c.bench_function("equal", move |b| b.iter(|| itertools::equal(alpha, beta)));
|
||||||
b.iter(|| {
|
|
||||||
itertools::equal(alpha, beta)
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_default(c: &mut Criterion) {
|
fn merge_default(c: &mut Criterion) {
|
||||||
let mut data1 = vec![0; 1024];
|
let mut data1 = vec![0; 1024];
|
||||||
let mut data2 = vec![0; 800];
|
let mut data2 = vec![0; 800];
|
||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
|
|
||||||
|
#[allow(clippy::explicit_counter_loop, clippy::unused_enumerate_index)]
|
||||||
for (_, elt) in data1.iter_mut().enumerate() {
|
for (_, elt) in data1.iter_mut().enumerate() {
|
||||||
*elt = x;
|
*elt = x;
|
||||||
x += 1;
|
x += 1;
|
||||||
@@ -493,9 +425,7 @@ fn merge_default(c: &mut Criterion) {
|
|||||||
let data2 = black_box(data2);
|
let data2 = black_box(data2);
|
||||||
|
|
||||||
c.bench_function("merge default", move |b| {
|
c.bench_function("merge default", move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| data1.iter().merge(&data2).count())
|
||||||
data1.iter().merge(&data2).count()
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,6 +433,8 @@ fn merge_by_cmp(c: &mut Criterion) {
|
|||||||
let mut data1 = vec![0; 1024];
|
let mut data1 = vec![0; 1024];
|
||||||
let mut data2 = vec![0; 800];
|
let mut data2 = vec![0; 800];
|
||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
|
|
||||||
|
#[allow(clippy::explicit_counter_loop, clippy::unused_enumerate_index)]
|
||||||
for (_, elt) in data1.iter_mut().enumerate() {
|
for (_, elt) in data1.iter_mut().enumerate() {
|
||||||
*elt = x;
|
*elt = x;
|
||||||
x += 1;
|
x += 1;
|
||||||
@@ -521,9 +453,7 @@ fn merge_by_cmp(c: &mut Criterion) {
|
|||||||
let data2 = black_box(data2);
|
let data2 = black_box(data2);
|
||||||
|
|
||||||
c.bench_function("merge by cmp", move |b| {
|
c.bench_function("merge by cmp", move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| data1.iter().merge_by(&data2, PartialOrd::le).count())
|
||||||
data1.iter().merge_by(&data2, PartialOrd::le).count()
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -531,6 +461,8 @@ fn merge_by_lt(c: &mut Criterion) {
|
|||||||
let mut data1 = vec![0; 1024];
|
let mut data1 = vec![0; 1024];
|
||||||
let mut data2 = vec![0; 800];
|
let mut data2 = vec![0; 800];
|
||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
|
|
||||||
|
#[allow(clippy::explicit_counter_loop, clippy::unused_enumerate_index)]
|
||||||
for (_, elt) in data1.iter_mut().enumerate() {
|
for (_, elt) in data1.iter_mut().enumerate() {
|
||||||
*elt = x;
|
*elt = x;
|
||||||
x += 1;
|
x += 1;
|
||||||
@@ -549,9 +481,7 @@ fn merge_by_lt(c: &mut Criterion) {
|
|||||||
let data2 = black_box(data2);
|
let data2 = black_box(data2);
|
||||||
|
|
||||||
c.bench_function("merge by lt", move |b| {
|
c.bench_function("merge by lt", move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| data1.iter().merge_by(&data2, |a, b| a <= b).count())
|
||||||
data1.iter().merge_by(&data2, |a, b| a <= b).count()
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -559,6 +489,8 @@ fn kmerge_default(c: &mut Criterion) {
|
|||||||
let mut data1 = vec![0; 1024];
|
let mut data1 = vec![0; 1024];
|
||||||
let mut data2 = vec![0; 800];
|
let mut data2 = vec![0; 800];
|
||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
|
|
||||||
|
#[allow(clippy::explicit_counter_loop, clippy::unused_enumerate_index)]
|
||||||
for (_, elt) in data1.iter_mut().enumerate() {
|
for (_, elt) in data1.iter_mut().enumerate() {
|
||||||
*elt = x;
|
*elt = x;
|
||||||
x += 1;
|
x += 1;
|
||||||
@@ -578,9 +510,7 @@ fn kmerge_default(c: &mut Criterion) {
|
|||||||
let its = &[data1.iter(), data2.iter()];
|
let its = &[data1.iter(), data2.iter()];
|
||||||
|
|
||||||
c.bench_function("kmerge default", move |b| {
|
c.bench_function("kmerge default", move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| its.iter().cloned().kmerge().count())
|
||||||
its.iter().cloned().kmerge().count()
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -589,7 +519,7 @@ fn kmerge_tenway(c: &mut Criterion) {
|
|||||||
|
|
||||||
let mut state = 1729u16;
|
let mut state = 1729u16;
|
||||||
fn rng(state: &mut u16) -> u16 {
|
fn rng(state: &mut u16) -> u16 {
|
||||||
let new = state.wrapping_mul(31421) + 6927;
|
let new = state.wrapping_mul(31421).wrapping_add(6927);
|
||||||
*state = new;
|
*state = new;
|
||||||
new
|
new
|
||||||
}
|
}
|
||||||
@@ -600,10 +530,10 @@ fn kmerge_tenway(c: &mut Criterion) {
|
|||||||
|
|
||||||
let mut chunks = Vec::new();
|
let mut chunks = Vec::new();
|
||||||
let mut rest = &mut data[..];
|
let mut rest = &mut data[..];
|
||||||
while rest.len() > 0 {
|
while !rest.is_empty() {
|
||||||
let chunk_len = 1 + rng(&mut state) % 512;
|
let chunk_len = 1 + rng(&mut state) % 512;
|
||||||
let chunk_len = cmp::min(rest.len(), chunk_len as usize);
|
let chunk_len = cmp::min(rest.len(), chunk_len as usize);
|
||||||
let (fst, tail) = {rest}.split_at_mut(chunk_len);
|
let (fst, tail) = { rest }.split_at_mut(chunk_len);
|
||||||
fst.sort();
|
fst.sort();
|
||||||
chunks.push(fst.iter().cloned());
|
chunks.push(fst.iter().cloned());
|
||||||
rest = tail;
|
rest = tail;
|
||||||
@@ -612,15 +542,14 @@ fn kmerge_tenway(c: &mut Criterion) {
|
|||||||
// println!("Chunk lengths: {}", chunks.iter().format_with(", ", |elt, f| f(&elt.len())));
|
// println!("Chunk lengths: {}", chunks.iter().format_with(", ", |elt, f| f(&elt.len())));
|
||||||
|
|
||||||
c.bench_function("kmerge tenway", move |b| {
|
c.bench_function("kmerge tenway", move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| chunks.iter().cloned().kmerge().count())
|
||||||
chunks.iter().cloned().kmerge().count()
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fast_integer_sum<I>(iter: I) -> I::Item
|
fn fast_integer_sum<I>(iter: I) -> I::Item
|
||||||
where I: IntoIterator,
|
where
|
||||||
I::Item: Default + Add<Output=I::Item>
|
I: IntoIterator,
|
||||||
|
I::Item: Default + Add<Output = I::Item>,
|
||||||
{
|
{
|
||||||
iter.into_iter().fold(<_>::default(), |x, y| x + y)
|
iter.into_iter().fold(<_>::default(), |x, y| x + y)
|
||||||
}
|
}
|
||||||
@@ -629,9 +558,7 @@ fn step_vec_2(c: &mut Criterion) {
|
|||||||
let v = vec![0; 1024];
|
let v = vec![0; 1024];
|
||||||
|
|
||||||
c.bench_function("step vec 2", move |b| {
|
c.bench_function("step vec 2", move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| fast_integer_sum(cloned(v.iter().step_by(2))))
|
||||||
fast_integer_sum(cloned(v.iter().step_by(2)))
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -639,9 +566,7 @@ fn step_vec_10(c: &mut Criterion) {
|
|||||||
let v = vec![0; 1024];
|
let v = vec![0; 1024];
|
||||||
|
|
||||||
c.bench_function("step vec 10", move |b| {
|
c.bench_function("step vec 10", move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| fast_integer_sum(cloned(v.iter().step_by(10))))
|
||||||
fast_integer_sum(cloned(v.iter().step_by(10)))
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -649,9 +574,7 @@ fn step_range_2(c: &mut Criterion) {
|
|||||||
let v = black_box(0..1024);
|
let v = black_box(0..1024);
|
||||||
|
|
||||||
c.bench_function("step range 2", move |b| {
|
c.bench_function("step range 2", move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| fast_integer_sum(v.clone().step_by(2)))
|
||||||
fast_integer_sum(v.clone().step_by(2))
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -659,9 +582,23 @@ fn step_range_10(c: &mut Criterion) {
|
|||||||
let v = black_box(0..1024);
|
let v = black_box(0..1024);
|
||||||
|
|
||||||
c.bench_function("step range 10", move |b| {
|
c.bench_function("step range 10", move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| fast_integer_sum(v.clone().step_by(10)))
|
||||||
fast_integer_sum(v.clone().step_by(10))
|
});
|
||||||
})
|
}
|
||||||
|
|
||||||
|
fn vec_iter_mut_partition(c: &mut Criterion) {
|
||||||
|
let data = std::iter::repeat(-1024i32..1024)
|
||||||
|
.take(256)
|
||||||
|
.flatten()
|
||||||
|
.collect_vec();
|
||||||
|
c.bench_function("vec iter mut partition", move |b| {
|
||||||
|
b.iter_batched(
|
||||||
|
|| data.clone(),
|
||||||
|
|mut data| {
|
||||||
|
black_box(itertools::partition(black_box(&mut data), |n| *n >= 0));
|
||||||
|
},
|
||||||
|
BatchSize::LargeInput,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -681,22 +618,6 @@ fn cartesian_product_iterator(c: &mut Criterion) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cartesian_product_fold(c: &mut Criterion) {
|
|
||||||
let xs = vec![0; 16];
|
|
||||||
|
|
||||||
c.bench_function("cartesian product fold", move |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut sum = 0;
|
|
||||||
iproduct!(&xs, &xs, &xs).fold((), |(), (&x, &y, &z)| {
|
|
||||||
sum += x;
|
|
||||||
sum += y;
|
|
||||||
sum += z;
|
|
||||||
});
|
|
||||||
sum
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn multi_cartesian_product_iterator(c: &mut Criterion) {
|
fn multi_cartesian_product_iterator(c: &mut Criterion) {
|
||||||
let xs = [vec![0; 16], vec![0; 16], vec![0; 16]];
|
let xs = [vec![0; 16], vec![0; 16], vec![0; 16]];
|
||||||
|
|
||||||
@@ -713,22 +634,6 @@ fn multi_cartesian_product_iterator(c: &mut Criterion) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn multi_cartesian_product_fold(c: &mut Criterion) {
|
|
||||||
let xs = [vec![0; 16], vec![0; 16], vec![0; 16]];
|
|
||||||
|
|
||||||
c.bench_function("multi cartesian product fold", move |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let mut sum = 0;
|
|
||||||
xs.iter().multi_cartesian_product().fold((), |(), x| {
|
|
||||||
sum += x[0];
|
|
||||||
sum += x[1];
|
|
||||||
sum += x[2];
|
|
||||||
});
|
|
||||||
sum
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cartesian_product_nested_for(c: &mut Criterion) {
|
fn cartesian_product_nested_for(c: &mut Criterion) {
|
||||||
let xs = vec![0; 16];
|
let xs = vec![0; 16];
|
||||||
|
|
||||||
@@ -753,9 +658,7 @@ fn all_equal(c: &mut Criterion) {
|
|||||||
let mut xs = vec![0; 5_000_000];
|
let mut xs = vec![0; 5_000_000];
|
||||||
xs.extend(vec![1; 5_000_000]);
|
xs.extend(vec![1; 5_000_000]);
|
||||||
|
|
||||||
c.bench_function("all equal", move |b| {
|
c.bench_function("all equal", move |b| b.iter(|| xs.iter().all_equal()));
|
||||||
b.iter(|| xs.iter().all_equal())
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_equal_for(c: &mut Criterion) {
|
fn all_equal_for(c: &mut Criterion) {
|
||||||
@@ -797,21 +700,17 @@ fn permutations_iter(c: &mut Criterion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.bench_function("permutations iter", move |b| {
|
c.bench_function("permutations iter", move |b| {
|
||||||
b.iter(|| {
|
b.iter(
|
||||||
for _ in NewIterator(0..PERM_COUNT).permutations(PERM_COUNT) {
|
|| {
|
||||||
|
for _ in NewIterator(0..PERM_COUNT).permutations(PERM_COUNT) {}
|
||||||
}
|
},
|
||||||
})
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn permutations_range(c: &mut Criterion) {
|
fn permutations_range(c: &mut Criterion) {
|
||||||
c.bench_function("permutations range", move |b| {
|
c.bench_function("permutations range", move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| for _ in (0..PERM_COUNT).permutations(PERM_COUNT) {})
|
||||||
for _ in (0..PERM_COUNT).permutations(PERM_COUNT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -819,11 +718,7 @@ fn permutations_slice(c: &mut Criterion) {
|
|||||||
let v = (0..PERM_COUNT).collect_vec();
|
let v = (0..PERM_COUNT).collect_vec();
|
||||||
|
|
||||||
c.bench_function("permutations slice", move |b| {
|
c.bench_function("permutations slice", move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| for _ in v.as_slice().iter().permutations(PERM_COUNT) {})
|
||||||
for _ in v.as_slice().iter().permutations(PERM_COUNT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -836,10 +731,6 @@ criterion_group!(
|
|||||||
zipdot_f32_default_zip,
|
zipdot_f32_default_zip,
|
||||||
zip_default_zip3,
|
zip_default_zip3,
|
||||||
zip_slices_ziptuple,
|
zip_slices_ziptuple,
|
||||||
zipslices,
|
|
||||||
zipslices_mut,
|
|
||||||
zipdot_i32_zipslices,
|
|
||||||
zipdot_f32_zipslices,
|
|
||||||
zip_checked_counted_loop,
|
zip_checked_counted_loop,
|
||||||
zipdot_i32_checked_counted_loop,
|
zipdot_i32_checked_counted_loop,
|
||||||
zipdot_f32_checked_counted_loop,
|
zipdot_f32_checked_counted_loop,
|
||||||
@@ -848,8 +739,8 @@ criterion_group!(
|
|||||||
zipdot_i32_unchecked_counted_loop,
|
zipdot_i32_unchecked_counted_loop,
|
||||||
zipdot_f32_unchecked_counted_loop,
|
zipdot_f32_unchecked_counted_loop,
|
||||||
zip_unchecked_counted_loop3,
|
zip_unchecked_counted_loop3,
|
||||||
group_by_lazy_1,
|
chunk_by_lazy_1,
|
||||||
group_by_lazy_2,
|
chunk_by_lazy_2,
|
||||||
slice_chunks,
|
slice_chunks,
|
||||||
chunks_lazy_1,
|
chunks_lazy_1,
|
||||||
equal,
|
equal,
|
||||||
@@ -862,10 +753,9 @@ criterion_group!(
|
|||||||
step_vec_10,
|
step_vec_10,
|
||||||
step_range_2,
|
step_range_2,
|
||||||
step_range_10,
|
step_range_10,
|
||||||
|
vec_iter_mut_partition,
|
||||||
cartesian_product_iterator,
|
cartesian_product_iterator,
|
||||||
cartesian_product_fold,
|
|
||||||
multi_cartesian_product_iterator,
|
multi_cartesian_product_iterator,
|
||||||
multi_cartesian_product_fold,
|
|
||||||
cartesian_product_nested_for,
|
cartesian_product_nested_for,
|
||||||
all_equal,
|
all_equal,
|
||||||
all_equal_for,
|
all_equal_for,
|
||||||
|
|||||||
@@ -111,15 +111,7 @@ fn comb_c14(c: &mut Criterion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
criterion_group!(
|
criterion_group!(
|
||||||
benches,
|
benches, comb_for1, comb_for2, comb_for3, comb_for4, comb_c1, comb_c2, comb_c3, comb_c4,
|
||||||
comb_for1,
|
|
||||||
comb_for2,
|
|
||||||
comb_for3,
|
|
||||||
comb_for4,
|
|
||||||
comb_c1,
|
|
||||||
comb_c2,
|
|
||||||
comb_c3,
|
|
||||||
comb_c4,
|
|
||||||
comb_c14,
|
comb_c14,
|
||||||
);
|
);
|
||||||
criterion_main!(benches);
|
criterion_main!(benches);
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
pub use self::zipslices::ZipSlices;
|
|
||||||
mod zipslices;
|
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
use std::cmp;
|
|
||||||
|
|
||||||
// Note: There are different ways to implement ZipSlices.
|
|
||||||
// This version performed the best in benchmarks.
|
|
||||||
//
|
|
||||||
// I also implemented a version with three pointers (tptr, tend, uptr),
|
|
||||||
// that mimiced slice::Iter and only checked bounds by using tptr == tend,
|
|
||||||
// but that was inferior to this solution.
|
|
||||||
|
|
||||||
/// An iterator which iterates two slices simultaneously.
|
|
||||||
///
|
|
||||||
/// `ZipSlices` acts like a double-ended `.zip()` iterator.
|
|
||||||
///
|
|
||||||
/// It was intended to be more efficient than `.zip()`, and it was, then
|
|
||||||
/// rustc changed how it optimizes so it can not promise improved performance
|
|
||||||
/// at this time.
|
|
||||||
///
|
|
||||||
/// Note that elements past the end of the shortest of the two slices are ignored.
|
|
||||||
///
|
|
||||||
/// Iterator element type for `ZipSlices<T, U>` is `(T::Item, U::Item)`. For example,
|
|
||||||
/// for a `ZipSlices<&'a [A], &'b mut [B]>`, the element type is `(&'a A, &'b mut B)`.
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ZipSlices<T, U> {
|
|
||||||
t: T,
|
|
||||||
u: U,
|
|
||||||
len: usize,
|
|
||||||
index: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b, A, B> ZipSlices<&'a [A], &'b [B]> {
|
|
||||||
/// Create a new `ZipSlices` from slices `a` and `b`.
|
|
||||||
///
|
|
||||||
/// Act like a double-ended `.zip()` iterator, but more efficiently.
|
|
||||||
///
|
|
||||||
/// Note that elements past the end of the shortest of the two slices are ignored.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn new(a: &'a [A], b: &'b [B]) -> Self {
|
|
||||||
let minl = cmp::min(a.len(), b.len());
|
|
||||||
ZipSlices {
|
|
||||||
t: a,
|
|
||||||
u: b,
|
|
||||||
len: minl,
|
|
||||||
index: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, U> ZipSlices<T, U>
|
|
||||||
where T: Slice,
|
|
||||||
U: Slice
|
|
||||||
{
|
|
||||||
/// Create a new `ZipSlices` from slices `a` and `b`.
|
|
||||||
///
|
|
||||||
/// Act like a double-ended `.zip()` iterator, but more efficiently.
|
|
||||||
///
|
|
||||||
/// Note that elements past the end of the shortest of the two slices are ignored.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_slices(a: T, b: U) -> Self {
|
|
||||||
let minl = cmp::min(a.len(), b.len());
|
|
||||||
ZipSlices {
|
|
||||||
t: a,
|
|
||||||
u: b,
|
|
||||||
len: minl,
|
|
||||||
index: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, U> Iterator for ZipSlices<T, U>
|
|
||||||
where T: Slice,
|
|
||||||
U: Slice
|
|
||||||
{
|
|
||||||
type Item = (T::Item, U::Item);
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
unsafe {
|
|
||||||
if self.index >= self.len {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let i = self.index;
|
|
||||||
self.index += 1;
|
|
||||||
Some((
|
|
||||||
self.t.get_unchecked(i),
|
|
||||||
self.u.get_unchecked(i)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
||||||
let len = self.len - self.index;
|
|
||||||
(len, Some(len))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, U> DoubleEndedIterator for ZipSlices<T, U>
|
|
||||||
where T: Slice,
|
|
||||||
U: Slice
|
|
||||||
{
|
|
||||||
#[inline(always)]
|
|
||||||
fn next_back(&mut self) -> Option<Self::Item> {
|
|
||||||
unsafe {
|
|
||||||
if self.index >= self.len {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
self.len -= 1;
|
|
||||||
let i = self.len;
|
|
||||||
Some((
|
|
||||||
self.t.get_unchecked(i),
|
|
||||||
self.u.get_unchecked(i)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, U> ExactSizeIterator for ZipSlices<T, U>
|
|
||||||
where T: Slice,
|
|
||||||
U: Slice
|
|
||||||
{}
|
|
||||||
|
|
||||||
unsafe impl<T, U> Slice for ZipSlices<T, U>
|
|
||||||
where T: Slice,
|
|
||||||
U: Slice
|
|
||||||
{
|
|
||||||
type Item = (T::Item, U::Item);
|
|
||||||
|
|
||||||
fn len(&self) -> usize {
|
|
||||||
self.len - self.index
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
|
|
||||||
(self.t.get_unchecked(i),
|
|
||||||
self.u.get_unchecked(i))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A helper trait to let `ZipSlices` accept both `&[T]` and `&mut [T]`.
|
|
||||||
///
|
|
||||||
/// Unsafe trait because:
|
|
||||||
///
|
|
||||||
/// - Implementors must guarantee that `get_unchecked` is valid for all indices `0..len()`.
|
|
||||||
pub unsafe trait Slice {
|
|
||||||
/// The type of a reference to the slice's elements
|
|
||||||
type Item;
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn len(&self) -> usize;
|
|
||||||
#[doc(hidden)]
|
|
||||||
unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<'a, T> Slice for &'a [T] {
|
|
||||||
type Item = &'a T;
|
|
||||||
#[inline(always)]
|
|
||||||
fn len(&self) -> usize { (**self).len() }
|
|
||||||
#[inline(always)]
|
|
||||||
unsafe fn get_unchecked(&mut self, i: usize) -> &'a T {
|
|
||||||
debug_assert!(i < self.len());
|
|
||||||
(**self).get_unchecked(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<'a, T> Slice for &'a mut [T] {
|
|
||||||
type Item = &'a mut T;
|
|
||||||
#[inline(always)]
|
|
||||||
fn len(&self) -> usize { (**self).len() }
|
|
||||||
#[inline(always)]
|
|
||||||
unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut T {
|
|
||||||
debug_assert!(i < self.len());
|
|
||||||
// override the lifetime constraints of &mut &'a mut [T]
|
|
||||||
(*(*self as *mut [T])).get_unchecked_mut(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn zipslices() {
|
|
||||||
|
|
||||||
let xs = [1, 2, 3, 4, 5, 6];
|
|
||||||
let ys = [1, 2, 3, 7];
|
|
||||||
::itertools::assert_equal(ZipSlices::new(&xs, &ys), xs.iter().zip(&ys));
|
|
||||||
|
|
||||||
let xs = [1, 2, 3, 4, 5, 6];
|
|
||||||
let mut ys = [0; 6];
|
|
||||||
for (x, y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) {
|
|
||||||
*y = *x;
|
|
||||||
}
|
|
||||||
::itertools::assert_equal(&xs, &ys);
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
|
#![allow(unstable_name_collisions)]
|
||||||
|
|
||||||
use criterion::{criterion_group, criterion_main, Criterion};
|
use criterion::{criterion_group, criterion_main, Criterion};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
struct Unspecialized<I>(I);
|
struct Unspecialized<I>(I);
|
||||||
|
|
||||||
impl<I> Iterator for Unspecialized<I>
|
impl<I> Iterator for Unspecialized<I>
|
||||||
where I: Iterator
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
type Item = I::Item;
|
type Item = I::Item;
|
||||||
|
|
||||||
@@ -25,8 +28,7 @@ mod specialization {
|
|||||||
pub mod intersperse {
|
pub mod intersperse {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub fn external(c: &mut Criterion)
|
pub fn external(c: &mut Criterion) {
|
||||||
{
|
|
||||||
let arr = [1; 1024];
|
let arr = [1; 1024];
|
||||||
|
|
||||||
c.bench_function("external", move |b| {
|
c.bench_function("external", move |b| {
|
||||||
@@ -40,23 +42,23 @@ mod specialization {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn internal_specialized(c: &mut Criterion)
|
pub fn internal_specialized(c: &mut Criterion) {
|
||||||
{
|
|
||||||
let arr = [1; 1024];
|
let arr = [1; 1024];
|
||||||
|
|
||||||
c.bench_function("internal specialized", move |b| {
|
c.bench_function("internal specialized", move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
|
#[allow(clippy::unnecessary_fold)]
|
||||||
arr.iter().intersperse(&0).fold(0, |acc, x| acc + x)
|
arr.iter().intersperse(&0).fold(0, |acc, x| acc + x)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn internal_unspecialized(c: &mut Criterion)
|
pub fn internal_unspecialized(c: &mut Criterion) {
|
||||||
{
|
|
||||||
let arr = [1; 1024];
|
let arr = [1; 1024];
|
||||||
|
|
||||||
c.bench_function("internal unspecialized", move |b| {
|
c.bench_function("internal unspecialized", move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
|
#[allow(clippy::unnecessary_fold)]
|
||||||
Unspecialized(arr.iter().intersperse(&0)).fold(0, |acc, x| acc + x)
|
Unspecialized(arr.iter().intersperse(&0)).fold(0, |acc, x| acc + x)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|||||||
61
third_party/rust/itertools/benches/k_smallest.rs
vendored
Normal file
61
third_party/rust/itertools/benches/k_smallest.rs
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
use criterion::{black_box, criterion_group, criterion_main, Bencher, BenchmarkId, Criterion};
|
||||||
|
use itertools::Itertools;
|
||||||
|
use rand::{rngs::StdRng, seq::SliceRandom, SeedableRng};
|
||||||
|
|
||||||
|
fn strict(b: &mut Bencher, (k, vals): &(usize, &Vec<usize>)) {
|
||||||
|
b.iter(|| black_box(vals.iter()).k_smallest(*k))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn relaxed(b: &mut Bencher, (k, vals): &(usize, &Vec<usize>)) {
|
||||||
|
b.iter(|| black_box(vals.iter()).k_smallest_relaxed(*k))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ascending(n: usize) -> Vec<usize> {
|
||||||
|
(0..n).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random(n: usize) -> Vec<usize> {
|
||||||
|
let mut vals = (0..n).collect_vec();
|
||||||
|
vals.shuffle(&mut StdRng::seed_from_u64(42));
|
||||||
|
vals
|
||||||
|
}
|
||||||
|
|
||||||
|
fn descending(n: usize) -> Vec<usize> {
|
||||||
|
(0..n).rev().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k_smallest(c: &mut Criterion, order: &str, vals: fn(usize) -> Vec<usize>) {
|
||||||
|
let mut g = c.benchmark_group(format!("k-smallest/{order}"));
|
||||||
|
|
||||||
|
for log_n in 20..23 {
|
||||||
|
let n = 1 << log_n;
|
||||||
|
|
||||||
|
let vals = vals(n);
|
||||||
|
|
||||||
|
for log_k in 7..10 {
|
||||||
|
let k = 1 << log_k;
|
||||||
|
|
||||||
|
let params = format!("{log_n}/{log_k}");
|
||||||
|
let input = (k, &vals);
|
||||||
|
g.bench_with_input(BenchmarkId::new("strict", ¶ms), &input, strict);
|
||||||
|
g.bench_with_input(BenchmarkId::new("relaxed", ¶ms), &input, relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k_smallest_asc(c: &mut Criterion) {
|
||||||
|
k_smallest(c, "asc", ascending);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k_smallest_rand(c: &mut Criterion) {
|
||||||
|
k_smallest(c, "rand", random);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k_smallest_desc(c: &mut Criterion) {
|
||||||
|
k_smallest(c, "desc", descending);
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group!(benches, k_smallest_asc, k_smallest_rand, k_smallest_desc);
|
||||||
|
criterion_main!(benches);
|
||||||
67
third_party/rust/itertools/benches/powerset.rs
vendored
67
third_party/rust/itertools/benches/powerset.rs
vendored
@@ -20,17 +20,64 @@ fn powerset_n(c: &mut Criterion, n: usize) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn powerset_0(c: &mut Criterion) { powerset_n(c, 0); }
|
fn powerset_n_fold(c: &mut Criterion, n: usize) {
|
||||||
|
let id = format!("powerset {} fold", n);
|
||||||
|
c.bench_function(id.as_str(), move |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
for _ in 0..calc_iters(n) {
|
||||||
|
(0..n).powerset().fold(0, |s, elt| s + black_box(elt).len());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn powerset_1(c: &mut Criterion) { powerset_n(c, 1); }
|
fn powerset_0(c: &mut Criterion) {
|
||||||
|
powerset_n(c, 0);
|
||||||
|
}
|
||||||
|
|
||||||
fn powerset_2(c: &mut Criterion) { powerset_n(c, 2); }
|
fn powerset_1(c: &mut Criterion) {
|
||||||
|
powerset_n(c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
fn powerset_4(c: &mut Criterion) { powerset_n(c, 4); }
|
fn powerset_2(c: &mut Criterion) {
|
||||||
|
powerset_n(c, 2);
|
||||||
|
}
|
||||||
|
|
||||||
fn powerset_8(c: &mut Criterion) { powerset_n(c, 8); }
|
fn powerset_4(c: &mut Criterion) {
|
||||||
|
powerset_n(c, 4);
|
||||||
|
}
|
||||||
|
|
||||||
fn powerset_12(c: &mut Criterion) { powerset_n(c, 12); }
|
fn powerset_8(c: &mut Criterion) {
|
||||||
|
powerset_n(c, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn powerset_12(c: &mut Criterion) {
|
||||||
|
powerset_n(c, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn powerset_0_fold(c: &mut Criterion) {
|
||||||
|
powerset_n_fold(c, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn powerset_1_fold(c: &mut Criterion) {
|
||||||
|
powerset_n_fold(c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn powerset_2_fold(c: &mut Criterion) {
|
||||||
|
powerset_n_fold(c, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn powerset_4_fold(c: &mut Criterion) {
|
||||||
|
powerset_n_fold(c, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn powerset_8_fold(c: &mut Criterion) {
|
||||||
|
powerset_n_fold(c, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn powerset_12_fold(c: &mut Criterion) {
|
||||||
|
powerset_n_fold(c, 12);
|
||||||
|
}
|
||||||
|
|
||||||
criterion_group!(
|
criterion_group!(
|
||||||
benches,
|
benches,
|
||||||
@@ -40,5 +87,11 @@ criterion_group!(
|
|||||||
powerset_4,
|
powerset_4,
|
||||||
powerset_8,
|
powerset_8,
|
||||||
powerset_12,
|
powerset_12,
|
||||||
|
powerset_0_fold,
|
||||||
|
powerset_1_fold,
|
||||||
|
powerset_2_fold,
|
||||||
|
powerset_4_fold,
|
||||||
|
powerset_8_fold,
|
||||||
|
powerset_12_fold,
|
||||||
);
|
);
|
||||||
criterion_main!(benches);
|
criterion_main!(benches);
|
||||||
|
|||||||
669
third_party/rust/itertools/benches/specializations.rs
vendored
Normal file
669
third_party/rust/itertools/benches/specializations.rs
vendored
Normal file
@@ -0,0 +1,669 @@
|
|||||||
|
#![allow(unstable_name_collisions)]
|
||||||
|
|
||||||
|
use criterion::black_box;
|
||||||
|
use criterion::BenchmarkId;
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
const NTH_INPUTS: &[usize] = &[0, 1, 2, 4, 8];
|
||||||
|
|
||||||
|
/// Create multiple functions each defining a benchmark group about iterator methods.
|
||||||
|
///
|
||||||
|
/// Each created group has functions with the following ids:
|
||||||
|
///
|
||||||
|
/// - `next`, `size_hint`, `count`, `last`, `nth`, `collect`, `fold`
|
||||||
|
/// - and when marked as `DoubleEndedIterator`: `next_back`, `nth_back`, `rfold`
|
||||||
|
/// - and when marked as `ExactSizeIterator`: `len`
|
||||||
|
///
|
||||||
|
/// Note that this macro can be called only once.
|
||||||
|
macro_rules! bench_specializations {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
$name:ident {
|
||||||
|
$($extra:ident)*
|
||||||
|
{$(
|
||||||
|
$init:stmt;
|
||||||
|
)*}
|
||||||
|
$iterator:expr
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
) => {
|
||||||
|
$(
|
||||||
|
#[allow(unused_must_use)]
|
||||||
|
fn $name(c: &mut ::criterion::Criterion) {
|
||||||
|
let mut bench_group = c.benchmark_group(stringify!($name));
|
||||||
|
$(
|
||||||
|
$init
|
||||||
|
)*
|
||||||
|
let bench_first_its = {
|
||||||
|
let mut bench_idx = 0;
|
||||||
|
[0; 1000].map(|_| {
|
||||||
|
let mut it = $iterator;
|
||||||
|
if bench_idx != 0 {
|
||||||
|
it.nth(bench_idx - 1);
|
||||||
|
}
|
||||||
|
bench_idx += 1;
|
||||||
|
it
|
||||||
|
})
|
||||||
|
};
|
||||||
|
bench_specializations!(@Iterator bench_group bench_first_its: $iterator);
|
||||||
|
$(
|
||||||
|
bench_specializations!(@$extra bench_group bench_first_its: $iterator);
|
||||||
|
)*
|
||||||
|
bench_group.finish();
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
|
||||||
|
::criterion::criterion_group!(benches, $($name, )*);
|
||||||
|
::criterion::criterion_main!(benches);
|
||||||
|
};
|
||||||
|
|
||||||
|
(@Iterator $group:ident $first_its:ident: $iterator:expr) => {
|
||||||
|
$group.bench_function("next", |bencher| bencher.iter(|| {
|
||||||
|
let mut it = $iterator;
|
||||||
|
while let Some(x) = it.next() {
|
||||||
|
black_box(x);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
$group.bench_function("size_hint", |bencher| bencher.iter(|| {
|
||||||
|
$first_its.iter().for_each(|it| {
|
||||||
|
black_box(it.size_hint());
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
$group.bench_function("count", |bencher| bencher.iter(|| {
|
||||||
|
$iterator.count()
|
||||||
|
}));
|
||||||
|
$group.bench_function("last", |bencher| bencher.iter(|| {
|
||||||
|
$iterator.last()
|
||||||
|
}));
|
||||||
|
for n in NTH_INPUTS {
|
||||||
|
$group.bench_with_input(BenchmarkId::new("nth", n), n, |bencher, n| bencher.iter(|| {
|
||||||
|
for start in 0_usize..10 {
|
||||||
|
let mut it = $iterator;
|
||||||
|
if let Some(s) = start.checked_sub(1) {
|
||||||
|
black_box(it.nth(s));
|
||||||
|
}
|
||||||
|
while let Some(x) = it.nth(*n) {
|
||||||
|
black_box(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
$group.bench_function("collect", |bencher| bencher.iter(|| {
|
||||||
|
$iterator.collect::<Vec<_>>()
|
||||||
|
}));
|
||||||
|
$group.bench_function("fold", |bencher| bencher.iter(|| {
|
||||||
|
$iterator.fold((), |(), x| {
|
||||||
|
black_box(x);
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
(@DoubleEndedIterator $group:ident $_first_its:ident: $iterator:expr) => {
|
||||||
|
$group.bench_function("next_back", |bencher| bencher.iter(|| {
|
||||||
|
let mut it = $iterator;
|
||||||
|
while let Some(x) = it.next_back() {
|
||||||
|
black_box(x);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
for n in NTH_INPUTS {
|
||||||
|
$group.bench_with_input(BenchmarkId::new("nth_back", n), n, |bencher, n| bencher.iter(|| {
|
||||||
|
for start in 0_usize..10 {
|
||||||
|
let mut it = $iterator;
|
||||||
|
if let Some(s) = start.checked_sub(1) {
|
||||||
|
black_box(it.nth_back(s));
|
||||||
|
}
|
||||||
|
while let Some(x) = it.nth_back(*n) {
|
||||||
|
black_box(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
$group.bench_function("rfold", |bencher| bencher.iter(|| {
|
||||||
|
$iterator.rfold((), |(), x| {
|
||||||
|
black_box(x);
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
(@ExactSizeIterator $group:ident $first_its:ident: $_iterator:expr) => {
|
||||||
|
$group.bench_function("len", |bencher| bencher.iter(|| {
|
||||||
|
$first_its.iter().for_each(|it| {
|
||||||
|
black_box(it.len());
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usage examples:
|
||||||
|
// - For `ZipLongest::fold` only:
|
||||||
|
// cargo bench --bench specializations zip_longest/fold
|
||||||
|
// - For `.combinations(k).nth(8)`:
|
||||||
|
// cargo bench --bench specializations combinations./nth/8
|
||||||
|
bench_specializations! {
|
||||||
|
interleave {
|
||||||
|
{
|
||||||
|
let v1 = black_box(vec![0; 1024]);
|
||||||
|
let v2 = black_box(vec![0; 768]);
|
||||||
|
}
|
||||||
|
v1.iter().interleave(&v2)
|
||||||
|
}
|
||||||
|
interleave_shortest {
|
||||||
|
{
|
||||||
|
let v1 = black_box(vec![0; 1024]);
|
||||||
|
let v2 = black_box(vec![0; 768]);
|
||||||
|
}
|
||||||
|
v1.iter().interleave_shortest(&v2)
|
||||||
|
}
|
||||||
|
batching {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().batching(Iterator::next)
|
||||||
|
}
|
||||||
|
tuple_windows1 {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().tuple_windows::<(_,)>()
|
||||||
|
}
|
||||||
|
tuple_windows2 {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().tuple_windows::<(_, _)>()
|
||||||
|
}
|
||||||
|
tuple_windows3 {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().tuple_windows::<(_, _, _)>()
|
||||||
|
}
|
||||||
|
tuple_windows4 {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().tuple_windows::<(_, _, _, _)>()
|
||||||
|
}
|
||||||
|
circular_tuple_windows1 {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().circular_tuple_windows::<(_,)>()
|
||||||
|
}
|
||||||
|
circular_tuple_windows2 {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().circular_tuple_windows::<(_, _)>()
|
||||||
|
}
|
||||||
|
circular_tuple_windows3 {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().circular_tuple_windows::<(_, _, _)>()
|
||||||
|
}
|
||||||
|
circular_tuple_windows4 {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().circular_tuple_windows::<(_, _, _, _)>()
|
||||||
|
}
|
||||||
|
tuples1 {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().tuples::<(_,)>()
|
||||||
|
}
|
||||||
|
tuples2 {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().tuples::<(_, _)>()
|
||||||
|
}
|
||||||
|
tuples3 {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().tuples::<(_, _, _)>()
|
||||||
|
}
|
||||||
|
tuples4 {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().tuples::<(_, _, _, _)>()
|
||||||
|
}
|
||||||
|
tuple_buffer {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 11]);
|
||||||
|
// Short but the buffer can't have 12 or more elements.
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut it = v.iter().tuples::<(_, _, _, _, _, _, _, _, _, _, _, _)>();
|
||||||
|
it.next(); // No element but it fills the buffer.
|
||||||
|
it.into_buffer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cartesian_product {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 16]);
|
||||||
|
}
|
||||||
|
itertools::iproduct!(&v, &v, &v)
|
||||||
|
}
|
||||||
|
multi_cartesian_product {
|
||||||
|
{
|
||||||
|
let vs = black_box([0; 3].map(|_| vec![0; 16]));
|
||||||
|
}
|
||||||
|
vs.iter().multi_cartesian_product()
|
||||||
|
}
|
||||||
|
coalesce {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().coalesce(|x, y| if x == y { Ok(x) } else { Err((x, y)) })
|
||||||
|
}
|
||||||
|
dedup {
|
||||||
|
{
|
||||||
|
let v = black_box((0..32).flat_map(|x| [x; 32]).collect_vec());
|
||||||
|
}
|
||||||
|
v.iter().dedup()
|
||||||
|
}
|
||||||
|
dedup_by {
|
||||||
|
{
|
||||||
|
let v = black_box((0..32).flat_map(|x| [x; 32]).collect_vec());
|
||||||
|
}
|
||||||
|
v.iter().dedup_by(PartialOrd::ge)
|
||||||
|
}
|
||||||
|
dedup_with_count {
|
||||||
|
{
|
||||||
|
let v = black_box((0..32).flat_map(|x| [x; 32]).collect_vec());
|
||||||
|
}
|
||||||
|
v.iter().dedup_with_count()
|
||||||
|
}
|
||||||
|
dedup_by_with_count {
|
||||||
|
{
|
||||||
|
let v = black_box((0..32).flat_map(|x| [x; 32]).collect_vec());
|
||||||
|
}
|
||||||
|
v.iter().dedup_by_with_count(PartialOrd::ge)
|
||||||
|
}
|
||||||
|
duplicates {
|
||||||
|
DoubleEndedIterator
|
||||||
|
{
|
||||||
|
let v = black_box((0..32).cycle().take(1024).collect_vec());
|
||||||
|
}
|
||||||
|
v.iter().duplicates()
|
||||||
|
}
|
||||||
|
duplicates_by {
|
||||||
|
DoubleEndedIterator
|
||||||
|
{
|
||||||
|
let v = black_box((0..1024).collect_vec());
|
||||||
|
}
|
||||||
|
v.iter().duplicates_by(|x| *x % 10)
|
||||||
|
}
|
||||||
|
unique {
|
||||||
|
DoubleEndedIterator
|
||||||
|
{
|
||||||
|
let v = black_box((0..32).cycle().take(1024).collect_vec());
|
||||||
|
}
|
||||||
|
v.iter().unique()
|
||||||
|
}
|
||||||
|
unique_by {
|
||||||
|
DoubleEndedIterator
|
||||||
|
{
|
||||||
|
let v = black_box((0..1024).collect_vec());
|
||||||
|
}
|
||||||
|
v.iter().unique_by(|x| *x % 50)
|
||||||
|
}
|
||||||
|
take_while_inclusive {
|
||||||
|
{
|
||||||
|
let v = black_box((0..1024).collect_vec());
|
||||||
|
}
|
||||||
|
v.iter().take_while_inclusive(|x| **x < 1000)
|
||||||
|
}
|
||||||
|
pad_using {
|
||||||
|
DoubleEndedIterator
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box((0..1024).collect_vec());
|
||||||
|
}
|
||||||
|
v.iter().copied().pad_using(2048, |i| 5 * i)
|
||||||
|
}
|
||||||
|
positions {
|
||||||
|
DoubleEndedIterator
|
||||||
|
{
|
||||||
|
let v = black_box((0..1024).collect_vec());
|
||||||
|
}
|
||||||
|
v.iter().positions(|x| x % 5 == 0)
|
||||||
|
}
|
||||||
|
update {
|
||||||
|
DoubleEndedIterator
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box((0_i32..1024).collect_vec());
|
||||||
|
}
|
||||||
|
v.iter().copied().update(|x| *x *= 7)
|
||||||
|
}
|
||||||
|
tuple_combinations1 {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().tuple_combinations::<(_,)>()
|
||||||
|
}
|
||||||
|
tuple_combinations2 {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 64]);
|
||||||
|
}
|
||||||
|
v.iter().tuple_combinations::<(_, _)>()
|
||||||
|
}
|
||||||
|
tuple_combinations3 {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 64]);
|
||||||
|
}
|
||||||
|
v.iter().tuple_combinations::<(_, _, _)>()
|
||||||
|
}
|
||||||
|
tuple_combinations4 {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 64]);
|
||||||
|
}
|
||||||
|
v.iter().tuple_combinations::<(_, _, _, _)>()
|
||||||
|
}
|
||||||
|
intersperse {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
let n = black_box(0);
|
||||||
|
}
|
||||||
|
v.iter().intersperse(&n)
|
||||||
|
}
|
||||||
|
intersperse_with {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
let n = black_box(0);
|
||||||
|
}
|
||||||
|
v.iter().intersperse_with(|| &n)
|
||||||
|
}
|
||||||
|
combinations1 {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1792]);
|
||||||
|
}
|
||||||
|
v.iter().combinations(1)
|
||||||
|
}
|
||||||
|
combinations2 {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 60]);
|
||||||
|
}
|
||||||
|
v.iter().combinations(2)
|
||||||
|
}
|
||||||
|
combinations3 {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 23]);
|
||||||
|
}
|
||||||
|
v.iter().combinations(3)
|
||||||
|
}
|
||||||
|
combinations4 {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 16]);
|
||||||
|
}
|
||||||
|
v.iter().combinations(4)
|
||||||
|
}
|
||||||
|
combinations_with_replacement1 {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 4096]);
|
||||||
|
}
|
||||||
|
v.iter().combinations_with_replacement(1)
|
||||||
|
}
|
||||||
|
combinations_with_replacement2 {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 90]);
|
||||||
|
}
|
||||||
|
v.iter().combinations_with_replacement(2)
|
||||||
|
}
|
||||||
|
combinations_with_replacement3 {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 28]);
|
||||||
|
}
|
||||||
|
v.iter().combinations_with_replacement(3)
|
||||||
|
}
|
||||||
|
combinations_with_replacement4 {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 16]);
|
||||||
|
}
|
||||||
|
v.iter().combinations_with_replacement(4)
|
||||||
|
}
|
||||||
|
permutations1 {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().permutations(1)
|
||||||
|
}
|
||||||
|
permutations2 {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 36]);
|
||||||
|
}
|
||||||
|
v.iter().permutations(2)
|
||||||
|
}
|
||||||
|
permutations3 {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 12]);
|
||||||
|
}
|
||||||
|
v.iter().permutations(3)
|
||||||
|
}
|
||||||
|
permutations4 {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 8]);
|
||||||
|
}
|
||||||
|
v.iter().permutations(4)
|
||||||
|
}
|
||||||
|
powerset {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 10]);
|
||||||
|
}
|
||||||
|
v.iter().powerset()
|
||||||
|
}
|
||||||
|
while_some {
|
||||||
|
{}
|
||||||
|
(0..)
|
||||||
|
.map(black_box)
|
||||||
|
.map(|i| char::from_digit(i, 16))
|
||||||
|
.while_some()
|
||||||
|
}
|
||||||
|
with_position {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box((0..10240).collect_vec());
|
||||||
|
}
|
||||||
|
v.iter().with_position()
|
||||||
|
}
|
||||||
|
zip_longest {
|
||||||
|
DoubleEndedIterator
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let xs = black_box(vec![0; 1024]);
|
||||||
|
let ys = black_box(vec![0; 768]);
|
||||||
|
}
|
||||||
|
xs.iter().zip_longest(ys.iter())
|
||||||
|
}
|
||||||
|
zip_eq {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().zip_eq(v.iter().rev())
|
||||||
|
}
|
||||||
|
multizip {
|
||||||
|
DoubleEndedIterator
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v1 = black_box(vec![0; 1024]);
|
||||||
|
let v2 = black_box(vec![0; 768]);
|
||||||
|
let v3 = black_box(vec![0; 2048]);
|
||||||
|
}
|
||||||
|
itertools::multizip((&v1, &v2, &v3))
|
||||||
|
}
|
||||||
|
izip {
|
||||||
|
DoubleEndedIterator
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v1 = black_box(vec![0; 1024]);
|
||||||
|
let v2 = black_box(vec![0; 768]);
|
||||||
|
let v3 = black_box(vec![0; 2048]);
|
||||||
|
}
|
||||||
|
itertools::izip!(&v1, &v2, &v3)
|
||||||
|
}
|
||||||
|
put_back {
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
itertools::put_back(&v).with_value(black_box(&0))
|
||||||
|
}
|
||||||
|
put_back_n {
|
||||||
|
{
|
||||||
|
let v1 = black_box(vec![0; 1024]);
|
||||||
|
let v2 = black_box(vec![0; 16]);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut it = itertools::put_back_n(&v1);
|
||||||
|
for n in &v2 {
|
||||||
|
it.put_back(n);
|
||||||
|
}
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exactly_one_error {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
}
|
||||||
|
// Use `at_most_one` would be similar.
|
||||||
|
v.iter().exactly_one().unwrap_err()
|
||||||
|
}
|
||||||
|
multipeek {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
let n = black_box(16);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut it = v.iter().multipeek();
|
||||||
|
for _ in 0..n {
|
||||||
|
it.peek();
|
||||||
|
}
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
peek_nth {
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0; 1024]);
|
||||||
|
let n = black_box(16);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut it = itertools::peek_nth(&v);
|
||||||
|
it.peek_nth(n);
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repeat_n {
|
||||||
|
DoubleEndedIterator
|
||||||
|
ExactSizeIterator
|
||||||
|
{}
|
||||||
|
itertools::repeat_n(black_box(0), black_box(1024))
|
||||||
|
}
|
||||||
|
merge {
|
||||||
|
{
|
||||||
|
let v1 = black_box((0..1024).collect_vec());
|
||||||
|
let v2 = black_box((0..768).collect_vec());
|
||||||
|
}
|
||||||
|
v1.iter().merge(&v2)
|
||||||
|
}
|
||||||
|
merge_by {
|
||||||
|
{
|
||||||
|
let v1 = black_box((0..1024).collect_vec());
|
||||||
|
let v2 = black_box((0..768).collect_vec());
|
||||||
|
}
|
||||||
|
v1.iter().merge_by(&v2, PartialOrd::ge)
|
||||||
|
}
|
||||||
|
merge_join_by_ordering {
|
||||||
|
{
|
||||||
|
let v1 = black_box((0..1024).collect_vec());
|
||||||
|
let v2 = black_box((0..768).collect_vec());
|
||||||
|
}
|
||||||
|
v1.iter().merge_join_by(&v2, Ord::cmp)
|
||||||
|
}
|
||||||
|
merge_join_by_bool {
|
||||||
|
{
|
||||||
|
let v1 = black_box((0..1024).collect_vec());
|
||||||
|
let v2 = black_box((0..768).collect_vec());
|
||||||
|
}
|
||||||
|
v1.iter().merge_join_by(&v2, PartialOrd::ge)
|
||||||
|
}
|
||||||
|
kmerge {
|
||||||
|
{
|
||||||
|
let vs = black_box(vec![vec![0; 1024], vec![0; 256], vec![0; 768]]);
|
||||||
|
}
|
||||||
|
vs.iter().kmerge()
|
||||||
|
}
|
||||||
|
kmerge_by {
|
||||||
|
{
|
||||||
|
let vs = black_box(vec![vec![0; 1024], vec![0; 256], vec![0; 768]]);
|
||||||
|
}
|
||||||
|
vs.iter().kmerge_by(PartialOrd::ge)
|
||||||
|
}
|
||||||
|
map_into {
|
||||||
|
DoubleEndedIterator
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box(vec![0_u8; 1024]);
|
||||||
|
}
|
||||||
|
v.iter().copied().map_into::<u32>()
|
||||||
|
}
|
||||||
|
map_ok {
|
||||||
|
DoubleEndedIterator
|
||||||
|
ExactSizeIterator
|
||||||
|
{
|
||||||
|
let v = black_box((0_u32..1024)
|
||||||
|
.map(|x| if x % 2 == 1 { Err(x) } else { Ok(x) })
|
||||||
|
.collect_vec());
|
||||||
|
}
|
||||||
|
v.iter().copied().map_ok(|x| x + 1)
|
||||||
|
}
|
||||||
|
filter_ok {
|
||||||
|
DoubleEndedIterator
|
||||||
|
{
|
||||||
|
let v = black_box((0_u32..1024)
|
||||||
|
.map(|x| if x % 2 == 1 { Err(x) } else { Ok(x) })
|
||||||
|
.collect_vec());
|
||||||
|
}
|
||||||
|
v.iter().copied().filter_ok(|x| x % 3 == 0)
|
||||||
|
}
|
||||||
|
filter_map_ok {
|
||||||
|
DoubleEndedIterator
|
||||||
|
{
|
||||||
|
let v = black_box((0_u32..1024)
|
||||||
|
.map(|x| if x % 2 == 1 { Err(x) } else { Ok(x) })
|
||||||
|
.collect_vec());
|
||||||
|
}
|
||||||
|
v.iter().copied().filter_map_ok(|x| if x % 3 == 0 { Some(x + 1) } else { None })
|
||||||
|
}
|
||||||
|
flatten_ok {
|
||||||
|
DoubleEndedIterator
|
||||||
|
{
|
||||||
|
let d = black_box(vec![0; 8]);
|
||||||
|
let v = black_box((0..512)
|
||||||
|
.map(|x| if x % 2 == 0 { Ok(&d) } else { Err(x) })
|
||||||
|
.collect_vec());
|
||||||
|
}
|
||||||
|
v.iter().copied().flatten_ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
use criterion::{criterion_group, criterion_main, Criterion};
|
#![allow(deprecated)]
|
||||||
use itertools::{Itertools, cloned};
|
|
||||||
|
|
||||||
trait IterEx : Iterator {
|
use criterion::{criterion_group, criterion_main, Criterion};
|
||||||
|
use itertools::{cloned, Itertools};
|
||||||
|
|
||||||
|
trait IterEx: Iterator {
|
||||||
// Another efficient implementation against which to compare,
|
// Another efficient implementation against which to compare,
|
||||||
// but needs `std` so is less desirable.
|
// but needs `std` so is less desirable.
|
||||||
fn tree_fold1_vec<F>(self, mut f: F) -> Option<Self::Item>
|
fn tree_reduce_vec<F>(self, mut f: F) -> Option<Self::Item>
|
||||||
where F: FnMut(Self::Item, Self::Item) -> Self::Item,
|
where
|
||||||
Self: Sized,
|
F: FnMut(Self::Item, Self::Item) -> Self::Item,
|
||||||
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let hint = self.size_hint().0;
|
let hint = self.size_hint().0;
|
||||||
let cap = std::mem::size_of::<usize>() * 8 - hint.leading_zeros() as usize;
|
let cap = std::mem::size_of::<usize>() * 8 - hint.leading_zeros() as usize;
|
||||||
@@ -21,24 +24,23 @@ trait IterEx : Iterator {
|
|||||||
stack.into_iter().fold1(f)
|
stack.into_iter().fold1(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T:Iterator> IterEx for T {}
|
impl<T: Iterator> IterEx for T {}
|
||||||
|
|
||||||
macro_rules! def_benchs {
|
macro_rules! def_benchs {
|
||||||
($N:expr,
|
($N:expr,
|
||||||
$FUN:ident,
|
$FUN:ident,
|
||||||
$BENCH_NAME:ident,
|
$BENCH_NAME:ident,
|
||||||
) => (
|
) => {
|
||||||
mod $BENCH_NAME {
|
mod $BENCH_NAME {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub fn sum(c: &mut Criterion) {
|
pub fn sum(c: &mut Criterion) {
|
||||||
let v: Vec<u32> = (0.. $N).collect();
|
let v: Vec<u32> = (0..$N).collect();
|
||||||
|
|
||||||
c.bench_function(&(stringify!($BENCH_NAME).replace('_', " ") + " sum"), move |b| {
|
c.bench_function(
|
||||||
b.iter(|| {
|
&(stringify!($BENCH_NAME).replace('_', " ") + " sum"),
|
||||||
cloned(&v).$FUN(|x, y| x + y)
|
move |b| b.iter(|| cloned(&v).$FUN(|x, y| x + y)),
|
||||||
})
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn complex_iter(c: &mut Criterion) {
|
pub fn complex_iter(c: &mut Criterion) {
|
||||||
@@ -46,11 +48,10 @@ macro_rules! def_benchs {
|
|||||||
let v = (5..).take($N / 2);
|
let v = (5..).take($N / 2);
|
||||||
let it = u.chain(v);
|
let it = u.chain(v);
|
||||||
|
|
||||||
c.bench_function(&(stringify!($BENCH_NAME).replace('_', " ") + " complex iter"), move |b| {
|
c.bench_function(
|
||||||
b.iter(|| {
|
&(stringify!($BENCH_NAME).replace('_', " ") + " complex iter"),
|
||||||
it.clone().map(|x| x as f32).$FUN(f32::atan2)
|
move |b| b.iter(|| it.clone().map(|x| x as f32).$FUN(f32::atan2)),
|
||||||
})
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn string_format(c: &mut Criterion) {
|
pub fn string_format(c: &mut Criterion) {
|
||||||
@@ -58,13 +59,18 @@ macro_rules! def_benchs {
|
|||||||
// size to not waste too much time in travis. The allocations
|
// size to not waste too much time in travis. The allocations
|
||||||
// in here are so expensive anyway that it'll still take
|
// in here are so expensive anyway that it'll still take
|
||||||
// way longer per iteration than the other two benchmarks.
|
// way longer per iteration than the other two benchmarks.
|
||||||
let v: Vec<u32> = (0.. ($N/4)).collect();
|
let v: Vec<u32> = (0..($N / 4)).collect();
|
||||||
|
|
||||||
c.bench_function(&(stringify!($BENCH_NAME).replace('_', " ") + " string format"), move |b| {
|
c.bench_function(
|
||||||
b.iter(|| {
|
&(stringify!($BENCH_NAME).replace('_', " ") + " string format"),
|
||||||
cloned(&v).map(|x| x.to_string()).$FUN(|x, y| format!("{} + {}", x, y))
|
move |b| {
|
||||||
})
|
b.iter(|| {
|
||||||
});
|
cloned(&v)
|
||||||
|
.map(|x| x.to_string())
|
||||||
|
.$FUN(|x, y| format!("{} + {}", x, y))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,71 +80,71 @@ macro_rules! def_benchs {
|
|||||||
$BENCH_NAME::complex_iter,
|
$BENCH_NAME::complex_iter,
|
||||||
$BENCH_NAME::string_format,
|
$BENCH_NAME::string_format,
|
||||||
);
|
);
|
||||||
)
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
def_benchs!{
|
def_benchs! {
|
||||||
10_000,
|
10_000,
|
||||||
fold1,
|
fold1,
|
||||||
fold1_10k,
|
fold1_10k,
|
||||||
}
|
}
|
||||||
|
|
||||||
def_benchs!{
|
def_benchs! {
|
||||||
10_000,
|
10_000,
|
||||||
tree_fold1,
|
tree_reduce,
|
||||||
tree_fold1_stack_10k,
|
tree_reduce_stack_10k,
|
||||||
}
|
}
|
||||||
|
|
||||||
def_benchs!{
|
def_benchs! {
|
||||||
10_000,
|
10_000,
|
||||||
tree_fold1_vec,
|
tree_reduce_vec,
|
||||||
tree_fold1_vec_10k,
|
tree_reduce_vec_10k,
|
||||||
}
|
}
|
||||||
|
|
||||||
def_benchs!{
|
def_benchs! {
|
||||||
100,
|
100,
|
||||||
fold1,
|
fold1,
|
||||||
fold1_100,
|
fold1_100,
|
||||||
}
|
}
|
||||||
|
|
||||||
def_benchs!{
|
def_benchs! {
|
||||||
100,
|
100,
|
||||||
tree_fold1,
|
tree_reduce,
|
||||||
tree_fold1_stack_100,
|
tree_reduce_stack_100,
|
||||||
}
|
}
|
||||||
|
|
||||||
def_benchs!{
|
def_benchs! {
|
||||||
100,
|
100,
|
||||||
tree_fold1_vec,
|
tree_reduce_vec,
|
||||||
tree_fold1_vec_100,
|
tree_reduce_vec_100,
|
||||||
}
|
}
|
||||||
|
|
||||||
def_benchs!{
|
def_benchs! {
|
||||||
8,
|
8,
|
||||||
fold1,
|
fold1,
|
||||||
fold1_08,
|
fold1_08,
|
||||||
}
|
}
|
||||||
|
|
||||||
def_benchs!{
|
def_benchs! {
|
||||||
8,
|
8,
|
||||||
tree_fold1,
|
tree_reduce,
|
||||||
tree_fold1_stack_08,
|
tree_reduce_stack_08,
|
||||||
}
|
}
|
||||||
|
|
||||||
def_benchs!{
|
def_benchs! {
|
||||||
8,
|
8,
|
||||||
tree_fold1_vec,
|
tree_reduce_vec,
|
||||||
tree_fold1_vec_08,
|
tree_reduce_vec_08,
|
||||||
}
|
}
|
||||||
|
|
||||||
criterion_main!(
|
criterion_main!(
|
||||||
fold1_10k,
|
fold1_10k,
|
||||||
tree_fold1_stack_10k,
|
tree_reduce_stack_10k,
|
||||||
tree_fold1_vec_10k,
|
tree_reduce_vec_10k,
|
||||||
fold1_100,
|
fold1_100,
|
||||||
tree_fold1_stack_100,
|
tree_reduce_stack_100,
|
||||||
tree_fold1_vec_100,
|
tree_reduce_vec_100,
|
||||||
fold1_08,
|
fold1_08,
|
||||||
tree_fold1_stack_08,
|
tree_reduce_stack_08,
|
||||||
tree_fold1_vec_08,
|
tree_reduce_vec_08,
|
||||||
);
|
);
|
||||||
27
third_party/rust/itertools/benches/tuples.rs
vendored
27
third_party/rust/itertools/benches/tuples.rs
vendored
@@ -33,7 +33,7 @@ fn sum_s4(s: &[u32]) -> u32 {
|
|||||||
s4(s[0], s[1], s[2], s[3])
|
s4(s[0], s[1], s[2], s[3])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sum_t1(s: &(&u32, )) -> u32 {
|
fn sum_t1(s: &(&u32,)) -> u32 {
|
||||||
s1(*s.0)
|
s1(*s.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,9 +60,9 @@ macro_rules! def_benchs {
|
|||||||
$WINDOWS:ident;
|
$WINDOWS:ident;
|
||||||
$FOR_CHUNKS:ident,
|
$FOR_CHUNKS:ident,
|
||||||
$FOR_WINDOWS:ident
|
$FOR_WINDOWS:ident
|
||||||
) => (
|
) => {
|
||||||
fn $FOR_CHUNKS(c: &mut Criterion) {
|
fn $FOR_CHUNKS(c: &mut Criterion) {
|
||||||
let v: Vec<u32> = (0.. $N * 1_000).collect();
|
let v: Vec<u32> = (0..$N * 1_000).collect();
|
||||||
let mut s = 0;
|
let mut s = 0;
|
||||||
c.bench_function(&stringify!($FOR_CHUNKS).replace('_', " "), move |b| {
|
c.bench_function(&stringify!($FOR_CHUNKS).replace('_', " "), move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
@@ -90,7 +90,7 @@ macro_rules! def_benchs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn $TUPLES(c: &mut Criterion) {
|
fn $TUPLES(c: &mut Criterion) {
|
||||||
let v: Vec<u32> = (0.. $N * 1_000).collect();
|
let v: Vec<u32> = (0..$N * 1_000).collect();
|
||||||
let mut s = 0;
|
let mut s = 0;
|
||||||
c.bench_function(&stringify!($TUPLES).replace('_', " "), move |b| {
|
c.bench_function(&stringify!($TUPLES).replace('_', " "), move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
@@ -103,7 +103,7 @@ macro_rules! def_benchs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn $CHUNKS(c: &mut Criterion) {
|
fn $CHUNKS(c: &mut Criterion) {
|
||||||
let v: Vec<u32> = (0.. $N * 1_000).collect();
|
let v: Vec<u32> = (0..$N * 1_000).collect();
|
||||||
let mut s = 0;
|
let mut s = 0;
|
||||||
c.bench_function(&stringify!($CHUNKS).replace('_', " "), move |b| {
|
c.bench_function(&stringify!($CHUNKS).replace('_', " "), move |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
@@ -150,10 +150,10 @@ macro_rules! def_benchs {
|
|||||||
$TUPLE_WINDOWS,
|
$TUPLE_WINDOWS,
|
||||||
$WINDOWS,
|
$WINDOWS,
|
||||||
);
|
);
|
||||||
)
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
def_benchs!{
|
def_benchs! {
|
||||||
1;
|
1;
|
||||||
benches_1,
|
benches_1,
|
||||||
sum_t1,
|
sum_t1,
|
||||||
@@ -166,7 +166,7 @@ def_benchs!{
|
|||||||
for_windows_1
|
for_windows_1
|
||||||
}
|
}
|
||||||
|
|
||||||
def_benchs!{
|
def_benchs! {
|
||||||
2;
|
2;
|
||||||
benches_2,
|
benches_2,
|
||||||
sum_t2,
|
sum_t2,
|
||||||
@@ -179,7 +179,7 @@ def_benchs!{
|
|||||||
for_windows_2
|
for_windows_2
|
||||||
}
|
}
|
||||||
|
|
||||||
def_benchs!{
|
def_benchs! {
|
||||||
3;
|
3;
|
||||||
benches_3,
|
benches_3,
|
||||||
sum_t3,
|
sum_t3,
|
||||||
@@ -192,7 +192,7 @@ def_benchs!{
|
|||||||
for_windows_3
|
for_windows_3
|
||||||
}
|
}
|
||||||
|
|
||||||
def_benchs!{
|
def_benchs! {
|
||||||
4;
|
4;
|
||||||
benches_4,
|
benches_4,
|
||||||
sum_t4,
|
sum_t4,
|
||||||
@@ -205,9 +205,4 @@ def_benchs!{
|
|||||||
for_windows_4
|
for_windows_4
|
||||||
}
|
}
|
||||||
|
|
||||||
criterion_main!(
|
criterion_main!(benches_1, benches_2, benches_3, benches_4,);
|
||||||
benches_1,
|
|
||||||
benches_2,
|
|
||||||
benches_3,
|
|
||||||
benches_4,
|
|
||||||
);
|
|
||||||
|
|||||||
1
third_party/rust/itertools/clippy.toml
vendored
1
third_party/rust/itertools/clippy.toml
vendored
@@ -1 +0,0 @@
|
|||||||
msrv = "1.36.0"
|
|
||||||
41
third_party/rust/itertools/examples/iris.rs
vendored
41
third_party/rust/itertools/examples/iris.rs
vendored
@@ -3,14 +3,13 @@
|
|||||||
/// and does some simple manipulations.
|
/// and does some simple manipulations.
|
||||||
///
|
///
|
||||||
/// Iterators and itertools functionality are used throughout.
|
/// Iterators and itertools functionality are used throughout.
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use std::num::ParseFloatError;
|
use std::num::ParseFloatError;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
static DATA: &'static str = include_str!("iris.data");
|
static DATA: &str = include_str!("iris.data");
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct Iris {
|
struct Iris {
|
||||||
@@ -18,6 +17,7 @@ struct Iris {
|
|||||||
data: [f32; 4],
|
data: [f32; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)] // fields are currently ignored
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
enum ParseError {
|
enum ParseError {
|
||||||
Numeric(ParseFloatError),
|
Numeric(ParseFloatError),
|
||||||
@@ -26,7 +26,7 @@ enum ParseError {
|
|||||||
|
|
||||||
impl From<ParseFloatError> for ParseError {
|
impl From<ParseFloatError> for ParseError {
|
||||||
fn from(err: ParseFloatError) -> Self {
|
fn from(err: ParseFloatError) -> Self {
|
||||||
ParseError::Numeric(err)
|
Self::Numeric(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,8 +35,11 @@ impl FromStr for Iris {
|
|||||||
type Err = ParseError;
|
type Err = ParseError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let mut iris = Iris { name: "".into(), data: [0.; 4] };
|
let mut iris = Self {
|
||||||
let mut parts = s.split(",").map(str::trim);
|
name: "".into(),
|
||||||
|
data: [0.; 4],
|
||||||
|
};
|
||||||
|
let mut parts = s.split(',').map(str::trim);
|
||||||
|
|
||||||
// using Iterator::by_ref()
|
// using Iterator::by_ref()
|
||||||
for (index, part) in parts.by_ref().take(4).enumerate() {
|
for (index, part) in parts.by_ref().take(4).enumerate() {
|
||||||
@@ -45,7 +48,7 @@ impl FromStr for Iris {
|
|||||||
if let Some(name) = parts.next() {
|
if let Some(name) = parts.next() {
|
||||||
iris.name = name.into();
|
iris.name = name.into();
|
||||||
} else {
|
} else {
|
||||||
return Err(ParseError::Other("Missing name"))
|
return Err(ParseError::Other("Missing name"));
|
||||||
}
|
}
|
||||||
Ok(iris)
|
Ok(iris)
|
||||||
}
|
}
|
||||||
@@ -53,12 +56,13 @@ impl FromStr for Iris {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// using Itertools::fold_results to create the result of parsing
|
// using Itertools::fold_results to create the result of parsing
|
||||||
let irises = DATA.lines()
|
let irises = DATA
|
||||||
.map(str::parse)
|
.lines()
|
||||||
.fold_ok(Vec::new(), |mut v, iris: Iris| {
|
.map(str::parse)
|
||||||
v.push(iris);
|
.fold_ok(Vec::new(), |mut v, iris: Iris| {
|
||||||
v
|
v.push(iris);
|
||||||
});
|
v
|
||||||
|
});
|
||||||
let mut irises = match irises {
|
let mut irises = match irises {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Error parsing: {:?}", e);
|
println!("Error parsing: {:?}", e);
|
||||||
@@ -74,19 +78,18 @@ fn main() {
|
|||||||
let mut plot_symbols = "+ox".chars().cycle();
|
let mut plot_symbols = "+ox".chars().cycle();
|
||||||
let mut symbolmap = HashMap::new();
|
let mut symbolmap = HashMap::new();
|
||||||
|
|
||||||
// using Itertools::group_by
|
// using Itertools::chunk_by
|
||||||
for (species, species_group) in &irises.iter().group_by(|iris| &iris.name) {
|
for (species, species_chunk) in &irises.iter().chunk_by(|iris| &iris.name) {
|
||||||
// assign a plot symbol
|
// assign a plot symbol
|
||||||
symbolmap.entry(species).or_insert_with(|| {
|
symbolmap
|
||||||
plot_symbols.next().unwrap()
|
.entry(species)
|
||||||
});
|
.or_insert_with(|| plot_symbols.next().unwrap());
|
||||||
println!("{} (symbol={})", species, symbolmap[species]);
|
println!("{} (symbol={})", species, symbolmap[species]);
|
||||||
|
|
||||||
for iris in species_group {
|
for iris in species_chunk {
|
||||||
// using Itertools::format for lazy formatting
|
// using Itertools::format for lazy formatting
|
||||||
println!("{:>3.1}", iris.data.iter().format(", "));
|
println!("{:>3.1}", iris.data.iter().format(", "));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look at all combinations of the four columns
|
// Look at all combinations of the four columns
|
||||||
|
|||||||
123
third_party/rust/itertools/src/adaptors/coalesce.rs
vendored
123
third_party/rust/itertools/src/adaptors/coalesce.rs
vendored
@@ -4,62 +4,78 @@ use std::iter::FusedIterator;
|
|||||||
use crate::size_hint;
|
use crate::size_hint;
|
||||||
|
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct CoalesceBy<I, F, T>
|
pub struct CoalesceBy<I, F, C>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
|
C: CountItem<I::Item>,
|
||||||
{
|
{
|
||||||
iter: I,
|
iter: I,
|
||||||
last: Option<T>,
|
/// `last` is `None` while no item have been taken out of `iter` (at definition).
|
||||||
|
/// Then `last` will be `Some(Some(item))` until `iter` is exhausted,
|
||||||
|
/// in which case `last` will be `Some(None)`.
|
||||||
|
last: Option<Option<C::CItem>>,
|
||||||
f: F,
|
f: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Clone, F: Clone, T: Clone> Clone for CoalesceBy<I, F, T>
|
impl<I, F, C> Clone for CoalesceBy<I, F, C>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Clone + Iterator,
|
||||||
|
F: Clone,
|
||||||
|
C: CountItem<I::Item>,
|
||||||
|
C::CItem: Clone,
|
||||||
{
|
{
|
||||||
clone_fields!(last, iter, f);
|
clone_fields!(last, iter, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, F, T> fmt::Debug for CoalesceBy<I, F, T>
|
impl<I, F, C> fmt::Debug for CoalesceBy<I, F, C>
|
||||||
where
|
where
|
||||||
I: Iterator + fmt::Debug,
|
I: Iterator + fmt::Debug,
|
||||||
T: fmt::Debug,
|
C: CountItem<I::Item>,
|
||||||
|
C::CItem: fmt::Debug,
|
||||||
{
|
{
|
||||||
debug_fmt_fields!(CoalesceBy, iter);
|
debug_fmt_fields!(CoalesceBy, iter, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CoalescePredicate<Item, T> {
|
pub trait CoalescePredicate<Item, T> {
|
||||||
fn coalesce_pair(&mut self, t: T, item: Item) -> Result<T, (T, T)>;
|
fn coalesce_pair(&mut self, t: T, item: Item) -> Result<T, (T, T)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, F, T> Iterator for CoalesceBy<I, F, T>
|
impl<I, F, C> Iterator for CoalesceBy<I, F, C>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
F: CoalescePredicate<I::Item, T>,
|
F: CoalescePredicate<I::Item, C::CItem>,
|
||||||
|
C: CountItem<I::Item>,
|
||||||
{
|
{
|
||||||
type Item = T;
|
type Item = C::CItem;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let Self { iter, last, f } = self;
|
||||||
// this fuses the iterator
|
// this fuses the iterator
|
||||||
let last = self.last.take()?;
|
let init = match last {
|
||||||
|
Some(elt) => elt.take(),
|
||||||
|
None => {
|
||||||
|
*last = Some(None);
|
||||||
|
iter.next().map(C::new)
|
||||||
|
}
|
||||||
|
}?;
|
||||||
|
|
||||||
let self_last = &mut self.last;
|
|
||||||
let self_f = &mut self.f;
|
|
||||||
Some(
|
Some(
|
||||||
self.iter
|
iter.try_fold(init, |accum, next| match f.coalesce_pair(accum, next) {
|
||||||
.try_fold(last, |last, next| match self_f.coalesce_pair(last, next) {
|
Ok(joined) => Ok(joined),
|
||||||
Ok(joined) => Ok(joined),
|
Err((last_, next_)) => {
|
||||||
Err((last_, next_)) => {
|
*last = Some(Some(next_));
|
||||||
*self_last = Some(next_);
|
Err(last_)
|
||||||
Err(last_)
|
}
|
||||||
}
|
})
|
||||||
})
|
.unwrap_or_else(|x| x),
|
||||||
.unwrap_or_else(|x| x),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
let (low, hi) = size_hint::add_scalar(self.iter.size_hint(), self.last.is_some() as usize);
|
let (low, hi) = size_hint::add_scalar(
|
||||||
|
self.iter.size_hint(),
|
||||||
|
matches!(self.last, Some(Some(_))) as usize,
|
||||||
|
);
|
||||||
((low > 0) as usize, hi)
|
((low > 0) as usize, hi)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,9 +83,13 @@ where
|
|||||||
where
|
where
|
||||||
FnAcc: FnMut(Acc, Self::Item) -> Acc,
|
FnAcc: FnMut(Acc, Self::Item) -> Acc,
|
||||||
{
|
{
|
||||||
if let Some(last) = self.last {
|
let Self {
|
||||||
let mut f = self.f;
|
mut iter,
|
||||||
let (last, acc) = self.iter.fold((last, acc), |(last, acc), elt| {
|
last,
|
||||||
|
mut f,
|
||||||
|
} = self;
|
||||||
|
if let Some(last) = last.unwrap_or_else(|| iter.next().map(C::new)) {
|
||||||
|
let (last, acc) = iter.fold((last, acc), |(last, acc), elt| {
|
||||||
match f.coalesce_pair(last, elt) {
|
match f.coalesce_pair(last, elt) {
|
||||||
Ok(joined) => (joined, acc),
|
Ok(joined) => (joined, acc),
|
||||||
Err((last_, next_)) => (next_, fn_acc(acc, last_)),
|
Err((last_, next_)) => (next_, fn_acc(acc, last_)),
|
||||||
@@ -82,12 +102,43 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Iterator, F: CoalescePredicate<I::Item, T>, T> FusedIterator for CoalesceBy<I, F, T> {}
|
impl<I, F, C> FusedIterator for CoalesceBy<I, F, C>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
F: CoalescePredicate<I::Item, C::CItem>,
|
||||||
|
C: CountItem<I::Item>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NoCount;
|
||||||
|
|
||||||
|
pub struct WithCount;
|
||||||
|
|
||||||
|
pub trait CountItem<T> {
|
||||||
|
type CItem;
|
||||||
|
fn new(t: T) -> Self::CItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> CountItem<T> for NoCount {
|
||||||
|
type CItem = T;
|
||||||
|
#[inline(always)]
|
||||||
|
fn new(t: T) -> T {
|
||||||
|
t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> CountItem<T> for WithCount {
|
||||||
|
type CItem = (usize, T);
|
||||||
|
#[inline(always)]
|
||||||
|
fn new(t: T) -> (usize, T) {
|
||||||
|
(1, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An iterator adaptor that may join together adjacent elements.
|
/// An iterator adaptor that may join together adjacent elements.
|
||||||
///
|
///
|
||||||
/// See [`.coalesce()`](crate::Itertools::coalesce) for more information.
|
/// See [`.coalesce()`](crate::Itertools::coalesce) for more information.
|
||||||
pub type Coalesce<I, F> = CoalesceBy<I, F, <I as Iterator>::Item>;
|
pub type Coalesce<I, F> = CoalesceBy<I, F, NoCount>;
|
||||||
|
|
||||||
impl<F, Item, T> CoalescePredicate<Item, T> for F
|
impl<F, Item, T> CoalescePredicate<Item, T> for F
|
||||||
where
|
where
|
||||||
@@ -99,12 +150,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `Coalesce`.
|
/// Create a new `Coalesce`.
|
||||||
pub fn coalesce<I, F>(mut iter: I, f: F) -> Coalesce<I, F>
|
pub fn coalesce<I, F>(iter: I, f: F) -> Coalesce<I, F>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
{
|
{
|
||||||
Coalesce {
|
Coalesce {
|
||||||
last: iter.next(),
|
last: None,
|
||||||
iter,
|
iter,
|
||||||
f,
|
f,
|
||||||
}
|
}
|
||||||
@@ -113,7 +164,7 @@ where
|
|||||||
/// An iterator adaptor that removes repeated duplicates, determining equality using a comparison function.
|
/// An iterator adaptor that removes repeated duplicates, determining equality using a comparison function.
|
||||||
///
|
///
|
||||||
/// See [`.dedup_by()`](crate::Itertools::dedup_by) or [`.dedup()`](crate::Itertools::dedup) for more information.
|
/// See [`.dedup_by()`](crate::Itertools::dedup_by) or [`.dedup()`](crate::Itertools::dedup) for more information.
|
||||||
pub type DedupBy<I, Pred> = CoalesceBy<I, DedupPred2CoalescePred<Pred>, <I as Iterator>::Item>;
|
pub type DedupBy<I, Pred> = CoalesceBy<I, DedupPred2CoalescePred<Pred>, NoCount>;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct DedupPred2CoalescePred<DP>(DP);
|
pub struct DedupPred2CoalescePred<DP>(DP);
|
||||||
@@ -156,12 +207,12 @@ impl<T, F: FnMut(&T, &T) -> bool> DedupPredicate<T> for F {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `DedupBy`.
|
/// Create a new `DedupBy`.
|
||||||
pub fn dedup_by<I, Pred>(mut iter: I, dedup_pred: Pred) -> DedupBy<I, Pred>
|
pub fn dedup_by<I, Pred>(iter: I, dedup_pred: Pred) -> DedupBy<I, Pred>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
{
|
{
|
||||||
DedupBy {
|
DedupBy {
|
||||||
last: iter.next(),
|
last: None,
|
||||||
iter,
|
iter,
|
||||||
f: DedupPred2CoalescePred(dedup_pred),
|
f: DedupPred2CoalescePred(dedup_pred),
|
||||||
}
|
}
|
||||||
@@ -186,7 +237,7 @@ where
|
|||||||
/// See [`.dedup_by_with_count()`](crate::Itertools::dedup_by_with_count) or
|
/// See [`.dedup_by_with_count()`](crate::Itertools::dedup_by_with_count) or
|
||||||
/// [`.dedup_with_count()`](crate::Itertools::dedup_with_count) for more information.
|
/// [`.dedup_with_count()`](crate::Itertools::dedup_with_count) for more information.
|
||||||
pub type DedupByWithCount<I, Pred> =
|
pub type DedupByWithCount<I, Pred> =
|
||||||
CoalesceBy<I, DedupPredWithCount2CoalescePred<Pred>, (usize, <I as Iterator>::Item)>;
|
CoalesceBy<I, DedupPredWithCount2CoalescePred<Pred>, WithCount>;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DedupPredWithCount2CoalescePred<DP>(DP);
|
pub struct DedupPredWithCount2CoalescePred<DP>(DP);
|
||||||
@@ -215,12 +266,12 @@ where
|
|||||||
pub type DedupWithCount<I> = DedupByWithCount<I, DedupEq>;
|
pub type DedupWithCount<I> = DedupByWithCount<I, DedupEq>;
|
||||||
|
|
||||||
/// Create a new `DedupByWithCount`.
|
/// Create a new `DedupByWithCount`.
|
||||||
pub fn dedup_by_with_count<I, Pred>(mut iter: I, dedup_pred: Pred) -> DedupByWithCount<I, Pred>
|
pub fn dedup_by_with_count<I, Pred>(iter: I, dedup_pred: Pred) -> DedupByWithCount<I, Pred>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
{
|
{
|
||||||
DedupByWithCount {
|
DedupByWithCount {
|
||||||
last: iter.next().map(|v| (1, v)),
|
last: None,
|
||||||
iter,
|
iter,
|
||||||
f: DedupPredWithCount2CoalescePred(dedup_pred),
|
f: DedupPredWithCount2CoalescePred(dedup_pred),
|
||||||
}
|
}
|
||||||
|
|||||||
20
third_party/rust/itertools/src/adaptors/map.rs
vendored
20
third_party/rust/itertools/src/adaptors/map.rs
vendored
@@ -4,8 +4,8 @@ use std::marker::PhantomData;
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct MapSpecialCase<I, F> {
|
pub struct MapSpecialCase<I, F> {
|
||||||
iter: I,
|
pub(crate) iter: I,
|
||||||
f: F,
|
pub(crate) f: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MapSpecialCaseFn<T> {
|
pub trait MapSpecialCaseFn<T> {
|
||||||
@@ -67,10 +67,6 @@ where
|
|||||||
/// See [`.map_ok()`](crate::Itertools::map_ok) for more information.
|
/// See [`.map_ok()`](crate::Itertools::map_ok) for more information.
|
||||||
pub type MapOk<I, F> = MapSpecialCase<I, MapSpecialCaseFnOk<F>>;
|
pub type MapOk<I, F> = MapSpecialCase<I, MapSpecialCaseFnOk<F>>;
|
||||||
|
|
||||||
/// See [`MapOk`].
|
|
||||||
#[deprecated(note = "Use MapOk instead", since = "0.10.0")]
|
|
||||||
pub type MapResults<I, F> = MapOk<I, F>;
|
|
||||||
|
|
||||||
impl<F, T, U, E> MapSpecialCaseFn<Result<T, E>> for MapSpecialCaseFnOk<F>
|
impl<F, T, U, E> MapSpecialCaseFn<Result<T, E>> for MapSpecialCaseFnOk<F>
|
||||||
where
|
where
|
||||||
F: FnMut(T) -> U,
|
F: FnMut(T) -> U,
|
||||||
@@ -112,9 +108,19 @@ impl<T: Into<U>, U> MapSpecialCaseFn<T> for MapSpecialCaseFnInto<U> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct MapSpecialCaseFnInto<U>(PhantomData<U>);
|
pub struct MapSpecialCaseFnInto<U>(PhantomData<U>);
|
||||||
|
|
||||||
|
impl<U> std::fmt::Debug for MapSpecialCaseFnInto<U> {
|
||||||
|
debug_fmt_fields!(MapSpecialCaseFnInto, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U> Clone for MapSpecialCaseFnInto<U> {
|
||||||
|
#[inline]
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new [`MapInto`] iterator.
|
/// Create a new [`MapInto`] iterator.
|
||||||
pub fn map_into<I, R>(iter: I) -> MapInto<I, R> {
|
pub fn map_into<I, R>(iter: I) -> MapInto<I, R> {
|
||||||
MapSpecialCase {
|
MapSpecialCase {
|
||||||
|
|||||||
960
third_party/rust/itertools/src/adaptors/mod.rs
vendored
960
third_party/rust/itertools/src/adaptors/mod.rs
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,29 +1,52 @@
|
|||||||
#![cfg(feature = "use_alloc")]
|
#![cfg(feature = "use_alloc")]
|
||||||
|
use Option::{self as State, None as ProductEnded, Some as ProductInProgress};
|
||||||
use crate::size_hint;
|
use Option::{self as CurrentItems, None as NotYetPopulated, Some as Populated};
|
||||||
use crate::Itertools;
|
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
use crate::size_hint;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
/// An iterator adaptor that iterates over the cartesian product of
|
/// An iterator adaptor that iterates over the cartesian product of
|
||||||
/// multiple iterators of type `I`.
|
/// multiple iterators of type `I`.
|
||||||
///
|
///
|
||||||
/// An iterator element type is `Vec<I>`.
|
/// An iterator element type is `Vec<I::Item>`.
|
||||||
///
|
///
|
||||||
/// See [`.multi_cartesian_product()`](crate::Itertools::multi_cartesian_product)
|
/// See [`.multi_cartesian_product()`](crate::Itertools::multi_cartesian_product)
|
||||||
/// for more information.
|
/// for more information.
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct MultiProduct<I>(Vec<MultiProductIter<I>>)
|
pub struct MultiProduct<I>(State<MultiProductInner<I>>)
|
||||||
where I: Iterator + Clone,
|
where
|
||||||
I::Item: Clone;
|
I: Iterator + Clone,
|
||||||
|
I::Item: Clone;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
/// Internals for `MultiProduct`.
|
||||||
|
struct MultiProductInner<I>
|
||||||
|
where
|
||||||
|
I: Iterator + Clone,
|
||||||
|
I::Item: Clone,
|
||||||
|
{
|
||||||
|
/// Holds the iterators.
|
||||||
|
iters: Vec<MultiProductIter<I>>,
|
||||||
|
/// Not populated at the beginning then it holds the current item of each iterator.
|
||||||
|
cur: CurrentItems<Vec<I::Item>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<I> std::fmt::Debug for MultiProduct<I>
|
impl<I> std::fmt::Debug for MultiProduct<I>
|
||||||
where
|
where
|
||||||
I: Iterator + Clone + std::fmt::Debug,
|
I: Iterator + Clone + std::fmt::Debug,
|
||||||
I::Item: Clone + std::fmt::Debug,
|
I::Item: Clone + std::fmt::Debug,
|
||||||
{
|
{
|
||||||
debug_fmt_fields!(CoalesceBy, 0);
|
debug_fmt_fields!(MultiProduct, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> std::fmt::Debug for MultiProductInner<I>
|
||||||
|
where
|
||||||
|
I: Iterator + Clone + std::fmt::Debug,
|
||||||
|
I::Item: Clone + std::fmt::Debug,
|
||||||
|
{
|
||||||
|
debug_fmt_fields!(MultiProductInner, iters, cur);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new cartesian product iterator over an arbitrary number
|
/// Create a new cartesian product iterator over an arbitrary number
|
||||||
@@ -31,200 +54,178 @@ where
|
|||||||
///
|
///
|
||||||
/// Iterator element is of type `Vec<H::Item::Item>`.
|
/// Iterator element is of type `Vec<H::Item::Item>`.
|
||||||
pub fn multi_cartesian_product<H>(iters: H) -> MultiProduct<<H::Item as IntoIterator>::IntoIter>
|
pub fn multi_cartesian_product<H>(iters: H) -> MultiProduct<<H::Item as IntoIterator>::IntoIter>
|
||||||
where H: Iterator,
|
where
|
||||||
H::Item: IntoIterator,
|
H: Iterator,
|
||||||
<H::Item as IntoIterator>::IntoIter: Clone,
|
H::Item: IntoIterator,
|
||||||
<H::Item as IntoIterator>::Item: Clone
|
<H::Item as IntoIterator>::IntoIter: Clone,
|
||||||
|
<H::Item as IntoIterator>::Item: Clone,
|
||||||
{
|
{
|
||||||
MultiProduct(iters.map(|i| MultiProductIter::new(i.into_iter())).collect())
|
let inner = MultiProductInner {
|
||||||
|
iters: iters
|
||||||
|
.map(|i| MultiProductIter::new(i.into_iter()))
|
||||||
|
.collect(),
|
||||||
|
cur: NotYetPopulated,
|
||||||
|
};
|
||||||
|
MultiProduct(ProductInProgress(inner))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
/// Holds the state of a single iterator within a `MultiProduct`.
|
/// Holds the state of a single iterator within a `MultiProduct`.
|
||||||
struct MultiProductIter<I>
|
struct MultiProductIter<I>
|
||||||
where I: Iterator + Clone,
|
where
|
||||||
I::Item: Clone
|
I: Iterator + Clone,
|
||||||
|
I::Item: Clone,
|
||||||
{
|
{
|
||||||
cur: Option<I::Item>,
|
|
||||||
iter: I,
|
iter: I,
|
||||||
iter_orig: I,
|
iter_orig: I,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Holds the current state during an iteration of a `MultiProduct`.
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum MultiProductIterState {
|
|
||||||
StartOfIter,
|
|
||||||
MidIter { on_first_iter: bool },
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I> MultiProduct<I>
|
|
||||||
where I: Iterator + Clone,
|
|
||||||
I::Item: Clone
|
|
||||||
{
|
|
||||||
/// Iterates the rightmost iterator, then recursively iterates iterators
|
|
||||||
/// to the left if necessary.
|
|
||||||
///
|
|
||||||
/// Returns true if the iteration succeeded, else false.
|
|
||||||
fn iterate_last(
|
|
||||||
multi_iters: &mut [MultiProductIter<I>],
|
|
||||||
mut state: MultiProductIterState
|
|
||||||
) -> bool {
|
|
||||||
use self::MultiProductIterState::*;
|
|
||||||
|
|
||||||
if let Some((last, rest)) = multi_iters.split_last_mut() {
|
|
||||||
let on_first_iter = match state {
|
|
||||||
StartOfIter => {
|
|
||||||
let on_first_iter = !last.in_progress();
|
|
||||||
state = MidIter { on_first_iter };
|
|
||||||
on_first_iter
|
|
||||||
},
|
|
||||||
MidIter { on_first_iter } => on_first_iter
|
|
||||||
};
|
|
||||||
|
|
||||||
if !on_first_iter {
|
|
||||||
last.iterate();
|
|
||||||
}
|
|
||||||
|
|
||||||
if last.in_progress() {
|
|
||||||
true
|
|
||||||
} else if MultiProduct::iterate_last(rest, state) {
|
|
||||||
last.reset();
|
|
||||||
last.iterate();
|
|
||||||
// If iterator is None twice consecutively, then iterator is
|
|
||||||
// empty; whole product is empty.
|
|
||||||
last.in_progress()
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Reached end of iterator list. On initialisation, return true.
|
|
||||||
// At end of iteration (final iterator finishes), finish.
|
|
||||||
match state {
|
|
||||||
StartOfIter => false,
|
|
||||||
MidIter { on_first_iter } => on_first_iter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the unwrapped value of the next iteration.
|
|
||||||
fn curr_iterator(&self) -> Vec<I::Item> {
|
|
||||||
self.0.iter().map(|multi_iter| {
|
|
||||||
multi_iter.cur.clone().unwrap()
|
|
||||||
}).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if iteration has started and has not yet finished; false
|
|
||||||
/// otherwise.
|
|
||||||
fn in_progress(&self) -> bool {
|
|
||||||
if let Some(last) = self.0.last() {
|
|
||||||
last.in_progress()
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I> MultiProductIter<I>
|
impl<I> MultiProductIter<I>
|
||||||
where I: Iterator + Clone,
|
where
|
||||||
I::Item: Clone
|
I: Iterator + Clone,
|
||||||
|
I::Item: Clone,
|
||||||
{
|
{
|
||||||
fn new(iter: I) -> Self {
|
fn new(iter: I) -> Self {
|
||||||
MultiProductIter {
|
Self {
|
||||||
cur: None,
|
|
||||||
iter: iter.clone(),
|
iter: iter.clone(),
|
||||||
iter_orig: iter
|
iter_orig: iter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate the managed iterator.
|
|
||||||
fn iterate(&mut self) {
|
|
||||||
self.cur = self.iter.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reset the managed iterator.
|
|
||||||
fn reset(&mut self) {
|
|
||||||
self.iter = self.iter_orig.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the current iterator has been started and has not yet
|
|
||||||
/// finished; false otherwise.
|
|
||||||
fn in_progress(&self) -> bool {
|
|
||||||
self.cur.is_some()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Iterator for MultiProduct<I>
|
impl<I> Iterator for MultiProduct<I>
|
||||||
where I: Iterator + Clone,
|
where
|
||||||
I::Item: Clone
|
I: Iterator + Clone,
|
||||||
|
I::Item: Clone,
|
||||||
{
|
{
|
||||||
type Item = Vec<I::Item>;
|
type Item = Vec<I::Item>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if MultiProduct::iterate_last(
|
// This fuses the iterator.
|
||||||
&mut self.0,
|
let inner = self.0.as_mut()?;
|
||||||
MultiProductIterState::StartOfIter
|
match &mut inner.cur {
|
||||||
) {
|
Populated(values) => {
|
||||||
Some(self.curr_iterator())
|
debug_assert!(!inner.iters.is_empty());
|
||||||
} else {
|
// Find (from the right) a non-finished iterator and
|
||||||
None
|
// reset the finished ones encountered.
|
||||||
|
for (iter, item) in inner.iters.iter_mut().zip(values.iter_mut()).rev() {
|
||||||
|
if let Some(new) = iter.iter.next() {
|
||||||
|
*item = new;
|
||||||
|
return Some(values.clone());
|
||||||
|
} else {
|
||||||
|
iter.iter = iter.iter_orig.clone();
|
||||||
|
// `cur` is populated so the untouched `iter_orig` can not be empty.
|
||||||
|
*item = iter.iter.next().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.0 = ProductEnded;
|
||||||
|
None
|
||||||
|
}
|
||||||
|
// Only the first time.
|
||||||
|
NotYetPopulated => {
|
||||||
|
let next: Option<Vec<_>> = inner.iters.iter_mut().map(|i| i.iter.next()).collect();
|
||||||
|
if next.is_none() || inner.iters.is_empty() {
|
||||||
|
// This cartesian product had at most one item to generate and now ends.
|
||||||
|
self.0 = ProductEnded;
|
||||||
|
} else {
|
||||||
|
inner.cur.clone_from(&next);
|
||||||
|
}
|
||||||
|
next
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count(self) -> usize {
|
fn count(self) -> usize {
|
||||||
if self.0.is_empty() {
|
match self.0 {
|
||||||
return 0;
|
ProductEnded => 0,
|
||||||
|
// The iterator is fresh so the count is the product of the length of each iterator:
|
||||||
|
// - If one of them is empty, stop counting.
|
||||||
|
// - Less `count()` calls than the general case.
|
||||||
|
ProductInProgress(MultiProductInner {
|
||||||
|
iters,
|
||||||
|
cur: NotYetPopulated,
|
||||||
|
}) => iters
|
||||||
|
.into_iter()
|
||||||
|
.map(|iter| iter.iter_orig.count())
|
||||||
|
.try_fold(1, |product, count| {
|
||||||
|
if count == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(product * count)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or_default(),
|
||||||
|
// The general case.
|
||||||
|
ProductInProgress(MultiProductInner {
|
||||||
|
iters,
|
||||||
|
cur: Populated(_),
|
||||||
|
}) => iters.into_iter().fold(0, |mut acc, iter| {
|
||||||
|
if acc != 0 {
|
||||||
|
acc *= iter.iter_orig.count();
|
||||||
|
}
|
||||||
|
acc + iter.iter.count()
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.in_progress() {
|
|
||||||
return self.0.into_iter().fold(1, |acc, multi_iter| {
|
|
||||||
acc * multi_iter.iter.count()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
self.0.into_iter().fold(
|
|
||||||
0,
|
|
||||||
|acc, MultiProductIter { iter, iter_orig, cur: _ }| {
|
|
||||||
let total_count = iter_orig.count();
|
|
||||||
let cur_count = iter.count();
|
|
||||||
acc * total_count + cur_count
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
// Not ExactSizeIterator because size may be larger than usize
|
match &self.0 {
|
||||||
if self.0.is_empty() {
|
ProductEnded => (0, Some(0)),
|
||||||
return (0, Some(0));
|
ProductInProgress(MultiProductInner {
|
||||||
}
|
iters,
|
||||||
|
cur: NotYetPopulated,
|
||||||
if !self.in_progress() {
|
}) => iters
|
||||||
return self.0.iter().fold((1, Some(1)), |acc, multi_iter| {
|
.iter()
|
||||||
size_hint::mul(acc, multi_iter.iter.size_hint())
|
.map(|iter| iter.iter_orig.size_hint())
|
||||||
});
|
.fold((1, Some(1)), size_hint::mul),
|
||||||
}
|
ProductInProgress(MultiProductInner {
|
||||||
|
iters,
|
||||||
self.0.iter().fold(
|
cur: Populated(_),
|
||||||
(0, Some(0)),
|
}) => {
|
||||||
|acc, &MultiProductIter { ref iter, ref iter_orig, cur: _ }| {
|
if let [first, tail @ ..] = &iters[..] {
|
||||||
let cur_size = iter.size_hint();
|
tail.iter().fold(first.iter.size_hint(), |mut sh, iter| {
|
||||||
let total_size = iter_orig.size_hint();
|
sh = size_hint::mul(sh, iter.iter_orig.size_hint());
|
||||||
size_hint::add(size_hint::mul(acc, total_size), cur_size)
|
size_hint::add(sh, iter.iter.size_hint())
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// Since it is populated, this cartesian product has started so `iters` is not empty.
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn last(self) -> Option<Self::Item> {
|
fn last(self) -> Option<Self::Item> {
|
||||||
let iter_count = self.0.len();
|
let MultiProductInner { iters, cur } = self.0?;
|
||||||
|
// Collect the last item of each iterator of the product.
|
||||||
let lasts: Self::Item = self.0.into_iter()
|
if let Populated(values) = cur {
|
||||||
.map(|multi_iter| multi_iter.iter.last())
|
let mut count = iters.len();
|
||||||
.while_some()
|
let last = iters
|
||||||
.collect();
|
.into_iter()
|
||||||
|
.zip(values)
|
||||||
if lasts.len() == iter_count {
|
.map(|(i, value)| {
|
||||||
Some(lasts)
|
i.iter.last().unwrap_or_else(|| {
|
||||||
|
// The iterator is empty, use its current `value`.
|
||||||
|
count -= 1;
|
||||||
|
value
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
if count == 0 {
|
||||||
|
// `values` was the last item.
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(last)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
iters.into_iter().map(|i| i.iter.last()).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<I> std::iter::FusedIterator for MultiProduct<I>
|
||||||
|
where
|
||||||
|
I: Iterator + Clone,
|
||||||
|
I::Item: Clone,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|||||||
320
third_party/rust/itertools/src/combinations.rs
vendored
320
third_party/rust/itertools/src/combinations.rs
vendored
@@ -1,61 +1,258 @@
|
|||||||
|
use core::array;
|
||||||
|
use core::borrow::BorrowMut;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::FusedIterator;
|
use std::iter::FusedIterator;
|
||||||
|
|
||||||
use super::lazy_buffer::LazyBuffer;
|
use super::lazy_buffer::LazyBuffer;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
use crate::adaptors::checked_binomial;
|
||||||
|
|
||||||
|
/// Iterator for `Vec` valued combinations returned by [`.combinations()`](crate::Itertools::combinations)
|
||||||
|
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.
|
||||||
|
pub fn combinations<I: Iterator>(iter: I, k: usize) -> Combinations<I>
|
||||||
|
where
|
||||||
|
I::Item: Clone,
|
||||||
|
{
|
||||||
|
Combinations::new(iter, (0..k).collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new `ArrayCombinations` from a clonable iterator.
|
||||||
|
pub fn array_combinations<I: Iterator, const K: usize>(iter: I) -> ArrayCombinations<I, K>
|
||||||
|
where
|
||||||
|
I::Item: Clone,
|
||||||
|
{
|
||||||
|
ArrayCombinations::new(iter, array::from_fn(|i| i))
|
||||||
|
}
|
||||||
|
|
||||||
/// An iterator to iterate through all the `k`-length combinations in an iterator.
|
/// An iterator to iterate through all the `k`-length combinations in an iterator.
|
||||||
///
|
///
|
||||||
/// See [`.combinations()`](crate::Itertools::combinations) for more information.
|
/// See [`.combinations()`](crate::Itertools::combinations) and [`.array_combinations()`](crate::Itertools::array_combinations) for more information.
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct Combinations<I: Iterator> {
|
pub struct CombinationsGeneric<I: Iterator, Idx> {
|
||||||
indices: Vec<usize>,
|
indices: Idx,
|
||||||
pool: LazyBuffer<I>,
|
pool: LazyBuffer<I>,
|
||||||
first: bool,
|
first: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Clone for Combinations<I>
|
/// A type holding indices of elements in a pool or buffer of items from an inner iterator
|
||||||
where I: Clone + Iterator,
|
/// and used to pick out different combinations in a generic way.
|
||||||
I::Item: Clone,
|
pub trait PoolIndex<T>: BorrowMut<[usize]> {
|
||||||
|
type Item;
|
||||||
|
|
||||||
|
fn extract_item<I: Iterator<Item = T>>(&self, pool: &LazyBuffer<I>) -> Self::Item
|
||||||
|
where
|
||||||
|
T: Clone;
|
||||||
|
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.borrow().len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PoolIndex<T> for Vec<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, const K: usize> PoolIndex<T> for [usize; K] {
|
||||||
|
type Item = [T; K];
|
||||||
|
|
||||||
|
fn extract_item<I: Iterator<Item = T>>(&self, pool: &LazyBuffer<I>) -> [T; K]
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
{
|
||||||
|
pool.get_array(*self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, Idx> Clone for CombinationsGeneric<I, Idx>
|
||||||
|
where
|
||||||
|
I: Iterator + Clone,
|
||||||
|
I::Item: Clone,
|
||||||
|
Idx: Clone,
|
||||||
{
|
{
|
||||||
clone_fields!(indices, pool, first);
|
clone_fields!(indices, pool, first);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> fmt::Debug for Combinations<I>
|
impl<I, Idx> fmt::Debug for CombinationsGeneric<I, Idx>
|
||||||
where I: Iterator + fmt::Debug,
|
where
|
||||||
I::Item: fmt::Debug,
|
I: Iterator + fmt::Debug,
|
||||||
|
I::Item: fmt::Debug,
|
||||||
|
Idx: fmt::Debug,
|
||||||
{
|
{
|
||||||
debug_fmt_fields!(Combinations, indices, pool, first);
|
debug_fmt_fields!(Combinations, indices, pool, first);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `Combinations` from a clonable iterator.
|
impl<I: Iterator, Idx: PoolIndex<I::Item>> CombinationsGeneric<I, Idx> {
|
||||||
pub fn combinations<I>(iter: I, k: usize) -> Combinations<I>
|
/// Constructor with arguments the inner iterator and the initial state for the indices.
|
||||||
where I: Iterator
|
fn new(iter: I, indices: Idx) -> Self {
|
||||||
{
|
Self {
|
||||||
let mut pool = LazyBuffer::new(iter);
|
indices,
|
||||||
pool.prefill(k);
|
pool: LazyBuffer::new(iter),
|
||||||
|
first: true,
|
||||||
Combinations {
|
}
|
||||||
indices: (0..k).collect(),
|
|
||||||
pool,
|
|
||||||
first: true,
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Iterator> Combinations<I> {
|
|
||||||
/// Returns the length of a combination produced by this iterator.
|
/// Returns the length of a combination produced by this iterator.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn k(&self) -> usize { self.indices.len() }
|
pub fn k(&self) -> usize {
|
||||||
|
self.indices.len()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the (current) length of the pool from which combination elements are
|
/// Returns the (current) length of the pool from which combination elements are
|
||||||
/// selected. This value can change between invocations of [`next`](Combinations::next).
|
/// selected. This value can change between invocations of [`next`](Combinations::next).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn n(&self) -> usize { self.pool.len() }
|
pub fn n(&self) -> usize {
|
||||||
|
self.pool.len()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a reference to the source iterator.
|
/// Returns a reference to the source pool.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn src(&self) -> &I { &self.pool.it }
|
pub(crate) fn src(&self) -> &LazyBuffer<I> {
|
||||||
|
&self.pool
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the length of the inner iterator and the count of remaining combinations.
|
||||||
|
pub(crate) fn n_and_count(self) -> (usize, usize) {
|
||||||
|
let Self {
|
||||||
|
indices,
|
||||||
|
pool,
|
||||||
|
first,
|
||||||
|
} = self;
|
||||||
|
let n = pool.count();
|
||||||
|
(n, remaining_for(n, first, indices.borrow()).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialises the iterator by filling a buffer with elements from the
|
||||||
|
/// iterator. Returns true if there are no combinations, false otherwise.
|
||||||
|
fn init(&mut self) -> bool {
|
||||||
|
self.pool.prefill(self.k());
|
||||||
|
let done = self.k() > self.n();
|
||||||
|
if !done {
|
||||||
|
self.first = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Increments indices representing the combination to advance to the next
|
||||||
|
/// (in lexicographic order by increasing sequence) combination. For example
|
||||||
|
/// if we have n=4 & k=2 then `[0, 1] -> [0, 2] -> [0, 3] -> [1, 2] -> ...`
|
||||||
|
///
|
||||||
|
/// Returns true if we've run out of combinations, false otherwise.
|
||||||
|
fn increment_indices(&mut self) -> bool {
|
||||||
|
// Borrow once instead of noise each time it's indexed
|
||||||
|
let indices = self.indices.borrow_mut();
|
||||||
|
|
||||||
|
if indices.is_empty() {
|
||||||
|
return true; // Done
|
||||||
|
}
|
||||||
|
// Scan from the end, looking for an index to increment
|
||||||
|
let mut i: usize = indices.len() - 1;
|
||||||
|
|
||||||
|
// Check if we need to consume more from the iterator
|
||||||
|
if indices[i] == self.pool.len() - 1 {
|
||||||
|
self.pool.get_next(); // may change pool size
|
||||||
|
}
|
||||||
|
|
||||||
|
while indices[i] == i + self.pool.len() - indices.len() {
|
||||||
|
if i > 0 {
|
||||||
|
i -= 1;
|
||||||
|
} else {
|
||||||
|
// Reached the last combination
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment index, and reset the ones to its right
|
||||||
|
indices[i] += 1;
|
||||||
|
for j in i + 1..indices.len() {
|
||||||
|
indices[j] = indices[j - 1] + 1;
|
||||||
|
}
|
||||||
|
// If we've made it this far, we haven't run out of combos
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the n-th item or the number of successful steps.
|
||||||
|
pub(crate) fn try_nth(&mut self, n: usize) -> Result<<Self as Iterator>::Item, usize>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
I::Item: Clone,
|
||||||
|
{
|
||||||
|
let done = if self.first {
|
||||||
|
self.init()
|
||||||
|
} else {
|
||||||
|
self.increment_indices()
|
||||||
|
};
|
||||||
|
if done {
|
||||||
|
return Err(0);
|
||||||
|
}
|
||||||
|
for i in 0..n {
|
||||||
|
if self.increment_indices() {
|
||||||
|
return Err(i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(self.indices.extract_item(&self.pool))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, Idx> Iterator for CombinationsGeneric<I, Idx>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
I::Item: Clone,
|
||||||
|
Idx: PoolIndex<I::Item>,
|
||||||
|
{
|
||||||
|
type Item = Idx::Item;
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let done = if self.first {
|
||||||
|
self.init()
|
||||||
|
} else {
|
||||||
|
self.increment_indices()
|
||||||
|
};
|
||||||
|
|
||||||
|
if done {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(self.indices.extract_item(&self.pool))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
||||||
|
self.try_nth(n).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
let (mut low, mut upp) = self.pool.size_hint();
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn count(self) -> usize {
|
||||||
|
self.n_and_count().1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, Idx> FusedIterator for CombinationsGeneric<I, Idx>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
I::Item: Clone,
|
||||||
|
Idx: PoolIndex<I::Item>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Iterator> Combinations<I> {
|
||||||
/// Resets this `Combinations` back to an initial state for combinations of length
|
/// Resets this `Combinations` back to an initial state for combinations of length
|
||||||
/// `k` over the same pool data source. If `k` is larger than the current length
|
/// `k` over the same pool data source. If `k` is larger than the current length
|
||||||
/// of the data pool an attempt is made to prefill the pool so that it holds `k`
|
/// of the data pool an attempt is made to prefill the pool so that it holds `k`
|
||||||
@@ -68,7 +265,6 @@ impl<I: Iterator> Combinations<I> {
|
|||||||
for i in 0..k {
|
for i in 0..k {
|
||||||
self.indices[i] = i;
|
self.indices[i] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
for i in 0..self.indices.len() {
|
for i in 0..self.indices.len() {
|
||||||
self.indices[i] = i;
|
self.indices[i] = i;
|
||||||
@@ -79,50 +275,34 @@ impl<I: Iterator> Combinations<I> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Iterator for Combinations<I>
|
/// For a given size `n`, return the count of remaining combinations or None if it would overflow.
|
||||||
where I: Iterator,
|
fn remaining_for(n: usize, first: bool, indices: &[usize]) -> Option<usize> {
|
||||||
I::Item: Clone
|
let k = indices.len();
|
||||||
{
|
if n < k {
|
||||||
type Item = Vec<I::Item>;
|
Some(0)
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
} else if first {
|
||||||
if self.first {
|
checked_binomial(n, k)
|
||||||
if self.k() > self.n() {
|
} else {
|
||||||
return None;
|
// https://en.wikipedia.org/wiki/Combinatorial_number_system
|
||||||
}
|
// http://www.site.uottawa.ca/~lucia/courses/5165-09/GenCombObj.pdf
|
||||||
self.first = false;
|
|
||||||
} else if self.indices.is_empty() {
|
|
||||||
return None;
|
|
||||||
} else {
|
|
||||||
// Scan from the end, looking for an index to increment
|
|
||||||
let mut i: usize = self.indices.len() - 1;
|
|
||||||
|
|
||||||
// Check if we need to consume more from the iterator
|
// The combinations generated after the current one can be counted by counting as follows:
|
||||||
if self.indices[i] == self.pool.len() - 1 {
|
// - The subsequent combinations that differ in indices[0]:
|
||||||
self.pool.get_next(); // may change pool size
|
// If subsequent combinations differ in indices[0], then their value for indices[0]
|
||||||
}
|
// must be at least 1 greater than the current indices[0].
|
||||||
|
// As indices is strictly monotonically sorted, this means we can effectively choose k values
|
||||||
|
// from (n - 1 - indices[0]), leading to binomial(n - 1 - indices[0], k) possibilities.
|
||||||
|
// - The subsequent combinations with same indices[0], but differing indices[1]:
|
||||||
|
// Here we can choose k - 1 values from (n - 1 - indices[1]) values,
|
||||||
|
// leading to binomial(n - 1 - indices[1], k - 1) possibilities.
|
||||||
|
// - (...)
|
||||||
|
// - The subsequent combinations with same indices[0..=i], but differing indices[i]:
|
||||||
|
// Here we can choose k - i values from (n - 1 - indices[i]) values: binomial(n - 1 - indices[i], k - i).
|
||||||
|
// Since subsequent combinations can in any index, we must sum up the aforementioned binomial coefficients.
|
||||||
|
|
||||||
while self.indices[i] == i + self.pool.len() - self.indices.len() {
|
// Below, `n0` resembles indices[i].
|
||||||
if i > 0 {
|
indices.iter().enumerate().try_fold(0usize, |sum, (i, n0)| {
|
||||||
i -= 1;
|
sum.checked_add(checked_binomial(n - 1 - *n0, k - i)?)
|
||||||
} else {
|
})
|
||||||
// Reached the last combination
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increment index, and reset the ones to its right
|
|
||||||
self.indices[i] += 1;
|
|
||||||
for j in i+1..self.indices.len() {
|
|
||||||
self.indices[j] = self.indices[j - 1] + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create result vector based on the indices
|
|
||||||
Some(self.indices.iter().map(|i| self.pool[*i].clone()).collect())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> FusedIterator for Combinations<I>
|
|
||||||
where I: Iterator,
|
|
||||||
I::Item: Clone
|
|
||||||
{}
|
|
||||||
|
|||||||
@@ -1,20 +1,23 @@
|
|||||||
|
use alloc::boxed::Box;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::FusedIterator;
|
use std::iter::FusedIterator;
|
||||||
|
|
||||||
use super::lazy_buffer::LazyBuffer;
|
use super::lazy_buffer::LazyBuffer;
|
||||||
|
use crate::adaptors::checked_binomial;
|
||||||
|
|
||||||
/// An iterator to iterate through all the `n`-length combinations in an iterator, with replacement.
|
/// An iterator to iterate through all the `n`-length combinations in an iterator, with replacement.
|
||||||
///
|
///
|
||||||
/// See [`.combinations_with_replacement()`](crate::Itertools::combinations_with_replacement)
|
/// See [`.combinations_with_replacement()`](crate::Itertools::combinations_with_replacement)
|
||||||
/// for more information.
|
/// for more information.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct CombinationsWithReplacement<I>
|
pub struct CombinationsWithReplacement<I>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
I::Item: Clone,
|
I::Item: Clone,
|
||||||
{
|
{
|
||||||
indices: Vec<usize>,
|
indices: Box<[usize]>,
|
||||||
pool: LazyBuffer<I>,
|
pool: LazyBuffer<I>,
|
||||||
first: bool,
|
first: bool,
|
||||||
}
|
}
|
||||||
@@ -24,18 +27,7 @@ where
|
|||||||
I: Iterator + fmt::Debug,
|
I: Iterator + fmt::Debug,
|
||||||
I::Item: fmt::Debug + Clone,
|
I::Item: fmt::Debug + Clone,
|
||||||
{
|
{
|
||||||
debug_fmt_fields!(Combinations, indices, pool, first);
|
debug_fmt_fields!(CombinationsWithReplacement, indices, pool, first);
|
||||||
}
|
|
||||||
|
|
||||||
impl<I> CombinationsWithReplacement<I>
|
|
||||||
where
|
|
||||||
I: Iterator,
|
|
||||||
I::Item: Clone,
|
|
||||||
{
|
|
||||||
/// Map the current mask over the pool to get an output combination
|
|
||||||
fn current(&self) -> Vec<I::Item> {
|
|
||||||
self.indices.iter().map(|i| self.pool[*i].clone()).collect()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `CombinationsWithReplacement` from a clonable iterator.
|
/// Create a new `CombinationsWithReplacement` from a clonable iterator.
|
||||||
@@ -44,7 +36,7 @@ where
|
|||||||
I: Iterator,
|
I: Iterator,
|
||||||
I::Item: Clone,
|
I::Item: Clone,
|
||||||
{
|
{
|
||||||
let indices: Vec<usize> = alloc::vec![0; k];
|
let indices = alloc::vec![0; k].into_boxed_slice();
|
||||||
let pool: LazyBuffer<I> = LazyBuffer::new(iter);
|
let pool: LazyBuffer<I> = LazyBuffer::new(iter);
|
||||||
|
|
||||||
CombinationsWithReplacement {
|
CombinationsWithReplacement {
|
||||||
@@ -54,51 +46,95 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<I> CombinationsWithReplacement<I>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
I::Item: Clone,
|
||||||
|
{
|
||||||
|
/// Increments indices representing the combination to advance to the next
|
||||||
|
/// (in lexicographic order by increasing sequence) combination.
|
||||||
|
///
|
||||||
|
/// Returns true if we've run out of combinations, false otherwise.
|
||||||
|
fn increment_indices(&mut self) -> bool {
|
||||||
|
// Check if we need to consume more from the iterator
|
||||||
|
// This will run while we increment our first index digit
|
||||||
|
self.pool.get_next();
|
||||||
|
|
||||||
|
// Work out where we need to update our indices
|
||||||
|
let mut increment = None;
|
||||||
|
for (i, indices_int) in self.indices.iter().enumerate().rev() {
|
||||||
|
if *indices_int < self.pool.len() - 1 {
|
||||||
|
increment = Some((i, indices_int + 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match increment {
|
||||||
|
// If we can update the indices further
|
||||||
|
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);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
// Otherwise, we're done
|
||||||
|
None => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<I> Iterator for CombinationsWithReplacement<I>
|
impl<I> Iterator for CombinationsWithReplacement<I>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
I::Item: Clone,
|
I::Item: Clone,
|
||||||
{
|
{
|
||||||
type Item = Vec<I::Item>;
|
type Item = Vec<I::Item>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
// If this is the first iteration, return early
|
|
||||||
if self.first {
|
if self.first {
|
||||||
// In empty edge cases, stop iterating immediately
|
// In empty edge cases, stop iterating immediately
|
||||||
return if !(self.indices.is_empty() || self.pool.get_next()) {
|
if !(self.indices.is_empty() || self.pool.get_next()) {
|
||||||
None
|
return None;
|
||||||
// Otherwise, yield the initial state
|
}
|
||||||
} else {
|
self.first = false;
|
||||||
self.first = false;
|
} else if self.increment_indices() {
|
||||||
Some(self.current())
|
return None;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
Some(self.pool.get_at(&self.indices))
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we need to consume more from the iterator
|
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
||||||
// This will run while we increment our first index digit
|
if self.first {
|
||||||
self.pool.get_next();
|
// In empty edge cases, stop iterating immediately
|
||||||
|
if !(self.indices.is_empty() || self.pool.get_next()) {
|
||||||
// Work out where we need to update our indices
|
return None;
|
||||||
let mut increment: Option<(usize, usize)> = None;
|
}
|
||||||
for (i, indices_int) in self.indices.iter().enumerate().rev() {
|
self.first = false;
|
||||||
if *indices_int < self.pool.len()-1 {
|
} else if self.increment_indices() {
|
||||||
increment = Some((i, indices_int + 1));
|
return None;
|
||||||
break;
|
}
|
||||||
|
for _ in 0..n {
|
||||||
|
if self.increment_indices() {
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some(self.pool.get_at(&self.indices))
|
||||||
|
}
|
||||||
|
|
||||||
match increment {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
// If we can update the indices further
|
let (mut low, mut upp) = self.pool.size_hint();
|
||||||
Some((increment_from, increment_value)) => {
|
low = remaining_for(low, self.first, &self.indices).unwrap_or(usize::MAX);
|
||||||
// We need to update the rightmost non-max value
|
upp = upp.and_then(|upp| remaining_for(upp, self.first, &self.indices));
|
||||||
// and all those to the right
|
(low, upp)
|
||||||
for indices_index in increment_from..self.indices.len() {
|
}
|
||||||
self.indices[indices_index] = increment_value;
|
|
||||||
}
|
fn count(self) -> usize {
|
||||||
Some(self.current())
|
let Self {
|
||||||
}
|
indices,
|
||||||
// Otherwise, we're done
|
pool,
|
||||||
None => None,
|
first,
|
||||||
}
|
} = self;
|
||||||
|
let n = pool.count();
|
||||||
|
remaining_for(n, first, &indices).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,4 +142,47 @@ impl<I> FusedIterator for CombinationsWithReplacement<I>
|
|||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
I::Item: Clone,
|
I::Item: Clone,
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// For a given size `n`, return the count of remaining combinations with replacement or None if it would overflow.
|
||||||
|
fn remaining_for(n: usize, first: bool, indices: &[usize]) -> Option<usize> {
|
||||||
|
// With a "stars and bars" representation, choose k values with replacement from n values is
|
||||||
|
// like choosing k out of k + n − 1 positions (hence binomial(k + n - 1, k) possibilities)
|
||||||
|
// to place k stars and therefore n - 1 bars.
|
||||||
|
// Example (n=4, k=6): ***|*||** represents [0,0,0,1,3,3].
|
||||||
|
let count = |n: usize, k: usize| {
|
||||||
|
let positions = if n == 0 {
|
||||||
|
k.saturating_sub(1)
|
||||||
|
} else {
|
||||||
|
(n - 1).checked_add(k)?
|
||||||
|
};
|
||||||
|
checked_binomial(positions, k)
|
||||||
|
};
|
||||||
|
let k = indices.len();
|
||||||
|
if first {
|
||||||
|
count(n, k)
|
||||||
|
} else {
|
||||||
|
// The algorithm is similar to the one for combinations *without replacement*,
|
||||||
|
// except we choose values *with replacement* and indices are *non-strictly* monotonically sorted.
|
||||||
|
|
||||||
|
// The combinations generated after the current one can be counted by counting as follows:
|
||||||
|
// - The subsequent combinations that differ in indices[0]:
|
||||||
|
// If subsequent combinations differ in indices[0], then their value for indices[0]
|
||||||
|
// must be at least 1 greater than the current indices[0].
|
||||||
|
// As indices is monotonically sorted, this means we can effectively choose k values with
|
||||||
|
// replacement from (n - 1 - indices[0]), leading to count(n - 1 - indices[0], k) possibilities.
|
||||||
|
// - The subsequent combinations with same indices[0], but differing indices[1]:
|
||||||
|
// Here we can choose k - 1 values with replacement from (n - 1 - indices[1]) values,
|
||||||
|
// leading to count(n - 1 - indices[1], k - 1) possibilities.
|
||||||
|
// - (...)
|
||||||
|
// - The subsequent combinations with same indices[0..=i], but differing indices[i]:
|
||||||
|
// Here we can choose k - i values with replacement from (n - 1 - indices[i]) values: count(n - 1 - indices[i], k - i).
|
||||||
|
// Since subsequent combinations can in any index, we must sum up the aforementioned binomial coefficients.
|
||||||
|
|
||||||
|
// Below, `n0` resembles indices[i].
|
||||||
|
indices.iter().enumerate().try_fold(0usize, |sum, (i, n0)| {
|
||||||
|
sum.checked_add(count(n - 1 - *n0, k - i)?)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
20
third_party/rust/itertools/src/concat_impl.rs
vendored
20
third_party/rust/itertools/src/concat_impl.rs
vendored
@@ -1,8 +1,6 @@
|
|||||||
use crate::Itertools;
|
|
||||||
|
|
||||||
/// Combine all an iterator's elements into one element by using [`Extend`].
|
/// Combine all an iterator's elements into one element by using [`Extend`].
|
||||||
///
|
///
|
||||||
/// [`IntoIterator`]-enabled version of [`Itertools::concat`].
|
/// [`IntoIterator`]-enabled version of [`Itertools::concat`](crate::Itertools::concat).
|
||||||
///
|
///
|
||||||
/// This combinator will extend the first item with each of the rest of the
|
/// This combinator will extend the first item with each of the rest of the
|
||||||
/// items of the iterator. If the iterator is empty, the default value of
|
/// items of the iterator. If the iterator is empty, the default value of
|
||||||
@@ -10,14 +8,20 @@ use crate::Itertools;
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use itertools::concat;
|
/// use itertools::concat;
|
||||||
///
|
///
|
||||||
/// let input = vec![vec![1], vec![2, 3], vec![4, 5, 6]];
|
/// let input = vec![vec![1], vec![2, 3], vec![4, 5, 6]];
|
||||||
/// assert_eq!(concat(input), vec![1, 2, 3, 4, 5, 6]);
|
/// assert_eq!(concat(input), vec![1, 2, 3, 4, 5, 6]);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn concat<I>(iterable: I) -> I::Item
|
pub fn concat<I>(iterable: I) -> I::Item
|
||||||
where I: IntoIterator,
|
where
|
||||||
I::Item: Extend<<<I as IntoIterator>::Item as IntoIterator>::Item> + IntoIterator + Default
|
I: IntoIterator,
|
||||||
|
I::Item: Extend<<<I as IntoIterator>::Item as IntoIterator>::Item> + IntoIterator + Default,
|
||||||
{
|
{
|
||||||
#[allow(deprecated)] //TODO: once msrv hits 1.51. replace `fold1` with `reduce`
|
iterable
|
||||||
iterable.into_iter().fold1(|mut a, b| { a.extend(b); a }).unwrap_or_default()
|
.into_iter()
|
||||||
|
.reduce(|mut a, b| {
|
||||||
|
a.extend(b);
|
||||||
|
a
|
||||||
|
})
|
||||||
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::adaptors::map::{MapSpecialCase, MapSpecialCaseFn};
|
||||||
|
|
||||||
macro_rules! impl_cons_iter(
|
macro_rules! impl_cons_iter(
|
||||||
($_A:ident, $_B:ident, ) => (); // stop
|
($_A:ident, $_B:ident, ) => (); // stop
|
||||||
@@ -5,60 +6,34 @@ macro_rules! impl_cons_iter(
|
|||||||
($A:ident, $($B:ident,)*) => (
|
($A:ident, $($B:ident,)*) => (
|
||||||
impl_cons_iter!($($B,)*);
|
impl_cons_iter!($($B,)*);
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
impl<X, Iter, $($B),*> Iterator for ConsTuples<Iter, (($($B,)*), X)>
|
impl<$($B),*, X> MapSpecialCaseFn<(($($B,)*), X)> for ConsTuplesFn {
|
||||||
where Iter: Iterator<Item = (($($B,)*), X)>,
|
type Out = ($($B,)* X, );
|
||||||
{
|
fn call(&mut self, (($($B,)*), X): (($($B,)*), X)) -> Self::Out {
|
||||||
type Item = ($($B,)* X, );
|
($($B,)* X, )
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
self.iter.next().map(|(($($B,)*), x)| ($($B,)* x, ))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
||||||
self.iter.size_hint()
|
|
||||||
}
|
|
||||||
fn fold<Acc, Fold>(self, accum: Acc, mut f: Fold) -> Acc
|
|
||||||
where Fold: FnMut(Acc, Self::Item) -> Acc,
|
|
||||||
{
|
|
||||||
self.iter.fold(accum, move |acc, (($($B,)*), x)| f(acc, ($($B,)* x, )))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
impl<X, Iter, $($B),*> DoubleEndedIterator for ConsTuples<Iter, (($($B,)*), X)>
|
|
||||||
where Iter: DoubleEndedIterator<Item = (($($B,)*), X)>,
|
|
||||||
{
|
|
||||||
fn next_back(&mut self) -> Option<Self::Item> {
|
|
||||||
self.iter.next().map(|(($($B,)*), x)| ($($B,)* x, ))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
);
|
);
|
||||||
);
|
);
|
||||||
|
|
||||||
impl_cons_iter!(A, B, C, D, E, F, G, H, I, J, K, L,);
|
impl_cons_iter!(A, B, C, D, E, F, G, H, I, J, K, L,);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ConsTuplesFn;
|
||||||
|
|
||||||
/// An iterator that maps an iterator of tuples like
|
/// An iterator that maps an iterator of tuples like
|
||||||
/// `((A, B), C)` to an iterator of `(A, B, C)`.
|
/// `((A, B), C)` to an iterator of `(A, B, C)`.
|
||||||
///
|
///
|
||||||
/// Used by the `iproduct!()` macro.
|
/// Used by the `iproduct!()` macro.
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
pub type ConsTuples<I> = MapSpecialCase<I, ConsTuplesFn>;
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ConsTuples<I, J>
|
|
||||||
where I: Iterator<Item=J>,
|
|
||||||
{
|
|
||||||
iter: I,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, J> Clone for ConsTuples<I, J>
|
|
||||||
where I: Clone + Iterator<Item=J>,
|
|
||||||
{
|
|
||||||
clone_fields!(iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create an iterator that maps for example iterators of
|
/// Create an iterator that maps for example iterators of
|
||||||
/// `((A, B), C)` to `(A, B, C)`.
|
/// `((A, B), C)` to `(A, B, C)`.
|
||||||
pub fn cons_tuples<I, J>(iterable: I) -> ConsTuples<I::IntoIter, J>
|
pub fn cons_tuples<I>(iterable: I) -> ConsTuples<I::IntoIter>
|
||||||
where I: IntoIterator<Item=J>
|
where
|
||||||
|
I: IntoIterator,
|
||||||
{
|
{
|
||||||
ConsTuples { iter: iterable.into_iter() }
|
ConsTuples {
|
||||||
|
iter: iterable.into_iter(),
|
||||||
|
f: ConsTuplesFn,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
71
third_party/rust/itertools/src/diff.rs
vendored
71
third_party/rust/itertools/src/diff.rs
vendored
@@ -1,10 +1,12 @@
|
|||||||
//! "Diff"ing iterators for caching elements to sequential collections without requiring the new
|
//! "Diff"ing iterators for caching elements to sequential collections without requiring the new
|
||||||
//! elements' iterator to be `Clone`.
|
//! elements' iterator to be `Clone`.
|
||||||
//!
|
//!
|
||||||
//! - [`Diff`] (produced by the [`diff_with`] function)
|
//! [`Diff`] (produced by the [`diff_with`] function)
|
||||||
//! describes the difference between two non-`Clone` iterators `I` and `J` after breaking ASAP from
|
//! describes the difference between two non-`Clone` iterators `I` and `J` after breaking ASAP from
|
||||||
//! a lock-step comparison.
|
//! a lock-step comparison.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
use crate::free::put_back;
|
use crate::free::put_back;
|
||||||
use crate::structs::PutBack;
|
use crate::structs::PutBack;
|
||||||
|
|
||||||
@@ -13,8 +15,9 @@ use crate::structs::PutBack;
|
|||||||
/// `Diff` represents the way in which the elements yielded by the iterator `I` differ to some
|
/// `Diff` represents the way in which the elements yielded by the iterator `I` differ to some
|
||||||
/// iterator `J`.
|
/// iterator `J`.
|
||||||
pub enum Diff<I, J>
|
pub enum Diff<I, J>
|
||||||
where I: Iterator,
|
where
|
||||||
J: Iterator
|
I: Iterator,
|
||||||
|
J: Iterator,
|
||||||
{
|
{
|
||||||
/// The index of the first non-matching element along with both iterator's remaining elements
|
/// The index of the first non-matching element along with both iterator's remaining elements
|
||||||
/// starting with the first mis-match.
|
/// starting with the first mis-match.
|
||||||
@@ -25,6 +28,43 @@ pub enum Diff<I, J>
|
|||||||
Longer(usize, PutBack<J>),
|
Longer(usize, PutBack<J>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<I, J> fmt::Debug for Diff<I, J>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
J: Iterator,
|
||||||
|
PutBack<I>: fmt::Debug,
|
||||||
|
PutBack<J>: fmt::Debug,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::FirstMismatch(idx, i, j) => f
|
||||||
|
.debug_tuple("FirstMismatch")
|
||||||
|
.field(idx)
|
||||||
|
.field(i)
|
||||||
|
.field(j)
|
||||||
|
.finish(),
|
||||||
|
Self::Shorter(idx, i) => f.debug_tuple("Shorter").field(idx).field(i).finish(),
|
||||||
|
Self::Longer(idx, j) => f.debug_tuple("Longer").field(idx).field(j).finish(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, J> Clone for Diff<I, J>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
J: Iterator,
|
||||||
|
PutBack<I>: Clone,
|
||||||
|
PutBack<J>: Clone,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::FirstMismatch(idx, i, j) => Self::FirstMismatch(*idx, i.clone(), j.clone()),
|
||||||
|
Self::Shorter(idx, i) => Self::Shorter(*idx, i.clone()),
|
||||||
|
Self::Longer(idx, j) => Self::Longer(*idx, j.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Compares every element yielded by both `i` and `j` with the given function in lock-step and
|
/// Compares every element yielded by both `i` and `j` with the given function in lock-step and
|
||||||
/// returns a [`Diff`] which describes how `j` differs from `i`.
|
/// returns a [`Diff`] which describes how `j` differs from `i`.
|
||||||
///
|
///
|
||||||
@@ -37,11 +77,11 @@ pub enum Diff<I, J>
|
|||||||
///
|
///
|
||||||
/// If `i` becomes exhausted before `j` becomes exhausted, the number of elements in `i` along with
|
/// If `i` becomes exhausted before `j` becomes exhausted, the number of elements in `i` along with
|
||||||
/// the remaining `j` elements will be returned as `Diff::Longer`.
|
/// the remaining `j` elements will be returned as `Diff::Longer`.
|
||||||
pub fn diff_with<I, J, F>(i: I, j: J, is_equal: F)
|
pub fn diff_with<I, J, F>(i: I, j: J, mut is_equal: F) -> Option<Diff<I::IntoIter, J::IntoIter>>
|
||||||
-> Option<Diff<I::IntoIter, J::IntoIter>>
|
where
|
||||||
where I: IntoIterator,
|
I: IntoIterator,
|
||||||
J: IntoIterator,
|
J: IntoIterator,
|
||||||
F: Fn(&I::Item, &J::Item) -> bool
|
F: FnMut(&I::Item, &J::Item) -> bool,
|
||||||
{
|
{
|
||||||
let mut i = i.into_iter();
|
let mut i = i.into_iter();
|
||||||
let mut j = j.into_iter();
|
let mut j = j.into_iter();
|
||||||
@@ -49,13 +89,16 @@ pub fn diff_with<I, J, F>(i: I, j: J, is_equal: F)
|
|||||||
while let Some(i_elem) = i.next() {
|
while let Some(i_elem) = i.next() {
|
||||||
match j.next() {
|
match j.next() {
|
||||||
None => return Some(Diff::Shorter(idx, put_back(i).with_value(i_elem))),
|
None => return Some(Diff::Shorter(idx, put_back(i).with_value(i_elem))),
|
||||||
Some(j_elem) => if !is_equal(&i_elem, &j_elem) {
|
Some(j_elem) => {
|
||||||
let remaining_i = put_back(i).with_value(i_elem);
|
if !is_equal(&i_elem, &j_elem) {
|
||||||
let remaining_j = put_back(j).with_value(j_elem);
|
let remaining_i = put_back(i).with_value(i_elem);
|
||||||
return Some(Diff::FirstMismatch(idx, remaining_i, remaining_j));
|
let remaining_j = put_back(j).with_value(j_elem);
|
||||||
},
|
return Some(Diff::FirstMismatch(idx, remaining_i, remaining_j));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
idx += 1;
|
idx += 1;
|
||||||
}
|
}
|
||||||
j.next().map(|j_elem| Diff::Longer(idx, put_back(j).with_value(j_elem)))
|
j.next()
|
||||||
|
.map(|j_elem| Diff::Longer(idx, put_back(j).with_value(j_elem)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ use std::hash::Hash;
|
|||||||
|
|
||||||
mod private {
|
mod private {
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::hash::Hash;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
@@ -22,7 +22,7 @@ mod private {
|
|||||||
|
|
||||||
impl<I: Iterator, Key: Eq + Hash, F> DuplicatesBy<I, Key, F> {
|
impl<I: Iterator, Key: Eq + Hash, F> DuplicatesBy<I, Key, F> {
|
||||||
pub(crate) fn new(iter: I, key_method: F) -> Self {
|
pub(crate) fn new(iter: I, key_method: F) -> Self {
|
||||||
DuplicatesBy {
|
Self {
|
||||||
iter,
|
iter,
|
||||||
meta: Meta {
|
meta: Meta {
|
||||||
used: HashMap::new(),
|
used: HashMap::new(),
|
||||||
@@ -77,7 +77,7 @@ mod private {
|
|||||||
type Item = I::Item;
|
type Item = I::Item;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let DuplicatesBy { iter, meta } = self;
|
let Self { iter, meta } = self;
|
||||||
iter.find_map(|v| meta.filter(v))
|
iter.find_map(|v| meta.filter(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ mod private {
|
|||||||
F: KeyMethod<Key, I::Item>,
|
F: KeyMethod<Key, I::Item>,
|
||||||
{
|
{
|
||||||
fn next_back(&mut self) -> Option<Self::Item> {
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
let DuplicatesBy { iter, meta } = self;
|
let Self { iter, meta } = self;
|
||||||
iter.rev().find_map(|v| meta.filter(v))
|
iter.rev().find_map(|v| meta.filter(v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,7 @@ mod private {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Apply the identity function to elements before checking them for equality.
|
/// Apply the identity function to elements before checking them for equality.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ById;
|
pub struct ById;
|
||||||
impl<V> KeyMethod<V, V> for ById {
|
impl<V> KeyMethod<V, V> for ById {
|
||||||
type Container = JustValue<V>;
|
type Container = JustValue<V>;
|
||||||
@@ -133,6 +133,7 @@ mod private {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Apply a user-supplied function to elements before checking them for equality.
|
/// Apply a user-supplied function to elements before checking them for equality.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct ByFn<F>(pub(crate) F);
|
pub struct ByFn<F>(pub(crate) F);
|
||||||
impl<F> fmt::Debug for ByFn<F> {
|
impl<F> fmt::Debug for ByFn<F> {
|
||||||
debug_fmt_fields!(ByFn,);
|
debug_fmt_fields!(ByFn,);
|
||||||
@@ -213,4 +214,3 @@ where
|
|||||||
{
|
{
|
||||||
Duplicates::new(iter, private::ById)
|
Duplicates::new(iter, private::ById)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
314
third_party/rust/itertools/src/either_or_both.rs
vendored
314
third_party/rust/itertools/src/either_or_both.rs
vendored
@@ -1,10 +1,12 @@
|
|||||||
|
use core::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use crate::EitherOrBoth::*;
|
use crate::EitherOrBoth::*;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
|
|
||||||
/// Value that either holds a single A or B, or both.
|
/// Value that either holds a single A or B, or both.
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
pub enum EitherOrBoth<A, B> {
|
pub enum EitherOrBoth<A, B = A> {
|
||||||
/// Both values are present.
|
/// Both values are present.
|
||||||
Both(A, B),
|
Both(A, B),
|
||||||
/// Only the left value of type `A` is present.
|
/// Only the left value of type `A` is present.
|
||||||
@@ -14,7 +16,7 @@ pub enum EitherOrBoth<A, B> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<A, B> EitherOrBoth<A, B> {
|
impl<A, B> EitherOrBoth<A, B> {
|
||||||
/// If `Left`, or `Both`, return true, otherwise, return false.
|
/// If `Left`, or `Both`, return true. Otherwise, return false.
|
||||||
pub fn has_left(&self) -> bool {
|
pub fn has_left(&self) -> bool {
|
||||||
self.as_ref().left().is_some()
|
self.as_ref().left().is_some()
|
||||||
}
|
}
|
||||||
@@ -24,31 +26,24 @@ impl<A, B> EitherOrBoth<A, B> {
|
|||||||
self.as_ref().right().is_some()
|
self.as_ref().right().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If Left, return true otherwise, return false.
|
/// If `Left`, return true. Otherwise, return false.
|
||||||
/// Exclusive version of [`has_left`](EitherOrBoth::has_left).
|
/// Exclusive version of [`has_left`](EitherOrBoth::has_left).
|
||||||
pub fn is_left(&self) -> bool {
|
pub fn is_left(&self) -> bool {
|
||||||
match *self {
|
matches!(self, Left(_))
|
||||||
Left(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If Right, return true otherwise, return false.
|
/// If `Right`, return true. Otherwise, return false.
|
||||||
/// Exclusive version of [`has_right`](EitherOrBoth::has_right).
|
/// Exclusive version of [`has_right`](EitherOrBoth::has_right).
|
||||||
pub fn is_right(&self) -> bool {
|
pub fn is_right(&self) -> bool {
|
||||||
match *self {
|
matches!(self, Right(_))
|
||||||
Right(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If Right, return true otherwise, return false.
|
/// If `Both`, return true. Otherwise, return false.
|
||||||
/// Equivalent to `self.as_ref().both().is_some()`.
|
|
||||||
pub fn is_both(&self) -> bool {
|
pub fn is_both(&self) -> bool {
|
||||||
self.as_ref().both().is_some()
|
self.as_ref().both().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If `Left`, or `Both`, return `Some` with the left value, otherwise, return `None`.
|
/// If `Left`, or `Both`, return `Some` with the left value. Otherwise, return `None`.
|
||||||
pub fn left(self) -> Option<A> {
|
pub fn left(self) -> Option<A> {
|
||||||
match self {
|
match self {
|
||||||
Left(left) | Both(left, _) => Some(left),
|
Left(left) | Both(left, _) => Some(left),
|
||||||
@@ -56,7 +51,7 @@ impl<A, B> EitherOrBoth<A, B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If `Right`, or `Both`, return `Some` with the right value, otherwise, return `None`.
|
/// If `Right`, or `Both`, return `Some` with the right value. Otherwise, return `None`.
|
||||||
pub fn right(self) -> Option<B> {
|
pub fn right(self) -> Option<B> {
|
||||||
match self {
|
match self {
|
||||||
Right(right) | Both(_, right) => Some(right),
|
Right(right) | Both(_, right) => Some(right),
|
||||||
@@ -64,7 +59,65 @@ impl<A, B> EitherOrBoth<A, B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If Both, return `Some` tuple containing left and right.
|
/// Return tuple of options corresponding to the left and right value respectively
|
||||||
|
///
|
||||||
|
/// If `Left` return `(Some(..), None)`, if `Right` return `(None,Some(..))`, else return
|
||||||
|
/// `(Some(..),Some(..))`
|
||||||
|
pub fn left_and_right(self) -> (Option<A>, Option<B>) {
|
||||||
|
self.map_any(Some, Some).or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If `Left`, return `Some` with the left value. If `Right` or `Both`, return `None`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // On the `Left` variant.
|
||||||
|
/// # use itertools::{EitherOrBoth, EitherOrBoth::{Left, Right, Both}};
|
||||||
|
/// let x: EitherOrBoth<_, ()> = Left("bonjour");
|
||||||
|
/// assert_eq!(x.just_left(), Some("bonjour"));
|
||||||
|
///
|
||||||
|
/// // On the `Right` variant.
|
||||||
|
/// let x: EitherOrBoth<(), _> = Right("hola");
|
||||||
|
/// assert_eq!(x.just_left(), None);
|
||||||
|
///
|
||||||
|
/// // On the `Both` variant.
|
||||||
|
/// let x = Both("bonjour", "hola");
|
||||||
|
/// assert_eq!(x.just_left(), None);
|
||||||
|
/// ```
|
||||||
|
pub fn just_left(self) -> Option<A> {
|
||||||
|
match self {
|
||||||
|
Left(left) => Some(left),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If `Right`, return `Some` with the right value. If `Left` or `Both`, return `None`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // On the `Left` variant.
|
||||||
|
/// # use itertools::{EitherOrBoth::{Left, Right, Both}, EitherOrBoth};
|
||||||
|
/// let x: EitherOrBoth<_, ()> = Left("auf wiedersehen");
|
||||||
|
/// assert_eq!(x.just_left(), Some("auf wiedersehen"));
|
||||||
|
///
|
||||||
|
/// // On the `Right` variant.
|
||||||
|
/// let x: EitherOrBoth<(), _> = Right("adios");
|
||||||
|
/// assert_eq!(x.just_left(), None);
|
||||||
|
///
|
||||||
|
/// // On the `Both` variant.
|
||||||
|
/// let x = Both("auf wiedersehen", "adios");
|
||||||
|
/// assert_eq!(x.just_left(), None);
|
||||||
|
/// ```
|
||||||
|
pub fn just_right(self) -> Option<B> {
|
||||||
|
match self {
|
||||||
|
Right(right) => Some(right),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If `Both`, return `Some` containing the left and right values. Otherwise, return `None`.
|
||||||
pub fn both(self) -> Option<(A, B)> {
|
pub fn both(self) -> Option<(A, B)> {
|
||||||
match self {
|
match self {
|
||||||
Both(a, b) => Some((a, b)),
|
Both(a, b) => Some((a, b)),
|
||||||
@@ -72,6 +125,28 @@ impl<A, B> EitherOrBoth<A, B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If `Left` or `Both`, return the left value. Otherwise, convert the right value and return it.
|
||||||
|
pub fn into_left(self) -> A
|
||||||
|
where
|
||||||
|
B: Into<A>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Left(a) | Both(a, _) => a,
|
||||||
|
Right(b) => b.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If `Right` or `Both`, return the right value. Otherwise, convert the left value and return it.
|
||||||
|
pub fn into_right(self) -> B
|
||||||
|
where
|
||||||
|
A: Into<B>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Right(b) | Both(_, b) => b,
|
||||||
|
Left(a) => a.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts from `&EitherOrBoth<A, B>` to `EitherOrBoth<&A, &B>`.
|
/// Converts from `&EitherOrBoth<A, B>` to `EitherOrBoth<&A, &B>`.
|
||||||
pub fn as_ref(&self) -> EitherOrBoth<&A, &B> {
|
pub fn as_ref(&self) -> EitherOrBoth<&A, &B> {
|
||||||
match *self {
|
match *self {
|
||||||
@@ -90,6 +165,32 @@ impl<A, B> EitherOrBoth<A, B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts from `&EitherOrBoth<A, B>` to `EitherOrBoth<&_, &_>` using the [`Deref`] trait.
|
||||||
|
pub fn as_deref(&self) -> EitherOrBoth<&A::Target, &B::Target>
|
||||||
|
where
|
||||||
|
A: Deref,
|
||||||
|
B: Deref,
|
||||||
|
{
|
||||||
|
match *self {
|
||||||
|
Left(ref left) => Left(left),
|
||||||
|
Right(ref right) => Right(right),
|
||||||
|
Both(ref left, ref right) => Both(left, right),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts from `&mut EitherOrBoth<A, B>` to `EitherOrBoth<&mut _, &mut _>` using the [`DerefMut`] trait.
|
||||||
|
pub fn as_deref_mut(&mut self) -> EitherOrBoth<&mut A::Target, &mut B::Target>
|
||||||
|
where
|
||||||
|
A: DerefMut,
|
||||||
|
B: DerefMut,
|
||||||
|
{
|
||||||
|
match *self {
|
||||||
|
Left(ref mut left) => Left(left),
|
||||||
|
Right(ref mut right) => Right(right),
|
||||||
|
Both(ref mut left, ref mut right) => Both(left, right),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert `EitherOrBoth<A, B>` to `EitherOrBoth<B, A>`.
|
/// Convert `EitherOrBoth<A, B>` to `EitherOrBoth<B, A>`.
|
||||||
pub fn flip(self) -> EitherOrBoth<B, A> {
|
pub fn flip(self) -> EitherOrBoth<B, A> {
|
||||||
match self {
|
match self {
|
||||||
@@ -200,9 +301,9 @@ impl<A, B> EitherOrBoth<A, B> {
|
|||||||
B: Default,
|
B: Default,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
EitherOrBoth::Left(l) => (l, B::default()),
|
Left(l) => (l, B::default()),
|
||||||
EitherOrBoth::Right(r) => (A::default(), r),
|
Right(r) => (A::default(), r),
|
||||||
EitherOrBoth::Both(l, r) => (l, r),
|
Both(l, r) => (l, r),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,10 +328,160 @@ impl<A, B> EitherOrBoth<A, B> {
|
|||||||
Both(inner_l, inner_r) => (inner_l, inner_r),
|
Both(inner_l, inner_r) => (inner_l, inner_r),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable reference to the left value. If the left value is not present,
|
||||||
|
/// it is replaced with `val`.
|
||||||
|
pub fn left_or_insert(&mut self, val: A) -> &mut A {
|
||||||
|
self.left_or_insert_with(|| val)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable reference to the right value. If the right value is not present,
|
||||||
|
/// it is replaced with `val`.
|
||||||
|
pub fn right_or_insert(&mut self, val: B) -> &mut B {
|
||||||
|
self.right_or_insert_with(|| val)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If the left value is not present, replace it the value computed by the closure `f`.
|
||||||
|
/// Returns a mutable reference to the now-present left value.
|
||||||
|
pub fn left_or_insert_with<F>(&mut self, f: F) -> &mut A
|
||||||
|
where
|
||||||
|
F: FnOnce() -> A,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Left(left) | Both(left, _) => left,
|
||||||
|
Right(_) => self.insert_left(f()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If the right value is not present, replace it the value computed by the closure `f`.
|
||||||
|
/// Returns a mutable reference to the now-present right value.
|
||||||
|
pub fn right_or_insert_with<F>(&mut self, f: F) -> &mut B
|
||||||
|
where
|
||||||
|
F: FnOnce() -> B,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Right(right) | Both(_, right) => right,
|
||||||
|
Left(_) => self.insert_right(f()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the `left` value of this instance, and returns a mutable reference to it.
|
||||||
|
/// Does not affect the `right` value.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # use itertools::{EitherOrBoth, EitherOrBoth::{Left, Right, Both}};
|
||||||
|
///
|
||||||
|
/// // Overwriting a pre-existing value.
|
||||||
|
/// let mut either: EitherOrBoth<_, ()> = Left(0_u32);
|
||||||
|
/// assert_eq!(*either.insert_left(69), 69);
|
||||||
|
///
|
||||||
|
/// // Inserting a second value.
|
||||||
|
/// let mut either = Right("no");
|
||||||
|
/// assert_eq!(*either.insert_left("yes"), "yes");
|
||||||
|
/// assert_eq!(either, Both("yes", "no"));
|
||||||
|
/// ```
|
||||||
|
pub fn insert_left(&mut self, val: A) -> &mut A {
|
||||||
|
match self {
|
||||||
|
Left(left) | Both(left, _) => {
|
||||||
|
*left = val;
|
||||||
|
left
|
||||||
|
}
|
||||||
|
Right(right) => {
|
||||||
|
// This is like a map in place operation. We move out of the reference,
|
||||||
|
// change the value, and then move back into the reference.
|
||||||
|
unsafe {
|
||||||
|
// SAFETY: We know this pointer is valid for reading since we got it from a reference.
|
||||||
|
let right = std::ptr::read(right as *mut _);
|
||||||
|
// SAFETY: Again, we know the pointer is valid since we got it from a reference.
|
||||||
|
std::ptr::write(self as *mut _, Both(val, right));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Both(left, _) = self {
|
||||||
|
left
|
||||||
|
} else {
|
||||||
|
// SAFETY: The above pattern will always match, since we just
|
||||||
|
// set `self` equal to `Both`.
|
||||||
|
unsafe { std::hint::unreachable_unchecked() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the `right` value of this instance, and returns a mutable reference to it.
|
||||||
|
/// Does not affect the `left` value.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # use itertools::{EitherOrBoth, EitherOrBoth::{Left, Both}};
|
||||||
|
/// // Overwriting a pre-existing value.
|
||||||
|
/// let mut either: EitherOrBoth<_, ()> = Left(0_u32);
|
||||||
|
/// assert_eq!(*either.insert_left(69), 69);
|
||||||
|
///
|
||||||
|
/// // 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));
|
||||||
|
/// ```
|
||||||
|
pub fn insert_right(&mut self, val: B) -> &mut B {
|
||||||
|
match self {
|
||||||
|
Right(right) | Both(_, right) => {
|
||||||
|
*right = val;
|
||||||
|
right
|
||||||
|
}
|
||||||
|
Left(left) => {
|
||||||
|
// This is like a map in place operation. We move out of the reference,
|
||||||
|
// change the value, and then move back into the reference.
|
||||||
|
unsafe {
|
||||||
|
// SAFETY: We know this pointer is valid for reading since we got it from a reference.
|
||||||
|
let left = std::ptr::read(left as *mut _);
|
||||||
|
// SAFETY: Again, we know the pointer is valid since we got it from a reference.
|
||||||
|
std::ptr::write(self as *mut _, Both(left, val));
|
||||||
|
}
|
||||||
|
if let Both(_, right) = self {
|
||||||
|
right
|
||||||
|
} else {
|
||||||
|
// SAFETY: The above pattern will always match, since we just
|
||||||
|
// set `self` equal to `Both`.
|
||||||
|
unsafe { std::hint::unreachable_unchecked() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set `self` to `Both(..)`, containing the specified left and right values,
|
||||||
|
/// and returns a mutable reference to those values.
|
||||||
|
pub fn insert_both(&mut self, left: A, right: B) -> (&mut A, &mut B) {
|
||||||
|
*self = Both(left, right);
|
||||||
|
if let Both(left, right) = self {
|
||||||
|
(left, right)
|
||||||
|
} else {
|
||||||
|
// SAFETY: The above pattern will always match, since we just
|
||||||
|
// set `self` equal to `Both`.
|
||||||
|
unsafe { std::hint::unreachable_unchecked() }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EitherOrBoth<T, T> {
|
impl<T> EitherOrBoth<T, T> {
|
||||||
/// Return either value of left, right, or the product of `f` applied where `Both` are present.
|
/// 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,
|
||||||
|
/// but fall back to the other (i.e. right resp. left) if the preferred one is not present.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # use itertools::EitherOrBoth;
|
||||||
|
/// assert_eq!(EitherOrBoth::Both(3, 7).reduce(u32::max), 7);
|
||||||
|
/// assert_eq!(EitherOrBoth::Left(3).reduce(u32::max), 3);
|
||||||
|
/// assert_eq!(EitherOrBoth::Right(7).reduce(u32::max), 7);
|
||||||
|
///
|
||||||
|
/// // Extract the left value if present, fall back to the right otherwise.
|
||||||
|
/// assert_eq!(EitherOrBoth::Left("left").reduce(|l, _r| l), "left");
|
||||||
|
/// assert_eq!(EitherOrBoth::Right("right").reduce(|l, _r| l), "right");
|
||||||
|
/// assert_eq!(EitherOrBoth::Both("left", "right").reduce(|l, _r| l), "left");
|
||||||
|
/// ```
|
||||||
pub fn reduce<F>(self, f: F) -> T
|
pub fn reduce<F>(self, f: F) -> T
|
||||||
where
|
where
|
||||||
F: FnOnce(T, T) -> T,
|
F: FnOnce(T, T) -> T,
|
||||||
@@ -243,12 +494,21 @@ impl<T> EitherOrBoth<T, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, B> Into<Option<Either<A, B>>> for EitherOrBoth<A, B> {
|
impl<A, B> From<EitherOrBoth<A, B>> for Option<Either<A, B>> {
|
||||||
fn into(self) -> Option<Either<A, B>> {
|
fn from(value: EitherOrBoth<A, B>) -> Self {
|
||||||
match self {
|
match value {
|
||||||
EitherOrBoth::Left(l) => Some(Either::Left(l)),
|
Left(l) => Some(Either::Left(l)),
|
||||||
EitherOrBoth::Right(r) => Some(Either::Right(r)),
|
Right(r) => Some(Either::Right(r)),
|
||||||
_ => None,
|
Both(..) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B> From<Either<A, B>> for EitherOrBoth<A, B> {
|
||||||
|
fn from(either: Either<A, B>) -> Self {
|
||||||
|
match either {
|
||||||
|
Either::Left(l) => Left(l),
|
||||||
|
Either::Right(l) => Right(l),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use either::Either;
|
|||||||
|
|
||||||
use crate::size_hint;
|
use crate::size_hint;
|
||||||
|
|
||||||
/// Iterator returned for the error case of `IterTools::exactly_one()`
|
/// Iterator returned for the error case of `Itertools::exactly_one()`
|
||||||
/// This iterator yields exactly the same elements as the input iterator.
|
/// This iterator yields exactly the same elements as the input iterator.
|
||||||
///
|
///
|
||||||
/// During the execution of `exactly_one` the iterator must be mutated. This wrapper
|
/// During the execution of `exactly_one` the iterator must be mutated. This wrapper
|
||||||
@@ -54,26 +54,37 @@ where
|
|||||||
Some(Either::Left([first, second])) => {
|
Some(Either::Left([first, second])) => {
|
||||||
self.first_two = Some(Either::Right(second));
|
self.first_two = Some(Either::Right(second));
|
||||||
Some(first)
|
Some(first)
|
||||||
},
|
|
||||||
Some(Either::Right(second)) => {
|
|
||||||
Some(second)
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
self.inner.next()
|
|
||||||
}
|
}
|
||||||
|
Some(Either::Right(second)) => Some(second),
|
||||||
|
None => self.inner.next(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
size_hint::add_scalar(self.inner.size_hint(), self.additional_len())
|
size_hint::add_scalar(self.inner.size_hint(), self.additional_len())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
fn fold<B, F>(self, mut init: B, mut f: F) -> B
|
||||||
|
where
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
match self.first_two {
|
||||||
|
Some(Either::Left([first, second])) => {
|
||||||
|
init = f(init, first);
|
||||||
|
init = f(init, second);
|
||||||
|
}
|
||||||
|
Some(Either::Right(second)) => init = f(init, second),
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
self.inner.fold(init, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<I> ExactSizeIterator for ExactlyOneError<I> where I: ExactSizeIterator {}
|
impl<I> ExactSizeIterator for ExactlyOneError<I> where I: ExactSizeIterator {}
|
||||||
|
|
||||||
impl<I> Display for ExactlyOneError<I>
|
impl<I> Display for ExactlyOneError<I>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
let additional = self.additional_len();
|
let additional = self.additional_len();
|
||||||
@@ -85,26 +96,30 @@ impl<I> Display for ExactlyOneError<I>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Debug for ExactlyOneError<I>
|
impl<I> Debug for ExactlyOneError<I>
|
||||||
where I: Iterator + Debug,
|
where
|
||||||
I::Item: Debug,
|
I: Iterator + Debug,
|
||||||
|
I::Item: Debug,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
|
let mut dbg = f.debug_struct("ExactlyOneError");
|
||||||
match &self.first_two {
|
match &self.first_two {
|
||||||
Some(Either::Left([first, second])) => {
|
Some(Either::Left([first, second])) => {
|
||||||
write!(f, "ExactlyOneError[First: {:?}, Second: {:?}, RemainingIter: {:?}]", first, second, self.inner)
|
dbg.field("first", first).field("second", second);
|
||||||
},
|
}
|
||||||
Some(Either::Right(second)) => {
|
Some(Either::Right(second)) => {
|
||||||
write!(f, "ExactlyOneError[Second: {:?}, RemainingIter: {:?}]", second, self.inner)
|
dbg.field("second", second);
|
||||||
}
|
|
||||||
None => {
|
|
||||||
write!(f, "ExactlyOneError[RemainingIter: {:?}]", self.inner)
|
|
||||||
}
|
}
|
||||||
|
None => {}
|
||||||
}
|
}
|
||||||
|
dbg.field("inner", &self.inner).finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "use_std")]
|
#[cfg(feature = "use_std")]
|
||||||
impl<I> Error for ExactlyOneError<I> where I: Iterator + Debug, I::Item: Debug, {}
|
impl<I> Error for ExactlyOneError<I>
|
||||||
|
where
|
||||||
|
I: Iterator + Debug,
|
||||||
|
I::Item: Debug,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use alloc::{vec, vec::Vec};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
/// Implementation guts for `min_set`, `min_set_by`, and `min_set_by_key`.
|
/// Implementation guts for `min_set`, `min_set_by`, and `min_set_by_key`.
|
||||||
|
|||||||
54
third_party/rust/itertools/src/flatten_ok.rs
vendored
54
third_party/rust/itertools/src/flatten_ok.rs
vendored
@@ -72,6 +72,29 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fold<B, F>(self, init: B, mut f: F) -> B
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
// Front
|
||||||
|
let mut acc = match self.inner_front {
|
||||||
|
Some(x) => x.fold(init, |a, o| f(a, Ok(o))),
|
||||||
|
None => init,
|
||||||
|
};
|
||||||
|
|
||||||
|
acc = self.iter.fold(acc, |acc, x| match x {
|
||||||
|
Ok(it) => it.into_iter().fold(acc, |a, o| f(a, Ok(o))),
|
||||||
|
Err(e) => f(acc, Err(e)),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Back
|
||||||
|
match self.inner_back {
|
||||||
|
Some(x) => x.fold(acc, |a, o| f(a, Ok(o))),
|
||||||
|
None => acc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
let inner_hint = |inner: &Option<T::IntoIter>| {
|
let inner_hint = |inner: &Option<T::IntoIter>| {
|
||||||
inner
|
inner
|
||||||
@@ -130,6 +153,29 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rfold<B, F>(self, init: B, mut f: F) -> B
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
// Back
|
||||||
|
let mut acc = match self.inner_back {
|
||||||
|
Some(x) => x.rfold(init, |a, o| f(a, Ok(o))),
|
||||||
|
None => init,
|
||||||
|
};
|
||||||
|
|
||||||
|
acc = self.iter.rfold(acc, |acc, x| match x {
|
||||||
|
Ok(it) => it.into_iter().rfold(acc, |a, o| f(a, Ok(o))),
|
||||||
|
Err(e) => f(acc, Err(e)),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Front
|
||||||
|
match self.inner_front {
|
||||||
|
Some(x) => x.rfold(acc, |a, o| f(a, Ok(o))),
|
||||||
|
None => acc,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, T, E> Clone for FlattenOk<I, T, E>
|
impl<I, T, E> Clone for FlattenOk<I, T, E>
|
||||||
@@ -147,13 +193,7 @@ where
|
|||||||
T: IntoIterator,
|
T: IntoIterator,
|
||||||
T::IntoIter: fmt::Debug,
|
T::IntoIter: fmt::Debug,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
debug_fmt_fields!(FlattenOk, iter, inner_front, inner_back);
|
||||||
f.debug_struct("FlattenOk")
|
|
||||||
.field("iter", &self.iter)
|
|
||||||
.field("inner_front", &self.inner_front)
|
|
||||||
.field("inner_back", &self.inner_back)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Only the iterator being flattened needs to implement [`FusedIterator`].
|
/// Only the iterator being flattened needs to implement [`FusedIterator`].
|
||||||
|
|||||||
113
third_party/rust/itertools/src/format.rs
vendored
113
third_party/rust/itertools/src/format.rs
vendored
@@ -1,5 +1,5 @@
|
|||||||
|
use std::cell::Cell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::cell::RefCell;
|
|
||||||
|
|
||||||
/// Format all iterator elements lazily, separated by `sep`.
|
/// Format all iterator elements lazily, separated by `sep`.
|
||||||
///
|
///
|
||||||
@@ -7,11 +7,10 @@ use std::cell::RefCell;
|
|||||||
/// exhausted.
|
/// exhausted.
|
||||||
///
|
///
|
||||||
/// See [`.format_with()`](crate::Itertools::format_with) for more information.
|
/// See [`.format_with()`](crate::Itertools::format_with) for more information.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct FormatWith<'a, I, F> {
|
pub struct FormatWith<'a, I, F> {
|
||||||
sep: &'a str,
|
sep: &'a str,
|
||||||
/// FormatWith uses interior mutability because Display::fmt takes &self.
|
/// `FormatWith` uses interior mutability because `Display::fmt` takes `&self`.
|
||||||
inner: RefCell<Option<(I, F)>>,
|
inner: Cell<Option<(I, F)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Format all iterator elements lazily, separated by `sep`.
|
/// Format all iterator elements lazily, separated by `sep`.
|
||||||
@@ -21,38 +20,40 @@ pub struct FormatWith<'a, I, F> {
|
|||||||
///
|
///
|
||||||
/// See [`.format()`](crate::Itertools::format)
|
/// See [`.format()`](crate::Itertools::format)
|
||||||
/// for more information.
|
/// for more information.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Format<'a, I> {
|
pub struct Format<'a, I> {
|
||||||
sep: &'a str,
|
sep: &'a str,
|
||||||
/// Format uses interior mutability because Display::fmt takes &self.
|
/// `Format` uses interior mutability because `Display::fmt` takes `&self`.
|
||||||
inner: RefCell<Option<I>>,
|
inner: Cell<Option<I>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_format<I, F>(iter: I, separator: &str, f: F) -> FormatWith<'_, I, F>
|
pub fn new_format<I, F>(iter: I, separator: &str, f: F) -> FormatWith<'_, I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
F: FnMut(I::Item, &mut dyn FnMut(&dyn fmt::Display) -> fmt::Result) -> fmt::Result
|
I: Iterator,
|
||||||
|
F: FnMut(I::Item, &mut dyn FnMut(&dyn fmt::Display) -> fmt::Result) -> fmt::Result,
|
||||||
{
|
{
|
||||||
FormatWith {
|
FormatWith {
|
||||||
sep: separator,
|
sep: separator,
|
||||||
inner: RefCell::new(Some((iter, f))),
|
inner: Cell::new(Some((iter, f))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_format_default<I>(iter: I, separator: &str) -> Format<'_, I>
|
pub fn new_format_default<I>(iter: I, separator: &str) -> Format<'_, I>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
Format {
|
Format {
|
||||||
sep: separator,
|
sep: separator,
|
||||||
inner: RefCell::new(Some(iter)),
|
inner: Cell::new(Some(iter)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I, F> fmt::Display for FormatWith<'a, I, F>
|
impl<I, F> fmt::Display for FormatWith<'_, I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
F: FnMut(I::Item, &mut dyn FnMut(&dyn fmt::Display) -> fmt::Result) -> fmt::Result
|
I: Iterator,
|
||||||
|
F: FnMut(I::Item, &mut dyn FnMut(&dyn fmt::Display) -> fmt::Result) -> fmt::Result,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let (mut iter, mut format) = match self.inner.borrow_mut().take() {
|
let (mut iter, mut format) = match self.inner.take() {
|
||||||
Some(t) => t,
|
Some(t) => t,
|
||||||
None => panic!("FormatWith: was already formatted once"),
|
None => panic!("FormatWith: was already formatted once"),
|
||||||
};
|
};
|
||||||
@@ -70,13 +71,26 @@ impl<'a, I, F> fmt::Display for FormatWith<'a, I, F>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I> Format<'a, I>
|
impl<I, F> fmt::Debug for FormatWith<'_, I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
|
F: FnMut(I::Item, &mut dyn FnMut(&dyn fmt::Display) -> fmt::Result) -> fmt::Result,
|
||||||
{
|
{
|
||||||
fn format<F>(&self, f: &mut fmt::Formatter, mut cb: F) -> fmt::Result
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
where F: FnMut(&I::Item, &mut fmt::Formatter) -> fmt::Result,
|
fmt::Display::fmt(self, f)
|
||||||
{
|
}
|
||||||
let mut iter = match self.inner.borrow_mut().take() {
|
}
|
||||||
|
|
||||||
|
impl<I> Format<'_, I>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
{
|
||||||
|
fn format(
|
||||||
|
&self,
|
||||||
|
f: &mut fmt::Formatter,
|
||||||
|
cb: fn(&I::Item, &mut fmt::Formatter) -> fmt::Result,
|
||||||
|
) -> fmt::Result {
|
||||||
|
let mut iter = match self.inner.take() {
|
||||||
Some(t) => t,
|
Some(t) => t,
|
||||||
None => panic!("Format: was already formatted once"),
|
None => panic!("Format: was already formatted once"),
|
||||||
};
|
};
|
||||||
@@ -109,5 +123,56 @@ macro_rules! impl_format {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_format!{Display Debug
|
impl_format! {Display Debug UpperExp LowerExp UpperHex LowerHex Octal Binary Pointer}
|
||||||
UpperExp LowerExp UpperHex LowerHex Octal Binary Pointer}
|
|
||||||
|
impl<I, F> Clone for FormatWith<'_, I, F>
|
||||||
|
where
|
||||||
|
(I, F): Clone,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
struct PutBackOnDrop<'r, 'a, I, F> {
|
||||||
|
into: &'r FormatWith<'a, I, F>,
|
||||||
|
inner: Option<(I, F)>,
|
||||||
|
}
|
||||||
|
// This ensures we preserve the state of the original `FormatWith` if `Clone` panics
|
||||||
|
impl<I, F> Drop for PutBackOnDrop<'_, '_, I, F> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.into.inner.set(self.inner.take())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let pbod = PutBackOnDrop {
|
||||||
|
inner: self.inner.take(),
|
||||||
|
into: self,
|
||||||
|
};
|
||||||
|
Self {
|
||||||
|
inner: Cell::new(pbod.inner.clone()),
|
||||||
|
sep: self.sep,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> Clone for Format<'_, I>
|
||||||
|
where
|
||||||
|
I: Clone,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
struct PutBackOnDrop<'r, 'a, I> {
|
||||||
|
into: &'r Format<'a, I>,
|
||||||
|
inner: Option<I>,
|
||||||
|
}
|
||||||
|
// This ensures we preserve the state of the original `FormatWith` if `Clone` panics
|
||||||
|
impl<I> Drop for PutBackOnDrop<'_, '_, I> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.into.inner.set(self.inner.take())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let pbod = PutBackOnDrop {
|
||||||
|
inner: self.inner.take(),
|
||||||
|
into: self,
|
||||||
|
};
|
||||||
|
Self {
|
||||||
|
inner: Cell::new(pbod.inner.clone()),
|
||||||
|
sep: self.sep,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
137
third_party/rust/itertools/src/free.rs
vendored
137
third_party/rust/itertools/src/free.rs
vendored
@@ -10,30 +10,24 @@ use std::iter::{self, Zip};
|
|||||||
type VecIntoIter<T> = alloc::vec::IntoIter<T>;
|
type VecIntoIter<T> = alloc::vec::IntoIter<T>;
|
||||||
|
|
||||||
#[cfg(feature = "use_alloc")]
|
#[cfg(feature = "use_alloc")]
|
||||||
use alloc::{
|
use alloc::string::String;
|
||||||
string::String,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::Itertools;
|
|
||||||
use crate::intersperse::{Intersperse, IntersperseWith};
|
use crate::intersperse::{Intersperse, IntersperseWith};
|
||||||
|
use crate::Itertools;
|
||||||
|
|
||||||
pub use crate::adaptors::{
|
pub use crate::adaptors::{interleave, put_back};
|
||||||
interleave,
|
|
||||||
merge,
|
|
||||||
put_back,
|
|
||||||
};
|
|
||||||
#[cfg(feature = "use_alloc")]
|
#[cfg(feature = "use_alloc")]
|
||||||
pub use crate::put_back_n_impl::put_back_n;
|
pub use crate::kmerge_impl::kmerge;
|
||||||
|
pub use crate::merge_join::{merge, merge_join_by};
|
||||||
#[cfg(feature = "use_alloc")]
|
#[cfg(feature = "use_alloc")]
|
||||||
pub use crate::multipeek_impl::multipeek;
|
pub use crate::multipeek_impl::multipeek;
|
||||||
#[cfg(feature = "use_alloc")]
|
#[cfg(feature = "use_alloc")]
|
||||||
pub use crate::peek_nth::peek_nth;
|
pub use crate::peek_nth::peek_nth;
|
||||||
#[cfg(feature = "use_alloc")]
|
#[cfg(feature = "use_alloc")]
|
||||||
pub use crate::kmerge_impl::kmerge;
|
pub use crate::put_back_n_impl::put_back_n;
|
||||||
pub use crate::zip_eq_impl::zip_eq;
|
|
||||||
pub use crate::merge_join::merge_join_by;
|
|
||||||
#[cfg(feature = "use_alloc")]
|
#[cfg(feature = "use_alloc")]
|
||||||
pub use crate::rciter_impl::rciter;
|
pub use crate::rciter_impl::rciter;
|
||||||
|
pub use crate::zip_eq_impl::zip_eq;
|
||||||
|
|
||||||
/// Iterate `iterable` with a particular value inserted between each element.
|
/// Iterate `iterable` with a particular value inserted between each element.
|
||||||
///
|
///
|
||||||
@@ -42,11 +36,12 @@ pub use crate::rciter_impl::rciter;
|
|||||||
/// ```
|
/// ```
|
||||||
/// use itertools::intersperse;
|
/// use itertools::intersperse;
|
||||||
///
|
///
|
||||||
/// itertools::assert_equal(intersperse((0..3), 8), vec![0, 8, 1, 8, 2]);
|
/// itertools::assert_equal(intersperse(0..3, 8), vec![0, 8, 1, 8, 2]);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn intersperse<I>(iterable: I, element: I::Item) -> Intersperse<I::IntoIter>
|
pub fn intersperse<I>(iterable: I, element: I::Item) -> Intersperse<I::IntoIter>
|
||||||
where I: IntoIterator,
|
where
|
||||||
<I as IntoIterator>::Item: Clone
|
I: IntoIterator,
|
||||||
|
<I as IntoIterator>::Item: Clone,
|
||||||
{
|
{
|
||||||
Itertools::intersperse(iterable.into_iter(), element)
|
Itertools::intersperse(iterable.into_iter(), element)
|
||||||
}
|
}
|
||||||
@@ -60,12 +55,13 @@ pub fn intersperse<I>(iterable: I, element: I::Item) -> Intersperse<I::IntoIter>
|
|||||||
/// use itertools::intersperse_with;
|
/// use itertools::intersperse_with;
|
||||||
///
|
///
|
||||||
/// let mut i = 10;
|
/// let mut i = 10;
|
||||||
/// itertools::assert_equal(intersperse_with((0..3), || { i -= 1; i }), vec![0, 9, 1, 8, 2]);
|
/// itertools::assert_equal(intersperse_with(0..3, || { i -= 1; i }), vec![0, 9, 1, 8, 2]);
|
||||||
/// assert_eq!(i, 8);
|
/// assert_eq!(i, 8);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn intersperse_with<I, F>(iterable: I, element: F) -> IntersperseWith<I::IntoIter, F>
|
pub fn intersperse_with<I, F>(iterable: I, element: F) -> IntersperseWith<I::IntoIter, F>
|
||||||
where I: IntoIterator,
|
where
|
||||||
F: FnMut() -> I::Item
|
I: IntoIterator,
|
||||||
|
F: FnMut() -> I::Item,
|
||||||
{
|
{
|
||||||
Itertools::intersperse_with(iterable.into_iter(), element)
|
Itertools::intersperse_with(iterable.into_iter(), element)
|
||||||
}
|
}
|
||||||
@@ -79,10 +75,12 @@ pub fn intersperse_with<I, F>(iterable: I, element: F) -> IntersperseWith<I::Int
|
|||||||
///
|
///
|
||||||
/// for (i, elt) in enumerate(&[1, 2, 3]) {
|
/// for (i, elt) in enumerate(&[1, 2, 3]) {
|
||||||
/// /* loop body */
|
/// /* loop body */
|
||||||
|
/// # let _ = (i, elt);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn enumerate<I>(iterable: I) -> iter::Enumerate<I::IntoIter>
|
pub fn enumerate<I>(iterable: I) -> iter::Enumerate<I::IntoIter>
|
||||||
where I: IntoIterator
|
where
|
||||||
|
I: IntoIterator,
|
||||||
{
|
{
|
||||||
iterable.into_iter().enumerate()
|
iterable.into_iter().enumerate()
|
||||||
}
|
}
|
||||||
@@ -96,11 +94,13 @@ pub fn enumerate<I>(iterable: I) -> iter::Enumerate<I::IntoIter>
|
|||||||
///
|
///
|
||||||
/// for elt in rev(&[1, 2, 3]) {
|
/// for elt in rev(&[1, 2, 3]) {
|
||||||
/// /* loop body */
|
/// /* loop body */
|
||||||
|
/// # let _ = elt;
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn rev<I>(iterable: I) -> iter::Rev<I::IntoIter>
|
pub fn rev<I>(iterable: I) -> iter::Rev<I::IntoIter>
|
||||||
where I: IntoIterator,
|
where
|
||||||
I::IntoIter: DoubleEndedIterator
|
I: IntoIterator,
|
||||||
|
I::IntoIter: DoubleEndedIterator,
|
||||||
{
|
{
|
||||||
iterable.into_iter().rev()
|
iterable.into_iter().rev()
|
||||||
}
|
}
|
||||||
@@ -108,7 +108,7 @@ pub fn rev<I>(iterable: I) -> iter::Rev<I::IntoIter>
|
|||||||
/// Converts the arguments to iterators and zips them.
|
/// Converts the arguments to iterators and zips them.
|
||||||
///
|
///
|
||||||
/// [`IntoIterator`] enabled version of [`Iterator::zip`].
|
/// [`IntoIterator`] enabled version of [`Iterator::zip`].
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@@ -121,23 +121,26 @@ pub fn rev<I>(iterable: I) -> iter::Rev<I::IntoIter>
|
|||||||
/// }
|
/// }
|
||||||
/// 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", since="0.10.4")]
|
#[deprecated(
|
||||||
|
note = "Use [std::iter::zip](https://doc.rust-lang.org/std/iter/fn.zip.html) instead",
|
||||||
|
since = "0.10.4"
|
||||||
|
)]
|
||||||
pub fn zip<I, J>(i: I, j: J) -> Zip<I::IntoIter, J::IntoIter>
|
pub fn zip<I, J>(i: I, j: J) -> Zip<I::IntoIter, J::IntoIter>
|
||||||
where I: IntoIterator,
|
where
|
||||||
J: IntoIterator
|
I: IntoIterator,
|
||||||
|
J: IntoIterator,
|
||||||
{
|
{
|
||||||
i.into_iter().zip(j)
|
i.into_iter().zip(j)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Takes two iterables and creates a new iterator over both in sequence.
|
||||||
/// Takes two iterables and creates a new iterator over both in sequence.
|
|
||||||
///
|
///
|
||||||
/// [`IntoIterator`] enabled version of [`Iterator::chain`].
|
/// [`IntoIterator`] enabled version of [`Iterator::chain`].
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```
|
/// ```
|
||||||
/// use itertools::chain;
|
/// 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]) {
|
/// for element in chain(&[1, 2, 3], &[4]) {
|
||||||
@@ -145,14 +148,18 @@ pub fn zip<I, J>(i: I, j: J) -> Zip<I::IntoIter, J::IntoIter>
|
|||||||
/// }
|
/// }
|
||||||
/// assert_eq!(result, vec![1, 2, 3, 4]);
|
/// assert_eq!(result, vec![1, 2, 3, 4]);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn chain<I, J>(i: I, j: J) -> iter::Chain<<I as IntoIterator>::IntoIter, <J as IntoIterator>::IntoIter>
|
pub fn chain<I, J>(
|
||||||
where I: IntoIterator,
|
i: I,
|
||||||
J: IntoIterator<Item = I::Item>
|
j: J,
|
||||||
|
) -> iter::Chain<<I as IntoIterator>::IntoIter, <J as IntoIterator>::IntoIter>
|
||||||
|
where
|
||||||
|
I: IntoIterator,
|
||||||
|
J: IntoIterator<Item = I::Item>,
|
||||||
{
|
{
|
||||||
i.into_iter().chain(j)
|
i.into_iter().chain(j)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an iterator that clones each element from &T to T
|
/// Create an iterator that clones each element from `&T` to `T`.
|
||||||
///
|
///
|
||||||
/// [`IntoIterator`] enabled version of [`Iterator::cloned`].
|
/// [`IntoIterator`] enabled version of [`Iterator::cloned`].
|
||||||
///
|
///
|
||||||
@@ -161,9 +168,10 @@ pub fn chain<I, J>(i: I, j: J) -> iter::Chain<<I as IntoIterator>::IntoIter, <J
|
|||||||
///
|
///
|
||||||
/// assert_eq!(cloned(b"abc").next(), Some(b'a'));
|
/// assert_eq!(cloned(b"abc").next(), Some(b'a'));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn cloned<'a, I, T: 'a>(iterable: I) -> iter::Cloned<I::IntoIter>
|
pub fn cloned<'a, I, T>(iterable: I) -> iter::Cloned<I::IntoIter>
|
||||||
where I: IntoIterator<Item=&'a T>,
|
where
|
||||||
T: Clone,
|
I: IntoIterator<Item = &'a T>,
|
||||||
|
T: Clone + 'a,
|
||||||
{
|
{
|
||||||
iterable.into_iter().cloned()
|
iterable.into_iter().cloned()
|
||||||
}
|
}
|
||||||
@@ -178,8 +186,9 @@ pub fn cloned<'a, I, T: 'a>(iterable: I) -> iter::Cloned<I::IntoIter>
|
|||||||
/// assert_eq!(fold(&[1., 2., 3.], 0., |a, &b| f32::max(a, b)), 3.);
|
/// assert_eq!(fold(&[1., 2., 3.], 0., |a, &b| f32::max(a, b)), 3.);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn fold<I, B, F>(iterable: I, init: B, f: F) -> B
|
pub fn fold<I, B, F>(iterable: I, init: B, f: F) -> B
|
||||||
where I: IntoIterator,
|
where
|
||||||
F: FnMut(B, I::Item) -> B
|
I: IntoIterator,
|
||||||
|
F: FnMut(B, I::Item) -> B,
|
||||||
{
|
{
|
||||||
iterable.into_iter().fold(init, f)
|
iterable.into_iter().fold(init, f)
|
||||||
}
|
}
|
||||||
@@ -194,8 +203,9 @@ pub fn fold<I, B, F>(iterable: I, init: B, f: F) -> B
|
|||||||
/// assert!(all(&[1, 2, 3], |elt| *elt > 0));
|
/// assert!(all(&[1, 2, 3], |elt| *elt > 0));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn all<I, F>(iterable: I, f: F) -> bool
|
pub fn all<I, F>(iterable: I, f: F) -> bool
|
||||||
where I: IntoIterator,
|
where
|
||||||
F: FnMut(I::Item) -> bool
|
I: IntoIterator,
|
||||||
|
F: FnMut(I::Item) -> bool,
|
||||||
{
|
{
|
||||||
iterable.into_iter().all(f)
|
iterable.into_iter().all(f)
|
||||||
}
|
}
|
||||||
@@ -210,8 +220,9 @@ pub fn all<I, F>(iterable: I, f: F) -> bool
|
|||||||
/// assert!(any(&[0, -1, 2], |elt| *elt > 0));
|
/// assert!(any(&[0, -1, 2], |elt| *elt > 0));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn any<I, F>(iterable: I, f: F) -> bool
|
pub fn any<I, F>(iterable: I, f: F) -> bool
|
||||||
where I: IntoIterator,
|
where
|
||||||
F: FnMut(I::Item) -> bool
|
I: IntoIterator,
|
||||||
|
F: FnMut(I::Item) -> bool,
|
||||||
{
|
{
|
||||||
iterable.into_iter().any(f)
|
iterable.into_iter().any(f)
|
||||||
}
|
}
|
||||||
@@ -226,8 +237,9 @@ pub fn any<I, F>(iterable: I, f: F) -> bool
|
|||||||
/// assert_eq!(max(0..10), Some(9));
|
/// assert_eq!(max(0..10), Some(9));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn max<I>(iterable: I) -> Option<I::Item>
|
pub fn max<I>(iterable: I) -> Option<I::Item>
|
||||||
where I: IntoIterator,
|
where
|
||||||
I::Item: Ord
|
I: IntoIterator,
|
||||||
|
I::Item: Ord,
|
||||||
{
|
{
|
||||||
iterable.into_iter().max()
|
iterable.into_iter().max()
|
||||||
}
|
}
|
||||||
@@ -242,14 +254,14 @@ pub fn max<I>(iterable: I) -> Option<I::Item>
|
|||||||
/// assert_eq!(min(0..10), Some(0));
|
/// assert_eq!(min(0..10), Some(0));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn min<I>(iterable: I) -> Option<I::Item>
|
pub fn min<I>(iterable: I) -> Option<I::Item>
|
||||||
where I: IntoIterator,
|
where
|
||||||
I::Item: Ord
|
I: IntoIterator,
|
||||||
|
I::Item: Ord,
|
||||||
{
|
{
|
||||||
iterable.into_iter().min()
|
iterable.into_iter().min()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Combine all iterator elements into one `String`, separated by `sep`.
|
||||||
/// Combine all iterator elements into one String, separated by `sep`.
|
|
||||||
///
|
///
|
||||||
/// [`IntoIterator`] enabled version of [`Itertools::join`].
|
/// [`IntoIterator`] enabled version of [`Itertools::join`].
|
||||||
///
|
///
|
||||||
@@ -260,8 +272,9 @@ pub fn min<I>(iterable: I) -> Option<I::Item>
|
|||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "use_alloc")]
|
#[cfg(feature = "use_alloc")]
|
||||||
pub fn join<I>(iterable: I, sep: &str) -> String
|
pub fn join<I>(iterable: I, sep: &str) -> String
|
||||||
where I: IntoIterator,
|
where
|
||||||
I::Item: Display
|
I: IntoIterator,
|
||||||
|
I::Item: Display,
|
||||||
{
|
{
|
||||||
iterable.into_iter().join(sep)
|
iterable.into_iter().join(sep)
|
||||||
}
|
}
|
||||||
@@ -278,9 +291,29 @@ pub fn join<I>(iterable: I, sep: &str) -> String
|
|||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "use_alloc")]
|
#[cfg(feature = "use_alloc")]
|
||||||
pub fn sorted<I>(iterable: I) -> VecIntoIter<I::Item>
|
pub fn sorted<I>(iterable: I) -> VecIntoIter<I::Item>
|
||||||
where I: IntoIterator,
|
where
|
||||||
I::Item: Ord
|
I: IntoIterator,
|
||||||
|
I::Item: Ord,
|
||||||
{
|
{
|
||||||
iterable.into_iter().sorted()
|
iterable.into_iter().sorted()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sort all iterator elements into a new iterator in ascending order.
|
||||||
|
/// This sort is unstable (i.e., may reorder equal elements).
|
||||||
|
///
|
||||||
|
/// [`IntoIterator`] enabled version of [`Itertools::sorted_unstable`].
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use itertools::sorted_unstable;
|
||||||
|
/// use itertools::assert_equal;
|
||||||
|
///
|
||||||
|
/// assert_equal(sorted_unstable("rust".chars()), "rstu".chars());
|
||||||
|
/// ```
|
||||||
|
#[cfg(feature = "use_alloc")]
|
||||||
|
pub fn sorted_unstable<I>(iterable: I) -> VecIntoIter<I::Item>
|
||||||
|
where
|
||||||
|
I: IntoIterator,
|
||||||
|
I::Item: Ord,
|
||||||
|
{
|
||||||
|
iterable.into_iter().sorted_unstable()
|
||||||
|
}
|
||||||
|
|||||||
18
third_party/rust/itertools/src/group_map.rs
vendored
18
third_party/rust/itertools/src/group_map.rs
vendored
@@ -9,8 +9,9 @@ use std::iter::Iterator;
|
|||||||
/// See [`.into_group_map()`](crate::Itertools::into_group_map)
|
/// See [`.into_group_map()`](crate::Itertools::into_group_map)
|
||||||
/// for more information.
|
/// for more information.
|
||||||
pub fn into_group_map<I, K, V>(iter: I) -> HashMap<K, Vec<V>>
|
pub fn into_group_map<I, K, V>(iter: I) -> HashMap<K, Vec<V>>
|
||||||
where I: Iterator<Item=(K, V)>,
|
where
|
||||||
K: Hash + Eq,
|
I: Iterator<Item = (K, V)>,
|
||||||
|
K: Hash + Eq,
|
||||||
{
|
{
|
||||||
let mut lookup = HashMap::new();
|
let mut lookup = HashMap::new();
|
||||||
|
|
||||||
@@ -21,12 +22,11 @@ pub fn into_group_map<I, K, V>(iter: I) -> HashMap<K, Vec<V>>
|
|||||||
lookup
|
lookup
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_group_map_by<I, K, V>(iter: I, f: impl Fn(&V) -> K) -> HashMap<K, Vec<V>>
|
pub fn into_group_map_by<I, K, V, F>(iter: I, mut f: F) -> HashMap<K, Vec<V>>
|
||||||
where
|
where
|
||||||
I: Iterator<Item=V>,
|
I: Iterator<Item = V>,
|
||||||
K: Hash + Eq,
|
K: Hash + Eq,
|
||||||
|
F: FnMut(&V) -> K,
|
||||||
{
|
{
|
||||||
into_group_map(
|
into_group_map(iter.map(|v| (f(&v), v)))
|
||||||
iter.map(|v| (f(&v), v))
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
252
third_party/rust/itertools/src/groupbylazy.rs
vendored
252
third_party/rust/itertools/src/groupbylazy.rs
vendored
@@ -1,14 +1,15 @@
|
|||||||
use std::cell::{Cell, RefCell};
|
|
||||||
use alloc::vec::{self, Vec};
|
use alloc::vec::{self, Vec};
|
||||||
|
use std::cell::{Cell, RefCell};
|
||||||
|
|
||||||
/// A trait to unify `FnMut` for `GroupBy` with the chunk key in `IntoChunks`
|
/// A trait to unify `FnMut` for `ChunkBy` with the chunk key in `IntoChunks`
|
||||||
trait KeyFunction<A> {
|
trait KeyFunction<A> {
|
||||||
type Key;
|
type Key;
|
||||||
fn call_mut(&mut self, arg: A) -> Self::Key;
|
fn call_mut(&mut self, arg: A) -> Self::Key;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, K, F: ?Sized> KeyFunction<A> for F
|
impl<A, K, F> KeyFunction<A> for F
|
||||||
where F: FnMut(A) -> K
|
where
|
||||||
|
F: FnMut(A) -> K + ?Sized,
|
||||||
{
|
{
|
||||||
type Key = K;
|
type Key = K;
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -17,9 +18,8 @@ impl<A, K, F: ?Sized> KeyFunction<A> for F
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// `ChunkIndex` acts like the grouping key function for `IntoChunks`
|
/// `ChunkIndex` acts like the grouping key function for `IntoChunks`
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
struct ChunkIndex {
|
struct ChunkIndex {
|
||||||
size: usize,
|
size: usize,
|
||||||
index: usize,
|
index: usize,
|
||||||
@@ -29,7 +29,7 @@ struct ChunkIndex {
|
|||||||
impl ChunkIndex {
|
impl ChunkIndex {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn new(size: usize) -> Self {
|
fn new(size: usize) -> Self {
|
||||||
ChunkIndex {
|
Self {
|
||||||
size,
|
size,
|
||||||
index: 0,
|
index: 0,
|
||||||
key: 0,
|
key: 0,
|
||||||
@@ -50,9 +50,10 @@ impl<A> KeyFunction<A> for ChunkIndex {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
struct GroupInner<K, I, F>
|
struct GroupInner<K, I, F>
|
||||||
where I: Iterator
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
key: F,
|
key: F,
|
||||||
iter: I,
|
iter: I,
|
||||||
@@ -65,19 +66,21 @@ struct GroupInner<K, I, F>
|
|||||||
/// Least index for which we still have elements buffered
|
/// Least index for which we still have elements buffered
|
||||||
oldest_buffered_group: usize,
|
oldest_buffered_group: usize,
|
||||||
/// Group index for `buffer[0]` -- the slots
|
/// Group index for `buffer[0]` -- the slots
|
||||||
/// bottom_group..oldest_buffered_group are unused and will be erased when
|
/// `bottom_group..oldest_buffered_group` are unused and will be erased when
|
||||||
/// that range is large enough.
|
/// that range is large enough.
|
||||||
bottom_group: usize,
|
bottom_group: usize,
|
||||||
/// Buffered groups, from `bottom_group` (index 0) to `top_group`.
|
/// Buffered groups, from `bottom_group` (index 0) to `top_group`.
|
||||||
buffer: Vec<vec::IntoIter<I::Item>>,
|
buffer: Vec<vec::IntoIter<I::Item>>,
|
||||||
/// index of last group iter that was dropped, usize::MAX == none
|
/// index of last group iter that was dropped,
|
||||||
|
/// `usize::MAX` initially when no group was dropped
|
||||||
dropped_group: usize,
|
dropped_group: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K, I, F> GroupInner<K, I, F>
|
impl<K, I, F> GroupInner<K, I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
F: for<'a> KeyFunction<&'a I::Item, Key=K>,
|
I: Iterator,
|
||||||
K: PartialEq,
|
F: for<'a> KeyFunction<&'a I::Item, Key = K>,
|
||||||
|
K: PartialEq,
|
||||||
{
|
{
|
||||||
/// `client`: Index of group that requests next element
|
/// `client`: Index of group that requests next element
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@@ -90,9 +93,8 @@ impl<K, I, F> GroupInner<K, I, F>
|
|||||||
*/
|
*/
|
||||||
if client < self.oldest_buffered_group {
|
if client < self.oldest_buffered_group {
|
||||||
None
|
None
|
||||||
} else if client < self.top_group ||
|
} else if client < self.top_group
|
||||||
(client == self.top_group &&
|
|| (client == self.top_group && self.buffer.len() > self.top_group - self.bottom_group)
|
||||||
self.buffer.len() > self.top_group - self.bottom_group)
|
|
||||||
{
|
{
|
||||||
self.lookup_buffer(client)
|
self.lookup_buffer(client)
|
||||||
} else if self.done {
|
} else if self.done {
|
||||||
@@ -118,8 +120,10 @@ impl<K, I, F> GroupInner<K, I, F>
|
|||||||
// `bottom_group..oldest_buffered_group` is unused, and if it's large enough, erase it.
|
// `bottom_group..oldest_buffered_group` is unused, and if it's large enough, erase it.
|
||||||
self.oldest_buffered_group += 1;
|
self.oldest_buffered_group += 1;
|
||||||
// skip forward further empty queues too
|
// skip forward further empty queues too
|
||||||
while self.buffer.get(self.oldest_buffered_group - self.bottom_group)
|
while self
|
||||||
.map_or(false, |buf| buf.len() == 0)
|
.buffer
|
||||||
|
.get(self.oldest_buffered_group - self.bottom_group)
|
||||||
|
.map_or(false, |buf| buf.len() == 0)
|
||||||
{
|
{
|
||||||
self.oldest_buffered_group += 1;
|
self.oldest_buffered_group += 1;
|
||||||
}
|
}
|
||||||
@@ -144,12 +148,14 @@ impl<K, I, F> GroupInner<K, I, F>
|
|||||||
fn next_element(&mut self) -> Option<I::Item> {
|
fn next_element(&mut self) -> Option<I::Item> {
|
||||||
debug_assert!(!self.done);
|
debug_assert!(!self.done);
|
||||||
match self.iter.next() {
|
match self.iter.next() {
|
||||||
None => { self.done = true; None }
|
None => {
|
||||||
|
self.done = true;
|
||||||
|
None
|
||||||
|
}
|
||||||
otherwise => otherwise,
|
otherwise => otherwise,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn step_buffering(&mut self, client: usize) -> Option<I::Item> {
|
fn step_buffering(&mut self, client: usize) -> Option<I::Item> {
|
||||||
// requested a later group -- walk through the current group up to
|
// requested a later group -- walk through the current group up to
|
||||||
@@ -171,11 +177,13 @@ impl<K, I, F> GroupInner<K, I, F>
|
|||||||
let key = self.key.call_mut(&elt);
|
let key = self.key.call_mut(&elt);
|
||||||
match self.current_key.take() {
|
match self.current_key.take() {
|
||||||
None => {}
|
None => {}
|
||||||
Some(old_key) => if old_key != key {
|
Some(old_key) => {
|
||||||
self.current_key = Some(key);
|
if old_key != key {
|
||||||
first_elt = Some(elt);
|
self.current_key = Some(key);
|
||||||
break;
|
first_elt = Some(elt);
|
||||||
},
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.current_key = Some(key);
|
self.current_key = Some(key);
|
||||||
if self.top_group != self.dropped_group {
|
if self.top_group != self.dropped_group {
|
||||||
@@ -220,12 +228,14 @@ impl<K, I, F> GroupInner<K, I, F>
|
|||||||
let key = self.key.call_mut(&elt);
|
let key = self.key.call_mut(&elt);
|
||||||
match self.current_key.take() {
|
match self.current_key.take() {
|
||||||
None => {}
|
None => {}
|
||||||
Some(old_key) => if old_key != key {
|
Some(old_key) => {
|
||||||
self.current_key = Some(key);
|
if old_key != key {
|
||||||
self.current_elt = Some(elt);
|
self.current_key = Some(key);
|
||||||
self.top_group += 1;
|
self.current_elt = Some(elt);
|
||||||
return None;
|
self.top_group += 1;
|
||||||
},
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.current_key = Some(key);
|
self.current_key = Some(key);
|
||||||
Some(elt)
|
Some(elt)
|
||||||
@@ -261,7 +271,8 @@ impl<K, I, F> GroupInner<K, I, F>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<K, I, F> GroupInner<K, I, F>
|
impl<K, I, F> GroupInner<K, I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
/// Called when a group is dropped
|
/// Called when a group is dropped
|
||||||
fn drop_group(&mut self, client: usize) {
|
fn drop_group(&mut self, client: usize) {
|
||||||
@@ -272,10 +283,14 @@ impl<K, I, F> GroupInner<K, I, F>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `GroupBy` is the storage for the lazy grouping operation.
|
#[deprecated(note = "Use `ChunkBy` instead", since = "0.13.0")]
|
||||||
|
/// See [`ChunkBy`](crate::structs::ChunkBy).
|
||||||
|
pub type GroupBy<K, I, F> = ChunkBy<K, I, F>;
|
||||||
|
|
||||||
|
/// `ChunkBy` is the storage for the lazy grouping operation.
|
||||||
///
|
///
|
||||||
/// If the groups are consumed in their original order, or if each
|
/// If the groups are consumed in their original order, or if each
|
||||||
/// group is dropped without keeping it around, then `GroupBy` uses
|
/// group is dropped without keeping it around, then `ChunkBy` uses
|
||||||
/// no allocations. It needs allocations only if several group iterators
|
/// no allocations. It needs allocations only if several group iterators
|
||||||
/// are alive at the same time.
|
/// are alive at the same time.
|
||||||
///
|
///
|
||||||
@@ -284,10 +299,11 @@ impl<K, I, F> GroupInner<K, I, F>
|
|||||||
/// value. It should be stored in a local variable or temporary and
|
/// value. It should be stored in a local variable or temporary and
|
||||||
/// iterated.
|
/// iterated.
|
||||||
///
|
///
|
||||||
/// See [`.group_by()`](crate::Itertools::group_by) for more information.
|
/// See [`.chunk_by()`](crate::Itertools::chunk_by) for more information.
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct GroupBy<K, I, F>
|
pub struct ChunkBy<K, I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
inner: RefCell<GroupInner<K, I, F>>,
|
inner: RefCell<GroupInner<K, I, F>>,
|
||||||
// the group iterator's current index. Keep this in the main value
|
// the group iterator's current index. Keep this in the main value
|
||||||
@@ -296,11 +312,12 @@ pub struct GroupBy<K, I, F>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new
|
/// Create a new
|
||||||
pub fn new<K, J, F>(iter: J, f: F) -> GroupBy<K, J::IntoIter, F>
|
pub fn new<K, J, F>(iter: J, f: F) -> ChunkBy<K, J::IntoIter, F>
|
||||||
where J: IntoIterator,
|
where
|
||||||
F: FnMut(&J::Item) -> K,
|
J: IntoIterator,
|
||||||
|
F: FnMut(&J::Item) -> K,
|
||||||
{
|
{
|
||||||
GroupBy {
|
ChunkBy {
|
||||||
inner: RefCell::new(GroupInner {
|
inner: RefCell::new(GroupInner {
|
||||||
key: f,
|
key: f,
|
||||||
iter: iter.into_iter(),
|
iter: iter.into_iter(),
|
||||||
@@ -317,13 +334,15 @@ pub fn new<K, J, F>(iter: J, f: F) -> GroupBy<K, J::IntoIter, F>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K, I, F> GroupBy<K, I, F>
|
impl<K, I, F> ChunkBy<K, I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
/// `client`: Index of group that requests next element
|
/// `client`: Index of group that requests next element
|
||||||
fn step(&self, client: usize) -> Option<I::Item>
|
fn step(&self, client: usize) -> Option<I::Item>
|
||||||
where F: FnMut(&I::Item) -> K,
|
where
|
||||||
K: PartialEq,
|
F: FnMut(&I::Item) -> K,
|
||||||
|
K: PartialEq,
|
||||||
{
|
{
|
||||||
self.inner.borrow_mut().step(client)
|
self.inner.borrow_mut().step(client)
|
||||||
}
|
}
|
||||||
@@ -334,11 +353,12 @@ impl<K, I, F> GroupBy<K, I, F>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, K, I, F> IntoIterator for &'a GroupBy<K, I, F>
|
impl<'a, K, I, F> IntoIterator for &'a ChunkBy<K, I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
I::Item: 'a,
|
I: Iterator,
|
||||||
F: FnMut(&I::Item) -> K,
|
I::Item: 'a,
|
||||||
K: PartialEq
|
F: FnMut(&I::Item) -> K,
|
||||||
|
K: PartialEq,
|
||||||
{
|
{
|
||||||
type Item = (K, Group<'a, K, I, F>);
|
type Item = (K, Group<'a, K, I, F>);
|
||||||
type IntoIter = Groups<'a, K, I, F>;
|
type IntoIter = Groups<'a, K, I, F>;
|
||||||
@@ -348,26 +368,29 @@ impl<'a, K, I, F> IntoIterator for &'a GroupBy<K, I, F>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// An iterator that yields the Group iterators.
|
/// An iterator that yields the Group iterators.
|
||||||
///
|
///
|
||||||
/// Iterator element type is `(K, Group)`:
|
/// Iterator element type is `(K, Group)`:
|
||||||
/// the group's key `K` and the group's iterator.
|
/// the group's key `K` and the group's iterator.
|
||||||
///
|
///
|
||||||
/// See [`.group_by()`](crate::Itertools::group_by) for more information.
|
/// See [`.chunk_by()`](crate::Itertools::chunk_by) for more information.
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct Groups<'a, K: 'a, I: 'a, F: 'a>
|
pub struct Groups<'a, K, I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
I::Item: 'a
|
I: Iterator + 'a,
|
||||||
|
I::Item: 'a,
|
||||||
|
K: 'a,
|
||||||
|
F: 'a,
|
||||||
{
|
{
|
||||||
parent: &'a GroupBy<K, I, F>,
|
parent: &'a ChunkBy<K, I, F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, K, I, F> Iterator for Groups<'a, K, I, F>
|
impl<'a, K, I, F> Iterator for Groups<'a, K, I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
I::Item: 'a,
|
I: Iterator,
|
||||||
F: FnMut(&I::Item) -> K,
|
I::Item: 'a,
|
||||||
K: PartialEq
|
F: FnMut(&I::Item) -> K,
|
||||||
|
K: PartialEq,
|
||||||
{
|
{
|
||||||
type Item = (K, Group<'a, K, I, F>);
|
type Item = (K, Group<'a, K, I, F>);
|
||||||
|
|
||||||
@@ -378,11 +401,14 @@ impl<'a, K, I, F> Iterator for Groups<'a, K, I, F>
|
|||||||
let inner = &mut *self.parent.inner.borrow_mut();
|
let inner = &mut *self.parent.inner.borrow_mut();
|
||||||
inner.step(index).map(|elt| {
|
inner.step(index).map(|elt| {
|
||||||
let key = inner.group_key(index);
|
let key = inner.group_key(index);
|
||||||
(key, Group {
|
(
|
||||||
parent: self.parent,
|
key,
|
||||||
index,
|
Group {
|
||||||
first: Some(elt),
|
parent: self.parent,
|
||||||
})
|
index,
|
||||||
|
first: Some(elt),
|
||||||
|
},
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -390,18 +416,22 @@ impl<'a, K, I, F> Iterator for Groups<'a, K, I, F>
|
|||||||
/// An iterator for the elements in a single group.
|
/// An iterator for the elements in a single group.
|
||||||
///
|
///
|
||||||
/// Iterator element type is `I::Item`.
|
/// Iterator element type is `I::Item`.
|
||||||
pub struct Group<'a, K: 'a, I: 'a, F: 'a>
|
pub struct Group<'a, K, I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
I::Item: 'a,
|
I: Iterator + 'a,
|
||||||
|
I::Item: 'a,
|
||||||
|
K: 'a,
|
||||||
|
F: 'a,
|
||||||
{
|
{
|
||||||
parent: &'a GroupBy<K, I, F>,
|
parent: &'a ChunkBy<K, I, F>,
|
||||||
index: usize,
|
index: usize,
|
||||||
first: Option<I::Item>,
|
first: Option<I::Item>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, K, I, F> Drop for Group<'a, K, I, F>
|
impl<'a, K, I, F> Drop for Group<'a, K, I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
I::Item: 'a,
|
I: Iterator,
|
||||||
|
I::Item: 'a,
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.parent.drop_group(self.index);
|
self.parent.drop_group(self.index);
|
||||||
@@ -409,10 +439,11 @@ impl<'a, K, I, F> Drop for Group<'a, K, I, F>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, K, I, F> Iterator for Group<'a, K, I, F>
|
impl<'a, K, I, F> Iterator for Group<'a, K, I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
I::Item: 'a,
|
I: Iterator,
|
||||||
F: FnMut(&I::Item) -> K,
|
I::Item: 'a,
|
||||||
K: PartialEq,
|
F: FnMut(&I::Item) -> K,
|
||||||
|
K: PartialEq,
|
||||||
{
|
{
|
||||||
type Item = I::Item;
|
type Item = I::Item;
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -428,7 +459,8 @@ impl<'a, K, I, F> Iterator for Group<'a, K, I, F>
|
|||||||
|
|
||||||
/// Create a new
|
/// Create a new
|
||||||
pub fn new_chunks<J>(iter: J, size: usize) -> IntoChunks<J::IntoIter>
|
pub fn new_chunks<J>(iter: J, size: usize) -> IntoChunks<J::IntoIter>
|
||||||
where J: IntoIterator,
|
where
|
||||||
|
J: IntoIterator,
|
||||||
{
|
{
|
||||||
IntoChunks {
|
IntoChunks {
|
||||||
inner: RefCell::new(GroupInner {
|
inner: RefCell::new(GroupInner {
|
||||||
@@ -447,10 +479,9 @@ pub fn new_chunks<J>(iter: J, size: usize) -> IntoChunks<J::IntoIter>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// `ChunkLazy` is the storage for a lazy chunking operation.
|
/// `ChunkLazy` is the storage for a lazy chunking operation.
|
||||||
///
|
///
|
||||||
/// `IntoChunks` behaves just like `GroupBy`: it is iterable, and
|
/// `IntoChunks` behaves just like `ChunkBy`: it is iterable, and
|
||||||
/// it only buffers if several chunk iterators are alive at the same time.
|
/// it only buffers if several chunk iterators are alive at the same time.
|
||||||
///
|
///
|
||||||
/// This type implements [`IntoIterator`] (it is **not** an iterator
|
/// This type implements [`IntoIterator`] (it is **not** an iterator
|
||||||
@@ -463,7 +494,8 @@ pub fn new_chunks<J>(iter: J, size: usize) -> IntoChunks<J::IntoIter>
|
|||||||
/// See [`.chunks()`](crate::Itertools::chunks) for more information.
|
/// See [`.chunks()`](crate::Itertools::chunks) for more information.
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct IntoChunks<I>
|
pub struct IntoChunks<I>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
inner: RefCell<GroupInner<usize, I, ChunkIndex>>,
|
inner: RefCell<GroupInner<usize, I, ChunkIndex>>,
|
||||||
// the chunk iterator's current index. Keep this in the main value
|
// the chunk iterator's current index. Keep this in the main value
|
||||||
@@ -471,9 +503,17 @@ pub struct IntoChunks<I>
|
|||||||
index: Cell<usize>,
|
index: Cell<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<I> Clone for IntoChunks<I>
|
||||||
|
where
|
||||||
|
I: Clone + Iterator,
|
||||||
|
I::Item: Clone,
|
||||||
|
{
|
||||||
|
clone_fields!(inner, index);
|
||||||
|
}
|
||||||
|
|
||||||
impl<I> IntoChunks<I>
|
impl<I> IntoChunks<I>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
/// `client`: Index of chunk that requests next element
|
/// `client`: Index of chunk that requests next element
|
||||||
fn step(&self, client: usize) -> Option<I::Item> {
|
fn step(&self, client: usize) -> Option<I::Item> {
|
||||||
@@ -487,36 +527,37 @@ impl<I> IntoChunks<I>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I> IntoIterator for &'a IntoChunks<I>
|
impl<'a, I> IntoIterator for &'a IntoChunks<I>
|
||||||
where I: Iterator,
|
where
|
||||||
I::Item: 'a,
|
I: Iterator,
|
||||||
|
I::Item: 'a,
|
||||||
{
|
{
|
||||||
type Item = Chunk<'a, I>;
|
type Item = Chunk<'a, I>;
|
||||||
type IntoIter = Chunks<'a, I>;
|
type IntoIter = Chunks<'a, I>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
Chunks {
|
Chunks { parent: self }
|
||||||
parent: self,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// An iterator that yields the Chunk iterators.
|
/// An iterator that yields the Chunk iterators.
|
||||||
///
|
///
|
||||||
/// Iterator element type is `Chunk`.
|
/// Iterator element type is `Chunk`.
|
||||||
///
|
///
|
||||||
/// See [`.chunks()`](crate::Itertools::chunks) for more information.
|
/// See [`.chunks()`](crate::Itertools::chunks) for more information.
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct Chunks<'a, I: 'a>
|
#[derive(Clone)]
|
||||||
where I: Iterator,
|
pub struct Chunks<'a, I>
|
||||||
I::Item: 'a,
|
where
|
||||||
|
I: Iterator + 'a,
|
||||||
|
I::Item: 'a,
|
||||||
{
|
{
|
||||||
parent: &'a IntoChunks<I>,
|
parent: &'a IntoChunks<I>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I> Iterator for Chunks<'a, I>
|
impl<'a, I> Iterator for Chunks<'a, I>
|
||||||
where I: Iterator,
|
where
|
||||||
I::Item: 'a,
|
I: Iterator,
|
||||||
|
I::Item: 'a,
|
||||||
{
|
{
|
||||||
type Item = Chunk<'a, I>;
|
type Item = Chunk<'a, I>;
|
||||||
|
|
||||||
@@ -525,12 +566,10 @@ impl<'a, I> Iterator for Chunks<'a, I>
|
|||||||
let index = self.parent.index.get();
|
let index = self.parent.index.get();
|
||||||
self.parent.index.set(index + 1);
|
self.parent.index.set(index + 1);
|
||||||
let inner = &mut *self.parent.inner.borrow_mut();
|
let inner = &mut *self.parent.inner.borrow_mut();
|
||||||
inner.step(index).map(|elt| {
|
inner.step(index).map(|elt| Chunk {
|
||||||
Chunk {
|
parent: self.parent,
|
||||||
parent: self.parent,
|
index,
|
||||||
index,
|
first: Some(elt),
|
||||||
first: Some(elt),
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -538,9 +577,10 @@ impl<'a, I> Iterator for Chunks<'a, I>
|
|||||||
/// An iterator for the elements in a single chunk.
|
/// An iterator for the elements in a single chunk.
|
||||||
///
|
///
|
||||||
/// Iterator element type is `I::Item`.
|
/// Iterator element type is `I::Item`.
|
||||||
pub struct Chunk<'a, I: 'a>
|
pub struct Chunk<'a, I>
|
||||||
where I: Iterator,
|
where
|
||||||
I::Item: 'a,
|
I: Iterator + 'a,
|
||||||
|
I::Item: 'a,
|
||||||
{
|
{
|
||||||
parent: &'a IntoChunks<I>,
|
parent: &'a IntoChunks<I>,
|
||||||
index: usize,
|
index: usize,
|
||||||
@@ -548,8 +588,9 @@ pub struct Chunk<'a, I: 'a>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I> Drop for Chunk<'a, I>
|
impl<'a, I> Drop for Chunk<'a, I>
|
||||||
where I: Iterator,
|
where
|
||||||
I::Item: 'a,
|
I: Iterator,
|
||||||
|
I::Item: 'a,
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.parent.drop_group(self.index);
|
self.parent.drop_group(self.index);
|
||||||
@@ -557,8 +598,9 @@ impl<'a, I> Drop for Chunk<'a, I>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I> Iterator for Chunk<'a, I>
|
impl<'a, I> Iterator for Chunk<'a, I>
|
||||||
where I: Iterator,
|
where
|
||||||
I::Item: 'a,
|
I: Iterator,
|
||||||
|
I::Item: 'a,
|
||||||
{
|
{
|
||||||
type Item = I::Item;
|
type Item = I::Item;
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|||||||
349
third_party/rust/itertools/src/grouping_map.rs
vendored
349
third_party/rust/itertools/src/grouping_map.rs
vendored
@@ -1,50 +1,58 @@
|
|||||||
#![cfg(feature = "use_std")]
|
use crate::{
|
||||||
|
adaptors::map::{MapSpecialCase, MapSpecialCaseFn},
|
||||||
use crate::MinMaxResult;
|
MinMaxResult,
|
||||||
use std::collections::HashMap;
|
};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
use std::ops::{Add, Mul};
|
use std::ops::{Add, Mul};
|
||||||
|
|
||||||
/// A wrapper to allow for an easy [`into_grouping_map_by`](crate::Itertools::into_grouping_map_by)
|
/// A wrapper to allow for an easy [`into_grouping_map_by`](crate::Itertools::into_grouping_map_by)
|
||||||
#[derive(Clone, Debug)]
|
pub type MapForGrouping<I, F> = MapSpecialCase<I, GroupingMapFn<F>>;
|
||||||
pub struct MapForGrouping<I, F>(I, F);
|
|
||||||
|
|
||||||
impl<I, F> MapForGrouping<I, F> {
|
#[derive(Clone)]
|
||||||
pub(crate) fn new(iter: I, key_mapper: F) -> Self {
|
pub struct GroupingMapFn<F>(F);
|
||||||
Self(iter, key_mapper)
|
|
||||||
|
impl<F> std::fmt::Debug for GroupingMapFn<F> {
|
||||||
|
debug_fmt_fields!(GroupingMapFn,);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V, K, F: FnMut(&V) -> K> MapSpecialCaseFn<V> for GroupingMapFn<F> {
|
||||||
|
type Out = (K, V);
|
||||||
|
fn call(&mut self, v: V) -> Self::Out {
|
||||||
|
((self.0)(&v), v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K, V, I, F> Iterator for MapForGrouping<I, F>
|
pub(crate) fn new_map_for_grouping<K, I: Iterator, F: FnMut(&I::Item) -> K>(
|
||||||
where I: Iterator<Item = V>,
|
iter: I,
|
||||||
K: Hash + Eq,
|
key_mapper: F,
|
||||||
F: FnMut(&V) -> K,
|
) -> MapForGrouping<I, F> {
|
||||||
{
|
MapSpecialCase {
|
||||||
type Item = (K, V);
|
iter,
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
f: GroupingMapFn(key_mapper),
|
||||||
self.0.next().map(|val| ((self.1)(&val), val))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new `GroupingMap` from `iter`
|
/// Creates a new `GroupingMap` from `iter`
|
||||||
pub fn new<I, K, V>(iter: I) -> GroupingMap<I>
|
pub fn new<I, K, V>(iter: I) -> GroupingMap<I>
|
||||||
where I: Iterator<Item = (K, V)>,
|
where
|
||||||
K: Hash + Eq,
|
I: Iterator<Item = (K, V)>,
|
||||||
|
K: Hash + Eq,
|
||||||
{
|
{
|
||||||
GroupingMap { iter }
|
GroupingMap { iter }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `GroupingMapBy` is an intermediate struct for efficient group-and-fold operations.
|
/// `GroupingMapBy` is an intermediate struct for efficient group-and-fold operations.
|
||||||
///
|
///
|
||||||
/// See [`GroupingMap`] for more informations.
|
/// See [`GroupingMap`] for more informations.
|
||||||
pub type GroupingMapBy<I, F> = GroupingMap<MapForGrouping<I, F>>;
|
pub type GroupingMapBy<I, F> = GroupingMap<MapForGrouping<I, F>>;
|
||||||
|
|
||||||
/// `GroupingMap` is an intermediate struct for efficient group-and-fold operations.
|
/// `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
|
/// It groups elements by their key and at the same time fold each group
|
||||||
/// using some aggregating operation.
|
/// using some aggregating operation.
|
||||||
///
|
///
|
||||||
/// No method on this struct performs temporary allocations.
|
/// No method on this struct performs temporary allocations.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[must_use = "GroupingMap is lazy and do nothing unless consumed"]
|
#[must_use = "GroupingMap is lazy and do nothing unless consumed"]
|
||||||
@@ -53,13 +61,14 @@ pub struct GroupingMap<I> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I, K, V> GroupingMap<I>
|
impl<I, K, V> GroupingMap<I>
|
||||||
where I: Iterator<Item = (K, V)>,
|
where
|
||||||
K: Hash + Eq,
|
I: Iterator<Item = (K, V)>,
|
||||||
|
K: Hash + Eq,
|
||||||
{
|
{
|
||||||
/// This is the generic way to perform any operation on a `GroupingMap`.
|
/// This is the generic way to perform any operation on a `GroupingMap`.
|
||||||
/// It's suggested to use this method only to implement custom operations
|
/// It's suggested to use this method only to implement custom operations
|
||||||
/// when the already provided ones are not enough.
|
/// when the already provided ones are not enough.
|
||||||
///
|
///
|
||||||
/// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
|
/// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
|
||||||
/// of each group sequentially, passing the previously accumulated value, a reference to the key
|
/// of each group sequentially, passing the previously accumulated value, a reference to the key
|
||||||
/// and the current element as arguments, and stores the results in an `HashMap`.
|
/// and the current element as arguments, and stores the results in an `HashMap`.
|
||||||
@@ -68,17 +77,17 @@ impl<I, K, V> GroupingMap<I>
|
|||||||
/// - the current value of the accumulator of the group if there is currently one;
|
/// - the current value of the accumulator of the group if there is currently one;
|
||||||
/// - a reference to the key of the group this element belongs to;
|
/// - a reference to the key of the group this element belongs to;
|
||||||
/// - the element from the source being aggregated;
|
/// - the element from the source being aggregated;
|
||||||
///
|
///
|
||||||
/// If `operation` returns `Some(element)` then the accumulator is updated with `element`,
|
/// If `operation` returns `Some(element)` then the accumulator is updated with `element`,
|
||||||
/// otherwise the previous accumulation is discarded.
|
/// otherwise the previous accumulation is discarded.
|
||||||
///
|
///
|
||||||
/// Return a `HashMap` associating the key of each group with the result of aggregation of
|
/// Return a `HashMap` associating the key of each group with the result of aggregation of
|
||||||
/// that group's elements. If the aggregation of the last element of a group discards the
|
/// that group's elements. If the aggregation of the last element of a group discards the
|
||||||
/// accumulator then there won't be an entry associated to that group's key.
|
/// accumulator then there won't be an entry associated to that group's key.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use itertools::Itertools;
|
/// use itertools::Itertools;
|
||||||
///
|
///
|
||||||
/// let data = vec![2, 8, 5, 7, 9, 0, 4, 10];
|
/// let data = vec![2, 8, 5, 7, 9, 0, 4, 10];
|
||||||
/// let lookup = data.into_iter()
|
/// let lookup = data.into_iter()
|
||||||
/// .into_grouping_map_by(|&n| n % 4)
|
/// .into_grouping_map_by(|&n| n % 4)
|
||||||
@@ -89,7 +98,7 @@ impl<I, K, V> GroupingMap<I>
|
|||||||
/// Some(acc.unwrap_or(0) + val)
|
/// Some(acc.unwrap_or(0) + val)
|
||||||
/// }
|
/// }
|
||||||
/// });
|
/// });
|
||||||
///
|
///
|
||||||
/// assert_eq!(lookup[&0], 4); // 0 resets the accumulator so only 4 is summed
|
/// assert_eq!(lookup[&0], 4); // 0 resets the accumulator so only 4 is summed
|
||||||
/// assert_eq!(lookup[&1], 5 + 9);
|
/// assert_eq!(lookup[&1], 5 + 9);
|
||||||
/// assert_eq!(lookup.get(&2), None); // 10 resets the accumulator and nothing is summed afterward
|
/// assert_eq!(lookup.get(&2), None); // 10 resets the accumulator and nothing is summed afterward
|
||||||
@@ -97,7 +106,8 @@ impl<I, K, V> GroupingMap<I>
|
|||||||
/// assert_eq!(lookup.len(), 3); // The final keys are only 0, 1 and 2
|
/// 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>
|
||||||
where FO: FnMut(Option<R>, &K, V) -> Option<R>,
|
where
|
||||||
|
FO: FnMut(Option<R>, &K, V) -> Option<R>,
|
||||||
{
|
{
|
||||||
let mut destination_map = HashMap::new();
|
let mut destination_map = HashMap::new();
|
||||||
|
|
||||||
@@ -111,6 +121,50 @@ impl<I, K, V> GroupingMap<I>
|
|||||||
destination_map
|
destination_map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
|
||||||
|
/// of each group sequentially, passing the previously accumulated value, a reference to the key
|
||||||
|
/// and the current element as arguments, and stores the results in a new map.
|
||||||
|
///
|
||||||
|
/// `init` is called to obtain the initial value of each accumulator.
|
||||||
|
///
|
||||||
|
/// `operation` is a function that is invoked on each element with the following parameters:
|
||||||
|
/// - the current value of the accumulator of the group;
|
||||||
|
/// - a reference to the key of the group this element belongs to;
|
||||||
|
/// - the element from the source being accumulated.
|
||||||
|
///
|
||||||
|
/// Return a `HashMap` associating the key of each group with the result of folding that group's elements.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use itertools::Itertools;
|
||||||
|
///
|
||||||
|
/// #[derive(Debug, Default)]
|
||||||
|
/// struct Accumulator {
|
||||||
|
/// acc: usize,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let lookup = (1..=7)
|
||||||
|
/// .into_grouping_map_by(|&n| n % 3)
|
||||||
|
/// .fold_with(|_key, _val| Default::default(), |Accumulator { acc }, _key, val| {
|
||||||
|
/// let acc = acc + val;
|
||||||
|
/// Accumulator { acc }
|
||||||
|
/// });
|
||||||
|
///
|
||||||
|
/// assert_eq!(lookup[&0].acc, 3 + 6);
|
||||||
|
/// assert_eq!(lookup[&1].acc, 1 + 4 + 7);
|
||||||
|
/// 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>
|
||||||
|
where
|
||||||
|
FI: FnMut(&K, &V) -> R,
|
||||||
|
FO: FnMut(R, &K, V) -> R,
|
||||||
|
{
|
||||||
|
self.aggregate(|acc, key, val| {
|
||||||
|
let acc = acc.unwrap_or_else(|| init(key, &val));
|
||||||
|
Some(operation(acc, key, val))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
|
/// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
|
||||||
/// of each group sequentially, passing the previously accumulated value, a reference to the key
|
/// of each group sequentially, passing the previously accumulated value, a reference to the key
|
||||||
/// and the current element as arguments, and stores the results in a new map.
|
/// and the current element as arguments, and stores the results in a new map.
|
||||||
@@ -123,27 +177,25 @@ impl<I, K, V> GroupingMap<I>
|
|||||||
/// - the element from the source being accumulated.
|
/// - the element from the source being accumulated.
|
||||||
///
|
///
|
||||||
/// Return a `HashMap` associating the key of each group with the result of folding that group's elements.
|
/// Return a `HashMap` associating the key of each group with the result of folding that group's elements.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use itertools::Itertools;
|
/// use itertools::Itertools;
|
||||||
///
|
///
|
||||||
/// let lookup = (1..=7)
|
/// let lookup = (1..=7)
|
||||||
/// .into_grouping_map_by(|&n| n % 3)
|
/// .into_grouping_map_by(|&n| n % 3)
|
||||||
/// .fold(0, |acc, _key, val| acc + val);
|
/// .fold(0, |acc, _key, val| acc + val);
|
||||||
///
|
///
|
||||||
/// assert_eq!(lookup[&0], 3 + 6);
|
/// assert_eq!(lookup[&0], 3 + 6);
|
||||||
/// assert_eq!(lookup[&1], 1 + 4 + 7);
|
/// assert_eq!(lookup[&1], 1 + 4 + 7);
|
||||||
/// assert_eq!(lookup[&2], 2 + 5);
|
/// assert_eq!(lookup[&2], 2 + 5);
|
||||||
/// assert_eq!(lookup.len(), 3);
|
/// assert_eq!(lookup.len(), 3);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn fold<FO, R>(self, init: R, mut operation: FO) -> HashMap<K, R>
|
pub fn fold<FO, R>(self, init: R, operation: FO) -> HashMap<K, R>
|
||||||
where R: Clone,
|
where
|
||||||
FO: FnMut(R, &K, V) -> R,
|
R: Clone,
|
||||||
|
FO: FnMut(R, &K, V) -> R,
|
||||||
{
|
{
|
||||||
self.aggregate(|acc, key, val| {
|
self.fold_with(|_, _| init.clone(), operation)
|
||||||
let acc = acc.unwrap_or_else(|| init.clone());
|
|
||||||
Some(operation(acc, key, val))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
|
/// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
|
||||||
@@ -158,23 +210,24 @@ impl<I, K, V> GroupingMap<I>
|
|||||||
/// - the element from the source being accumulated.
|
/// - the element from the source being accumulated.
|
||||||
///
|
///
|
||||||
/// Return a `HashMap` associating the key of each group with the result of folding that group's elements.
|
/// Return a `HashMap` associating the key of each group with the result of folding that group's elements.
|
||||||
///
|
///
|
||||||
/// [`fold`]: GroupingMap::fold
|
/// [`fold`]: GroupingMap::fold
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use itertools::Itertools;
|
/// use itertools::Itertools;
|
||||||
///
|
///
|
||||||
/// let lookup = (1..=7)
|
/// let lookup = (1..=7)
|
||||||
/// .into_grouping_map_by(|&n| n % 3)
|
/// .into_grouping_map_by(|&n| n % 3)
|
||||||
/// .fold_first(|acc, _key, val| acc + val);
|
/// .reduce(|acc, _key, val| acc + val);
|
||||||
///
|
///
|
||||||
/// assert_eq!(lookup[&0], 3 + 6);
|
/// assert_eq!(lookup[&0], 3 + 6);
|
||||||
/// assert_eq!(lookup[&1], 1 + 4 + 7);
|
/// assert_eq!(lookup[&1], 1 + 4 + 7);
|
||||||
/// assert_eq!(lookup[&2], 2 + 5);
|
/// assert_eq!(lookup[&2], 2 + 5);
|
||||||
/// assert_eq!(lookup.len(), 3);
|
/// assert_eq!(lookup.len(), 3);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn fold_first<FO>(self, mut operation: FO) -> HashMap<K, V>
|
pub fn reduce<FO>(self, mut operation: FO) -> HashMap<K, V>
|
||||||
where FO: FnMut(V, &K, V) -> V,
|
where
|
||||||
|
FO: FnMut(V, &K, V) -> V,
|
||||||
{
|
{
|
||||||
self.aggregate(|acc, key, val| {
|
self.aggregate(|acc, key, val| {
|
||||||
Some(match acc {
|
Some(match acc {
|
||||||
@@ -184,250 +237,271 @@ impl<I, K, V> GroupingMap<I>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See [`.reduce()`](GroupingMap::reduce).
|
||||||
|
#[deprecated(note = "Use .reduce() instead", since = "0.13.0")]
|
||||||
|
pub fn fold_first<FO>(self, operation: FO) -> HashMap<K, V>
|
||||||
|
where
|
||||||
|
FO: FnMut(V, &K, V) -> V,
|
||||||
|
{
|
||||||
|
self.reduce(operation)
|
||||||
|
}
|
||||||
|
|
||||||
/// Groups elements from the `GroupingMap` source by key and collects the elements of each group in
|
/// Groups elements from the `GroupingMap` source by key and collects the elements of each group in
|
||||||
/// an instance of `C`. The iteration order is preserved when inserting elements.
|
/// an instance of `C`. The iteration order is preserved when inserting elements.
|
||||||
///
|
///
|
||||||
/// Return a `HashMap` associating the key of each group with the collection containing that group's elements.
|
/// Return a `HashMap` associating the key of each group with the collection containing that group's elements.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use itertools::Itertools;
|
/// use itertools::Itertools;
|
||||||
/// use std::collections::HashSet;
|
/// use std::collections::HashSet;
|
||||||
///
|
///
|
||||||
/// let lookup = vec![0, 1, 2, 3, 4, 5, 6, 2, 3, 6].into_iter()
|
/// let lookup = vec![0, 1, 2, 3, 4, 5, 6, 2, 3, 6].into_iter()
|
||||||
/// .into_grouping_map_by(|&n| n % 3)
|
/// .into_grouping_map_by(|&n| n % 3)
|
||||||
/// .collect::<HashSet<_>>();
|
/// .collect::<HashSet<_>>();
|
||||||
///
|
///
|
||||||
/// assert_eq!(lookup[&0], vec![0, 3, 6].into_iter().collect::<HashSet<_>>());
|
/// assert_eq!(lookup[&0], vec![0, 3, 6].into_iter().collect::<HashSet<_>>());
|
||||||
/// assert_eq!(lookup[&1], vec![1, 4].into_iter().collect::<HashSet<_>>());
|
/// assert_eq!(lookup[&1], vec![1, 4].into_iter().collect::<HashSet<_>>());
|
||||||
/// assert_eq!(lookup[&2], vec![2, 5].into_iter().collect::<HashSet<_>>());
|
/// assert_eq!(lookup[&2], vec![2, 5].into_iter().collect::<HashSet<_>>());
|
||||||
/// assert_eq!(lookup.len(), 3);
|
/// assert_eq!(lookup.len(), 3);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn collect<C>(self) -> HashMap<K, C>
|
pub fn collect<C>(self) -> HashMap<K, C>
|
||||||
where C: Default + Extend<V>,
|
where
|
||||||
|
C: Default + Extend<V>,
|
||||||
{
|
{
|
||||||
let mut destination_map = HashMap::new();
|
let mut destination_map = HashMap::new();
|
||||||
|
|
||||||
self.iter.for_each(|(key, val)| {
|
self.iter.for_each(|(key, val)| {
|
||||||
destination_map.entry(key).or_insert_with(C::default).extend(Some(val));
|
destination_map
|
||||||
|
.entry(key)
|
||||||
|
.or_insert_with(C::default)
|
||||||
|
.extend(Some(val));
|
||||||
});
|
});
|
||||||
|
|
||||||
destination_map
|
destination_map
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Groups elements from the `GroupingMap` source by key and finds the maximum of each group.
|
/// Groups elements from the `GroupingMap` source by key and finds the maximum of each group.
|
||||||
///
|
///
|
||||||
/// If several elements are equally maximum, the last element is picked.
|
/// If several elements are equally maximum, the last element is picked.
|
||||||
///
|
///
|
||||||
/// Returns a `HashMap` associating the key of each group with the maximum of that group's elements.
|
/// Returns a `HashMap` associating the key of each group with the maximum of that group's elements.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use itertools::Itertools;
|
/// use itertools::Itertools;
|
||||||
///
|
///
|
||||||
/// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
|
/// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
|
||||||
/// .into_grouping_map_by(|&n| n % 3)
|
/// .into_grouping_map_by(|&n| n % 3)
|
||||||
/// .max();
|
/// .max();
|
||||||
///
|
///
|
||||||
/// assert_eq!(lookup[&0], 12);
|
/// assert_eq!(lookup[&0], 12);
|
||||||
/// assert_eq!(lookup[&1], 7);
|
/// assert_eq!(lookup[&1], 7);
|
||||||
/// assert_eq!(lookup[&2], 8);
|
/// assert_eq!(lookup[&2], 8);
|
||||||
/// assert_eq!(lookup.len(), 3);
|
/// assert_eq!(lookup.len(), 3);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn max(self) -> HashMap<K, V>
|
pub fn max(self) -> HashMap<K, V>
|
||||||
where V: Ord,
|
where
|
||||||
|
V: Ord,
|
||||||
{
|
{
|
||||||
self.max_by(|_, v1, v2| V::cmp(v1, v2))
|
self.max_by(|_, v1, v2| V::cmp(v1, v2))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Groups elements from the `GroupingMap` source by key and finds the maximum of each group
|
/// Groups elements from the `GroupingMap` source by key and finds the maximum of each group
|
||||||
/// with respect to the specified comparison function.
|
/// with respect to the specified comparison function.
|
||||||
///
|
///
|
||||||
/// If several elements are equally maximum, the last element is picked.
|
/// If several elements are equally maximum, the last element is picked.
|
||||||
///
|
///
|
||||||
/// Returns a `HashMap` associating the key of each group with the maximum of that group's elements.
|
/// Returns a `HashMap` associating the key of each group with the maximum of that group's elements.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use itertools::Itertools;
|
/// use itertools::Itertools;
|
||||||
///
|
///
|
||||||
/// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
|
/// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
|
||||||
/// .into_grouping_map_by(|&n| n % 3)
|
/// .into_grouping_map_by(|&n| n % 3)
|
||||||
/// .max_by(|_key, x, y| y.cmp(x));
|
/// .max_by(|_key, x, y| y.cmp(x));
|
||||||
///
|
///
|
||||||
/// assert_eq!(lookup[&0], 3);
|
/// assert_eq!(lookup[&0], 3);
|
||||||
/// assert_eq!(lookup[&1], 1);
|
/// assert_eq!(lookup[&1], 1);
|
||||||
/// assert_eq!(lookup[&2], 5);
|
/// assert_eq!(lookup[&2], 5);
|
||||||
/// assert_eq!(lookup.len(), 3);
|
/// 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>
|
||||||
where F: FnMut(&K, &V, &V) -> Ordering,
|
where
|
||||||
|
F: FnMut(&K, &V, &V) -> Ordering,
|
||||||
{
|
{
|
||||||
self.fold_first(|acc, key, val| match compare(key, &acc, &val) {
|
self.reduce(|acc, key, val| match compare(key, &acc, &val) {
|
||||||
Ordering::Less | Ordering::Equal => val,
|
Ordering::Less | Ordering::Equal => val,
|
||||||
Ordering::Greater => acc
|
Ordering::Greater => acc,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Groups elements from the `GroupingMap` source by key and finds the element of each group
|
/// Groups elements from the `GroupingMap` source by key and finds the element of each group
|
||||||
/// that gives the maximum from the specified function.
|
/// that gives the maximum from the specified function.
|
||||||
///
|
///
|
||||||
/// If several elements are equally maximum, the last element is picked.
|
/// If several elements are equally maximum, the last element is picked.
|
||||||
///
|
///
|
||||||
/// Returns a `HashMap` associating the key of each group with the maximum of that group's elements.
|
/// Returns a `HashMap` associating the key of each group with the maximum of that group's elements.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use itertools::Itertools;
|
/// use itertools::Itertools;
|
||||||
///
|
///
|
||||||
/// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
|
/// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
|
||||||
/// .into_grouping_map_by(|&n| n % 3)
|
/// .into_grouping_map_by(|&n| n % 3)
|
||||||
/// .max_by_key(|_key, &val| val % 4);
|
/// .max_by_key(|_key, &val| val % 4);
|
||||||
///
|
///
|
||||||
/// assert_eq!(lookup[&0], 3);
|
/// assert_eq!(lookup[&0], 3);
|
||||||
/// assert_eq!(lookup[&1], 7);
|
/// assert_eq!(lookup[&1], 7);
|
||||||
/// assert_eq!(lookup[&2], 5);
|
/// assert_eq!(lookup[&2], 5);
|
||||||
/// assert_eq!(lookup.len(), 3);
|
/// 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>
|
||||||
where F: FnMut(&K, &V) -> CK,
|
where
|
||||||
CK: Ord,
|
F: FnMut(&K, &V) -> CK,
|
||||||
|
CK: Ord,
|
||||||
{
|
{
|
||||||
self.max_by(|key, v1, v2| f(key, v1).cmp(&f(key, v2)))
|
self.max_by(|key, v1, v2| f(key, v1).cmp(&f(key, v2)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Groups elements from the `GroupingMap` source by key and finds the minimum of each group.
|
/// Groups elements from the `GroupingMap` source by key and finds the minimum of each group.
|
||||||
///
|
///
|
||||||
/// If several elements are equally minimum, the first element is picked.
|
/// If several elements are equally minimum, the first element is picked.
|
||||||
///
|
///
|
||||||
/// Returns a `HashMap` associating the key of each group with the minimum of that group's elements.
|
/// Returns a `HashMap` associating the key of each group with the minimum of that group's elements.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use itertools::Itertools;
|
/// use itertools::Itertools;
|
||||||
///
|
///
|
||||||
/// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
|
/// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
|
||||||
/// .into_grouping_map_by(|&n| n % 3)
|
/// .into_grouping_map_by(|&n| n % 3)
|
||||||
/// .min();
|
/// .min();
|
||||||
///
|
///
|
||||||
/// assert_eq!(lookup[&0], 3);
|
/// assert_eq!(lookup[&0], 3);
|
||||||
/// assert_eq!(lookup[&1], 1);
|
/// assert_eq!(lookup[&1], 1);
|
||||||
/// assert_eq!(lookup[&2], 5);
|
/// assert_eq!(lookup[&2], 5);
|
||||||
/// assert_eq!(lookup.len(), 3);
|
/// assert_eq!(lookup.len(), 3);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn min(self) -> HashMap<K, V>
|
pub fn min(self) -> HashMap<K, V>
|
||||||
where V: Ord,
|
where
|
||||||
|
V: Ord,
|
||||||
{
|
{
|
||||||
self.min_by(|_, v1, v2| V::cmp(v1, v2))
|
self.min_by(|_, v1, v2| V::cmp(v1, v2))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Groups elements from the `GroupingMap` source by key and finds the minimum of each group
|
/// Groups elements from the `GroupingMap` source by key and finds the minimum of each group
|
||||||
/// with respect to the specified comparison function.
|
/// with respect to the specified comparison function.
|
||||||
///
|
///
|
||||||
/// If several elements are equally minimum, the first element is picked.
|
/// If several elements are equally minimum, the first element is picked.
|
||||||
///
|
///
|
||||||
/// Returns a `HashMap` associating the key of each group with the minimum of that group's elements.
|
/// Returns a `HashMap` associating the key of each group with the minimum of that group's elements.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use itertools::Itertools;
|
/// use itertools::Itertools;
|
||||||
///
|
///
|
||||||
/// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
|
/// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
|
||||||
/// .into_grouping_map_by(|&n| n % 3)
|
/// .into_grouping_map_by(|&n| n % 3)
|
||||||
/// .min_by(|_key, x, y| y.cmp(x));
|
/// .min_by(|_key, x, y| y.cmp(x));
|
||||||
///
|
///
|
||||||
/// assert_eq!(lookup[&0], 12);
|
/// assert_eq!(lookup[&0], 12);
|
||||||
/// assert_eq!(lookup[&1], 7);
|
/// assert_eq!(lookup[&1], 7);
|
||||||
/// assert_eq!(lookup[&2], 8);
|
/// assert_eq!(lookup[&2], 8);
|
||||||
/// assert_eq!(lookup.len(), 3);
|
/// 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>
|
||||||
where F: FnMut(&K, &V, &V) -> Ordering,
|
where
|
||||||
|
F: FnMut(&K, &V, &V) -> Ordering,
|
||||||
{
|
{
|
||||||
self.fold_first(|acc, key, val| match compare(key, &acc, &val) {
|
self.reduce(|acc, key, val| match compare(key, &acc, &val) {
|
||||||
Ordering::Less | Ordering::Equal => acc,
|
Ordering::Less | Ordering::Equal => acc,
|
||||||
Ordering::Greater => val
|
Ordering::Greater => val,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Groups elements from the `GroupingMap` source by key and finds the element of each group
|
/// Groups elements from the `GroupingMap` source by key and finds the element of each group
|
||||||
/// that gives the minimum from the specified function.
|
/// that gives the minimum from the specified function.
|
||||||
///
|
///
|
||||||
/// If several elements are equally minimum, the first element is picked.
|
/// If several elements are equally minimum, the first element is picked.
|
||||||
///
|
///
|
||||||
/// Returns a `HashMap` associating the key of each group with the minimum of that group's elements.
|
/// Returns a `HashMap` associating the key of each group with the minimum of that group's elements.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use itertools::Itertools;
|
/// use itertools::Itertools;
|
||||||
///
|
///
|
||||||
/// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
|
/// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
|
||||||
/// .into_grouping_map_by(|&n| n % 3)
|
/// .into_grouping_map_by(|&n| n % 3)
|
||||||
/// .min_by_key(|_key, &val| val % 4);
|
/// .min_by_key(|_key, &val| val % 4);
|
||||||
///
|
///
|
||||||
/// assert_eq!(lookup[&0], 12);
|
/// assert_eq!(lookup[&0], 12);
|
||||||
/// assert_eq!(lookup[&1], 4);
|
/// assert_eq!(lookup[&1], 4);
|
||||||
/// assert_eq!(lookup[&2], 8);
|
/// assert_eq!(lookup[&2], 8);
|
||||||
/// assert_eq!(lookup.len(), 3);
|
/// 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>
|
||||||
where F: FnMut(&K, &V) -> CK,
|
where
|
||||||
CK: Ord,
|
F: FnMut(&K, &V) -> CK,
|
||||||
|
CK: Ord,
|
||||||
{
|
{
|
||||||
self.min_by(|key, v1, v2| f(key, v1).cmp(&f(key, v2)))
|
self.min_by(|key, v1, v2| f(key, v1).cmp(&f(key, v2)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Groups elements from the `GroupingMap` source by key and find the maximum and minimum of
|
/// Groups elements from the `GroupingMap` source by key and find the maximum and minimum of
|
||||||
/// each group.
|
/// each group.
|
||||||
///
|
///
|
||||||
/// If several elements are equally maximum, the last element is picked.
|
/// If several elements are equally maximum, the last element is picked.
|
||||||
/// If several elements are equally minimum, the first element is picked.
|
/// If several elements are equally minimum, the first element is picked.
|
||||||
///
|
///
|
||||||
/// See [.minmax()](crate::Itertools::minmax) for the non-grouping version.
|
/// See [`Itertools::minmax`](crate::Itertools::minmax) for the non-grouping version.
|
||||||
///
|
///
|
||||||
/// Differences from the non grouping version:
|
/// Differences from the non grouping version:
|
||||||
/// - It never produces a `MinMaxResult::NoElements`
|
/// - It never produces a `MinMaxResult::NoElements`
|
||||||
/// - It doesn't have any speedup
|
/// - It doesn't have any speedup
|
||||||
///
|
///
|
||||||
/// Returns a `HashMap` associating the key of each group with the minimum and maximum of that group's elements.
|
/// Returns a `HashMap` associating the key of each group with the minimum and maximum of that group's elements.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use itertools::Itertools;
|
/// use itertools::Itertools;
|
||||||
/// use itertools::MinMaxResult::{OneElement, MinMax};
|
/// use itertools::MinMaxResult::{OneElement, MinMax};
|
||||||
///
|
///
|
||||||
/// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter()
|
/// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter()
|
||||||
/// .into_grouping_map_by(|&n| n % 3)
|
/// .into_grouping_map_by(|&n| n % 3)
|
||||||
/// .minmax();
|
/// .minmax();
|
||||||
///
|
///
|
||||||
/// assert_eq!(lookup[&0], MinMax(3, 12));
|
/// assert_eq!(lookup[&0], MinMax(3, 12));
|
||||||
/// assert_eq!(lookup[&1], MinMax(1, 7));
|
/// assert_eq!(lookup[&1], MinMax(1, 7));
|
||||||
/// assert_eq!(lookup[&2], OneElement(5));
|
/// assert_eq!(lookup[&2], OneElement(5));
|
||||||
/// assert_eq!(lookup.len(), 3);
|
/// assert_eq!(lookup.len(), 3);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn minmax(self) -> HashMap<K, MinMaxResult<V>>
|
pub fn minmax(self) -> HashMap<K, MinMaxResult<V>>
|
||||||
where V: Ord,
|
where
|
||||||
|
V: Ord,
|
||||||
{
|
{
|
||||||
self.minmax_by(|_, v1, v2| V::cmp(v1, v2))
|
self.minmax_by(|_, v1, v2| V::cmp(v1, v2))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Groups elements from the `GroupingMap` source by key and find the maximum and minimum of
|
/// Groups elements from the `GroupingMap` source by key and find the maximum and minimum of
|
||||||
/// each group with respect to the specified comparison function.
|
/// each group with respect to the specified comparison function.
|
||||||
///
|
///
|
||||||
/// If several elements are equally maximum, the last element is picked.
|
/// If several elements are equally maximum, the last element is picked.
|
||||||
/// If several elements are equally minimum, the first element is picked.
|
/// If several elements are equally minimum, the first element is picked.
|
||||||
///
|
///
|
||||||
/// It has the same differences from the non-grouping version as `minmax`.
|
/// It has the same differences from the non-grouping version as `minmax`.
|
||||||
///
|
///
|
||||||
/// Returns a `HashMap` associating the key of each group with the minimum and maximum of that group's elements.
|
/// Returns a `HashMap` associating the key of each group with the minimum and maximum of that group's elements.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use itertools::Itertools;
|
/// use itertools::Itertools;
|
||||||
/// use itertools::MinMaxResult::{OneElement, MinMax};
|
/// use itertools::MinMaxResult::{OneElement, MinMax};
|
||||||
///
|
///
|
||||||
/// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter()
|
/// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter()
|
||||||
/// .into_grouping_map_by(|&n| n % 3)
|
/// .into_grouping_map_by(|&n| n % 3)
|
||||||
/// .minmax_by(|_key, x, y| y.cmp(x));
|
/// .minmax_by(|_key, x, y| y.cmp(x));
|
||||||
///
|
///
|
||||||
/// assert_eq!(lookup[&0], MinMax(12, 3));
|
/// assert_eq!(lookup[&0], MinMax(12, 3));
|
||||||
/// assert_eq!(lookup[&1], MinMax(7, 1));
|
/// assert_eq!(lookup[&1], MinMax(7, 1));
|
||||||
/// assert_eq!(lookup[&2], OneElement(5));
|
/// assert_eq!(lookup[&2], OneElement(5));
|
||||||
/// assert_eq!(lookup.len(), 3);
|
/// 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>>
|
||||||
where F: FnMut(&K, &V, &V) -> Ordering,
|
where
|
||||||
|
F: FnMut(&K, &V, &V) -> Ordering,
|
||||||
{
|
{
|
||||||
self.aggregate(|acc, key, val| {
|
self.aggregate(|acc, key, val| {
|
||||||
Some(match acc {
|
Some(match acc {
|
||||||
@@ -455,81 +529,84 @@ impl<I, K, V> GroupingMap<I>
|
|||||||
|
|
||||||
/// Groups elements from the `GroupingMap` source by key and find the elements of each group
|
/// Groups elements from the `GroupingMap` source by key and find the elements of each group
|
||||||
/// that gives the minimum and maximum from the specified function.
|
/// that gives the minimum and maximum from the specified function.
|
||||||
///
|
///
|
||||||
/// If several elements are equally maximum, the last element is picked.
|
/// If several elements are equally maximum, the last element is picked.
|
||||||
/// If several elements are equally minimum, the first element is picked.
|
/// If several elements are equally minimum, the first element is picked.
|
||||||
///
|
///
|
||||||
/// It has the same differences from the non-grouping version as `minmax`.
|
/// It has the same differences from the non-grouping version as `minmax`.
|
||||||
///
|
///
|
||||||
/// Returns a `HashMap` associating the key of each group with the minimum and maximum of that group's elements.
|
/// Returns a `HashMap` associating the key of each group with the minimum and maximum of that group's elements.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use itertools::Itertools;
|
/// use itertools::Itertools;
|
||||||
/// use itertools::MinMaxResult::{OneElement, MinMax};
|
/// use itertools::MinMaxResult::{OneElement, MinMax};
|
||||||
///
|
///
|
||||||
/// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter()
|
/// let lookup = vec![1, 3, 4, 5, 7, 9, 12].into_iter()
|
||||||
/// .into_grouping_map_by(|&n| n % 3)
|
/// .into_grouping_map_by(|&n| n % 3)
|
||||||
/// .minmax_by_key(|_key, &val| val % 4);
|
/// .minmax_by_key(|_key, &val| val % 4);
|
||||||
///
|
///
|
||||||
/// assert_eq!(lookup[&0], MinMax(12, 3));
|
/// assert_eq!(lookup[&0], MinMax(12, 3));
|
||||||
/// assert_eq!(lookup[&1], MinMax(4, 7));
|
/// assert_eq!(lookup[&1], MinMax(4, 7));
|
||||||
/// assert_eq!(lookup[&2], OneElement(5));
|
/// assert_eq!(lookup[&2], OneElement(5));
|
||||||
/// assert_eq!(lookup.len(), 3);
|
/// 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>>
|
||||||
where F: FnMut(&K, &V) -> CK,
|
where
|
||||||
CK: Ord,
|
F: FnMut(&K, &V) -> CK,
|
||||||
|
CK: Ord,
|
||||||
{
|
{
|
||||||
self.minmax_by(|key, v1, v2| f(key, v1).cmp(&f(key, v2)))
|
self.minmax_by(|key, v1, v2| f(key, v1).cmp(&f(key, v2)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Groups elements from the `GroupingMap` source by key and sums them.
|
/// Groups elements from the `GroupingMap` source by key and sums them.
|
||||||
///
|
///
|
||||||
/// This is just a shorthand for `self.fold_first(|acc, _, val| acc + val)`.
|
/// This is just a shorthand for `self.reduce(|acc, _, val| acc + val)`.
|
||||||
/// It is more limited than `Iterator::sum` since it doesn't use the `Sum` trait.
|
/// It is more limited than `Iterator::sum` since it doesn't use the `Sum` trait.
|
||||||
///
|
///
|
||||||
/// Returns a `HashMap` associating the key of each group with the sum of that group's elements.
|
/// Returns a `HashMap` associating the key of each group with the sum of that group's elements.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use itertools::Itertools;
|
/// use itertools::Itertools;
|
||||||
///
|
///
|
||||||
/// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
|
/// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
|
||||||
/// .into_grouping_map_by(|&n| n % 3)
|
/// .into_grouping_map_by(|&n| n % 3)
|
||||||
/// .sum();
|
/// .sum();
|
||||||
///
|
///
|
||||||
/// assert_eq!(lookup[&0], 3 + 9 + 12);
|
/// assert_eq!(lookup[&0], 3 + 9 + 12);
|
||||||
/// assert_eq!(lookup[&1], 1 + 4 + 7);
|
/// assert_eq!(lookup[&1], 1 + 4 + 7);
|
||||||
/// assert_eq!(lookup[&2], 5 + 8);
|
/// assert_eq!(lookup[&2], 5 + 8);
|
||||||
/// assert_eq!(lookup.len(), 3);
|
/// assert_eq!(lookup.len(), 3);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn sum(self) -> HashMap<K, V>
|
pub fn sum(self) -> HashMap<K, V>
|
||||||
where V: Add<V, Output = V>
|
where
|
||||||
|
V: Add<V, Output = V>,
|
||||||
{
|
{
|
||||||
self.fold_first(|acc, _, val| acc + val)
|
self.reduce(|acc, _, val| acc + val)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Groups elements from the `GroupingMap` source by key and multiply them.
|
/// Groups elements from the `GroupingMap` source by key and multiply them.
|
||||||
///
|
///
|
||||||
/// This is just a shorthand for `self.fold_first(|acc, _, val| acc * val)`.
|
/// This is just a shorthand for `self.reduce(|acc, _, val| acc * val)`.
|
||||||
/// It is more limited than `Iterator::product` since it doesn't use the `Product` trait.
|
/// It is more limited than `Iterator::product` since it doesn't use the `Product` trait.
|
||||||
///
|
///
|
||||||
/// Returns a `HashMap` associating the key of each group with the product of that group's elements.
|
/// Returns a `HashMap` associating the key of each group with the product of that group's elements.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use itertools::Itertools;
|
/// use itertools::Itertools;
|
||||||
///
|
///
|
||||||
/// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
|
/// let lookup = vec![1, 3, 4, 5, 7, 8, 9, 12].into_iter()
|
||||||
/// .into_grouping_map_by(|&n| n % 3)
|
/// .into_grouping_map_by(|&n| n % 3)
|
||||||
/// .product();
|
/// .product();
|
||||||
///
|
///
|
||||||
/// assert_eq!(lookup[&0], 3 * 9 * 12);
|
/// assert_eq!(lookup[&0], 3 * 9 * 12);
|
||||||
/// assert_eq!(lookup[&1], 1 * 4 * 7);
|
/// assert_eq!(lookup[&1], 1 * 4 * 7);
|
||||||
/// assert_eq!(lookup[&2], 5 * 8);
|
/// assert_eq!(lookup[&2], 5 * 8);
|
||||||
/// assert_eq!(lookup.len(), 3);
|
/// assert_eq!(lookup.len(), 3);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn product(self) -> HashMap<K, V>
|
pub fn product(self) -> HashMap<K, V>
|
||||||
where V: Mul<V, Output = V>,
|
where
|
||||||
|
V: Mul<V, Output = V>,
|
||||||
{
|
{
|
||||||
self.fold_first(|acc, _, val| acc * val)
|
self.reduce(|acc, _, val| acc * val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//!
|
//!
|
||||||
//! Implementation's internal macros
|
//! Implementation's internal macros
|
||||||
|
|
||||||
macro_rules! debug_fmt_fields {
|
macro_rules! debug_fmt_fields {
|
||||||
@@ -27,3 +27,8 @@ macro_rules! clone_fields {
|
|||||||
macro_rules! ignore_ident{
|
macro_rules! ignore_ident{
|
||||||
($id:ident, $($t:tt)*) => {$($t)*};
|
($id:ident, $($t:tt)*) => {$($t)*};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! count_ident {
|
||||||
|
() => {0};
|
||||||
|
($i0:ident $($i:ident)*) => {1 + count_ident!($($i)*)};
|
||||||
|
}
|
||||||
|
|||||||
94
third_party/rust/itertools/src/intersperse.rs
vendored
94
third_party/rust/itertools/src/intersperse.rs
vendored
@@ -1,5 +1,5 @@
|
|||||||
use std::iter::{Fuse, FusedIterator};
|
|
||||||
use super::size_hint;
|
use super::size_hint;
|
||||||
|
use std::iter::{Fuse, FusedIterator};
|
||||||
|
|
||||||
pub trait IntersperseElement<Item> {
|
pub trait IntersperseElement<Item> {
|
||||||
fn generate(&mut self) -> Item;
|
fn generate(&mut self) -> Item;
|
||||||
@@ -26,12 +26,13 @@ pub type Intersperse<I> = IntersperseWith<I, IntersperseElementSimple<<I as Iter
|
|||||||
|
|
||||||
/// Create a new Intersperse iterator
|
/// Create a new Intersperse iterator
|
||||||
pub fn intersperse<I>(iter: I, elt: I::Item) -> Intersperse<I>
|
pub fn intersperse<I>(iter: I, elt: I::Item) -> Intersperse<I>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
intersperse_with(iter, IntersperseElementSimple(elt))
|
intersperse_with(iter, IntersperseElementSimple(elt))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Item, F: FnMut()->Item> IntersperseElement<Item> for F {
|
impl<Item, F: FnMut() -> Item> IntersperseElement<Item> for F {
|
||||||
fn generate(&mut self) -> Item {
|
fn generate(&mut self) -> Item {
|
||||||
self()
|
self()
|
||||||
}
|
}
|
||||||
@@ -48,71 +49,94 @@ impl<Item, F: FnMut()->Item> IntersperseElement<Item> for F {
|
|||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct IntersperseWith<I, ElemF>
|
pub struct IntersperseWith<I, ElemF>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
element: ElemF,
|
element: ElemF,
|
||||||
iter: Fuse<I>,
|
iter: Fuse<I>,
|
||||||
peek: Option<I::Item>,
|
/// `peek` is None while no item have been taken out of `iter` (at definition).
|
||||||
|
/// Then `peek` will alternatively be `Some(None)` and `Some(Some(item))`,
|
||||||
|
/// where `None` indicates it's time to generate from `element` (unless `iter` is empty).
|
||||||
|
peek: Option<Option<I::Item>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `IntersperseWith` iterator
|
/// Create a new `IntersperseWith` iterator
|
||||||
pub fn intersperse_with<I, ElemF>(iter: I, elt: ElemF) -> IntersperseWith<I, ElemF>
|
pub fn intersperse_with<I, ElemF>(iter: I, elt: ElemF) -> IntersperseWith<I, ElemF>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
let mut iter = iter.fuse();
|
|
||||||
IntersperseWith {
|
IntersperseWith {
|
||||||
peek: iter.next(),
|
peek: None,
|
||||||
iter,
|
iter: iter.fuse(),
|
||||||
element: elt,
|
element: elt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, ElemF> Iterator for IntersperseWith<I, ElemF>
|
impl<I, ElemF> Iterator for IntersperseWith<I, ElemF>
|
||||||
where I: Iterator,
|
where
|
||||||
ElemF: IntersperseElement<I::Item>
|
I: Iterator,
|
||||||
|
ElemF: IntersperseElement<I::Item>,
|
||||||
{
|
{
|
||||||
type Item = I::Item;
|
type Item = I::Item;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if self.peek.is_some() {
|
let Self {
|
||||||
self.peek.take()
|
element,
|
||||||
} else {
|
iter,
|
||||||
self.peek = self.iter.next();
|
peek,
|
||||||
if self.peek.is_some() {
|
} = self;
|
||||||
Some(self.element.generate())
|
match peek {
|
||||||
} else {
|
Some(item @ Some(_)) => item.take(),
|
||||||
None
|
Some(None) => match iter.next() {
|
||||||
|
new @ Some(_) => {
|
||||||
|
*peek = Some(new);
|
||||||
|
Some(element.generate())
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
*peek = Some(None);
|
||||||
|
iter.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
// 2 * SH + { 1 or 0 }
|
let mut sh = self.iter.size_hint();
|
||||||
let has_peek = self.peek.is_some() as usize;
|
sh = size_hint::add(sh, sh);
|
||||||
let sh = self.iter.size_hint();
|
match self.peek {
|
||||||
size_hint::add_scalar(size_hint::add(sh, sh), has_peek)
|
Some(Some(_)) => size_hint::add_scalar(sh, 1),
|
||||||
|
Some(None) => sh,
|
||||||
|
None => size_hint::sub_scalar(sh, 1),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold<B, F>(mut self, init: B, mut f: F) -> B where
|
fn fold<B, F>(self, init: B, mut f: F) -> B
|
||||||
Self: Sized, F: FnMut(B, Self::Item) -> B,
|
where
|
||||||
|
Self: Sized,
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
{
|
{
|
||||||
|
let Self {
|
||||||
|
mut element,
|
||||||
|
mut iter,
|
||||||
|
peek,
|
||||||
|
} = self;
|
||||||
let mut accum = init;
|
let mut accum = init;
|
||||||
|
|
||||||
if let Some(x) = self.peek.take() {
|
if let Some(x) = peek.unwrap_or_else(|| iter.next()) {
|
||||||
accum = f(accum, x);
|
accum = f(accum, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
let element = &mut self.element;
|
iter.fold(accum, |accum, x| {
|
||||||
|
let accum = f(accum, element.generate());
|
||||||
self.iter.fold(accum,
|
f(accum, x)
|
||||||
|accum, x| {
|
|
||||||
let accum = f(accum, element.generate());
|
|
||||||
f(accum, x)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, ElemF> FusedIterator for IntersperseWith<I, ElemF>
|
impl<I, ElemF> FusedIterator for IntersperseWith<I, ElemF>
|
||||||
where I: Iterator,
|
where
|
||||||
ElemF: IntersperseElement<I::Item>
|
I: Iterator,
|
||||||
{}
|
ElemF: IntersperseElement<I::Item>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|||||||
116
third_party/rust/itertools/src/iter_index.rs
vendored
Normal file
116
third_party/rust/itertools/src/iter_index.rs
vendored
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
use core::iter::{Skip, Take};
|
||||||
|
use core::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
|
||||||
|
|
||||||
|
#[cfg(doc)]
|
||||||
|
use crate::Itertools;
|
||||||
|
|
||||||
|
mod private_iter_index {
|
||||||
|
use core::ops;
|
||||||
|
|
||||||
|
pub trait Sealed {}
|
||||||
|
|
||||||
|
impl Sealed for ops::Range<usize> {}
|
||||||
|
impl Sealed for ops::RangeInclusive<usize> {}
|
||||||
|
impl Sealed for ops::RangeTo<usize> {}
|
||||||
|
impl Sealed for ops::RangeToInclusive<usize> {}
|
||||||
|
impl Sealed for ops::RangeFrom<usize> {}
|
||||||
|
impl Sealed for ops::RangeFull {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used by [`Itertools::get`] to know which iterator
|
||||||
|
/// to turn different ranges into.
|
||||||
|
pub trait IteratorIndex<I>: private_iter_index::Sealed
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
{
|
||||||
|
/// The type returned for this type of index.
|
||||||
|
type Output: Iterator<Item = I::Item>;
|
||||||
|
|
||||||
|
/// Returns an adapted iterator for the current index.
|
||||||
|
///
|
||||||
|
/// Prefer calling [`Itertools::get`] instead
|
||||||
|
/// of calling this directly.
|
||||||
|
fn index(self, from: I) -> Self::Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> IteratorIndex<I> for Range<usize>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
{
|
||||||
|
type Output = Skip<Take<I>>;
|
||||||
|
|
||||||
|
fn index(self, iter: I) -> Self::Output {
|
||||||
|
iter.take(self.end).skip(self.start)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> IteratorIndex<I> for RangeInclusive<usize>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
{
|
||||||
|
type Output = Take<Skip<I>>;
|
||||||
|
|
||||||
|
fn index(self, iter: I) -> Self::Output {
|
||||||
|
// end - start + 1 without overflowing if possible
|
||||||
|
let length = if *self.end() == usize::MAX {
|
||||||
|
assert_ne!(*self.start(), 0);
|
||||||
|
self.end() - self.start() + 1
|
||||||
|
} else {
|
||||||
|
(self.end() + 1).saturating_sub(*self.start())
|
||||||
|
};
|
||||||
|
iter.skip(*self.start()).take(length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> IteratorIndex<I> for RangeTo<usize>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
{
|
||||||
|
type Output = Take<I>;
|
||||||
|
|
||||||
|
fn index(self, iter: I) -> Self::Output {
|
||||||
|
iter.take(self.end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> IteratorIndex<I> for RangeToInclusive<usize>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
{
|
||||||
|
type Output = Take<I>;
|
||||||
|
|
||||||
|
fn index(self, iter: I) -> Self::Output {
|
||||||
|
assert_ne!(self.end, usize::MAX);
|
||||||
|
iter.take(self.end + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> IteratorIndex<I> for RangeFrom<usize>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
{
|
||||||
|
type Output = Skip<I>;
|
||||||
|
|
||||||
|
fn index(self, iter: I) -> Self::Output {
|
||||||
|
iter.skip(self.start)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> IteratorIndex<I> for RangeFull
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
{
|
||||||
|
type Output = I;
|
||||||
|
|
||||||
|
fn index(self, iter: I) -> Self::Output {
|
||||||
|
iter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get<I, R>(iter: I, index: R) -> R::Output
|
||||||
|
where
|
||||||
|
I: IntoIterator,
|
||||||
|
R: IteratorIndex<I::IntoIter>,
|
||||||
|
{
|
||||||
|
index.index(iter.into_iter())
|
||||||
|
}
|
||||||
144
third_party/rust/itertools/src/k_smallest.rs
vendored
144
third_party/rust/itertools/src/k_smallest.rs
vendored
@@ -1,20 +1,138 @@
|
|||||||
use alloc::collections::BinaryHeap;
|
use alloc::vec::Vec;
|
||||||
use core::cmp::Ord;
|
use core::cmp::Ordering;
|
||||||
|
|
||||||
pub(crate) fn k_smallest<T: Ord, I: Iterator<Item = T>>(mut iter: I, k: usize) -> BinaryHeap<T> {
|
/// Consumes a given iterator, returning the minimum elements in **ascending** order.
|
||||||
if k == 0 { return BinaryHeap::new(); }
|
pub(crate) fn k_smallest_general<I, F>(iter: I, k: usize, mut comparator: F) -> Vec<I::Item>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
F: FnMut(&I::Item, &I::Item) -> Ordering,
|
||||||
|
{
|
||||||
|
/// Sift the element currently at `origin` away from the root until it is properly ordered.
|
||||||
|
///
|
||||||
|
/// This will leave **larger** elements closer to the root of the heap.
|
||||||
|
fn sift_down<T, F>(heap: &mut [T], is_less_than: &mut F, mut origin: usize)
|
||||||
|
where
|
||||||
|
F: FnMut(&T, &T) -> bool,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn children_of(n: usize) -> (usize, usize) {
|
||||||
|
(2 * n + 1, 2 * n + 2)
|
||||||
|
}
|
||||||
|
|
||||||
let mut heap = iter.by_ref().take(k).collect::<BinaryHeap<_>>();
|
while origin < heap.len() {
|
||||||
|
let (left_idx, right_idx) = children_of(origin);
|
||||||
|
if left_idx >= heap.len() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
iter.for_each(|i| {
|
let replacement_idx =
|
||||||
debug_assert_eq!(heap.len(), k);
|
if right_idx < heap.len() && is_less_than(&heap[left_idx], &heap[right_idx]) {
|
||||||
// Equivalent to heap.push(min(i, heap.pop())) but more efficient.
|
right_idx
|
||||||
// This should be done with a single `.peek_mut().unwrap()` but
|
} else {
|
||||||
// `PeekMut` sifts-down unconditionally on Rust 1.46.0 and prior.
|
left_idx
|
||||||
if *heap.peek().unwrap() > i {
|
};
|
||||||
*heap.peek_mut().unwrap() = i;
|
|
||||||
|
if is_less_than(&heap[origin], &heap[replacement_idx]) {
|
||||||
|
heap.swap(origin, replacement_idx);
|
||||||
|
origin = replacement_idx;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if k == 0 {
|
||||||
|
iter.last();
|
||||||
|
return Vec::new();
|
||||||
|
}
|
||||||
|
if k == 1 {
|
||||||
|
return iter.min_by(comparator).into_iter().collect();
|
||||||
|
}
|
||||||
|
let mut iter = iter.fuse();
|
||||||
|
let mut storage: Vec<I::Item> = iter.by_ref().take(k).collect();
|
||||||
|
|
||||||
|
let mut is_less_than = move |a: &_, b: &_| comparator(a, b) == Ordering::Less;
|
||||||
|
|
||||||
|
// Rearrange the storage into a valid heap by reordering from the second-bottom-most layer up to the root.
|
||||||
|
// Slightly faster than ordering on each insert, but only by a factor of lg(k).
|
||||||
|
// The resulting heap has the **largest** item on top.
|
||||||
|
for i in (0..=(storage.len() / 2)).rev() {
|
||||||
|
sift_down(&mut storage, &mut is_less_than, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
iter.for_each(|val| {
|
||||||
|
debug_assert_eq!(storage.len(), k);
|
||||||
|
if is_less_than(&val, &storage[0]) {
|
||||||
|
// Treating this as an push-and-pop saves having to write a sift-up implementation.
|
||||||
|
// https://en.wikipedia.org/wiki/Binary_heap#Insert_then_extract
|
||||||
|
storage[0] = val;
|
||||||
|
// We retain the smallest items we've seen so far, but ordered largest first so we can drop the largest efficiently.
|
||||||
|
sift_down(&mut storage, &mut is_less_than, 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
heap
|
// Ultimately the items need to be in least-first, strict order, but the heap is currently largest-first.
|
||||||
|
// To achieve this, repeatedly,
|
||||||
|
// 1) "pop" the largest item off the heap into the tail slot of the underlying storage,
|
||||||
|
// 2) shrink the logical size of the heap by 1,
|
||||||
|
// 3) restore the heap property over the remaining items.
|
||||||
|
let mut heap = &mut storage[..];
|
||||||
|
while heap.len() > 1 {
|
||||||
|
let last_idx = heap.len() - 1;
|
||||||
|
heap.swap(0, last_idx);
|
||||||
|
// Sifting over a truncated slice means that the sifting will not disturb already popped elements.
|
||||||
|
heap = &mut heap[..last_idx];
|
||||||
|
sift_down(heap, &mut is_less_than, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
storage
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn k_smallest_relaxed_general<I, F>(iter: I, k: usize, mut comparator: F) -> Vec<I::Item>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
F: FnMut(&I::Item, &I::Item) -> Ordering,
|
||||||
|
{
|
||||||
|
if k == 0 {
|
||||||
|
iter.last();
|
||||||
|
return Vec::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut iter = iter.fuse();
|
||||||
|
let mut buf = iter.by_ref().take(2 * k).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if buf.len() < k {
|
||||||
|
buf.sort_unstable_by(&mut comparator);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.select_nth_unstable_by(k - 1, &mut comparator);
|
||||||
|
buf.truncate(k);
|
||||||
|
|
||||||
|
iter.for_each(|val| {
|
||||||
|
if comparator(&val, &buf[k - 1]) != Ordering::Less {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_ne!(buf.len(), buf.capacity());
|
||||||
|
buf.push(val);
|
||||||
|
|
||||||
|
if buf.len() == 2 * k {
|
||||||
|
buf.select_nth_unstable_by(k - 1, &mut comparator);
|
||||||
|
buf.truncate(k);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
buf.sort_unstable_by(&mut comparator);
|
||||||
|
buf.truncate(k);
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn key_to_cmp<T, K, F>(mut key: F) -> impl FnMut(&T, &T) -> Ordering
|
||||||
|
where
|
||||||
|
F: FnMut(&T) -> K,
|
||||||
|
K: Ord,
|
||||||
|
{
|
||||||
|
move |a, b| key(a).cmp(&key(b))
|
||||||
}
|
}
|
||||||
|
|||||||
102
third_party/rust/itertools/src/kmerge_impl.rs
vendored
102
third_party/rust/itertools/src/kmerge_impl.rs
vendored
@@ -1,10 +1,9 @@
|
|||||||
use crate::size_hint;
|
use crate::size_hint;
|
||||||
use crate::Itertools;
|
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use std::fmt;
|
||||||
use std::iter::FusedIterator;
|
use std::iter::FusedIterator;
|
||||||
use std::mem::replace;
|
use std::mem::replace;
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
/// Head element and Tail iterator pair
|
/// Head element and Tail iterator pair
|
||||||
///
|
///
|
||||||
@@ -15,24 +14,21 @@ use std::fmt;
|
|||||||
/// `KMerge` into a min-heap.
|
/// `KMerge` into a min-heap.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct HeadTail<I>
|
struct HeadTail<I>
|
||||||
where I: Iterator
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
head: I::Item,
|
head: I::Item,
|
||||||
tail: I,
|
tail: I,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> HeadTail<I>
|
impl<I> HeadTail<I>
|
||||||
where I: Iterator
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
/// Constructs a `HeadTail` from an `Iterator`. Returns `None` if the `Iterator` is empty.
|
/// Constructs a `HeadTail` from an `Iterator`. Returns `None` if the `Iterator` is empty.
|
||||||
fn new(mut it: I) -> Option<HeadTail<I>> {
|
fn new(mut it: I) -> Option<Self> {
|
||||||
let head = it.next();
|
let head = it.next();
|
||||||
head.map(|h| {
|
head.map(|h| Self { head: h, tail: it })
|
||||||
HeadTail {
|
|
||||||
head: h,
|
|
||||||
tail: it,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the next element and update `head`, returning the old head in `Some`.
|
/// Get the next element and update `head`, returning the old head in `Some`.
|
||||||
@@ -53,15 +49,17 @@ impl<I> HeadTail<I>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Clone for HeadTail<I>
|
impl<I> Clone for HeadTail<I>
|
||||||
where I: Iterator + Clone,
|
where
|
||||||
I::Item: Clone
|
I: Iterator + Clone,
|
||||||
|
I::Item: Clone,
|
||||||
{
|
{
|
||||||
clone_fields!(head, tail);
|
clone_fields!(head, tail);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make `data` a heap (min-heap w.r.t the sorting).
|
/// Make `data` a heap (min-heap w.r.t the sorting).
|
||||||
fn heapify<T, S>(data: &mut [T], mut less_than: S)
|
fn heapify<T, S>(data: &mut [T], mut less_than: S)
|
||||||
where S: FnMut(&T, &T) -> bool
|
where
|
||||||
|
S: FnMut(&T, &T) -> bool,
|
||||||
{
|
{
|
||||||
for i in (0..data.len() / 2).rev() {
|
for i in (0..data.len() / 2).rev() {
|
||||||
sift_down(data, i, &mut less_than);
|
sift_down(data, i, &mut less_than);
|
||||||
@@ -70,7 +68,8 @@ fn heapify<T, S>(data: &mut [T], mut less_than: S)
|
|||||||
|
|
||||||
/// Sift down element at `index` (`heap` is a min-heap wrt the ordering)
|
/// Sift down element at `index` (`heap` is a min-heap wrt the ordering)
|
||||||
fn sift_down<T, S>(heap: &mut [T], index: usize, mut less_than: S)
|
fn sift_down<T, S>(heap: &mut [T], index: usize, mut less_than: S)
|
||||||
where S: FnMut(&T, &T) -> bool
|
where
|
||||||
|
S: FnMut(&T, &T) -> bool,
|
||||||
{
|
{
|
||||||
debug_assert!(index <= heap.len());
|
debug_assert!(index <= heap.len());
|
||||||
let mut pos = index;
|
let mut pos = index;
|
||||||
@@ -81,7 +80,7 @@ fn sift_down<T, S>(heap: &mut [T], index: usize, mut less_than: S)
|
|||||||
while child + 1 < heap.len() {
|
while child + 1 < heap.len() {
|
||||||
// pick the smaller of the two children
|
// pick the smaller of the two children
|
||||||
// use arithmetic to avoid an unpredictable branch
|
// use arithmetic to avoid an unpredictable branch
|
||||||
child += less_than(&heap[child+1], &heap[child]) as usize;
|
child += less_than(&heap[child + 1], &heap[child]) as usize;
|
||||||
|
|
||||||
// sift down is done if we are already in order
|
// sift down is done if we are already in order
|
||||||
if !less_than(&heap[child], &heap[pos]) {
|
if !less_than(&heap[child], &heap[pos]) {
|
||||||
@@ -119,7 +118,7 @@ impl<T: PartialOrd> KMergePredicate<T> for KMergeByLt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, F: FnMut(&T, &T)->bool> KMergePredicate<T> for F {
|
impl<T, F: FnMut(&T, &T) -> bool> KMergePredicate<T> for F {
|
||||||
fn kmerge_pred(&mut self, a: &T, b: &T) -> bool {
|
fn kmerge_pred(&mut self, a: &T, b: &T) -> bool {
|
||||||
self(a, b)
|
self(a, b)
|
||||||
}
|
}
|
||||||
@@ -128,19 +127,21 @@ impl<T, F: FnMut(&T, &T)->bool> KMergePredicate<T> for F {
|
|||||||
/// Create an iterator that merges elements of the contained iterators using
|
/// Create an iterator that merges elements of the contained iterators using
|
||||||
/// the ordering function.
|
/// the ordering function.
|
||||||
///
|
///
|
||||||
/// [`IntoIterator`] enabled version of [`Itertools::kmerge`].
|
/// [`IntoIterator`] enabled version of [`Itertools::kmerge`](crate::Itertools::kmerge).
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use itertools::kmerge;
|
/// use itertools::kmerge;
|
||||||
///
|
///
|
||||||
/// for elt in kmerge(vec![vec![0, 2, 4], vec![1, 3, 5], vec![6, 7]]) {
|
/// for elt in kmerge(vec![vec![0, 2, 4], vec![1, 3, 5], vec![6, 7]]) {
|
||||||
/// /* loop body */
|
/// /* loop body */
|
||||||
|
/// # let _ = elt;
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn kmerge<I>(iterable: I) -> KMerge<<I::Item as IntoIterator>::IntoIter>
|
pub fn kmerge<I>(iterable: I) -> KMerge<<I::Item as IntoIterator>::IntoIter>
|
||||||
where I: IntoIterator,
|
where
|
||||||
I::Item: IntoIterator,
|
I: IntoIterator,
|
||||||
<<I as IntoIterator>::Item as IntoIterator>::Item: PartialOrd
|
I::Item: IntoIterator,
|
||||||
|
<<I as IntoIterator>::Item as IntoIterator>::Item: PartialOrd,
|
||||||
{
|
{
|
||||||
kmerge_by(iterable, KMergeByLt)
|
kmerge_by(iterable, KMergeByLt)
|
||||||
}
|
}
|
||||||
@@ -152,29 +153,34 @@ pub fn kmerge<I>(iterable: I) -> KMerge<<I::Item as IntoIterator>::IntoIter>
|
|||||||
///
|
///
|
||||||
/// See [`.kmerge_by()`](crate::Itertools::kmerge_by) for more
|
/// See [`.kmerge_by()`](crate::Itertools::kmerge_by) for more
|
||||||
/// information.
|
/// information.
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "this iterator adaptor is not lazy but does nearly nothing unless consumed"]
|
||||||
pub struct KMergeBy<I, F>
|
pub struct KMergeBy<I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
heap: Vec<HeadTail<I>>,
|
heap: Vec<HeadTail<I>>,
|
||||||
less_than: F,
|
less_than: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, F> fmt::Debug for KMergeBy<I, F>
|
impl<I, F> fmt::Debug for KMergeBy<I, F>
|
||||||
where I: Iterator + fmt::Debug,
|
where
|
||||||
I::Item: fmt::Debug,
|
I: Iterator + fmt::Debug,
|
||||||
|
I::Item: fmt::Debug,
|
||||||
{
|
{
|
||||||
debug_fmt_fields!(KMergeBy, heap);
|
debug_fmt_fields!(KMergeBy, heap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an iterator that merges elements of the contained iterators.
|
/// Create an iterator that merges elements of the contained iterators.
|
||||||
///
|
///
|
||||||
/// [`IntoIterator`] enabled version of [`Itertools::kmerge_by`].
|
/// [`IntoIterator`] enabled version of [`Itertools::kmerge_by`](crate::Itertools::kmerge_by).
|
||||||
pub fn kmerge_by<I, F>(iterable: I, mut less_than: F)
|
pub fn kmerge_by<I, F>(
|
||||||
-> KMergeBy<<I::Item as IntoIterator>::IntoIter, F>
|
iterable: I,
|
||||||
where I: IntoIterator,
|
mut less_than: F,
|
||||||
I::Item: IntoIterator,
|
) -> KMergeBy<<I::Item as IntoIterator>::IntoIter, F>
|
||||||
F: KMergePredicate<<<I as IntoIterator>::Item as IntoIterator>::Item>,
|
where
|
||||||
|
I: IntoIterator,
|
||||||
|
I::Item: IntoIterator,
|
||||||
|
F: KMergePredicate<<<I as IntoIterator>::Item as IntoIterator>::Item>,
|
||||||
{
|
{
|
||||||
let iter = iterable.into_iter();
|
let iter = iterable.into_iter();
|
||||||
let (lower, _) = iter.size_hint();
|
let (lower, _) = iter.size_hint();
|
||||||
@@ -185,16 +191,18 @@ pub fn kmerge_by<I, F>(iterable: I, mut less_than: F)
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I, F> Clone for KMergeBy<I, F>
|
impl<I, F> Clone for KMergeBy<I, F>
|
||||||
where I: Iterator + Clone,
|
where
|
||||||
I::Item: Clone,
|
I: Iterator + Clone,
|
||||||
F: Clone,
|
I::Item: Clone,
|
||||||
|
F: Clone,
|
||||||
{
|
{
|
||||||
clone_fields!(heap, less_than);
|
clone_fields!(heap, less_than);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, F> Iterator for KMergeBy<I, F>
|
impl<I, F> Iterator for KMergeBy<I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
F: KMergePredicate<I::Item>
|
I: Iterator,
|
||||||
|
F: KMergePredicate<I::Item>,
|
||||||
{
|
{
|
||||||
type Item = I::Item;
|
type Item = I::Item;
|
||||||
|
|
||||||
@@ -208,20 +216,24 @@ impl<I, F> Iterator for KMergeBy<I, F>
|
|||||||
self.heap.swap_remove(0).head
|
self.heap.swap_remove(0).head
|
||||||
};
|
};
|
||||||
let less_than = &mut self.less_than;
|
let less_than = &mut self.less_than;
|
||||||
sift_down(&mut self.heap, 0, |a, b| less_than.kmerge_pred(&a.head, &b.head));
|
sift_down(&mut self.heap, 0, |a, b| {
|
||||||
|
less_than.kmerge_pred(&a.head, &b.head)
|
||||||
|
});
|
||||||
Some(result)
|
Some(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
#[allow(deprecated)] //TODO: once msrv hits 1.51. replace `fold1` with `reduce`
|
self.heap
|
||||||
self.heap.iter()
|
.iter()
|
||||||
.map(|i| i.size_hint())
|
.map(|i| i.size_hint())
|
||||||
.fold1(size_hint::add)
|
.reduce(size_hint::add)
|
||||||
.unwrap_or((0, Some(0)))
|
.unwrap_or((0, Some(0)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, F> FusedIterator for KMergeBy<I, F>
|
impl<I, F> FusedIterator for KMergeBy<I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
F: KMergePredicate<I::Item>
|
I: Iterator,
|
||||||
{}
|
F: KMergePredicate<I::Item>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|||||||
48
third_party/rust/itertools/src/lazy_buffer.rs
vendored
48
third_party/rust/itertools/src/lazy_buffer.rs
vendored
@@ -1,10 +1,12 @@
|
|||||||
use std::ops::Index;
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use std::iter::Fuse;
|
||||||
|
use std::ops::Index;
|
||||||
|
|
||||||
|
use crate::size_hint::{self, SizeHint};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LazyBuffer<I: Iterator> {
|
pub struct LazyBuffer<I: Iterator> {
|
||||||
pub it: I,
|
it: Fuse<I>,
|
||||||
done: bool,
|
|
||||||
buffer: Vec<I::Item>,
|
buffer: Vec<I::Item>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -12,10 +14,9 @@ impl<I> LazyBuffer<I>
|
|||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
{
|
{
|
||||||
pub fn new(it: I) -> LazyBuffer<I> {
|
pub fn new(it: I) -> Self {
|
||||||
LazyBuffer {
|
Self {
|
||||||
it,
|
it: it.fuse(),
|
||||||
done: false,
|
|
||||||
buffer: Vec::new(),
|
buffer: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,36 +25,51 @@ where
|
|||||||
self.buffer.len()
|
self.buffer.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn size_hint(&self) -> SizeHint {
|
||||||
|
size_hint::add_scalar(self.it.size_hint(), self.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn count(self) -> usize {
|
||||||
|
self.len() + self.it.count()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_next(&mut self) -> bool {
|
pub fn get_next(&mut self) -> bool {
|
||||||
if self.done {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if let Some(x) = self.it.next() {
|
if let Some(x) = self.it.next() {
|
||||||
self.buffer.push(x);
|
self.buffer.push(x);
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
self.done = true;
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prefill(&mut self, len: usize) {
|
pub fn prefill(&mut self, len: usize) {
|
||||||
let buffer_len = self.buffer.len();
|
let buffer_len = self.buffer.len();
|
||||||
|
if len > buffer_len {
|
||||||
if !self.done && len > buffer_len {
|
|
||||||
let delta = len - buffer_len;
|
let delta = len - buffer_len;
|
||||||
|
|
||||||
self.buffer.extend(self.it.by_ref().take(delta));
|
self.buffer.extend(self.it.by_ref().take(delta));
|
||||||
self.done = self.buffer.len() < len;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<I> LazyBuffer<I>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
I::Item: Clone,
|
||||||
|
{
|
||||||
|
pub fn get_at(&self, indices: &[usize]) -> Vec<I::Item> {
|
||||||
|
indices.iter().map(|i| self.buffer[*i].clone()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_array<const K: usize>(&self, indices: [usize; K]) -> [I::Item; K] {
|
||||||
|
indices.map(|i| self.buffer[i].clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<I, J> Index<J> for LazyBuffer<I>
|
impl<I, J> Index<J> for LazyBuffer<I>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
I::Item: Sized,
|
I::Item: Sized,
|
||||||
Vec<I::Item>: Index<J>
|
Vec<I::Item>: Index<J>,
|
||||||
{
|
{
|
||||||
type Output = <Vec<I::Item> as Index<J>>::Output;
|
type Output = <Vec<I::Item> as Index<J>>::Output;
|
||||||
|
|
||||||
|
|||||||
2047
third_party/rust/itertools/src/lib.rs
vendored
2047
third_party/rust/itertools/src/lib.rs
vendored
File diff suppressed because it is too large
Load Diff
397
third_party/rust/itertools/src/merge_join.rs
vendored
397
third_party/rust/itertools/src/merge_join.rs
vendored
@@ -1,151 +1,315 @@
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::iter::Fuse;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::iter::{Fuse, FusedIterator};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use super::adaptors::{PutBack, put_back};
|
use either::Either;
|
||||||
|
|
||||||
|
use super::adaptors::{put_back, PutBack};
|
||||||
use crate::either_or_both::EitherOrBoth;
|
use crate::either_or_both::EitherOrBoth;
|
||||||
|
use crate::size_hint::{self, SizeHint};
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
use crate::Itertools;
|
use crate::Itertools;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MergeLte;
|
||||||
|
|
||||||
|
/// An iterator adaptor that merges the two base iterators in ascending order.
|
||||||
|
/// If both base iterators are sorted (ascending), the result is sorted.
|
||||||
|
///
|
||||||
|
/// Iterator element type is `I::Item`.
|
||||||
|
///
|
||||||
|
/// See [`.merge()`](crate::Itertools::merge_by) for more information.
|
||||||
|
pub type Merge<I, J> = MergeBy<I, J, MergeLte>;
|
||||||
|
|
||||||
|
/// Create an iterator that merges elements in `i` and `j`.
|
||||||
|
///
|
||||||
|
/// [`IntoIterator`] enabled version of [`Itertools::merge`](crate::Itertools::merge).
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use itertools::merge;
|
||||||
|
///
|
||||||
|
/// for elt in merge(&[1, 2, 3], &[2, 3, 4]) {
|
||||||
|
/// /* loop body */
|
||||||
|
/// # let _ = elt;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn merge<I, J>(
|
||||||
|
i: I,
|
||||||
|
j: J,
|
||||||
|
) -> Merge<<I as IntoIterator>::IntoIter, <J as IntoIterator>::IntoIter>
|
||||||
|
where
|
||||||
|
I: IntoIterator,
|
||||||
|
J: IntoIterator<Item = I::Item>,
|
||||||
|
I::Item: PartialOrd,
|
||||||
|
{
|
||||||
|
merge_by_new(i, j, MergeLte)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An iterator adaptor that merges the two base iterators in ascending order.
|
||||||
|
/// If both base iterators are sorted (ascending), the result is sorted.
|
||||||
|
///
|
||||||
|
/// Iterator element type is `I::Item`.
|
||||||
|
///
|
||||||
|
/// See [`.merge_by()`](crate::Itertools::merge_by) for more information.
|
||||||
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
|
pub struct MergeBy<I: Iterator, J: Iterator, F> {
|
||||||
|
left: PutBack<Fuse<I>>,
|
||||||
|
right: PutBack<Fuse<J>>,
|
||||||
|
cmp_fn: F,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a `MergeBy` iterator.
|
||||||
|
pub fn merge_by_new<I, J, F>(a: I, b: J, cmp: F) -> MergeBy<I::IntoIter, J::IntoIter, F>
|
||||||
|
where
|
||||||
|
I: IntoIterator,
|
||||||
|
J: IntoIterator<Item = I::Item>,
|
||||||
|
{
|
||||||
|
MergeBy {
|
||||||
|
left: put_back(a.into_iter().fuse()),
|
||||||
|
right: put_back(b.into_iter().fuse()),
|
||||||
|
cmp_fn: cmp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order.
|
/// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order.
|
||||||
///
|
///
|
||||||
/// [`IntoIterator`] enabled version of [`Itertools::merge_join_by`].
|
/// [`IntoIterator`] enabled version of [`Itertools::merge_join_by`].
|
||||||
pub fn merge_join_by<I, J, F>(left: I, right: J, cmp_fn: F)
|
pub fn merge_join_by<I, J, F, T>(
|
||||||
-> MergeJoinBy<I::IntoIter, J::IntoIter, F>
|
left: I,
|
||||||
where I: IntoIterator,
|
right: J,
|
||||||
J: IntoIterator,
|
cmp_fn: F,
|
||||||
F: FnMut(&I::Item, &J::Item) -> Ordering
|
) -> MergeJoinBy<I::IntoIter, J::IntoIter, F>
|
||||||
|
where
|
||||||
|
I: IntoIterator,
|
||||||
|
J: IntoIterator,
|
||||||
|
F: FnMut(&I::Item, &J::Item) -> T,
|
||||||
{
|
{
|
||||||
MergeJoinBy {
|
MergeBy {
|
||||||
left: put_back(left.into_iter().fuse()),
|
left: put_back(left.into_iter().fuse()),
|
||||||
right: put_back(right.into_iter().fuse()),
|
right: put_back(right.into_iter().fuse()),
|
||||||
cmp_fn,
|
cmp_fn: MergeFuncLR(cmp_fn, PhantomData),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator adaptor that merge-joins items from the two base iterators in ascending order.
|
/// An iterator adaptor that merge-joins items from the two base iterators in ascending order.
|
||||||
///
|
///
|
||||||
/// See [`.merge_join_by()`](crate::Itertools::merge_join_by) for more information.
|
/// See [`.merge_join_by()`](crate::Itertools::merge_join_by) for more information.
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
pub type MergeJoinBy<I, J, F> =
|
||||||
pub struct MergeJoinBy<I: Iterator, J: Iterator, F> {
|
MergeBy<I, J, MergeFuncLR<F, <F as FuncLR<<I as Iterator>::Item, <J as Iterator>::Item>>::T>>;
|
||||||
left: PutBack<Fuse<I>>,
|
|
||||||
right: PutBack<Fuse<J>>,
|
#[derive(Clone, Debug)]
|
||||||
cmp_fn: F
|
pub struct MergeFuncLR<F, T>(F, PhantomData<T>);
|
||||||
|
|
||||||
|
pub trait FuncLR<L, R> {
|
||||||
|
type T;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, J, F> Clone for MergeJoinBy<I, J, F>
|
impl<L, R, T, F: FnMut(&L, &R) -> T> FuncLR<L, R> for F {
|
||||||
where I: Iterator,
|
type T = T;
|
||||||
J: Iterator,
|
|
||||||
PutBack<Fuse<I>>: Clone,
|
|
||||||
PutBack<Fuse<J>>: Clone,
|
|
||||||
F: Clone,
|
|
||||||
{
|
|
||||||
clone_fields!(left, right, cmp_fn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, J, F> fmt::Debug for MergeJoinBy<I, J, F>
|
pub trait OrderingOrBool<L, R> {
|
||||||
where I: Iterator + fmt::Debug,
|
type MergeResult;
|
||||||
I::Item: fmt::Debug,
|
fn left(left: L) -> Self::MergeResult;
|
||||||
J: Iterator + fmt::Debug,
|
fn right(right: R) -> Self::MergeResult;
|
||||||
J::Item: fmt::Debug,
|
// "merge" never returns (Some(...), Some(...), ...) so Option<Either<I::Item, J::Item>>
|
||||||
{
|
// is appealing but it is always followed by two put_backs, so we think the compiler is
|
||||||
debug_fmt_fields!(MergeJoinBy, left, right);
|
// smart enough to optimize it. Or we could move put_backs into "merge".
|
||||||
|
fn merge(&mut self, left: L, right: R) -> (Option<Either<L, R>>, Self::MergeResult);
|
||||||
|
fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, J, F> Iterator for MergeJoinBy<I, J, F>
|
impl<L, R, F: FnMut(&L, &R) -> Ordering> OrderingOrBool<L, R> for MergeFuncLR<F, Ordering> {
|
||||||
where I: Iterator,
|
type MergeResult = EitherOrBoth<L, R>;
|
||||||
J: Iterator,
|
fn left(left: L) -> Self::MergeResult {
|
||||||
F: FnMut(&I::Item, &J::Item) -> Ordering
|
EitherOrBoth::Left(left)
|
||||||
{
|
}
|
||||||
type Item = EitherOrBoth<I::Item, J::Item>;
|
fn right(right: R) -> Self::MergeResult {
|
||||||
|
EitherOrBoth::Right(right)
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
}
|
||||||
match (self.left.next(), self.right.next()) {
|
fn merge(&mut self, left: L, right: R) -> (Option<Either<L, R>>, Self::MergeResult) {
|
||||||
(None, None) => None,
|
match self.0(&left, &right) {
|
||||||
(Some(left), None) =>
|
Ordering::Equal => (None, EitherOrBoth::Both(left, right)),
|
||||||
Some(EitherOrBoth::Left(left)),
|
Ordering::Less => (Some(Either::Right(right)), EitherOrBoth::Left(left)),
|
||||||
(None, Some(right)) =>
|
Ordering::Greater => (Some(Either::Left(left)), EitherOrBoth::Right(right)),
|
||||||
Some(EitherOrBoth::Right(right)),
|
|
||||||
(Some(left), Some(right)) => {
|
|
||||||
match (self.cmp_fn)(&left, &right) {
|
|
||||||
Ordering::Equal =>
|
|
||||||
Some(EitherOrBoth::Both(left, right)),
|
|
||||||
Ordering::Less => {
|
|
||||||
self.right.put_back(right);
|
|
||||||
Some(EitherOrBoth::Left(left))
|
|
||||||
},
|
|
||||||
Ordering::Greater => {
|
|
||||||
self.left.put_back(left);
|
|
||||||
Some(EitherOrBoth::Right(right))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint {
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
let (a_lower, a_upper) = left;
|
||||||
let (a_lower, a_upper) = self.left.size_hint();
|
let (b_lower, b_upper) = right;
|
||||||
let (b_lower, b_upper) = self.right.size_hint();
|
|
||||||
|
|
||||||
let lower = ::std::cmp::max(a_lower, b_lower);
|
let lower = ::std::cmp::max(a_lower, b_lower);
|
||||||
|
|
||||||
let upper = match (a_upper, b_upper) {
|
let upper = match (a_upper, b_upper) {
|
||||||
(Some(x), Some(y)) => x.checked_add(y),
|
(Some(x), Some(y)) => x.checked_add(y),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
(lower, upper)
|
(lower, upper)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn count(mut self) -> usize {
|
impl<L, R, F: FnMut(&L, &R) -> bool> OrderingOrBool<L, R> for MergeFuncLR<F, bool> {
|
||||||
let mut count = 0;
|
type MergeResult = Either<L, R>;
|
||||||
loop {
|
fn left(left: L) -> Self::MergeResult {
|
||||||
match (self.left.next(), self.right.next()) {
|
Either::Left(left)
|
||||||
(None, None) => break count,
|
}
|
||||||
(Some(_left), None) => break count + 1 + self.left.into_parts().1.count(),
|
fn right(right: R) -> Self::MergeResult {
|
||||||
(None, Some(_right)) => break count + 1 + self.right.into_parts().1.count(),
|
Either::Right(right)
|
||||||
(Some(left), Some(right)) => {
|
}
|
||||||
count += 1;
|
fn merge(&mut self, left: L, right: R) -> (Option<Either<L, R>>, Self::MergeResult) {
|
||||||
match (self.cmp_fn)(&left, &right) {
|
if self.0(&left, &right) {
|
||||||
Ordering::Equal => {}
|
(Some(Either::Right(right)), Either::Left(left))
|
||||||
Ordering::Less => self.right.put_back(right),
|
} else {
|
||||||
Ordering::Greater => self.left.put_back(left),
|
(Some(Either::Left(left)), Either::Right(right))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint {
|
||||||
|
// Not ExactSizeIterator because size may be larger than usize
|
||||||
|
size_hint::add(left, right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, F: FnMut(&T, &T) -> bool> OrderingOrBool<T, T> for F {
|
||||||
|
type MergeResult = T;
|
||||||
|
fn left(left: T) -> Self::MergeResult {
|
||||||
|
left
|
||||||
|
}
|
||||||
|
fn right(right: T) -> Self::MergeResult {
|
||||||
|
right
|
||||||
|
}
|
||||||
|
fn merge(&mut self, left: T, right: T) -> (Option<Either<T, T>>, Self::MergeResult) {
|
||||||
|
if self(&left, &right) {
|
||||||
|
(Some(Either::Right(right)), left)
|
||||||
|
} else {
|
||||||
|
(Some(Either::Left(left)), right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint {
|
||||||
|
// Not ExactSizeIterator because size may be larger than usize
|
||||||
|
size_hint::add(left, right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PartialOrd> OrderingOrBool<T, T> for MergeLte {
|
||||||
|
type MergeResult = T;
|
||||||
|
fn left(left: T) -> Self::MergeResult {
|
||||||
|
left
|
||||||
|
}
|
||||||
|
fn right(right: T) -> Self::MergeResult {
|
||||||
|
right
|
||||||
|
}
|
||||||
|
fn merge(&mut self, left: T, right: T) -> (Option<Either<T, T>>, Self::MergeResult) {
|
||||||
|
if left <= right {
|
||||||
|
(Some(Either::Right(right)), left)
|
||||||
|
} else {
|
||||||
|
(Some(Either::Left(left)), right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint {
|
||||||
|
// Not ExactSizeIterator because size may be larger than usize
|
||||||
|
size_hint::add(left, right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, J, F> Clone for MergeBy<I, J, F>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
J: Iterator,
|
||||||
|
PutBack<Fuse<I>>: Clone,
|
||||||
|
PutBack<Fuse<J>>: Clone,
|
||||||
|
F: Clone,
|
||||||
|
{
|
||||||
|
clone_fields!(left, right, cmp_fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, J, F> fmt::Debug for MergeBy<I, J, F>
|
||||||
|
where
|
||||||
|
I: Iterator + fmt::Debug,
|
||||||
|
I::Item: fmt::Debug,
|
||||||
|
J: Iterator + fmt::Debug,
|
||||||
|
J::Item: fmt::Debug,
|
||||||
|
{
|
||||||
|
debug_fmt_fields!(MergeBy, left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, J, F> Iterator for MergeBy<I, J, F>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
J: Iterator,
|
||||||
|
F: OrderingOrBool<I::Item, J::Item>,
|
||||||
|
{
|
||||||
|
type Item = F::MergeResult;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
match (self.left.next(), self.right.next()) {
|
||||||
|
(None, None) => None,
|
||||||
|
(Some(left), None) => Some(F::left(left)),
|
||||||
|
(None, Some(right)) => Some(F::right(right)),
|
||||||
|
(Some(left), Some(right)) => {
|
||||||
|
let (not_next, next) = self.cmp_fn.merge(left, right);
|
||||||
|
match not_next {
|
||||||
|
Some(Either::Left(l)) => {
|
||||||
|
self.left.put_back(l);
|
||||||
}
|
}
|
||||||
|
Some(Either::Right(r)) => {
|
||||||
|
self.right.put_back(r);
|
||||||
|
}
|
||||||
|
None => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(next)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn last(mut self) -> Option<Self::Item> {
|
fn fold<B, G>(mut self, init: B, mut f: G) -> B
|
||||||
let mut previous_element = None;
|
where
|
||||||
|
Self: Sized,
|
||||||
|
G: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
let mut acc = init;
|
||||||
|
let mut left = self.left.next();
|
||||||
|
let mut right = self.right.next();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match (self.left.next(), self.right.next()) {
|
match (left, right) {
|
||||||
(None, None) => break previous_element,
|
(Some(l), Some(r)) => match self.cmp_fn.merge(l, r) {
|
||||||
(Some(left), None) => {
|
(Some(Either::Right(r)), x) => {
|
||||||
break Some(EitherOrBoth::Left(
|
acc = f(acc, x);
|
||||||
self.left.into_parts().1.last().unwrap_or(left),
|
left = self.left.next();
|
||||||
))
|
right = Some(r);
|
||||||
}
|
|
||||||
(None, Some(right)) => {
|
|
||||||
break Some(EitherOrBoth::Right(
|
|
||||||
self.right.into_parts().1.last().unwrap_or(right),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
(Some(left), Some(right)) => {
|
|
||||||
previous_element = match (self.cmp_fn)(&left, &right) {
|
|
||||||
Ordering::Equal => Some(EitherOrBoth::Both(left, right)),
|
|
||||||
Ordering::Less => {
|
|
||||||
self.right.put_back(right);
|
|
||||||
Some(EitherOrBoth::Left(left))
|
|
||||||
}
|
|
||||||
Ordering::Greater => {
|
|
||||||
self.left.put_back(left);
|
|
||||||
Some(EitherOrBoth::Right(right))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
(Some(Either::Left(l)), x) => {
|
||||||
|
acc = f(acc, x);
|
||||||
|
left = Some(l);
|
||||||
|
right = self.right.next();
|
||||||
|
}
|
||||||
|
(None, x) => {
|
||||||
|
acc = f(acc, x);
|
||||||
|
left = self.left.next();
|
||||||
|
right = self.right.next();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(Some(l), None) => {
|
||||||
|
self.left.put_back(l);
|
||||||
|
acc = self.left.fold(acc, |acc, x| f(acc, F::left(x)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
(None, Some(r)) => {
|
||||||
|
self.right.put_back(r);
|
||||||
|
acc = self.right.fold(acc, |acc, x| f(acc, F::right(x)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
(None, None) => {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> SizeHint {
|
||||||
|
F::size_hint(self.left.size_hint(), self.right.size_hint())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
|
fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
|
||||||
@@ -156,14 +320,29 @@ impl<I, J, F> Iterator for MergeJoinBy<I, J, F>
|
|||||||
n -= 1;
|
n -= 1;
|
||||||
match (self.left.next(), self.right.next()) {
|
match (self.left.next(), self.right.next()) {
|
||||||
(None, None) => break None,
|
(None, None) => break None,
|
||||||
(Some(_left), None) => break self.left.nth(n).map(EitherOrBoth::Left),
|
(Some(_left), None) => break self.left.nth(n).map(F::left),
|
||||||
(None, Some(_right)) => break self.right.nth(n).map(EitherOrBoth::Right),
|
(None, Some(_right)) => break self.right.nth(n).map(F::right),
|
||||||
(Some(left), Some(right)) => match (self.cmp_fn)(&left, &right) {
|
(Some(left), Some(right)) => {
|
||||||
Ordering::Equal => {}
|
let (not_next, _) = self.cmp_fn.merge(left, right);
|
||||||
Ordering::Less => self.right.put_back(right),
|
match not_next {
|
||||||
Ordering::Greater => self.left.put_back(left),
|
Some(Either::Left(l)) => {
|
||||||
},
|
self.left.put_back(l);
|
||||||
|
}
|
||||||
|
Some(Either::Right(r)) => {
|
||||||
|
self.right.put_back(r);
|
||||||
|
}
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<I, J, F> FusedIterator for MergeBy<I, J, F>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
J: Iterator,
|
||||||
|
F: OrderingOrBool<I::Item, J::Item>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|||||||
45
third_party/rust/itertools/src/minmax.rs
vendored
45
third_party/rust/itertools/src/minmax.rs
vendored
@@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
/// `MinMaxResult` is an enum returned by `minmax`.
|
/// `MinMaxResult` is an enum returned by `minmax`.
|
||||||
///
|
///
|
||||||
/// See [`.minmax()`](crate::Itertools::minmax) for more detail.
|
/// See [`.minmax()`](crate::Itertools::minmax) for more detail.
|
||||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum MinMaxResult<T> {
|
pub enum MinMaxResult<T> {
|
||||||
/// Empty iterator
|
/// Empty iterator
|
||||||
NoElements,
|
NoElements,
|
||||||
@@ -12,7 +11,7 @@ pub enum MinMaxResult<T> {
|
|||||||
|
|
||||||
/// More than one element in the iterator, the first element is not larger
|
/// More than one element in the iterator, the first element is not larger
|
||||||
/// than the second
|
/// than the second
|
||||||
MinMax(T, T)
|
MinMax(T, T),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone> MinMaxResult<T> {
|
impl<T: Clone> MinMaxResult<T> {
|
||||||
@@ -36,34 +35,36 @@ impl<T: Clone> MinMaxResult<T> {
|
|||||||
/// let r = MinMax(1, 2);
|
/// let r = MinMax(1, 2);
|
||||||
/// assert_eq!(r.into_option(), Some((1, 2)));
|
/// assert_eq!(r.into_option(), Some((1, 2)));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn into_option(self) -> Option<(T,T)> {
|
pub fn into_option(self) -> Option<(T, T)> {
|
||||||
match self {
|
match self {
|
||||||
MinMaxResult::NoElements => None,
|
Self::NoElements => None,
|
||||||
MinMaxResult::OneElement(x) => Some((x.clone(), x)),
|
Self::OneElement(x) => Some((x.clone(), x)),
|
||||||
MinMaxResult::MinMax(x, y) => Some((x, y))
|
Self::MinMax(x, y) => Some((x, y)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation guts for `minmax` and `minmax_by_key`.
|
/// Implementation guts for `minmax` and `minmax_by_key`.
|
||||||
pub fn minmax_impl<I, K, F, L>(mut it: I, mut key_for: F,
|
pub fn minmax_impl<I, K, F, L>(mut it: I, mut key_for: F, mut lt: L) -> MinMaxResult<I::Item>
|
||||||
mut lt: L) -> MinMaxResult<I::Item>
|
where
|
||||||
where I: Iterator,
|
I: Iterator,
|
||||||
F: FnMut(&I::Item) -> K,
|
F: FnMut(&I::Item) -> K,
|
||||||
L: FnMut(&I::Item, &I::Item, &K, &K) -> bool,
|
L: FnMut(&I::Item, &I::Item, &K, &K) -> bool,
|
||||||
{
|
{
|
||||||
let (mut min, mut max, mut min_key, mut max_key) = match it.next() {
|
let (mut min, mut max, mut min_key, mut max_key) = match it.next() {
|
||||||
None => return MinMaxResult::NoElements,
|
None => return MinMaxResult::NoElements,
|
||||||
Some(x) => {
|
Some(x) => match it.next() {
|
||||||
match it.next() {
|
None => return MinMaxResult::OneElement(x),
|
||||||
None => return MinMaxResult::OneElement(x),
|
Some(y) => {
|
||||||
Some(y) => {
|
let xk = key_for(&x);
|
||||||
let xk = key_for(&x);
|
let yk = key_for(&y);
|
||||||
let yk = key_for(&y);
|
if !lt(&y, &x, &yk, &xk) {
|
||||||
if !lt(&y, &x, &yk, &xk) {(x, y, xk, yk)} else {(y, x, yk, xk)}
|
(x, y, xk, yk)
|
||||||
|
} else {
|
||||||
|
(y, x, yk, xk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@@ -74,7 +75,7 @@ pub fn minmax_impl<I, K, F, L>(mut it: I, mut key_for: F,
|
|||||||
// for 2 elements.
|
// for 2 elements.
|
||||||
let first = match it.next() {
|
let first = match it.next() {
|
||||||
None => break,
|
None => break,
|
||||||
Some(x) => x
|
Some(x) => x,
|
||||||
};
|
};
|
||||||
let second = match it.next() {
|
let second = match it.next() {
|
||||||
None => {
|
None => {
|
||||||
@@ -86,7 +87,7 @@ pub fn minmax_impl<I, K, F, L>(mut it: I, mut key_for: F,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Some(x) => x
|
Some(x) => x,
|
||||||
};
|
};
|
||||||
let first_key = key_for(&first);
|
let first_key = key_for(&first);
|
||||||
let second_key = key_for(&second);
|
let second_key = key_for(&second);
|
||||||
|
|||||||
49
third_party/rust/itertools/src/multipeek_impl.rs
vendored
49
third_party/rust/itertools/src/multipeek_impl.rs
vendored
@@ -1,14 +1,16 @@
|
|||||||
use std::iter::Fuse;
|
|
||||||
use alloc::collections::VecDeque;
|
|
||||||
use crate::size_hint;
|
use crate::size_hint;
|
||||||
use crate::PeekingNext;
|
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
use crate::Itertools;
|
use crate::Itertools;
|
||||||
|
use crate::PeekingNext;
|
||||||
|
use alloc::collections::VecDeque;
|
||||||
|
use std::iter::Fuse;
|
||||||
|
|
||||||
/// See [`multipeek()`] for more information.
|
/// See [`multipeek()`] for more information.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct MultiPeek<I>
|
pub struct MultiPeek<I>
|
||||||
where I: Iterator
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
iter: Fuse<I>,
|
iter: Fuse<I>,
|
||||||
buf: VecDeque<I::Item>,
|
buf: VecDeque<I::Item>,
|
||||||
@@ -20,7 +22,8 @@ pub struct MultiPeek<I>
|
|||||||
///
|
///
|
||||||
/// [`IntoIterator`] enabled version of [`Itertools::multipeek`].
|
/// [`IntoIterator`] enabled version of [`Itertools::multipeek`].
|
||||||
pub fn multipeek<I>(iterable: I) -> MultiPeek<I::IntoIter>
|
pub fn multipeek<I>(iterable: I) -> MultiPeek<I::IntoIter>
|
||||||
where I: IntoIterator
|
where
|
||||||
|
I: IntoIterator,
|
||||||
{
|
{
|
||||||
MultiPeek {
|
MultiPeek {
|
||||||
iter: iterable.into_iter().fuse(),
|
iter: iterable.into_iter().fuse(),
|
||||||
@@ -30,7 +33,8 @@ pub fn multipeek<I>(iterable: I) -> MultiPeek<I::IntoIter>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I> MultiPeek<I>
|
impl<I> MultiPeek<I>
|
||||||
where I: Iterator
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
/// Reset the peeking “cursor”
|
/// Reset the peeking “cursor”
|
||||||
pub fn reset_peek(&mut self) {
|
pub fn reset_peek(&mut self) {
|
||||||
@@ -62,24 +66,31 @@ impl<I: Iterator> MultiPeek<I> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I> PeekingNext for MultiPeek<I>
|
impl<I> PeekingNext for MultiPeek<I>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||||
where F: FnOnce(&Self::Item) -> bool
|
where
|
||||||
|
F: FnOnce(&Self::Item) -> bool,
|
||||||
{
|
{
|
||||||
if self.buf.is_empty() {
|
if self.buf.is_empty() {
|
||||||
if let Some(r) = self.peek() {
|
if let Some(r) = self.peek() {
|
||||||
if !accept(r) { return None }
|
if !accept(r) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let Some(r) = self.buf.front() {
|
||||||
|
if !accept(r) {
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
} else if let Some(r) = self.buf.get(0) {
|
|
||||||
if !accept(r) { return None }
|
|
||||||
}
|
}
|
||||||
self.next()
|
self.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Iterator for MultiPeek<I>
|
impl<I> Iterator for MultiPeek<I>
|
||||||
where I: Iterator
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
type Item = I::Item;
|
type Item = I::Item;
|
||||||
|
|
||||||
@@ -91,11 +102,15 @@ impl<I> Iterator for MultiPeek<I>
|
|||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
size_hint::add_scalar(self.iter.size_hint(), self.buf.len())
|
size_hint::add_scalar(self.iter.size_hint(), self.buf.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fold<B, F>(self, mut init: B, mut f: F) -> B
|
||||||
|
where
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
init = self.buf.into_iter().fold(init, &mut f);
|
||||||
|
self.iter.fold(init, f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same size
|
// Same size
|
||||||
impl<I> ExactSizeIterator for MultiPeek<I>
|
impl<I> ExactSizeIterator for MultiPeek<I> where I: ExactSizeIterator {}
|
||||||
where I: ExactSizeIterator
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
269
third_party/rust/itertools/src/next_array.rs
vendored
Normal file
269
third_party/rust/itertools/src/next_array.rs
vendored
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
use core::mem::{self, MaybeUninit};
|
||||||
|
|
||||||
|
/// An array of at most `N` elements.
|
||||||
|
struct ArrayBuilder<T, const N: usize> {
|
||||||
|
/// The (possibly uninitialized) elements of the `ArrayBuilder`.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The elements of `arr[..len]` are valid `T`s.
|
||||||
|
arr: [MaybeUninit<T>; N],
|
||||||
|
|
||||||
|
/// The number of leading elements of `arr` that are valid `T`s, len <= N.
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, const N: usize> ArrayBuilder<T, N> {
|
||||||
|
/// Initializes a new, empty `ArrayBuilder`.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
// SAFETY: The safety invariant of `arr` trivially holds for `len = 0`.
|
||||||
|
Self {
|
||||||
|
arr: [(); N].map(|_| MaybeUninit::uninit()),
|
||||||
|
len: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pushes `value` onto the end of the array.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// This panics if `self.len >= N`.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn push(&mut self, value: T) {
|
||||||
|
// PANICS: This will panic if `self.len >= N`.
|
||||||
|
let place = &mut self.arr[self.len];
|
||||||
|
// SAFETY: The safety invariant of `self.arr` applies to elements at
|
||||||
|
// indices `0..self.len` — not to the element at `self.len`. Writing to
|
||||||
|
// the element at index `self.len` therefore does not violate the safety
|
||||||
|
// invariant of `self.arr`. Even if this line panics, we have not
|
||||||
|
// created any intermediate invalid state.
|
||||||
|
*place = MaybeUninit::new(value);
|
||||||
|
// Lemma: `self.len < N`. By invariant, `self.len <= N`. Above, we index
|
||||||
|
// into `self.arr`, which has size `N`, at index `self.len`. If `self.len == N`
|
||||||
|
// at that point, that index would be out-of-bounds, and the index
|
||||||
|
// operation would panic. Thus, `self.len != N`, and since `self.len <= N`,
|
||||||
|
// that means that `self.len < N`.
|
||||||
|
//
|
||||||
|
// PANICS: Since `self.len < N`, and since `N <= usize::MAX`,
|
||||||
|
// `self.len + 1 <= usize::MAX`, and so `self.len += 1` will not
|
||||||
|
// overflow. Overflow is the only panic condition of `+=`.
|
||||||
|
//
|
||||||
|
// SAFETY:
|
||||||
|
// - We are required to uphold the invariant that `self.len <= N`.
|
||||||
|
// Since, by the preceding lemma, `self.len < N` at this point in the
|
||||||
|
// code, `self.len += 1` results in `self.len <= N`.
|
||||||
|
// - We are required to uphold the invariant that `self.arr[..self.len]`
|
||||||
|
// are valid instances of `T`. Since this invariant already held when
|
||||||
|
// this method was called, and since we only increment `self.len`
|
||||||
|
// by 1 here, we only need to prove that the element at
|
||||||
|
// `self.arr[self.len]` (using the value of `self.len` before incrementing)
|
||||||
|
// is valid. Above, we construct `place` to point to `self.arr[self.len]`,
|
||||||
|
// and then initialize `*place` to `MaybeUninit::new(value)`, which is
|
||||||
|
// a valid `T` by construction.
|
||||||
|
self.len += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consumes the elements in the `ArrayBuilder` and returns them as an array
|
||||||
|
/// `[T; N]`.
|
||||||
|
///
|
||||||
|
/// If `self.len() < N`, this returns `None`.
|
||||||
|
pub fn take(&mut self) -> Option<[T; N]> {
|
||||||
|
if self.len == N {
|
||||||
|
// SAFETY: Decreasing the value of `self.len` cannot violate the
|
||||||
|
// safety invariant on `self.arr`.
|
||||||
|
self.len = 0;
|
||||||
|
|
||||||
|
// SAFETY: Since `self.len` is 0, `self.arr` may safely contain
|
||||||
|
// uninitialized elements.
|
||||||
|
let arr = mem::replace(&mut self.arr, [(); N].map(|_| MaybeUninit::uninit()));
|
||||||
|
|
||||||
|
Some(arr.map(|v| {
|
||||||
|
// SAFETY: We know that all elements of `arr` are valid because
|
||||||
|
// we checked that `len == N`.
|
||||||
|
unsafe { v.assume_init() }
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, const N: usize> AsMut<[T]> for ArrayBuilder<T, N> {
|
||||||
|
fn as_mut(&mut self) -> &mut [T] {
|
||||||
|
let valid = &mut self.arr[..self.len];
|
||||||
|
// SAFETY: By invariant on `self.arr`, the elements of `self.arr` at
|
||||||
|
// indices `0..self.len` are in a valid state. Since `valid` references
|
||||||
|
// only these elements, the safety precondition of
|
||||||
|
// `slice_assume_init_mut` is satisfied.
|
||||||
|
unsafe { slice_assume_init_mut(valid) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, const N: usize> Drop for ArrayBuilder<T, N> {
|
||||||
|
// We provide a non-trivial `Drop` impl, because the trivial impl would be a
|
||||||
|
// no-op; `MaybeUninit<T>` has no innate awareness of its own validity, and
|
||||||
|
// so it can only forget its contents. By leveraging the safety invariant of
|
||||||
|
// `self.arr`, we do know which elements of `self.arr` are valid, and can
|
||||||
|
// selectively run their destructors.
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// SAFETY:
|
||||||
|
// - by invariant on `&mut [T]`, `self.as_mut()` is:
|
||||||
|
// - valid for reads and writes
|
||||||
|
// - properly aligned
|
||||||
|
// - non-null
|
||||||
|
// - the dropped `T` are valid for dropping; they do not have any
|
||||||
|
// additional library invariants that we've violated
|
||||||
|
// - no other pointers to `valid` exist (since we're in the context of
|
||||||
|
// `drop`)
|
||||||
|
unsafe { core::ptr::drop_in_place(self.as_mut()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assuming all the elements are initialized, get a mutable slice to them.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller guarantees that the elements `T` referenced by `slice` are in a
|
||||||
|
/// valid state.
|
||||||
|
unsafe fn slice_assume_init_mut<T>(slice: &mut [MaybeUninit<T>]) -> &mut [T] {
|
||||||
|
// SAFETY: Casting `&mut [MaybeUninit<T>]` to `&mut [T]` is sound, because
|
||||||
|
// `MaybeUninit<T>` is guaranteed to have the same size, alignment and ABI
|
||||||
|
// as `T`, and because the caller has guaranteed that `slice` is in the
|
||||||
|
// valid state.
|
||||||
|
unsafe { &mut *(slice as *mut [MaybeUninit<T>] as *mut [T]) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Equivalent to `it.next_array()`.
|
||||||
|
pub(crate) fn next_array<I, const N: usize>(it: &mut I) -> Option<[I::Item; N]>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
{
|
||||||
|
let mut builder = ArrayBuilder::new();
|
||||||
|
for _ in 0..N {
|
||||||
|
builder.push(it.next()?);
|
||||||
|
}
|
||||||
|
builder.take()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::ArrayBuilder;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn zero_len_take() {
|
||||||
|
let mut builder = ArrayBuilder::<(), 0>::new();
|
||||||
|
let taken = builder.take();
|
||||||
|
assert_eq!(taken, Some([(); 0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn zero_len_push() {
|
||||||
|
let mut builder = ArrayBuilder::<(), 0>::new();
|
||||||
|
builder.push(());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn push_4() {
|
||||||
|
let mut builder = ArrayBuilder::<(), 4>::new();
|
||||||
|
assert_eq!(builder.take(), None);
|
||||||
|
|
||||||
|
builder.push(());
|
||||||
|
assert_eq!(builder.take(), None);
|
||||||
|
|
||||||
|
builder.push(());
|
||||||
|
assert_eq!(builder.take(), None);
|
||||||
|
|
||||||
|
builder.push(());
|
||||||
|
assert_eq!(builder.take(), None);
|
||||||
|
|
||||||
|
builder.push(());
|
||||||
|
assert_eq!(builder.take(), Some([(); 4]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tracked_drop() {
|
||||||
|
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||||
|
use std::sync::atomic::{AtomicU16, Ordering};
|
||||||
|
|
||||||
|
static DROPPED: AtomicU16 = AtomicU16::new(0);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
struct TrackedDrop;
|
||||||
|
|
||||||
|
impl Drop for TrackedDrop {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
DROPPED.fetch_add(1, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let builder = ArrayBuilder::<TrackedDrop, 0>::new();
|
||||||
|
assert_eq!(DROPPED.load(Ordering::Relaxed), 0);
|
||||||
|
drop(builder);
|
||||||
|
assert_eq!(DROPPED.load(Ordering::Relaxed), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut builder = ArrayBuilder::<TrackedDrop, 2>::new();
|
||||||
|
builder.push(TrackedDrop);
|
||||||
|
assert_eq!(builder.take(), None);
|
||||||
|
assert_eq!(DROPPED.load(Ordering::Relaxed), 0);
|
||||||
|
drop(builder);
|
||||||
|
assert_eq!(DROPPED.swap(0, Ordering::Relaxed), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut builder = ArrayBuilder::<TrackedDrop, 2>::new();
|
||||||
|
builder.push(TrackedDrop);
|
||||||
|
builder.push(TrackedDrop);
|
||||||
|
assert!(matches!(builder.take(), Some(_)));
|
||||||
|
assert_eq!(DROPPED.swap(0, Ordering::Relaxed), 2);
|
||||||
|
drop(builder);
|
||||||
|
assert_eq!(DROPPED.load(Ordering::Relaxed), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut builder = ArrayBuilder::<TrackedDrop, 2>::new();
|
||||||
|
|
||||||
|
builder.push(TrackedDrop);
|
||||||
|
builder.push(TrackedDrop);
|
||||||
|
|
||||||
|
assert!(catch_unwind(AssertUnwindSafe(|| {
|
||||||
|
builder.push(TrackedDrop);
|
||||||
|
}))
|
||||||
|
.is_err());
|
||||||
|
|
||||||
|
assert_eq!(DROPPED.load(Ordering::Relaxed), 1);
|
||||||
|
|
||||||
|
drop(builder);
|
||||||
|
|
||||||
|
assert_eq!(DROPPED.swap(0, Ordering::Relaxed), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut builder = ArrayBuilder::<TrackedDrop, 2>::new();
|
||||||
|
|
||||||
|
builder.push(TrackedDrop);
|
||||||
|
builder.push(TrackedDrop);
|
||||||
|
|
||||||
|
assert!(catch_unwind(AssertUnwindSafe(|| {
|
||||||
|
builder.push(TrackedDrop);
|
||||||
|
}))
|
||||||
|
.is_err());
|
||||||
|
|
||||||
|
assert_eq!(DROPPED.load(Ordering::Relaxed), 1);
|
||||||
|
|
||||||
|
assert!(matches!(builder.take(), Some(_)));
|
||||||
|
|
||||||
|
assert_eq!(DROPPED.load(Ordering::Relaxed), 3);
|
||||||
|
|
||||||
|
builder.push(TrackedDrop);
|
||||||
|
builder.push(TrackedDrop);
|
||||||
|
|
||||||
|
assert!(matches!(builder.take(), Some(_)));
|
||||||
|
|
||||||
|
assert_eq!(DROPPED.swap(0, Ordering::Relaxed), 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
third_party/rust/itertools/src/pad_tail.rs
vendored
58
third_party/rust/itertools/src/pad_tail.rs
vendored
@@ -1,5 +1,5 @@
|
|||||||
use std::iter::{Fuse, FusedIterator};
|
|
||||||
use crate::size_hint;
|
use crate::size_hint;
|
||||||
|
use std::iter::{Fuse, FusedIterator};
|
||||||
|
|
||||||
/// An iterator adaptor that pads a sequence to a minimum length by filling
|
/// An iterator adaptor that pads a sequence to a minimum length by filling
|
||||||
/// missing elements using a closure.
|
/// missing elements using a closure.
|
||||||
@@ -25,8 +25,9 @@ where
|
|||||||
|
|
||||||
/// Create a new `PadUsing` iterator.
|
/// 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, min: usize, filler: F) -> PadUsing<I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
F: FnMut(usize) -> I::Item
|
I: Iterator,
|
||||||
|
F: FnMut(usize) -> I::Item,
|
||||||
{
|
{
|
||||||
PadUsing {
|
PadUsing {
|
||||||
iter: iter.fuse(),
|
iter: iter.fuse(),
|
||||||
@@ -37,8 +38,9 @@ pub fn pad_using<I, F>(iter: I, min: usize, filler: F) -> PadUsing<I, F>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I, F> Iterator for PadUsing<I, F>
|
impl<I, F> Iterator for PadUsing<I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
F: FnMut(usize) -> I::Item
|
I: Iterator,
|
||||||
|
F: FnMut(usize) -> I::Item,
|
||||||
{
|
{
|
||||||
type Item = I::Item;
|
type Item = I::Item;
|
||||||
|
|
||||||
@@ -53,7 +55,7 @@ impl<I, F> Iterator for PadUsing<I, F>
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
e => {
|
e => {
|
||||||
self.pos += 1;
|
self.pos += 1;
|
||||||
e
|
e
|
||||||
@@ -65,11 +67,24 @@ impl<I, F> Iterator for PadUsing<I, F>
|
|||||||
let tail = self.min.saturating_sub(self.pos);
|
let tail = self.min.saturating_sub(self.pos);
|
||||||
size_hint::max(self.iter.size_hint(), (tail, Some(tail)))
|
size_hint::max(self.iter.size_hint(), (tail, Some(tail)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, F> DoubleEndedIterator for PadUsing<I, F>
|
impl<I, F> DoubleEndedIterator for PadUsing<I, F>
|
||||||
where I: DoubleEndedIterator + ExactSizeIterator,
|
where
|
||||||
F: FnMut(usize) -> I::Item
|
I: DoubleEndedIterator + ExactSizeIterator,
|
||||||
|
F: FnMut(usize) -> I::Item,
|
||||||
{
|
{
|
||||||
fn next_back(&mut self) -> Option<Self::Item> {
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
if self.min == 0 {
|
if self.min == 0 {
|
||||||
@@ -82,15 +97,28 @@ impl<I, F> DoubleEndedIterator for PadUsing<I, F>
|
|||||||
Some((self.filler)(self.min))
|
Some((self.filler)(self.min))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, F> ExactSizeIterator for PadUsing<I, F>
|
impl<I, F> ExactSizeIterator for PadUsing<I, F>
|
||||||
where I: ExactSizeIterator,
|
where
|
||||||
F: FnMut(usize) -> I::Item
|
I: ExactSizeIterator,
|
||||||
{}
|
F: FnMut(usize) -> I::Item,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
impl<I, F> FusedIterator for PadUsing<I, F>
|
impl<I, F> FusedIterator for PadUsing<I, F>
|
||||||
where I: FusedIterator,
|
where
|
||||||
F: FnMut(usize) -> I::Item
|
I: FusedIterator,
|
||||||
{}
|
F: FnMut(usize) -> I::Item,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|||||||
94
third_party/rust/itertools/src/peek_nth.rs
vendored
94
third_party/rust/itertools/src/peek_nth.rs
vendored
@@ -5,6 +5,7 @@ use std::iter::Fuse;
|
|||||||
|
|
||||||
/// See [`peek_nth()`] for more information.
|
/// See [`peek_nth()`] for more information.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct PeekNth<I>
|
pub struct PeekNth<I>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
@@ -34,30 +35,35 @@ impl<I> PeekNth<I>
|
|||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
{
|
{
|
||||||
/// Works exactly like the `peek` method in `std::iter::Peekable`
|
/// Works exactly like the `peek` method in [`std::iter::Peekable`].
|
||||||
pub fn peek(&mut self) -> Option<&I::Item> {
|
pub fn peek(&mut self) -> Option<&I::Item> {
|
||||||
self.peek_nth(0)
|
self.peek_nth(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Works exactly like the `peek_mut` method in [`std::iter::Peekable`].
|
||||||
|
pub fn peek_mut(&mut self) -> Option<&mut I::Item> {
|
||||||
|
self.peek_nth_mut(0)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a reference to the `nth` value without advancing the iterator.
|
/// Returns a reference to the `nth` value without advancing the iterator.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// Basic usage:
|
/// Basic usage:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```
|
||||||
/// use itertools::peek_nth;
|
/// use itertools::peek_nth;
|
||||||
///
|
///
|
||||||
/// let xs = vec![1,2,3];
|
/// let xs = vec![1, 2, 3];
|
||||||
/// let mut iter = peek_nth(xs.iter());
|
/// let mut iter = peek_nth(xs.into_iter());
|
||||||
///
|
///
|
||||||
/// assert_eq!(iter.peek_nth(0), Some(&&1));
|
/// assert_eq!(iter.peek_nth(0), Some(&1));
|
||||||
/// assert_eq!(iter.next(), Some(&1));
|
/// assert_eq!(iter.next(), Some(1));
|
||||||
///
|
///
|
||||||
/// // The iterator does not advance even if we call `peek_nth` multiple times
|
/// // The iterator does not advance even if we call `peek_nth` multiple times
|
||||||
/// assert_eq!(iter.peek_nth(0), Some(&&2));
|
/// assert_eq!(iter.peek_nth(0), Some(&2));
|
||||||
/// assert_eq!(iter.peek_nth(1), Some(&&3));
|
/// assert_eq!(iter.peek_nth(1), Some(&3));
|
||||||
/// assert_eq!(iter.next(), Some(&2));
|
/// assert_eq!(iter.next(), Some(2));
|
||||||
///
|
///
|
||||||
/// // Calling `peek_nth` past the end of the iterator will return `None`
|
/// // Calling `peek_nth` past the end of the iterator will return `None`
|
||||||
/// assert_eq!(iter.peek_nth(1), None);
|
/// assert_eq!(iter.peek_nth(1), None);
|
||||||
@@ -69,6 +75,68 @@ where
|
|||||||
|
|
||||||
self.buf.get(n)
|
self.buf.get(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable reference to the `nth` value without advancing the iterator.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Basic usage:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use itertools::peek_nth;
|
||||||
|
///
|
||||||
|
/// let xs = vec![1, 2, 3, 4, 5];
|
||||||
|
/// let mut iter = peek_nth(xs.into_iter());
|
||||||
|
///
|
||||||
|
/// assert_eq!(iter.peek_nth_mut(0), Some(&mut 1));
|
||||||
|
/// assert_eq!(iter.next(), Some(1));
|
||||||
|
///
|
||||||
|
/// // The iterator does not advance even if we call `peek_nth_mut` multiple times
|
||||||
|
/// assert_eq!(iter.peek_nth_mut(0), Some(&mut 2));
|
||||||
|
/// assert_eq!(iter.peek_nth_mut(1), Some(&mut 3));
|
||||||
|
/// assert_eq!(iter.next(), Some(2));
|
||||||
|
///
|
||||||
|
/// // Peek into the iterator and set the value behind the mutable reference.
|
||||||
|
/// if let Some(p) = iter.peek_nth_mut(1) {
|
||||||
|
/// assert_eq!(*p, 4);
|
||||||
|
/// *p = 9;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // The value we put in reappears as the iterator continues.
|
||||||
|
/// assert_eq!(iter.next(), Some(3));
|
||||||
|
/// assert_eq!(iter.next(), Some(9));
|
||||||
|
///
|
||||||
|
/// // Calling `peek_nth_mut` past the end of the iterator will return `None`
|
||||||
|
/// assert_eq!(iter.peek_nth_mut(1), None);
|
||||||
|
/// ```
|
||||||
|
pub fn peek_nth_mut(&mut self, n: usize) -> Option<&mut I::Item> {
|
||||||
|
let unbuffered_items = (n + 1).saturating_sub(self.buf.len());
|
||||||
|
|
||||||
|
self.buf.extend(self.iter.by_ref().take(unbuffered_items));
|
||||||
|
|
||||||
|
self.buf.get_mut(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Works exactly like the `next_if` method in [`std::iter::Peekable`].
|
||||||
|
pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> {
|
||||||
|
match self.next() {
|
||||||
|
Some(item) if func(&item) => Some(item),
|
||||||
|
Some(item) => {
|
||||||
|
self.buf.push_front(item);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Works exactly like the `next_if_eq` method in [`std::iter::Peekable`].
|
||||||
|
pub fn next_if_eq<T>(&mut self, expected: &T) -> Option<I::Item>
|
||||||
|
where
|
||||||
|
T: ?Sized,
|
||||||
|
I::Item: PartialEq<T>,
|
||||||
|
{
|
||||||
|
self.next_if(|next| next == expected)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Iterator for PeekNth<I>
|
impl<I> Iterator for PeekNth<I>
|
||||||
@@ -84,6 +152,14 @@ where
|
|||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
size_hint::add_scalar(self.iter.size_hint(), self.buf.len())
|
size_hint::add_scalar(self.iter.size_hint(), self.buf.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fold<B, F>(self, mut init: B, mut f: F) -> B
|
||||||
|
where
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
init = self.buf.into_iter().fold(init, &mut f);
|
||||||
|
self.iter.fold(init, f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> ExactSizeIterator for PeekNth<I> where I: ExactSizeIterator {}
|
impl<I> ExactSizeIterator for PeekNth<I> where I: ExactSizeIterator {}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use std::iter::Peekable;
|
|
||||||
use crate::PutBack;
|
use crate::PutBack;
|
||||||
#[cfg(feature = "use_alloc")]
|
#[cfg(feature = "use_alloc")]
|
||||||
use crate::PutBackN;
|
use crate::PutBackN;
|
||||||
|
use crate::RepeatN;
|
||||||
|
use std::iter::Peekable;
|
||||||
|
|
||||||
/// An iterator that allows peeking at an element before deciding to accept it.
|
/// An iterator that allows peeking at an element before deciding to accept it.
|
||||||
///
|
///
|
||||||
@@ -10,20 +11,36 @@ use crate::PutBackN;
|
|||||||
///
|
///
|
||||||
/// This is implemented by peeking adaptors like peekable and put back,
|
/// This is implemented by peeking adaptors like peekable and put back,
|
||||||
/// but also by a few iterators that can be peeked natively, like the slice’s
|
/// but also by a few iterators that can be peeked natively, like the slice’s
|
||||||
/// by reference iterator (`std::slice::Iter`).
|
/// by reference iterator ([`std::slice::Iter`]).
|
||||||
pub trait PeekingNext : Iterator {
|
pub trait PeekingNext: Iterator {
|
||||||
/// Pass a reference to the next iterator element to the closure `accept`;
|
/// Pass a reference to the next iterator element to the closure `accept`;
|
||||||
/// if `accept` returns true, return it as the next element,
|
/// if `accept` returns `true`, return it as the next element,
|
||||||
/// else None.
|
/// else `None`.
|
||||||
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||||
where F: FnOnce(&Self::Item) -> bool;
|
where
|
||||||
|
Self: Sized,
|
||||||
|
F: FnOnce(&Self::Item) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> PeekingNext for &mut I
|
||||||
|
where
|
||||||
|
I: PeekingNext,
|
||||||
|
{
|
||||||
|
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||||
|
where
|
||||||
|
F: FnOnce(&Self::Item) -> bool,
|
||||||
|
{
|
||||||
|
(*self).peeking_next(accept)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> PeekingNext for Peekable<I>
|
impl<I> PeekingNext for Peekable<I>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||||
where F: FnOnce(&Self::Item) -> bool
|
where
|
||||||
|
F: FnOnce(&Self::Item) -> bool,
|
||||||
{
|
{
|
||||||
if let Some(r) = self.peek() {
|
if let Some(r) = self.peek() {
|
||||||
if !accept(r) {
|
if !accept(r) {
|
||||||
@@ -35,10 +52,12 @@ impl<I> PeekingNext for Peekable<I>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I> PeekingNext for PutBack<I>
|
impl<I> PeekingNext for PutBack<I>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||||
where F: FnOnce(&Self::Item) -> bool
|
where
|
||||||
|
F: FnOnce(&Self::Item) -> bool,
|
||||||
{
|
{
|
||||||
if let Some(r) = self.next() {
|
if let Some(r) = self.next() {
|
||||||
if !accept(&r) {
|
if !accept(&r) {
|
||||||
@@ -54,10 +73,12 @@ impl<I> PeekingNext for PutBack<I>
|
|||||||
|
|
||||||
#[cfg(feature = "use_alloc")]
|
#[cfg(feature = "use_alloc")]
|
||||||
impl<I> PeekingNext for PutBackN<I>
|
impl<I> PeekingNext for PutBackN<I>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||||
where F: FnOnce(&Self::Item) -> bool
|
where
|
||||||
|
F: FnOnce(&Self::Item) -> bool,
|
||||||
{
|
{
|
||||||
if let Some(r) = self.next() {
|
if let Some(r) = self.next() {
|
||||||
if !accept(&r) {
|
if !accept(&r) {
|
||||||
@@ -71,39 +92,51 @@ impl<I> PeekingNext for PutBackN<I>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Clone> PeekingNext for RepeatN<T> {
|
||||||
|
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||||
|
where
|
||||||
|
F: FnOnce(&Self::Item) -> bool,
|
||||||
|
{
|
||||||
|
let r = self.elt.as_ref()?;
|
||||||
|
if !accept(r) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
self.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An iterator adaptor that takes items while a closure returns `true`.
|
/// An iterator adaptor that takes items while a closure returns `true`.
|
||||||
///
|
///
|
||||||
/// See [`.peeking_take_while()`](crate::Itertools::peeking_take_while)
|
/// See [`.peeking_take_while()`](crate::Itertools::peeking_take_while)
|
||||||
/// for more information.
|
/// for more information.
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct PeekingTakeWhile<'a, I: 'a, F>
|
pub struct PeekingTakeWhile<'a, I, F>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator + 'a,
|
||||||
{
|
{
|
||||||
iter: &'a mut I,
|
iter: &'a mut I,
|
||||||
f: F,
|
f: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I: 'a, F> std::fmt::Debug for PeekingTakeWhile<'a, I, F>
|
impl<'a, I, F> std::fmt::Debug for PeekingTakeWhile<'a, I, F>
|
||||||
where
|
where
|
||||||
I: Iterator + std::fmt::Debug,
|
I: Iterator + std::fmt::Debug + 'a,
|
||||||
{
|
{
|
||||||
debug_fmt_fields!(PeekingTakeWhile, iter);
|
debug_fmt_fields!(PeekingTakeWhile, iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a `PeekingTakeWhile`
|
/// 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,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
PeekingTakeWhile {
|
PeekingTakeWhile { iter, f }
|
||||||
iter,
|
|
||||||
f,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I, F> Iterator for PeekingTakeWhile<'a, I, F>
|
impl<I, F> Iterator for PeekingTakeWhile<'_, I, F>
|
||||||
where I: PeekingNext,
|
where
|
||||||
F: FnMut(&I::Item) -> bool,
|
I: PeekingNext,
|
||||||
|
F: FnMut(&I::Item) -> bool,
|
||||||
{
|
{
|
||||||
type Item = I::Item;
|
type Item = I::Item;
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
@@ -115,6 +148,20 @@ impl<'a, I, F> Iterator for PeekingTakeWhile<'a, I, F>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<I, F> PeekingNext for PeekingTakeWhile<'_, I, F>
|
||||||
|
where
|
||||||
|
I: PeekingNext,
|
||||||
|
F: FnMut(&I::Item) -> bool,
|
||||||
|
{
|
||||||
|
fn peeking_next<G>(&mut self, g: G) -> Option<Self::Item>
|
||||||
|
where
|
||||||
|
G: FnOnce(&Self::Item) -> bool,
|
||||||
|
{
|
||||||
|
let f = &mut self.f;
|
||||||
|
self.iter.peeking_next(|r| f(r) && g(r))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Some iterators are so lightweight we can simply clone them to save their
|
// Some iterators are so lightweight we can simply clone them to save their
|
||||||
// state and use that for peeking.
|
// state and use that for peeking.
|
||||||
macro_rules! peeking_next_by_clone {
|
macro_rules! peeking_next_by_clone {
|
||||||
@@ -151,4 +198,4 @@ peeking_next_by_clone! { ['a, T] alloc::collections::vec_deque::Iter<'a, T> }
|
|||||||
|
|
||||||
// cloning a Rev has no extra overhead; peekable and put backs are never DEI.
|
// cloning a Rev has no extra overhead; peekable and put backs are never DEI.
|
||||||
peeking_next_by_clone! { [I: Clone + PeekingNext + DoubleEndedIterator]
|
peeking_next_by_clone! { [I: Clone + PeekingNext + DoubleEndedIterator]
|
||||||
::std::iter::Rev<I> }
|
::std::iter::Rev<I> }
|
||||||
|
|||||||
329
third_party/rust/itertools/src/permutations.rs
vendored
329
third_party/rust/itertools/src/permutations.rs
vendored
@@ -1,8 +1,11 @@
|
|||||||
|
use alloc::boxed::Box;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
|
use std::iter::FusedIterator;
|
||||||
|
|
||||||
use super::lazy_buffer::LazyBuffer;
|
use super::lazy_buffer::LazyBuffer;
|
||||||
|
use crate::size_hint::{self, SizeHint};
|
||||||
|
|
||||||
/// An iterator adaptor that iterates through all the `k`-permutations of the
|
/// An iterator adaptor that iterates through all the `k`-permutations of the
|
||||||
/// elements from an iterator.
|
/// elements from an iterator.
|
||||||
@@ -16,262 +19,168 @@ pub struct Permutations<I: Iterator> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Clone for Permutations<I>
|
impl<I> Clone for Permutations<I>
|
||||||
where I: Clone + Iterator,
|
where
|
||||||
I::Item: Clone,
|
I: Clone + Iterator,
|
||||||
|
I::Item: Clone,
|
||||||
{
|
{
|
||||||
clone_fields!(vals, state);
|
clone_fields!(vals, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
enum PermutationState {
|
enum PermutationState {
|
||||||
StartUnknownLen {
|
/// No permutation generated yet.
|
||||||
k: usize,
|
Start { k: usize },
|
||||||
|
/// Values from the iterator are not fully loaded yet so `n` is still unknown.
|
||||||
|
Buffered { k: usize, min_n: usize },
|
||||||
|
/// All values from the iterator are known so `n` is known.
|
||||||
|
Loaded {
|
||||||
|
indices: Box<[usize]>,
|
||||||
|
cycles: Box<[usize]>,
|
||||||
},
|
},
|
||||||
OngoingUnknownLen {
|
/// No permutation left to generate.
|
||||||
k: usize,
|
End,
|
||||||
min_n: usize,
|
|
||||||
},
|
|
||||||
Complete(CompleteState),
|
|
||||||
Empty,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
enum CompleteState {
|
|
||||||
Start {
|
|
||||||
n: usize,
|
|
||||||
k: usize,
|
|
||||||
},
|
|
||||||
Ongoing {
|
|
||||||
indices: Vec<usize>,
|
|
||||||
cycles: Vec<usize>,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum CompleteStateRemaining {
|
|
||||||
Known(usize),
|
|
||||||
Overflow,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> fmt::Debug for Permutations<I>
|
impl<I> fmt::Debug for Permutations<I>
|
||||||
where I: Iterator + fmt::Debug,
|
where
|
||||||
I::Item: fmt::Debug,
|
I: Iterator + fmt::Debug,
|
||||||
|
I::Item: fmt::Debug,
|
||||||
{
|
{
|
||||||
debug_fmt_fields!(Permutations, vals, state);
|
debug_fmt_fields!(Permutations, vals, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn permutations<I: Iterator>(iter: I, k: usize) -> Permutations<I> {
|
pub fn permutations<I: Iterator>(iter: I, k: usize) -> Permutations<I> {
|
||||||
let mut vals = LazyBuffer::new(iter);
|
|
||||||
|
|
||||||
if k == 0 {
|
|
||||||
// Special case, yields single empty vec; `n` is irrelevant
|
|
||||||
let state = PermutationState::Complete(CompleteState::Start { n: 0, k: 0 });
|
|
||||||
|
|
||||||
return Permutations {
|
|
||||||
vals,
|
|
||||||
state
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut enough_vals = true;
|
|
||||||
|
|
||||||
while vals.len() < k {
|
|
||||||
if !vals.get_next() {
|
|
||||||
enough_vals = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let state = if enough_vals {
|
|
||||||
PermutationState::StartUnknownLen { k }
|
|
||||||
} else {
|
|
||||||
PermutationState::Empty
|
|
||||||
};
|
|
||||||
|
|
||||||
Permutations {
|
Permutations {
|
||||||
vals,
|
vals: LazyBuffer::new(iter),
|
||||||
state
|
state: PermutationState::Start { k },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Iterator for Permutations<I>
|
impl<I> Iterator for Permutations<I>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
I::Item: Clone
|
I::Item: Clone,
|
||||||
{
|
{
|
||||||
type Item = Vec<I::Item>;
|
type Item = Vec<I::Item>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
self.advance();
|
let Self { vals, state } = self;
|
||||||
|
match state {
|
||||||
let &mut Permutations { ref vals, ref state } = self;
|
PermutationState::Start { k: 0 } => {
|
||||||
|
*state = PermutationState::End;
|
||||||
match *state {
|
Some(Vec::new())
|
||||||
PermutationState::StartUnknownLen { .. } => panic!("unexpected iterator state"),
|
|
||||||
PermutationState::OngoingUnknownLen { k, min_n } => {
|
|
||||||
let latest_idx = min_n - 1;
|
|
||||||
let indices = (0..(k - 1)).chain(once(latest_idx));
|
|
||||||
|
|
||||||
Some(indices.map(|i| vals[i].clone()).collect())
|
|
||||||
}
|
}
|
||||||
PermutationState::Complete(CompleteState::Ongoing { ref indices, ref cycles }) => {
|
&mut PermutationState::Start { k } => {
|
||||||
|
vals.prefill(k);
|
||||||
|
if vals.len() != k {
|
||||||
|
*state = PermutationState::End;
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
*state = PermutationState::Buffered { k, min_n: k };
|
||||||
|
Some(vals[0..k].to_vec())
|
||||||
|
}
|
||||||
|
PermutationState::Buffered { ref k, min_n } => {
|
||||||
|
if vals.get_next() {
|
||||||
|
let item = (0..*k - 1)
|
||||||
|
.chain(once(*min_n))
|
||||||
|
.map(|i| vals[i].clone())
|
||||||
|
.collect();
|
||||||
|
*min_n += 1;
|
||||||
|
Some(item)
|
||||||
|
} else {
|
||||||
|
let n = *min_n;
|
||||||
|
let prev_iteration_count = n - *k + 1;
|
||||||
|
let mut indices: Box<[_]> = (0..n).collect();
|
||||||
|
let mut cycles: Box<[_]> = (n - k..n).rev().collect();
|
||||||
|
// Advance the state to the correct point.
|
||||||
|
for _ in 0..prev_iteration_count {
|
||||||
|
if advance(&mut indices, &mut cycles) {
|
||||||
|
*state = PermutationState::End;
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let item = vals.get_at(&indices[0..*k]);
|
||||||
|
*state = PermutationState::Loaded { indices, cycles };
|
||||||
|
Some(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PermutationState::Loaded { indices, cycles } => {
|
||||||
|
if advance(indices, cycles) {
|
||||||
|
*state = PermutationState::End;
|
||||||
|
return None;
|
||||||
|
}
|
||||||
let k = cycles.len();
|
let k = cycles.len();
|
||||||
Some(indices[0..k].iter().map(|&i| vals[i].clone()).collect())
|
Some(vals.get_at(&indices[0..k]))
|
||||||
},
|
}
|
||||||
PermutationState::Complete(CompleteState::Start { .. }) | PermutationState::Empty => None
|
PermutationState::End => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count(self) -> usize {
|
fn count(self) -> usize {
|
||||||
fn from_complete(complete_state: CompleteState) -> usize {
|
let Self { vals, state } = self;
|
||||||
match complete_state.remaining() {
|
let n = vals.count();
|
||||||
CompleteStateRemaining::Known(count) => count,
|
state.size_hint_for(n).1.unwrap()
|
||||||
CompleteStateRemaining::Overflow => {
|
|
||||||
panic!("Iterator count greater than usize::MAX");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let Permutations { vals, state } = self;
|
|
||||||
match state {
|
|
||||||
PermutationState::StartUnknownLen { k } => {
|
|
||||||
let n = vals.len() + vals.it.count();
|
|
||||||
let complete_state = CompleteState::Start { n, k };
|
|
||||||
|
|
||||||
from_complete(complete_state)
|
|
||||||
}
|
|
||||||
PermutationState::OngoingUnknownLen { k, min_n } => {
|
|
||||||
let prev_iteration_count = min_n - k + 1;
|
|
||||||
let n = vals.len() + vals.it.count();
|
|
||||||
let complete_state = CompleteState::Start { n, k };
|
|
||||||
|
|
||||||
from_complete(complete_state) - prev_iteration_count
|
|
||||||
},
|
|
||||||
PermutationState::Complete(state) => from_complete(state),
|
|
||||||
PermutationState::Empty => 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> SizeHint {
|
||||||
match self.state {
|
let (mut low, mut upp) = self.vals.size_hint();
|
||||||
PermutationState::StartUnknownLen { .. } |
|
low = self.state.size_hint_for(low).0;
|
||||||
PermutationState::OngoingUnknownLen { .. } => (0, None), // TODO can we improve this lower bound?
|
upp = upp.and_then(|n| self.state.size_hint_for(n).1);
|
||||||
PermutationState::Complete(ref state) => match state.remaining() {
|
(low, upp)
|
||||||
CompleteStateRemaining::Known(count) => (count, Some(count)),
|
|
||||||
CompleteStateRemaining::Overflow => (::std::usize::MAX, None)
|
|
||||||
}
|
|
||||||
PermutationState::Empty => (0, Some(0))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Permutations<I>
|
impl<I> FusedIterator for Permutations<I>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
I::Item: Clone
|
I::Item: Clone,
|
||||||
{
|
{
|
||||||
fn advance(&mut self) {
|
}
|
||||||
let &mut Permutations { ref mut vals, ref mut state } = self;
|
|
||||||
|
|
||||||
*state = match *state {
|
fn advance(indices: &mut [usize], cycles: &mut [usize]) -> bool {
|
||||||
PermutationState::StartUnknownLen { k } => {
|
let n = indices.len();
|
||||||
PermutationState::OngoingUnknownLen { k, min_n: k }
|
let k = cycles.len();
|
||||||
}
|
// NOTE: if `cycles` are only zeros, then we reached the last permutation.
|
||||||
PermutationState::OngoingUnknownLen { k, min_n } => {
|
for i in (0..k).rev() {
|
||||||
if vals.get_next() {
|
if cycles[i] == 0 {
|
||||||
PermutationState::OngoingUnknownLen { k, min_n: min_n + 1 }
|
cycles[i] = n - i - 1;
|
||||||
} else {
|
indices[i..].rotate_left(1);
|
||||||
let n = min_n;
|
} else {
|
||||||
let prev_iteration_count = n - k + 1;
|
let swap_index = n - cycles[i];
|
||||||
let mut complete_state = CompleteState::Start { n, k };
|
indices.swap(i, swap_index);
|
||||||
|
cycles[i] -= 1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
// Advance the complete-state iterator to the correct point
|
impl PermutationState {
|
||||||
for _ in 0..(prev_iteration_count + 1) {
|
fn size_hint_for(&self, n: usize) -> SizeHint {
|
||||||
complete_state.advance();
|
// At the beginning, there are `n!/(n-k)!` items to come.
|
||||||
}
|
let at_start = |n, k| {
|
||||||
|
debug_assert!(n >= k);
|
||||||
PermutationState::Complete(complete_state)
|
let total = (n - k + 1..=n).try_fold(1usize, |acc, i| acc.checked_mul(i));
|
||||||
}
|
(total.unwrap_or(usize::MAX), total)
|
||||||
}
|
|
||||||
PermutationState::Complete(ref mut state) => {
|
|
||||||
state.advance();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PermutationState::Empty => { return; }
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CompleteState {
|
|
||||||
fn advance(&mut self) {
|
|
||||||
*self = match *self {
|
|
||||||
CompleteState::Start { n, k } => {
|
|
||||||
let indices = (0..n).collect();
|
|
||||||
let cycles = ((n - k)..n).rev().collect();
|
|
||||||
|
|
||||||
CompleteState::Ongoing {
|
|
||||||
cycles,
|
|
||||||
indices
|
|
||||||
}
|
|
||||||
},
|
|
||||||
CompleteState::Ongoing { ref mut indices, ref mut cycles } => {
|
|
||||||
let n = indices.len();
|
|
||||||
let k = cycles.len();
|
|
||||||
|
|
||||||
for i in (0..k).rev() {
|
|
||||||
if cycles[i] == 0 {
|
|
||||||
cycles[i] = n - i - 1;
|
|
||||||
|
|
||||||
let to_push = indices.remove(i);
|
|
||||||
indices.push(to_push);
|
|
||||||
} else {
|
|
||||||
let swap_index = n - cycles[i];
|
|
||||||
indices.swap(i, swap_index);
|
|
||||||
|
|
||||||
cycles[i] -= 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CompleteState::Start { n, k }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remaining(&self) -> CompleteStateRemaining {
|
|
||||||
use self::CompleteStateRemaining::{Known, Overflow};
|
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
CompleteState::Start { n, k } => {
|
Self::Start { k } if n < k => (0, Some(0)),
|
||||||
if n < k {
|
Self::Start { k } => at_start(n, k),
|
||||||
return Known(0);
|
Self::Buffered { k, min_n } => {
|
||||||
}
|
// Same as `Start` minus the previously generated items.
|
||||||
|
size_hint::sub_scalar(at_start(n, k), min_n - k + 1)
|
||||||
let count: Option<usize> = (n - k + 1..n + 1).fold(Some(1), |acc, i| {
|
}
|
||||||
acc.and_then(|acc| acc.checked_mul(i))
|
Self::Loaded {
|
||||||
|
ref indices,
|
||||||
|
ref cycles,
|
||||||
|
} => {
|
||||||
|
let count = cycles.iter().enumerate().try_fold(0usize, |acc, (i, &c)| {
|
||||||
|
acc.checked_mul(indices.len() - i)
|
||||||
|
.and_then(|count| count.checked_add(c))
|
||||||
});
|
});
|
||||||
|
(count.unwrap_or(usize::MAX), count)
|
||||||
match count {
|
|
||||||
Some(count) => Known(count),
|
|
||||||
None => Overflow
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CompleteState::Ongoing { ref indices, ref cycles } => {
|
|
||||||
let mut count: usize = 0;
|
|
||||||
|
|
||||||
for (i, &c) in cycles.iter().enumerate() {
|
|
||||||
let radix = indices.len() - i;
|
|
||||||
let next_count = count.checked_mul(radix)
|
|
||||||
.and_then(|count| count.checked_add(c));
|
|
||||||
|
|
||||||
count = match next_count {
|
|
||||||
Some(count) => count,
|
|
||||||
None => { return Overflow; }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Known(count)
|
|
||||||
}
|
}
|
||||||
|
Self::End => (0, Some(0)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
129
third_party/rust/itertools/src/powerset.rs
vendored
129
third_party/rust/itertools/src/powerset.rs
vendored
@@ -1,10 +1,10 @@
|
|||||||
|
use alloc::vec::Vec;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::FusedIterator;
|
use std::iter::FusedIterator;
|
||||||
use std::usize;
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
|
|
||||||
use super::combinations::{Combinations, combinations};
|
use super::combinations::{combinations, Combinations};
|
||||||
use super::size_hint;
|
use crate::adaptors::checked_binomial;
|
||||||
|
use crate::size_hint::{self, SizeHint};
|
||||||
|
|
||||||
/// An iterator to iterate through the powerset of the elements from an iterator.
|
/// An iterator to iterate through the powerset of the elements from an iterator.
|
||||||
///
|
///
|
||||||
@@ -13,78 +13,119 @@ use super::size_hint;
|
|||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct Powerset<I: Iterator> {
|
pub struct Powerset<I: Iterator> {
|
||||||
combs: Combinations<I>,
|
combs: Combinations<I>,
|
||||||
// Iterator `position` (equal to count of yielded elements).
|
|
||||||
pos: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Clone for Powerset<I>
|
impl<I> Clone for Powerset<I>
|
||||||
where I: Clone + Iterator,
|
where
|
||||||
I::Item: Clone,
|
I: Clone + Iterator,
|
||||||
|
I::Item: Clone,
|
||||||
{
|
{
|
||||||
clone_fields!(combs, pos);
|
clone_fields!(combs);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> fmt::Debug for Powerset<I>
|
impl<I> fmt::Debug for Powerset<I>
|
||||||
where I: Iterator + fmt::Debug,
|
where
|
||||||
I::Item: fmt::Debug,
|
I: Iterator + fmt::Debug,
|
||||||
|
I::Item: fmt::Debug,
|
||||||
{
|
{
|
||||||
debug_fmt_fields!(Powerset, combs, pos);
|
debug_fmt_fields!(Powerset, combs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `Powerset` from a clonable iterator.
|
/// Create a new `Powerset` from a clonable iterator.
|
||||||
pub fn powerset<I>(src: I) -> Powerset<I>
|
pub fn powerset<I>(src: I) -> Powerset<I>
|
||||||
where I: Iterator,
|
where
|
||||||
I::Item: Clone,
|
I: Iterator,
|
||||||
|
I::Item: Clone,
|
||||||
{
|
{
|
||||||
Powerset {
|
Powerset {
|
||||||
combs: combinations(src, 0),
|
combs: combinations(src, 0),
|
||||||
pos: 0,
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Iterator> Powerset<I> {
|
||||||
|
/// Returns true if `k` has been incremented, false otherwise.
|
||||||
|
fn increment_k(&mut self) -> bool {
|
||||||
|
if self.combs.k() < self.combs.n() || self.combs.k() == 0 {
|
||||||
|
self.combs.reset(self.combs.k() + 1);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Iterator for Powerset<I>
|
impl<I> Iterator for Powerset<I>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
I::Item: Clone,
|
I::Item: Clone,
|
||||||
{
|
{
|
||||||
type Item = Vec<I::Item>;
|
type Item = Vec<I::Item>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if let Some(elt) = self.combs.next() {
|
if let Some(elt) = self.combs.next() {
|
||||||
self.pos = self.pos.saturating_add(1);
|
|
||||||
Some(elt)
|
Some(elt)
|
||||||
} else if self.combs.k() < self.combs.n()
|
} else if self.increment_k() {
|
||||||
|| self.combs.k() == 0
|
self.combs.next()
|
||||||
{
|
|
||||||
self.combs.reset(self.combs.k() + 1);
|
|
||||||
self.combs.next().map(|elt| {
|
|
||||||
self.pos = self.pos.saturating_add(1);
|
|
||||||
elt
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
|
||||||
// Total bounds for source iterator.
|
loop {
|
||||||
let src_total = size_hint::add_scalar(self.combs.src().size_hint(), self.combs.n());
|
match self.combs.try_nth(n) {
|
||||||
|
Ok(item) => return Some(item),
|
||||||
// Total bounds for self ( length(powerset(set) == 2 ^ length(set) )
|
Err(steps) => {
|
||||||
let self_total = size_hint::pow_scalar_base(2, src_total);
|
if !self.increment_k() {
|
||||||
|
return None;
|
||||||
if self.pos < usize::MAX {
|
}
|
||||||
// Subtract count of elements already yielded from total.
|
n -= steps;
|
||||||
size_hint::sub_scalar(self_total, self.pos)
|
}
|
||||||
} else {
|
}
|
||||||
// Fallback: self.pos is saturated and no longer reliable.
|
|
||||||
(0, self_total.1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> SizeHint {
|
||||||
|
let k = self.combs.k();
|
||||||
|
// Total bounds for source iterator.
|
||||||
|
let (n_min, n_max) = self.combs.src().size_hint();
|
||||||
|
let low = remaining_for(n_min, k).unwrap_or(usize::MAX);
|
||||||
|
let upp = n_max.and_then(|n| remaining_for(n, k));
|
||||||
|
size_hint::add(self.combs.size_hint(), (low, upp))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count(self) -> usize {
|
||||||
|
let k = self.combs.k();
|
||||||
|
let (n, combs_count) = self.combs.n_and_count();
|
||||||
|
combs_count + remaining_for(n, k).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold<B, F>(self, mut init: B, mut f: F) -> B
|
||||||
|
where
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
let mut it = self.combs;
|
||||||
|
if it.k() == 0 {
|
||||||
|
init = it.by_ref().fold(init, &mut f);
|
||||||
|
it.reset(1);
|
||||||
|
}
|
||||||
|
init = it.by_ref().fold(init, &mut f);
|
||||||
|
// n is now known for sure because k >= 1 and all k-combinations have been generated.
|
||||||
|
for k in it.k() + 1..=it.n() {
|
||||||
|
it.reset(k);
|
||||||
|
init = it.by_ref().fold(init, &mut f);
|
||||||
|
}
|
||||||
|
init
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> FusedIterator for Powerset<I>
|
impl<I> FusedIterator for Powerset<I>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
I::Item: Clone,
|
I::Item: Clone,
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remaining_for(n: usize, k: usize) -> Option<usize> {
|
||||||
|
(k + 1..=n).try_fold(0usize, |sum, i| sum.checked_add(checked_binomial(n, i)?))
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#[cfg(doc)]
|
||||||
|
use crate::Itertools;
|
||||||
|
|
||||||
/// An iterator that produces only the `T` values as long as the
|
/// An iterator that produces only the `T` values as long as the
|
||||||
/// inner iterator produces `Ok(T)`.
|
/// inner iterator produces `Ok(T)`.
|
||||||
@@ -11,13 +13,10 @@ pub struct ProcessResults<'a, I, E: 'a> {
|
|||||||
iter: I,
|
iter: I,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I, T, E> Iterator for ProcessResults<'a, I, E>
|
impl<I, E> ProcessResults<'_, I, E> {
|
||||||
where I: Iterator<Item = Result<T, E>>
|
#[inline(always)]
|
||||||
{
|
fn next_body<T>(&mut self, item: Option<Result<T, E>>) -> Option<T> {
|
||||||
type Item = T;
|
match item {
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
match self.iter.next() {
|
|
||||||
Some(Ok(x)) => Some(x),
|
Some(Ok(x)) => Some(x),
|
||||||
Some(Err(e)) => {
|
Some(Err(e)) => {
|
||||||
*self.error = Err(e);
|
*self.error = Err(e);
|
||||||
@@ -26,6 +25,18 @@ impl<'a, I, T, E> Iterator for ProcessResults<'a, I, E>
|
|||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, T, E> Iterator for ProcessResults<'_, I, E>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = Result<T, E>>,
|
||||||
|
{
|
||||||
|
type Item = T;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let item = self.iter.next();
|
||||||
|
self.next_body(item)
|
||||||
|
}
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
(0, self.iter.size_hint().1)
|
(0, self.iter.size_hint().1)
|
||||||
@@ -49,49 +60,49 @@ impl<'a, I, T, E> Iterator for ProcessResults<'a, I, E>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<I, T, E> DoubleEndedIterator for ProcessResults<'_, I, E>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = Result<T, E>>,
|
||||||
|
I: DoubleEndedIterator,
|
||||||
|
{
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
let item = self.iter.next_back();
|
||||||
|
self.next_body(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rfold<B, F>(mut self, init: B, mut f: F) -> B
|
||||||
|
where
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
let error = self.error;
|
||||||
|
self.iter
|
||||||
|
.try_rfold(init, |acc, opt| match opt {
|
||||||
|
Ok(x) => Ok(f(acc, x)),
|
||||||
|
Err(e) => {
|
||||||
|
*error = Err(e);
|
||||||
|
Err(acc)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|e| e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// “Lift” a function of the values of an iterator so that it can process
|
/// “Lift” a function of the values of an iterator so that it can process
|
||||||
/// an iterator of `Result` values instead.
|
/// an iterator of `Result` values instead.
|
||||||
///
|
///
|
||||||
/// `iterable` is an iterator or iterable with `Result<T, E>` elements, where
|
/// [`IntoIterator`] enabled version of [`Itertools::process_results`].
|
||||||
/// `T` is the value type and `E` the error type.
|
|
||||||
///
|
|
||||||
/// `processor` is a closure that receives an adapted version of the iterable
|
|
||||||
/// as the only argument — the adapted iterator produces elements of type `T`,
|
|
||||||
/// as long as the original iterator produces `Ok` values.
|
|
||||||
///
|
|
||||||
/// If the original iterable produces an error at any point, the adapted
|
|
||||||
/// iterator ends and the `process_results` function will return the
|
|
||||||
/// error iself.
|
|
||||||
///
|
|
||||||
/// Otherwise, the return value from the closure is returned wrapped
|
|
||||||
/// inside `Ok`.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use itertools::process_results;
|
|
||||||
///
|
|
||||||
/// type R = Result<i32, &'static str>;
|
|
||||||
///
|
|
||||||
/// let first_values: Vec<R> = vec![Ok(1), Ok(0), Ok(3)];
|
|
||||||
/// let second_values: Vec<R> = vec![Ok(2), Ok(1), Err("overflow")];
|
|
||||||
///
|
|
||||||
/// // “Lift” the iterator .max() method to work on the values in Results using process_results
|
|
||||||
///
|
|
||||||
/// let first_max = process_results(first_values, |iter| iter.max().unwrap_or(0));
|
|
||||||
/// let second_max = process_results(second_values, |iter| iter.max().unwrap_or(0));
|
|
||||||
///
|
|
||||||
/// assert_eq!(first_max, Ok(3));
|
|
||||||
/// assert!(second_max.is_err());
|
|
||||||
/// ```
|
|
||||||
pub fn process_results<I, F, T, E, R>(iterable: I, processor: F) -> Result<R, E>
|
pub fn process_results<I, F, T, E, R>(iterable: I, processor: F) -> Result<R, E>
|
||||||
where I: IntoIterator<Item = Result<T, E>>,
|
where
|
||||||
F: FnOnce(ProcessResults<I::IntoIter, E>) -> R
|
I: IntoIterator<Item = Result<T, E>>,
|
||||||
|
F: FnOnce(ProcessResults<I::IntoIter, E>) -> R,
|
||||||
{
|
{
|
||||||
let iter = iterable.into_iter();
|
let iter = iterable.into_iter();
|
||||||
let mut error = Ok(());
|
let mut error = Ok(());
|
||||||
|
|
||||||
let result = processor(ProcessResults { error: &mut error, iter });
|
let result = processor(ProcessResults {
|
||||||
|
error: &mut error,
|
||||||
|
iter,
|
||||||
|
});
|
||||||
|
|
||||||
error.map(|_| result)
|
error.map(|_| result)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use crate::size_hint;
|
|||||||
///
|
///
|
||||||
/// Iterator element type is `I::Item`.
|
/// Iterator element type is `I::Item`.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct PutBackN<I: Iterator> {
|
pub struct PutBackN<I: Iterator> {
|
||||||
top: Vec<I::Item>,
|
top: Vec<I::Item>,
|
||||||
iter: I,
|
iter: I,
|
||||||
@@ -17,7 +18,8 @@ pub struct PutBackN<I: Iterator> {
|
|||||||
///
|
///
|
||||||
/// Iterator element type is `I::Item`.
|
/// Iterator element type is `I::Item`.
|
||||||
pub fn put_back_n<I>(iterable: I) -> PutBackN<I::IntoIter>
|
pub fn put_back_n<I>(iterable: I) -> PutBackN<I::IntoIter>
|
||||||
where I: IntoIterator
|
where
|
||||||
|
I: IntoIterator,
|
||||||
{
|
{
|
||||||
PutBackN {
|
PutBackN {
|
||||||
top: Vec::new(),
|
top: Vec::new(),
|
||||||
@@ -26,7 +28,8 @@ pub fn put_back_n<I>(iterable: I) -> PutBackN<I::IntoIter>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Iterator> PutBackN<I> {
|
impl<I: Iterator> PutBackN<I> {
|
||||||
/// Puts x in front of the iterator.
|
/// Puts `x` in front of the iterator.
|
||||||
|
///
|
||||||
/// The values are yielded in order of the most recently put back
|
/// The values are yielded in order of the most recently put back
|
||||||
/// values first.
|
/// values first.
|
||||||
///
|
///
|
||||||
@@ -57,5 +60,12 @@ impl<I: Iterator> Iterator for PutBackN<I> {
|
|||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
size_hint::add_scalar(self.iter.size_hint(), self.top.len())
|
size_hint::add_scalar(self.iter.size_hint(), self.top.len())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
fn fold<B, F>(self, mut init: B, mut f: F) -> B
|
||||||
|
where
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
init = self.top.into_iter().rfold(init, &mut f);
|
||||||
|
self.iter.fold(init, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
27
third_party/rust/itertools/src/rciter_impl.rs
vendored
27
third_party/rust/itertools/src/rciter_impl.rs
vendored
@@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
use std::iter::{FusedIterator, IntoIterator};
|
|
||||||
use alloc::rc::Rc;
|
use alloc::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::iter::{FusedIterator, IntoIterator};
|
||||||
|
|
||||||
/// A wrapper for `Rc<RefCell<I>>`, that implements the `Iterator` trait.
|
/// A wrapper for `Rc<RefCell<I>>`, that implements the `Iterator` trait.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct RcIter<I> {
|
pub struct RcIter<I> {
|
||||||
/// The boxed iterator.
|
/// The boxed iterator.
|
||||||
pub rciter: Rc<RefCell<I>>,
|
pub rciter: Rc<RefCell<I>>,
|
||||||
@@ -45,9 +45,12 @@ pub struct RcIter<I> {
|
|||||||
/// `.next()`, i.e. if it somehow participates in an “iterator knot”
|
/// `.next()`, i.e. if it somehow participates in an “iterator knot”
|
||||||
/// where it is an adaptor of itself.
|
/// where it is an adaptor of itself.
|
||||||
pub fn rciter<I>(iterable: I) -> RcIter<I::IntoIter>
|
pub fn rciter<I>(iterable: I) -> RcIter<I::IntoIter>
|
||||||
where I: IntoIterator
|
where
|
||||||
|
I: IntoIterator,
|
||||||
{
|
{
|
||||||
RcIter { rciter: Rc::new(RefCell::new(iterable.into_iter())) }
|
RcIter {
|
||||||
|
rciter: Rc::new(RefCell::new(iterable.into_iter())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Clone for RcIter<I> {
|
impl<I> Clone for RcIter<I> {
|
||||||
@@ -55,7 +58,8 @@ impl<I> Clone for RcIter<I> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<A, I> Iterator for RcIter<I>
|
impl<A, I> Iterator for RcIter<I>
|
||||||
where I: Iterator<Item = A>
|
where
|
||||||
|
I: Iterator<Item = A>,
|
||||||
{
|
{
|
||||||
type Item = A;
|
type Item = A;
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -73,7 +77,8 @@ impl<A, I> Iterator for RcIter<I>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I> DoubleEndedIterator for RcIter<I>
|
impl<I> DoubleEndedIterator for RcIter<I>
|
||||||
where I: DoubleEndedIterator
|
where
|
||||||
|
I: DoubleEndedIterator,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next_back(&mut self) -> Option<Self::Item> {
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
@@ -82,8 +87,9 @@ impl<I> DoubleEndedIterator for RcIter<I>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return an iterator from `&RcIter<I>` (by simply cloning it).
|
/// Return an iterator from `&RcIter<I>` (by simply cloning it).
|
||||||
impl<'a, I> IntoIterator for &'a RcIter<I>
|
impl<I> IntoIterator for &RcIter<I>
|
||||||
where I: Iterator
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
type Item = I::Item;
|
type Item = I::Item;
|
||||||
type IntoIter = RcIter<I>;
|
type IntoIter = RcIter<I>;
|
||||||
@@ -93,7 +99,4 @@ impl<'a, I> IntoIterator for &'a RcIter<I>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<A, I> FusedIterator for RcIter<I> where I: FusedIterator<Item = A> {}
|
||||||
impl<A, I> FusedIterator for RcIter<I>
|
|
||||||
where I: FusedIterator<Item = A>
|
|
||||||
{}
|
|
||||||
|
|||||||
48
third_party/rust/itertools/src/repeatn.rs
vendored
48
third_party/rust/itertools/src/repeatn.rs
vendored
@@ -6,23 +6,28 @@ use std::iter::FusedIterator;
|
|||||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct RepeatN<A> {
|
pub struct RepeatN<A> {
|
||||||
elt: Option<A>,
|
pub(crate) elt: Option<A>,
|
||||||
n: usize,
|
n: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an iterator that produces `n` repetitions of `element`.
|
/// Create an iterator that produces `n` repetitions of `element`.
|
||||||
pub fn repeat_n<A>(element: A, n: usize) -> RepeatN<A>
|
pub fn repeat_n<A>(element: A, n: usize) -> RepeatN<A>
|
||||||
where A: Clone,
|
where
|
||||||
|
A: Clone,
|
||||||
{
|
{
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
RepeatN { elt: None, n, }
|
RepeatN { elt: None, n }
|
||||||
} else {
|
} else {
|
||||||
RepeatN { elt: Some(element), n, }
|
RepeatN {
|
||||||
|
elt: Some(element),
|
||||||
|
n,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> Iterator for RepeatN<A>
|
impl<A> Iterator for RepeatN<A>
|
||||||
where A: Clone
|
where
|
||||||
|
A: Clone,
|
||||||
{
|
{
|
||||||
type Item = A;
|
type Item = A;
|
||||||
|
|
||||||
@@ -39,21 +44,40 @@ impl<A> Iterator for RepeatN<A>
|
|||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
(self.n, Some(self.n))
|
(self.n, Some(self.n))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fold<B, F>(self, mut init: B, mut f: F) -> B
|
||||||
|
where
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self { elt: Some(elt), n } => {
|
||||||
|
debug_assert!(n > 0);
|
||||||
|
init = (1..n).map(|_| elt.clone()).fold(init, &mut f);
|
||||||
|
f(init, elt)
|
||||||
|
}
|
||||||
|
_ => init,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> DoubleEndedIterator for RepeatN<A>
|
impl<A> DoubleEndedIterator for RepeatN<A>
|
||||||
where A: Clone
|
where
|
||||||
|
A: Clone,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next_back(&mut self) -> Option<Self::Item> {
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
self.next()
|
self.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn rfold<B, F>(self, init: B, f: F) -> B
|
||||||
|
where
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
self.fold(init, f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> ExactSizeIterator for RepeatN<A>
|
impl<A> ExactSizeIterator for RepeatN<A> where A: Clone {}
|
||||||
where A: Clone
|
|
||||||
{}
|
|
||||||
|
|
||||||
impl<A> FusedIterator for RepeatN<A>
|
impl<A> FusedIterator for RepeatN<A> where A: Clone {}
|
||||||
where A: Clone
|
|
||||||
{}
|
|
||||||
|
|||||||
39
third_party/rust/itertools/src/size_hint.rs
vendored
39
third_party/rust/itertools/src/size_hint.rs
vendored
@@ -1,9 +1,7 @@
|
|||||||
//! Arithmetic on `Iterator.size_hint()` values.
|
//! Arithmetic on `Iterator.size_hint()` values.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use std::usize;
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::u32;
|
|
||||||
|
|
||||||
/// `SizeHint` is the return type of `Iterator::size_hint()`.
|
/// `SizeHint` is the return type of `Iterator::size_hint()`.
|
||||||
pub type SizeHint = (usize, Option<usize>);
|
pub type SizeHint = (usize, Option<usize>);
|
||||||
@@ -31,7 +29,6 @@ pub fn add_scalar(sh: SizeHint, x: usize) -> SizeHint {
|
|||||||
|
|
||||||
/// Subtract `x` correctly from a `SizeHint`.
|
/// Subtract `x` correctly from a `SizeHint`.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn sub_scalar(sh: SizeHint, x: usize) -> SizeHint {
|
pub fn sub_scalar(sh: SizeHint, x: usize) -> SizeHint {
|
||||||
let (mut low, mut hi) = sh;
|
let (mut low, mut hi) = sh;
|
||||||
low = low.saturating_sub(x);
|
low = low.saturating_sub(x);
|
||||||
@@ -39,22 +36,7 @@ pub fn sub_scalar(sh: SizeHint, x: usize) -> SizeHint {
|
|||||||
(low, hi)
|
(low, hi)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Multiply `SizeHint` correctly
|
/// Multiply `SizeHint` correctly
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// use std::usize;
|
|
||||||
/// use itertools::size_hint;
|
|
||||||
///
|
|
||||||
/// assert_eq!(size_hint::mul((3, Some(4)), (3, Some(4))),
|
|
||||||
/// (9, Some(16)));
|
|
||||||
///
|
|
||||||
/// assert_eq!(size_hint::mul((3, Some(4)), (usize::MAX, None)),
|
|
||||||
/// (usize::MAX, None));
|
|
||||||
///
|
|
||||||
/// assert_eq!(size_hint::mul((3, None), (0, Some(0))),
|
|
||||||
/// (0, Some(0)));
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mul(a: SizeHint, b: SizeHint) -> SizeHint {
|
pub fn mul(a: SizeHint, b: SizeHint) -> SizeHint {
|
||||||
let low = a.0.saturating_mul(b.0);
|
let low = a.0.saturating_mul(b.0);
|
||||||
@@ -75,20 +57,6 @@ pub fn mul_scalar(sh: SizeHint, x: usize) -> SizeHint {
|
|||||||
(low, hi)
|
(low, hi)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Raise `base` correctly by a `SizeHint` exponent.
|
|
||||||
#[inline]
|
|
||||||
pub fn pow_scalar_base(base: usize, exp: SizeHint) -> SizeHint {
|
|
||||||
let exp_low = cmp::min(exp.0, u32::MAX as usize) as u32;
|
|
||||||
let low = base.saturating_pow(exp_low);
|
|
||||||
|
|
||||||
let hi = exp.1.and_then(|exp| {
|
|
||||||
let exp_hi = cmp::min(exp, u32::MAX as usize) as u32;
|
|
||||||
base.checked_pow(exp_hi)
|
|
||||||
});
|
|
||||||
|
|
||||||
(low, hi)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the maximum
|
/// Return the maximum
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn max(a: SizeHint, b: SizeHint) -> SizeHint {
|
pub fn max(a: SizeHint, b: SizeHint) -> SizeHint {
|
||||||
@@ -117,3 +85,10 @@ pub fn min(a: SizeHint, b: SizeHint) -> SizeHint {
|
|||||||
};
|
};
|
||||||
(lower, upper)
|
(lower, upper)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_size_hints() {
|
||||||
|
assert_eq!(mul((3, Some(4)), (3, Some(4))), (9, Some(16)));
|
||||||
|
assert_eq!(mul((3, Some(4)), (usize::MAX, None)), (usize::MAX, None));
|
||||||
|
assert_eq!(mul((3, None), (0, Some(0))), (0, Some(0)));
|
||||||
|
}
|
||||||
|
|||||||
98
third_party/rust/itertools/src/sources.rs
vendored
98
third_party/rust/itertools/src/sources.rs
vendored
@@ -5,62 +5,6 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
/// See [`repeat_call`](crate::repeat_call) for more information.
|
|
||||||
#[derive(Clone)]
|
|
||||||
#[deprecated(note="Use std repeat_with() instead", since="0.8.0")]
|
|
||||||
pub struct RepeatCall<F> {
|
|
||||||
f: F,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F> fmt::Debug for RepeatCall<F>
|
|
||||||
{
|
|
||||||
debug_fmt_fields!(RepeatCall, );
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An iterator source that produces elements indefinitely by calling
|
|
||||||
/// a given closure.
|
|
||||||
///
|
|
||||||
/// Iterator element type is the return type of the closure.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use itertools::repeat_call;
|
|
||||||
/// use itertools::Itertools;
|
|
||||||
/// use std::collections::BinaryHeap;
|
|
||||||
///
|
|
||||||
/// let mut heap = BinaryHeap::from(vec![2, 5, 3, 7, 8]);
|
|
||||||
///
|
|
||||||
/// // extract each element in sorted order
|
|
||||||
/// for element in repeat_call(|| heap.pop()).while_some() {
|
|
||||||
/// print!("{}", element);
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// itertools::assert_equal(
|
|
||||||
/// repeat_call(|| 1).take(5),
|
|
||||||
/// vec![1, 1, 1, 1, 1]
|
|
||||||
/// );
|
|
||||||
/// ```
|
|
||||||
#[deprecated(note="Use std repeat_with() instead", since="0.8.0")]
|
|
||||||
pub fn repeat_call<F, A>(function: F) -> RepeatCall<F>
|
|
||||||
where F: FnMut() -> A
|
|
||||||
{
|
|
||||||
RepeatCall { f: function }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A, F> Iterator for RepeatCall<F>
|
|
||||||
where F: FnMut() -> A
|
|
||||||
{
|
|
||||||
type Item = A;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
Some((self.f)())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
||||||
(usize::max_value(), None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new unfold source with the specified closure as the "iterator
|
/// Creates a new unfold source with the specified closure as the "iterator
|
||||||
/// function" and an initial state to eventually pass to the closure
|
/// function" and an initial state to eventually pass to the closure
|
||||||
///
|
///
|
||||||
@@ -97,8 +41,13 @@ impl<A, F> Iterator for RepeatCall<F>
|
|||||||
/// vec![1, 1, 2, 3, 5, 8, 13, 21]);
|
/// vec![1, 1, 2, 3, 5, 8, 13, 21]);
|
||||||
/// assert_eq!(fibonacci.last(), Some(2_971_215_073))
|
/// assert_eq!(fibonacci.last(), Some(2_971_215_073))
|
||||||
/// ```
|
/// ```
|
||||||
|
#[deprecated(
|
||||||
|
note = "Use [std::iter::from_fn](https://doc.rust-lang.org/std/iter/fn.from_fn.html) instead",
|
||||||
|
since = "0.13.0"
|
||||||
|
)]
|
||||||
pub fn unfold<A, St, F>(initial_state: St, f: F) -> Unfold<St, F>
|
pub fn unfold<A, St, F>(initial_state: St, f: F) -> Unfold<St, F>
|
||||||
where F: FnMut(&mut St) -> Option<A>
|
where
|
||||||
|
F: FnMut(&mut St) -> Option<A>,
|
||||||
{
|
{
|
||||||
Unfold {
|
Unfold {
|
||||||
f,
|
f,
|
||||||
@@ -107,7 +56,8 @@ pub fn unfold<A, St, F>(initial_state: St, f: F) -> Unfold<St, F>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<St, F> fmt::Debug for Unfold<St, F>
|
impl<St, F> fmt::Debug for Unfold<St, F>
|
||||||
where St: fmt::Debug,
|
where
|
||||||
|
St: fmt::Debug,
|
||||||
{
|
{
|
||||||
debug_fmt_fields!(Unfold, state);
|
debug_fmt_fields!(Unfold, state);
|
||||||
}
|
}
|
||||||
@@ -115,6 +65,10 @@ impl<St, F> fmt::Debug for Unfold<St, F>
|
|||||||
/// See [`unfold`](crate::unfold) for more information.
|
/// See [`unfold`](crate::unfold) for more information.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
|
#[deprecated(
|
||||||
|
note = "Use [std::iter::FromFn](https://doc.rust-lang.org/std/iter/struct.FromFn.html) instead",
|
||||||
|
since = "0.13.0"
|
||||||
|
)]
|
||||||
pub struct Unfold<St, F> {
|
pub struct Unfold<St, F> {
|
||||||
f: F,
|
f: F,
|
||||||
/// Internal state that will be passed to the closure on the next iteration
|
/// Internal state that will be passed to the closure on the next iteration
|
||||||
@@ -122,7 +76,8 @@ pub struct Unfold<St, F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<A, St, F> Iterator for Unfold<St, F>
|
impl<A, St, F> Iterator for Unfold<St, F>
|
||||||
where F: FnMut(&mut St) -> Option<A>
|
where
|
||||||
|
F: FnMut(&mut St) -> Option<A>,
|
||||||
{
|
{
|
||||||
type Item = A;
|
type Item = A;
|
||||||
|
|
||||||
@@ -144,13 +99,15 @@ pub struct Iterate<St, F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<St, F> fmt::Debug for Iterate<St, F>
|
impl<St, F> fmt::Debug for Iterate<St, F>
|
||||||
where St: fmt::Debug,
|
where
|
||||||
|
St: fmt::Debug,
|
||||||
{
|
{
|
||||||
debug_fmt_fields!(Iterate, state);
|
debug_fmt_fields!(Iterate, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<St, F> Iterator for Iterate<St, F>
|
impl<St, F> Iterator for Iterate<St, F>
|
||||||
where F: FnMut(&St) -> St
|
where
|
||||||
|
F: FnMut(&St) -> St,
|
||||||
{
|
{
|
||||||
type Item = St;
|
type Item = St;
|
||||||
|
|
||||||
@@ -162,7 +119,7 @@ impl<St, F> Iterator for Iterate<St, F>
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
(usize::max_value(), None)
|
(usize::MAX, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,10 +128,23 @@ impl<St, F> Iterator for Iterate<St, F>
|
|||||||
/// ```
|
/// ```
|
||||||
/// use itertools::iterate;
|
/// use itertools::iterate;
|
||||||
///
|
///
|
||||||
/// itertools::assert_equal(iterate(1, |&i| i * 3).take(5), vec![1, 3, 9, 27, 81]);
|
/// itertools::assert_equal(iterate(1, |i| i % 3 + 1).take(5), vec![1, 2, 3, 1, 2]);
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// **Panics** if compute the next value does.
|
||||||
|
///
|
||||||
|
/// ```should_panic
|
||||||
|
/// # use itertools::iterate;
|
||||||
|
/// let mut it = iterate(25u32, |x| x - 10).take_while(|&x| x > 10);
|
||||||
|
/// assert_eq!(it.next(), Some(25)); // `Iterate` holds 15.
|
||||||
|
/// assert_eq!(it.next(), Some(15)); // `Iterate` holds 5.
|
||||||
|
/// it.next(); // `5 - 10` overflows.
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// You can alternatively use [`core::iter::successors`] as it better describes a finite iterator.
|
||||||
pub fn iterate<St, F>(initial_value: St, f: F) -> Iterate<St, F>
|
pub fn iterate<St, F>(initial_value: St, f: F) -> Iterate<St, F>
|
||||||
where F: FnMut(&St) -> St
|
where
|
||||||
|
F: FnMut(&St) -> St,
|
||||||
{
|
{
|
||||||
Iterate {
|
Iterate {
|
||||||
state: initial_value,
|
state: initial_value,
|
||||||
|
|||||||
96
third_party/rust/itertools/src/take_while_inclusive.rs
vendored
Normal file
96
third_party/rust/itertools/src/take_while_inclusive.rs
vendored
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
use core::iter::FusedIterator;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// An iterator adaptor that consumes elements while the given predicate is
|
||||||
|
/// `true`, including the element for which the predicate first returned
|
||||||
|
/// `false`.
|
||||||
|
///
|
||||||
|
/// See [`.take_while_inclusive()`](crate::Itertools::take_while_inclusive)
|
||||||
|
/// for more information.
|
||||||
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct TakeWhileInclusive<I, F> {
|
||||||
|
iter: I,
|
||||||
|
predicate: F,
|
||||||
|
done: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, F> TakeWhileInclusive<I, F>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
F: FnMut(&I::Item) -> bool,
|
||||||
|
{
|
||||||
|
/// Create a new [`TakeWhileInclusive`] from an iterator and a predicate.
|
||||||
|
pub(crate) fn new(iter: I, predicate: F) -> Self {
|
||||||
|
Self {
|
||||||
|
iter,
|
||||||
|
predicate,
|
||||||
|
done: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, F> fmt::Debug for TakeWhileInclusive<I, F>
|
||||||
|
where
|
||||||
|
I: Iterator + fmt::Debug,
|
||||||
|
{
|
||||||
|
debug_fmt_fields!(TakeWhileInclusive, iter, done);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, F> Iterator for TakeWhileInclusive<I, F>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
F: FnMut(&I::Item) -> bool,
|
||||||
|
{
|
||||||
|
type Item = I::Item;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.done {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
self.iter.next().map(|item| {
|
||||||
|
if !(self.predicate)(&item) {
|
||||||
|
self.done = true;
|
||||||
|
}
|
||||||
|
item
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
if self.done {
|
||||||
|
(0, Some(0))
|
||||||
|
} else {
|
||||||
|
(0, self.iter.size_hint().1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold<B, Fold>(mut self, init: B, mut f: Fold) -> B
|
||||||
|
where
|
||||||
|
Fold: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
if self.done {
|
||||||
|
init
|
||||||
|
} else {
|
||||||
|
let predicate = &mut self.predicate;
|
||||||
|
self.iter
|
||||||
|
.try_fold(init, |mut acc, item| {
|
||||||
|
let is_ok = predicate(&item);
|
||||||
|
acc = f(acc, item);
|
||||||
|
if is_ok {
|
||||||
|
Ok(acc)
|
||||||
|
} else {
|
||||||
|
Err(acc)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|err| err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, F> FusedIterator for TakeWhileInclusive<I, F>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
F: FnMut(&I::Item) -> bool,
|
||||||
|
{
|
||||||
|
}
|
||||||
37
third_party/rust/itertools/src/tee.rs
vendored
37
third_party/rust/itertools/src/tee.rs
vendored
@@ -1,8 +1,8 @@
|
|||||||
use super::size_hint;
|
use super::size_hint;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use alloc::collections::VecDeque;
|
use alloc::collections::VecDeque;
|
||||||
use alloc::rc::Rc;
|
use alloc::rc::Rc;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
/// Common buffer object for the two tee halves
|
/// Common buffer object for the two tee halves
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -19,24 +19,37 @@ struct TeeBuffer<A, I> {
|
|||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Tee<I>
|
pub struct Tee<I>
|
||||||
where I: Iterator
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
rcbuffer: Rc<RefCell<TeeBuffer<I::Item, I>>>,
|
rcbuffer: Rc<RefCell<TeeBuffer<I::Item, I>>>,
|
||||||
id: bool,
|
id: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new<I>(iter: I) -> (Tee<I>, Tee<I>)
|
pub fn new<I>(iter: I) -> (Tee<I>, Tee<I>)
|
||||||
where I: Iterator
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
let buffer = TeeBuffer{backlog: VecDeque::new(), iter, owner: false};
|
let buffer = TeeBuffer {
|
||||||
let t1 = Tee{rcbuffer: Rc::new(RefCell::new(buffer)), id: true};
|
backlog: VecDeque::new(),
|
||||||
let t2 = Tee{rcbuffer: t1.rcbuffer.clone(), id: false};
|
iter,
|
||||||
|
owner: false,
|
||||||
|
};
|
||||||
|
let t1 = Tee {
|
||||||
|
rcbuffer: Rc::new(RefCell::new(buffer)),
|
||||||
|
id: true,
|
||||||
|
};
|
||||||
|
let t2 = Tee {
|
||||||
|
rcbuffer: t1.rcbuffer.clone(),
|
||||||
|
id: false,
|
||||||
|
};
|
||||||
(t1, t2)
|
(t1, t2)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Iterator for Tee<I>
|
impl<I> Iterator for Tee<I>
|
||||||
where I: Iterator,
|
where
|
||||||
I::Item: Clone
|
I: Iterator,
|
||||||
|
I::Item: Clone,
|
||||||
{
|
{
|
||||||
type Item = I::Item;
|
type Item = I::Item;
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
@@ -73,6 +86,8 @@ impl<I> Iterator for Tee<I>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I> ExactSizeIterator for Tee<I>
|
impl<I> ExactSizeIterator for Tee<I>
|
||||||
where I: ExactSizeIterator,
|
where
|
||||||
I::Item: Clone
|
I: ExactSizeIterator,
|
||||||
{}
|
I::Item: Clone,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|||||||
252
third_party/rust/itertools/src/tuple_impl.rs
vendored
252
third_party/rust/itertools/src/tuple_impl.rs
vendored
@@ -1,10 +1,10 @@
|
|||||||
//! Some iterator that produces tuples
|
//! Some iterator that produces tuples
|
||||||
|
|
||||||
|
use std::iter::Cycle;
|
||||||
use std::iter::Fuse;
|
use std::iter::Fuse;
|
||||||
use std::iter::FusedIterator;
|
use std::iter::FusedIterator;
|
||||||
use std::iter::Take;
|
|
||||||
use std::iter::Cycle;
|
use crate::size_hint;
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
// `HomogeneousTuple` is a public facade for `TupleCollect`, allowing
|
// `HomogeneousTuple` is a public facade for `TupleCollect`, allowing
|
||||||
// tuple-related methods to be used by clients in generic contexts, while
|
// tuple-related methods to be used by clients in generic contexts, while
|
||||||
@@ -12,9 +12,7 @@ use std::marker::PhantomData;
|
|||||||
// See https://github.com/rust-itertools/itertools/issues/387
|
// See https://github.com/rust-itertools/itertools/issues/387
|
||||||
|
|
||||||
/// Implemented for homogeneous tuples of size up to 12.
|
/// Implemented for homogeneous tuples of size up to 12.
|
||||||
pub trait HomogeneousTuple
|
pub trait HomogeneousTuple: TupleCollect {}
|
||||||
: TupleCollect
|
|
||||||
{}
|
|
||||||
|
|
||||||
impl<T: TupleCollect> HomogeneousTuple for T {}
|
impl<T: TupleCollect> HomogeneousTuple for T {}
|
||||||
|
|
||||||
@@ -24,25 +22,25 @@ impl<T: TupleCollect> HomogeneousTuple for T {}
|
|||||||
/// [`Tuples::into_buffer()`].
|
/// [`Tuples::into_buffer()`].
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct TupleBuffer<T>
|
pub struct TupleBuffer<T>
|
||||||
where T: HomogeneousTuple
|
where
|
||||||
|
T: HomogeneousTuple,
|
||||||
{
|
{
|
||||||
cur: usize,
|
cur: usize,
|
||||||
buf: T::Buffer,
|
buf: T::Buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> TupleBuffer<T>
|
impl<T> TupleBuffer<T>
|
||||||
where T: HomogeneousTuple
|
where
|
||||||
|
T: HomogeneousTuple,
|
||||||
{
|
{
|
||||||
fn new(buf: T::Buffer) -> Self {
|
fn new(buf: T::Buffer) -> Self {
|
||||||
TupleBuffer {
|
Self { cur: 0, buf }
|
||||||
cur: 0,
|
|
||||||
buf,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Iterator for TupleBuffer<T>
|
impl<T> Iterator for TupleBuffer<T>
|
||||||
where T: HomogeneousTuple
|
where
|
||||||
|
T: HomogeneousTuple,
|
||||||
{
|
{
|
||||||
type Item = T::Item;
|
type Item = T::Item;
|
||||||
|
|
||||||
@@ -61,18 +59,16 @@ impl<T> Iterator for TupleBuffer<T>
|
|||||||
let len = if buffer.is_empty() {
|
let len = if buffer.is_empty() {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
buffer.iter()
|
buffer
|
||||||
.position(|x| x.is_none())
|
.iter()
|
||||||
.unwrap_or_else(|| buffer.len())
|
.position(|x| x.is_none())
|
||||||
|
.unwrap_or(buffer.len())
|
||||||
};
|
};
|
||||||
(len, Some(len))
|
(len, Some(len))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ExactSizeIterator for TupleBuffer<T>
|
impl<T> ExactSizeIterator for TupleBuffer<T> where T: HomogeneousTuple {}
|
||||||
where T: HomogeneousTuple
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An iterator that groups the items in tuples of a specific size.
|
/// An iterator that groups the items in tuples of a specific size.
|
||||||
///
|
///
|
||||||
@@ -80,8 +76,9 @@ impl<T> ExactSizeIterator for TupleBuffer<T>
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct Tuples<I, T>
|
pub struct Tuples<I, T>
|
||||||
where I: Iterator<Item = T::Item>,
|
where
|
||||||
T: HomogeneousTuple
|
I: Iterator<Item = T::Item>,
|
||||||
|
T: HomogeneousTuple,
|
||||||
{
|
{
|
||||||
iter: Fuse<I>,
|
iter: Fuse<I>,
|
||||||
buf: T::Buffer,
|
buf: T::Buffer,
|
||||||
@@ -89,8 +86,9 @@ pub struct Tuples<I, T>
|
|||||||
|
|
||||||
/// Create a new tuples iterator.
|
/// Create a new tuples iterator.
|
||||||
pub fn tuples<I, T>(iter: I) -> Tuples<I, T>
|
pub fn tuples<I, T>(iter: I) -> Tuples<I, T>
|
||||||
where I: Iterator<Item = T::Item>,
|
where
|
||||||
T: HomogeneousTuple
|
I: Iterator<Item = T::Item>,
|
||||||
|
T: HomogeneousTuple,
|
||||||
{
|
{
|
||||||
Tuples {
|
Tuples {
|
||||||
iter: iter.fuse(),
|
iter: iter.fuse(),
|
||||||
@@ -99,19 +97,50 @@ pub fn tuples<I, T>(iter: I) -> Tuples<I, T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I, T> Iterator for Tuples<I, T>
|
impl<I, T> Iterator for Tuples<I, T>
|
||||||
where I: Iterator<Item = T::Item>,
|
where
|
||||||
T: HomogeneousTuple
|
I: Iterator<Item = T::Item>,
|
||||||
|
T: HomogeneousTuple,
|
||||||
{
|
{
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
T::collect_from_iter(&mut self.iter, &mut self.buf)
|
T::collect_from_iter(&mut self.iter, &mut self.buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
// The number of elts we've drawn from the underlying iterator, but have
|
||||||
|
// not yet produced as a tuple.
|
||||||
|
let buffered = T::buffer_len(&self.buf);
|
||||||
|
// To that, we must add the size estimates of the underlying iterator.
|
||||||
|
let (unbuffered_lo, unbuffered_hi) = self.iter.size_hint();
|
||||||
|
// The total low estimate is the sum of the already-buffered elements,
|
||||||
|
// plus the low estimate of remaining unbuffered elements, divided by
|
||||||
|
// the tuple size.
|
||||||
|
let total_lo = add_then_div(unbuffered_lo, buffered, T::num_items()).unwrap_or(usize::MAX);
|
||||||
|
// And likewise for the total high estimate, but using the high estimate
|
||||||
|
// of the remaining unbuffered elements.
|
||||||
|
let total_hi = unbuffered_hi.and_then(|hi| add_then_div(hi, buffered, T::num_items()));
|
||||||
|
(total_lo, total_hi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `(n + a) / d` avoiding overflow when possible, returns `None` if it overflows.
|
||||||
|
fn add_then_div(n: usize, a: usize, d: usize) -> Option<usize> {
|
||||||
|
debug_assert_ne!(d, 0);
|
||||||
|
(n / d).checked_add(a / d)?.checked_add((n % d + a % d) / d)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, T> ExactSizeIterator for Tuples<I, T>
|
||||||
|
where
|
||||||
|
I: ExactSizeIterator<Item = T::Item>,
|
||||||
|
T: HomogeneousTuple,
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, T> Tuples<I, T>
|
impl<I, T> Tuples<I, T>
|
||||||
where I: Iterator<Item = T::Item>,
|
where
|
||||||
T: HomogeneousTuple
|
I: Iterator<Item = T::Item>,
|
||||||
|
T: HomogeneousTuple,
|
||||||
{
|
{
|
||||||
/// Return a buffer with the produced items that was not enough to be grouped in a tuple.
|
/// Return a buffer with the produced items that was not enough to be grouped in a tuple.
|
||||||
///
|
///
|
||||||
@@ -128,7 +157,6 @@ impl<I, T> Tuples<I, T>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// An iterator over all contiguous windows that produces tuples of a specific size.
|
/// An iterator over all contiguous windows that produces tuples of a specific size.
|
||||||
///
|
///
|
||||||
/// See [`.tuple_windows()`](crate::Itertools::tuple_windows) for more
|
/// See [`.tuple_windows()`](crate::Itertools::tuple_windows) for more
|
||||||
@@ -136,125 +164,167 @@ impl<I, T> Tuples<I, T>
|
|||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct TupleWindows<I, T>
|
pub struct TupleWindows<I, T>
|
||||||
where I: Iterator<Item = T::Item>,
|
where
|
||||||
T: HomogeneousTuple
|
I: Iterator<Item = T::Item>,
|
||||||
|
T: HomogeneousTuple,
|
||||||
{
|
{
|
||||||
iter: I,
|
iter: I,
|
||||||
last: Option<T>,
|
last: Option<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new tuple windows iterator.
|
/// Create a new tuple windows iterator.
|
||||||
pub fn tuple_windows<I, T>(mut iter: I) -> TupleWindows<I, T>
|
pub fn tuple_windows<I, T>(iter: I) -> TupleWindows<I, T>
|
||||||
where I: Iterator<Item = T::Item>,
|
where
|
||||||
T: HomogeneousTuple,
|
I: Iterator<Item = T::Item>,
|
||||||
T::Item: Clone
|
T: HomogeneousTuple,
|
||||||
|
T::Item: Clone,
|
||||||
{
|
{
|
||||||
use std::iter::once;
|
TupleWindows { last: None, iter }
|
||||||
|
|
||||||
let mut last = None;
|
|
||||||
if T::num_items() != 1 {
|
|
||||||
// put in a duplicate item in front of the tuple; this simplifies
|
|
||||||
// .next() function.
|
|
||||||
if let Some(item) = iter.next() {
|
|
||||||
let iter = once(item.clone()).chain(once(item)).chain(&mut iter);
|
|
||||||
last = T::collect_from_iter_no_buf(iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TupleWindows {
|
|
||||||
iter,
|
|
||||||
last,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, T> Iterator for TupleWindows<I, T>
|
impl<I, T> Iterator for TupleWindows<I, T>
|
||||||
where I: Iterator<Item = T::Item>,
|
where
|
||||||
T: HomogeneousTuple + Clone,
|
I: Iterator<Item = T::Item>,
|
||||||
T::Item: Clone
|
T: HomogeneousTuple + Clone,
|
||||||
|
T::Item: Clone,
|
||||||
{
|
{
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if T::num_items() == 1 {
|
if T::num_items() == 1 {
|
||||||
return T::collect_from_iter_no_buf(&mut self.iter)
|
return T::collect_from_iter_no_buf(&mut self.iter);
|
||||||
}
|
}
|
||||||
if let Some(ref mut last) = self.last {
|
if let Some(new) = self.iter.next() {
|
||||||
if let Some(new) = self.iter.next() {
|
if let Some(ref mut last) = self.last {
|
||||||
last.left_shift_push(new);
|
last.left_shift_push(new);
|
||||||
return Some(last.clone());
|
Some(last.clone())
|
||||||
|
} else {
|
||||||
|
use std::iter::once;
|
||||||
|
let iter = once(new).chain(&mut self.iter);
|
||||||
|
self.last = T::collect_from_iter_no_buf(iter);
|
||||||
|
self.last.clone()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
None
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
let mut sh = self.iter.size_hint();
|
||||||
|
// Adjust the size hint at the beginning
|
||||||
|
// OR when `num_items == 1` (but it does not change the size hint).
|
||||||
|
if self.last.is_none() {
|
||||||
|
sh = size_hint::sub_scalar(sh, T::num_items() - 1);
|
||||||
|
}
|
||||||
|
sh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, T> FusedIterator for TupleWindows<I, T>
|
impl<I, T> ExactSizeIterator for TupleWindows<I, T>
|
||||||
where I: FusedIterator<Item = T::Item>,
|
where
|
||||||
T: HomogeneousTuple + Clone,
|
I: ExactSizeIterator<Item = T::Item>,
|
||||||
T::Item: Clone
|
T: HomogeneousTuple + Clone,
|
||||||
{}
|
T::Item: Clone,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// An iterator over all windows,wrapping back to the first elements when the
|
impl<I, T> FusedIterator for TupleWindows<I, T>
|
||||||
|
where
|
||||||
|
I: FusedIterator<Item = T::Item>,
|
||||||
|
T: HomogeneousTuple + Clone,
|
||||||
|
T::Item: Clone,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An iterator over all windows, wrapping back to the first elements when the
|
||||||
/// window would otherwise exceed the length of the iterator, producing tuples
|
/// window would otherwise exceed the length of the iterator, producing tuples
|
||||||
/// of a specific size.
|
/// of a specific size.
|
||||||
///
|
///
|
||||||
/// See [`.circular_tuple_windows()`](crate::Itertools::circular_tuple_windows) for more
|
/// See [`.circular_tuple_windows()`](crate::Itertools::circular_tuple_windows) for more
|
||||||
/// information.
|
/// information.
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CircularTupleWindows<I, T: Clone>
|
pub struct CircularTupleWindows<I, T>
|
||||||
where I: Iterator<Item = T::Item> + Clone,
|
where
|
||||||
T: TupleCollect + Clone
|
I: Iterator<Item = T::Item> + Clone,
|
||||||
|
T: TupleCollect + Clone,
|
||||||
{
|
{
|
||||||
iter: Take<TupleWindows<Cycle<I>, T>>,
|
iter: TupleWindows<Cycle<I>, T>,
|
||||||
phantom_data: PhantomData<T>
|
len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn circular_tuple_windows<I, T>(iter: I) -> CircularTupleWindows<I, T>
|
pub fn circular_tuple_windows<I, T>(iter: I) -> CircularTupleWindows<I, T>
|
||||||
where I: Iterator<Item = T::Item> + Clone + ExactSizeIterator,
|
where
|
||||||
T: TupleCollect + Clone,
|
I: Iterator<Item = T::Item> + Clone + ExactSizeIterator,
|
||||||
T::Item: Clone
|
T: TupleCollect + Clone,
|
||||||
|
T::Item: Clone,
|
||||||
{
|
{
|
||||||
let len = iter.len();
|
let len = iter.len();
|
||||||
let iter = tuple_windows(iter.cycle()).take(len);
|
let iter = tuple_windows(iter.cycle());
|
||||||
|
|
||||||
CircularTupleWindows {
|
CircularTupleWindows { iter, len }
|
||||||
iter,
|
|
||||||
phantom_data: PhantomData{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, T> Iterator for CircularTupleWindows<I, T>
|
impl<I, T> Iterator for CircularTupleWindows<I, T>
|
||||||
where I: Iterator<Item = T::Item> + Clone,
|
where
|
||||||
T: TupleCollect + Clone,
|
I: Iterator<Item = T::Item> + Clone,
|
||||||
T::Item: Clone
|
T: TupleCollect + Clone,
|
||||||
|
T::Item: Clone,
|
||||||
{
|
{
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
self.iter.next()
|
if self.len != 0 {
|
||||||
|
self.len -= 1;
|
||||||
|
self.iter.next()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
(self.len, Some(self.len))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, T> ExactSizeIterator for CircularTupleWindows<I, T>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = T::Item> + Clone,
|
||||||
|
T: TupleCollect + Clone,
|
||||||
|
T::Item: Clone,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, T> FusedIterator for CircularTupleWindows<I, T>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = T::Item> + Clone,
|
||||||
|
T: TupleCollect + Clone,
|
||||||
|
T::Item: Clone,
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TupleCollect: Sized {
|
pub trait TupleCollect: Sized {
|
||||||
type Item;
|
type Item;
|
||||||
type Buffer: Default + AsRef<[Option<Self::Item>]> + AsMut<[Option<Self::Item>]>;
|
type Buffer: Default + AsRef<[Option<Self::Item>]> + AsMut<[Option<Self::Item>]>;
|
||||||
|
|
||||||
|
fn buffer_len(buf: &Self::Buffer) -> usize {
|
||||||
|
let s = buf.as_ref();
|
||||||
|
s.iter().position(Option::is_none).unwrap_or(s.len())
|
||||||
|
}
|
||||||
|
|
||||||
fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
|
fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
|
||||||
where I: IntoIterator<Item = Self::Item>;
|
where
|
||||||
|
I: IntoIterator<Item = Self::Item>;
|
||||||
|
|
||||||
fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
|
fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
|
||||||
where I: IntoIterator<Item = Self::Item>;
|
where
|
||||||
|
I: IntoIterator<Item = Self::Item>;
|
||||||
|
|
||||||
fn num_items() -> usize;
|
fn num_items() -> usize;
|
||||||
|
|
||||||
fn left_shift_push(&mut self, item: Self::Item);
|
fn left_shift_push(&mut self, item: Self::Item);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! count_ident{
|
|
||||||
() => {0};
|
|
||||||
($i0:ident, $($i:ident,)*) => {1 + count_ident!($($i,)*)};
|
|
||||||
}
|
|
||||||
macro_rules! rev_for_each_ident{
|
macro_rules! rev_for_each_ident{
|
||||||
($m:ident, ) => {};
|
($m:ident, ) => {};
|
||||||
($m:ident, $i0:ident, $($i:ident,)*) => {
|
($m:ident, $i0:ident, $($i:ident,)*) => {
|
||||||
@@ -269,7 +339,7 @@ macro_rules! impl_tuple_collect {
|
|||||||
impl_tuple_collect!($($Y,)*);
|
impl_tuple_collect!($($Y,)*);
|
||||||
impl<A> TupleCollect for ($(ignore_ident!($Y, A),)*) {
|
impl<A> TupleCollect for ($(ignore_ident!($Y, A),)*) {
|
||||||
type Item = A;
|
type Item = A;
|
||||||
type Buffer = [Option<A>; count_ident!($($Y,)*) - 1];
|
type Buffer = [Option<A>; count_ident!($($Y)*) - 1];
|
||||||
|
|
||||||
#[allow(unused_assignments, unused_mut)]
|
#[allow(unused_assignments, unused_mut)]
|
||||||
fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
|
fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
|
||||||
@@ -312,7 +382,7 @@ macro_rules! impl_tuple_collect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn num_items() -> usize {
|
fn num_items() -> usize {
|
||||||
count_ident!($($Y,)*)
|
count_ident!($($Y)*)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn left_shift_push(&mut self, mut item: A) {
|
fn left_shift_push(&mut self, mut item: A) {
|
||||||
|
|||||||
117
third_party/rust/itertools/src/unique_impl.rs
vendored
117
third_party/rust/itertools/src/unique_impl.rs
vendored
@@ -1,7 +1,7 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::hash::Hash;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::hash::Hash;
|
||||||
use std::iter::FusedIterator;
|
use std::iter::FusedIterator;
|
||||||
|
|
||||||
/// An iterator adapter to filter out duplicate elements.
|
/// An iterator adapter to filter out duplicate elements.
|
||||||
@@ -19,17 +19,19 @@ pub struct UniqueBy<I: Iterator, V, F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I, V, F> fmt::Debug for UniqueBy<I, V, F>
|
impl<I, V, F> fmt::Debug for UniqueBy<I, V, F>
|
||||||
where I: Iterator + fmt::Debug,
|
where
|
||||||
V: fmt::Debug + Hash + Eq,
|
I: Iterator + fmt::Debug,
|
||||||
|
V: fmt::Debug + Hash + Eq,
|
||||||
{
|
{
|
||||||
debug_fmt_fields!(UniqueBy, iter, used);
|
debug_fmt_fields!(UniqueBy, iter, used);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `UniqueBy` iterator.
|
/// Create a new `UniqueBy` iterator.
|
||||||
pub fn unique_by<I, V, F>(iter: I, f: F) -> UniqueBy<I, V, F>
|
pub fn unique_by<I, V, F>(iter: I, f: F) -> UniqueBy<I, V, F>
|
||||||
where V: Eq + Hash,
|
where
|
||||||
F: FnMut(&I::Item) -> V,
|
V: Eq + Hash,
|
||||||
I: Iterator,
|
F: FnMut(&I::Item) -> V,
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
UniqueBy {
|
UniqueBy {
|
||||||
iter,
|
iter,
|
||||||
@@ -40,8 +42,9 @@ pub fn unique_by<I, V, F>(iter: I, f: F) -> UniqueBy<I, V, F>
|
|||||||
|
|
||||||
// count the number of new unique keys in iterable (`used` is the set already seen)
|
// 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>(mut used: HashMap<K, ()>, iterable: I) -> usize
|
||||||
where I: IntoIterator<Item=K>,
|
where
|
||||||
K: Hash + Eq,
|
I: IntoIterator<Item = K>,
|
||||||
|
K: Hash + Eq,
|
||||||
{
|
{
|
||||||
let iter = iterable.into_iter();
|
let iter = iterable.into_iter();
|
||||||
let current_used = used.len();
|
let current_used = used.len();
|
||||||
@@ -50,20 +53,16 @@ fn count_new_keys<I, K>(mut used: HashMap<K, ()>, iterable: I) -> usize
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I, V, F> Iterator for UniqueBy<I, V, F>
|
impl<I, V, F> Iterator for UniqueBy<I, V, F>
|
||||||
where I: Iterator,
|
where
|
||||||
V: Eq + Hash,
|
I: Iterator,
|
||||||
F: FnMut(&I::Item) -> V
|
V: Eq + Hash,
|
||||||
|
F: FnMut(&I::Item) -> V,
|
||||||
{
|
{
|
||||||
type Item = I::Item;
|
type Item = I::Item;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
while let Some(v) = self.iter.next() {
|
let Self { iter, used, f } = self;
|
||||||
let key = (self.f)(&v);
|
iter.find(|v| used.insert(f(v), ()).is_none())
|
||||||
if self.used.insert(key, ()).is_none() {
|
|
||||||
return Some(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -79,42 +78,42 @@ impl<I, V, F> Iterator for UniqueBy<I, V, F>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I, V, F> DoubleEndedIterator for UniqueBy<I, V, F>
|
impl<I, V, F> DoubleEndedIterator for UniqueBy<I, V, F>
|
||||||
where I: DoubleEndedIterator,
|
where
|
||||||
V: Eq + Hash,
|
I: DoubleEndedIterator,
|
||||||
F: FnMut(&I::Item) -> V
|
V: Eq + Hash,
|
||||||
|
F: FnMut(&I::Item) -> V,
|
||||||
{
|
{
|
||||||
fn next_back(&mut self) -> Option<Self::Item> {
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
while let Some(v) = self.iter.next_back() {
|
let Self { iter, used, f } = self;
|
||||||
let key = (self.f)(&v);
|
iter.rfind(|v| used.insert(f(v), ()).is_none())
|
||||||
if self.used.insert(key, ()).is_none() {
|
|
||||||
return Some(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, V, F> FusedIterator for UniqueBy<I, V, F>
|
impl<I, V, F> FusedIterator for UniqueBy<I, V, F>
|
||||||
where I: FusedIterator,
|
where
|
||||||
V: Eq + Hash,
|
I: FusedIterator,
|
||||||
F: FnMut(&I::Item) -> V
|
V: Eq + Hash,
|
||||||
{}
|
F: FnMut(&I::Item) -> V,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
impl<I> Iterator for Unique<I>
|
impl<I> Iterator for Unique<I>
|
||||||
where I: Iterator,
|
where
|
||||||
I::Item: Eq + Hash + Clone
|
I: Iterator,
|
||||||
|
I::Item: Eq + Hash + Clone,
|
||||||
{
|
{
|
||||||
type Item = I::Item;
|
type Item = I::Item;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
while let Some(v) = self.iter.iter.next() {
|
let UniqueBy { iter, used, .. } = &mut self.iter;
|
||||||
if let Entry::Vacant(entry) = self.iter.used.entry(v) {
|
iter.find_map(|v| {
|
||||||
|
if let Entry::Vacant(entry) = used.entry(v) {
|
||||||
let elt = entry.key().clone();
|
let elt = entry.key().clone();
|
||||||
entry.insert(());
|
entry.insert(());
|
||||||
return Some(elt);
|
return Some(elt);
|
||||||
}
|
}
|
||||||
}
|
None
|
||||||
None
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -129,51 +128,61 @@ impl<I> Iterator for Unique<I>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I> DoubleEndedIterator for Unique<I>
|
impl<I> DoubleEndedIterator for Unique<I>
|
||||||
where I: DoubleEndedIterator,
|
where
|
||||||
I::Item: Eq + Hash + Clone
|
I: DoubleEndedIterator,
|
||||||
|
I::Item: Eq + Hash + Clone,
|
||||||
{
|
{
|
||||||
fn next_back(&mut self) -> Option<Self::Item> {
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
while let Some(v) = self.iter.iter.next_back() {
|
let UniqueBy { iter, used, .. } = &mut self.iter;
|
||||||
if let Entry::Vacant(entry) = self.iter.used.entry(v) {
|
iter.rev().find_map(|v| {
|
||||||
|
if let Entry::Vacant(entry) = used.entry(v) {
|
||||||
let elt = entry.key().clone();
|
let elt = entry.key().clone();
|
||||||
entry.insert(());
|
entry.insert(());
|
||||||
return Some(elt);
|
return Some(elt);
|
||||||
}
|
}
|
||||||
}
|
None
|
||||||
None
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> FusedIterator for Unique<I>
|
impl<I> FusedIterator for Unique<I>
|
||||||
where I: FusedIterator,
|
where
|
||||||
I::Item: Eq + Hash + Clone
|
I: FusedIterator,
|
||||||
{}
|
I::Item: Eq + Hash + Clone,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// An iterator adapter to filter out duplicate elements.
|
/// An iterator adapter to filter out duplicate elements.
|
||||||
///
|
///
|
||||||
/// See [`.unique()`](crate::Itertools::unique) for more information.
|
/// See [`.unique()`](crate::Itertools::unique) for more information.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct Unique<I: Iterator> {
|
pub struct Unique<I>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
I::Item: Eq + Hash + Clone,
|
||||||
|
{
|
||||||
iter: UniqueBy<I, I::Item, ()>,
|
iter: UniqueBy<I, I::Item, ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> fmt::Debug for Unique<I>
|
impl<I> fmt::Debug for Unique<I>
|
||||||
where I: Iterator + fmt::Debug,
|
where
|
||||||
I::Item: Hash + Eq + fmt::Debug,
|
I: Iterator + fmt::Debug,
|
||||||
|
I::Item: Hash + Eq + fmt::Debug + Clone,
|
||||||
{
|
{
|
||||||
debug_fmt_fields!(Unique, iter);
|
debug_fmt_fields!(Unique, iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unique<I>(iter: I) -> Unique<I>
|
pub fn unique<I>(iter: I) -> Unique<I>
|
||||||
where I: Iterator,
|
where
|
||||||
I::Item: Eq + Hash,
|
I: Iterator,
|
||||||
|
I::Item: Eq + Hash + Clone,
|
||||||
{
|
{
|
||||||
Unique {
|
Unique {
|
||||||
iter: UniqueBy {
|
iter: UniqueBy {
|
||||||
iter,
|
iter,
|
||||||
used: HashMap::new(),
|
used: HashMap::new(),
|
||||||
f: (),
|
f: (),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
third_party/rust/itertools/src/unziptuple.rs
vendored
2
third_party/rust/itertools/src/unziptuple.rs
vendored
@@ -1,6 +1,6 @@
|
|||||||
/// Converts an iterator of tuples into a tuple of containers.
|
/// Converts an iterator of tuples into a tuple of containers.
|
||||||
///
|
///
|
||||||
/// `unzip()` consumes an entire iterator of n-ary tuples, producing `n` collections, one for each
|
/// `multiunzip()` consumes an entire iterator of n-ary tuples, producing `n` collections, one for each
|
||||||
/// column.
|
/// column.
|
||||||
///
|
///
|
||||||
/// This function is, in some sense, the opposite of [`multizip`].
|
/// This function is, in some sense, the opposite of [`multizip`].
|
||||||
|
|||||||
94
third_party/rust/itertools/src/with_position.rs
vendored
94
third_party/rust/itertools/src/with_position.rs
vendored
@@ -1,28 +1,40 @@
|
|||||||
use std::iter::{Fuse,Peekable, FusedIterator};
|
use std::fmt;
|
||||||
|
use std::iter::{Fuse, FusedIterator, Peekable};
|
||||||
|
|
||||||
/// An iterator adaptor that wraps each element in an [`Position`].
|
/// An iterator adaptor that wraps each element in an [`Position`].
|
||||||
///
|
///
|
||||||
/// Iterator element type is `Position<I::Item>`.
|
/// Iterator element type is `(Position, I::Item)`.
|
||||||
///
|
///
|
||||||
/// See [`.with_position()`](crate::Itertools::with_position) for more information.
|
/// See [`.with_position()`](crate::Itertools::with_position) for more information.
|
||||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
pub struct WithPosition<I>
|
pub struct WithPosition<I>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
handled_first: bool,
|
handled_first: bool,
|
||||||
peekable: Peekable<Fuse<I>>,
|
peekable: Peekable<Fuse<I>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<I> fmt::Debug for WithPosition<I>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
Peekable<Fuse<I>>: fmt::Debug,
|
||||||
|
{
|
||||||
|
debug_fmt_fields!(WithPosition, handled_first, peekable);
|
||||||
|
}
|
||||||
|
|
||||||
impl<I> Clone for WithPosition<I>
|
impl<I> Clone for WithPosition<I>
|
||||||
where I: Clone + Iterator,
|
where
|
||||||
I::Item: Clone,
|
I: Clone + Iterator,
|
||||||
|
I::Item: Clone,
|
||||||
{
|
{
|
||||||
clone_fields!(handled_first, peekable);
|
clone_fields!(handled_first, peekable);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `WithPosition` iterator.
|
/// Create a new `WithPosition` iterator.
|
||||||
pub fn with_position<I>(iter: I) -> WithPosition<I>
|
pub fn with_position<I>(iter: I) -> WithPosition<I>
|
||||||
where I: Iterator,
|
where
|
||||||
|
I: Iterator,
|
||||||
{
|
{
|
||||||
WithPosition {
|
WithPosition {
|
||||||
handled_first: false,
|
handled_first: false,
|
||||||
@@ -30,36 +42,24 @@ pub fn with_position<I>(iter: I) -> WithPosition<I>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A value yielded by `WithPosition`.
|
/// The first component of the value yielded by `WithPosition`.
|
||||||
/// Indicates the position of this element in the iterator results.
|
/// Indicates the position of this element in the iterator results.
|
||||||
///
|
///
|
||||||
/// See [`.with_position()`](crate::Itertools::with_position) for more information.
|
/// See [`.with_position()`](crate::Itertools::with_position) for more information.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Position<T> {
|
pub enum Position {
|
||||||
/// This is the first element.
|
/// This is the first element.
|
||||||
First(T),
|
First,
|
||||||
/// This is neither the first nor the last element.
|
/// This is neither the first nor the last element.
|
||||||
Middle(T),
|
Middle,
|
||||||
/// This is the last element.
|
/// This is the last element.
|
||||||
Last(T),
|
Last,
|
||||||
/// This is the only element.
|
/// This is the only element.
|
||||||
Only(T),
|
Only,
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Position<T> {
|
|
||||||
/// Return the inner value.
|
|
||||||
pub fn into_inner(self) -> T {
|
|
||||||
match self {
|
|
||||||
Position::First(x) |
|
|
||||||
Position::Middle(x) |
|
|
||||||
Position::Last(x) |
|
|
||||||
Position::Only(x) => x,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Iterator> Iterator for WithPosition<I> {
|
impl<I: Iterator> Iterator for WithPosition<I> {
|
||||||
type Item = Position<I::Item>;
|
type Item = (Position, I::Item);
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
match self.peekable.next() {
|
match self.peekable.next() {
|
||||||
@@ -70,15 +70,15 @@ impl<I: Iterator> Iterator for WithPosition<I> {
|
|||||||
// Peek to see if this is also the last item,
|
// Peek to see if this is also the last item,
|
||||||
// in which case tag it as `Only`.
|
// in which case tag it as `Only`.
|
||||||
match self.peekable.peek() {
|
match self.peekable.peek() {
|
||||||
Some(_) => Some(Position::First(item)),
|
Some(_) => Some((Position::First, item)),
|
||||||
None => Some(Position::Only(item)),
|
None => Some((Position::Only, item)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Have seen the first item, and there's something left.
|
// Have seen the first item, and there's something left.
|
||||||
// Peek to see if this is the last item.
|
// Peek to see if this is the last item.
|
||||||
match self.peekable.peek() {
|
match self.peekable.peek() {
|
||||||
Some(_) => Some(Position::Middle(item)),
|
Some(_) => Some((Position::Middle, item)),
|
||||||
None => Some(Position::Last(item)),
|
None => Some((Position::Last, item)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,11 +90,35 @@ impl<I: Iterator> Iterator for WithPosition<I> {
|
|||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
self.peekable.size_hint()
|
self.peekable.size_hint()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fold<B, F>(mut self, mut init: B, mut f: F) -> B
|
||||||
|
where
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
if let Some(mut head) = self.peekable.next() {
|
||||||
|
if !self.handled_first {
|
||||||
|
// The current head is `First` or `Only`,
|
||||||
|
// it depends if there is another item or not.
|
||||||
|
match self.peekable.next() {
|
||||||
|
Some(second) => {
|
||||||
|
let first = std::mem::replace(&mut head, second);
|
||||||
|
init = f(init, (Position::First, first));
|
||||||
|
}
|
||||||
|
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))
|
||||||
|
});
|
||||||
|
// The "head" is now the last item.
|
||||||
|
init = f(init, (Position::Last, head));
|
||||||
|
}
|
||||||
|
init
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> ExactSizeIterator for WithPosition<I>
|
impl<I> ExactSizeIterator for WithPosition<I> where I: ExactSizeIterator {}
|
||||||
where I: ExactSizeIterator,
|
|
||||||
{ }
|
|
||||||
|
|
||||||
impl<I: Iterator> FusedIterator for WithPosition<I>
|
impl<I: Iterator> FusedIterator for WithPosition<I> {}
|
||||||
{}
|
|
||||||
|
|||||||
29
third_party/rust/itertools/src/zip_eq_impl.rs
vendored
29
third_party/rust/itertools/src/zip_eq_impl.rs
vendored
@@ -1,6 +1,7 @@
|
|||||||
use super::size_hint;
|
use super::size_hint;
|
||||||
|
|
||||||
/// An iterator which iterates two other iterators simultaneously
|
/// An iterator which iterates two other iterators simultaneously
|
||||||
|
/// and panic if they have different lengths.
|
||||||
///
|
///
|
||||||
/// See [`.zip_eq()`](crate::Itertools::zip_eq) for more information.
|
/// See [`.zip_eq()`](crate::Itertools::zip_eq) for more information.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@@ -10,9 +11,7 @@ pub struct ZipEq<I, J> {
|
|||||||
b: J,
|
b: J,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate `i` and `j` in lock step.
|
/// Zips two iterators but **panics** if they are not of the same length.
|
||||||
///
|
|
||||||
/// **Panics** if the iterators are not of the same length.
|
|
||||||
///
|
///
|
||||||
/// [`IntoIterator`] enabled version of [`Itertools::zip_eq`](crate::Itertools::zip_eq).
|
/// [`IntoIterator`] enabled version of [`Itertools::zip_eq`](crate::Itertools::zip_eq).
|
||||||
///
|
///
|
||||||
@@ -22,11 +21,13 @@ pub struct ZipEq<I, J> {
|
|||||||
/// let data = [1, 2, 3, 4, 5];
|
/// let data = [1, 2, 3, 4, 5];
|
||||||
/// for (a, b) in zip_eq(&data[..data.len() - 1], &data[1..]) {
|
/// for (a, b) in zip_eq(&data[..data.len() - 1], &data[1..]) {
|
||||||
/// /* loop body */
|
/// /* loop body */
|
||||||
|
/// # let _ = (a, b);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn zip_eq<I, J>(i: I, j: J) -> ZipEq<I::IntoIter, J::IntoIter>
|
pub fn zip_eq<I, J>(i: I, j: J) -> ZipEq<I::IntoIter, J::IntoIter>
|
||||||
where I: IntoIterator,
|
where
|
||||||
J: IntoIterator
|
I: IntoIterator,
|
||||||
|
J: IntoIterator,
|
||||||
{
|
{
|
||||||
ZipEq {
|
ZipEq {
|
||||||
a: i.into_iter(),
|
a: i.into_iter(),
|
||||||
@@ -35,8 +36,9 @@ pub fn zip_eq<I, J>(i: I, j: J) -> ZipEq<I::IntoIter, J::IntoIter>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I, J> Iterator for ZipEq<I, J>
|
impl<I, J> Iterator for ZipEq<I, J>
|
||||||
where I: Iterator,
|
where
|
||||||
J: Iterator
|
I: Iterator,
|
||||||
|
J: Iterator,
|
||||||
{
|
{
|
||||||
type Item = (I::Item, J::Item);
|
type Item = (I::Item, J::Item);
|
||||||
|
|
||||||
@@ -44,8 +46,9 @@ impl<I, J> Iterator for ZipEq<I, J>
|
|||||||
match (self.a.next(), self.b.next()) {
|
match (self.a.next(), self.b.next()) {
|
||||||
(None, None) => None,
|
(None, None) => None,
|
||||||
(Some(a), Some(b)) => Some((a, b)),
|
(Some(a), Some(b)) => Some((a, b)),
|
||||||
(None, Some(_)) | (Some(_), None) =>
|
(None, Some(_)) | (Some(_), None) => {
|
||||||
panic!("itertools: .zip_eq() reached end of one iterator before the other")
|
panic!("itertools: .zip_eq() reached end of one iterator before the other")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,6 +58,8 @@ impl<I, J> Iterator for ZipEq<I, J>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<I, J> ExactSizeIterator for ZipEq<I, J>
|
impl<I, J> ExactSizeIterator for ZipEq<I, J>
|
||||||
where I: ExactSizeIterator,
|
where
|
||||||
J: ExactSizeIterator
|
I: ExactSizeIterator,
|
||||||
{}
|
J: ExactSizeIterator,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|||||||
82
third_party/rust/itertools/src/zip_longest.rs
vendored
82
third_party/rust/itertools/src/zip_longest.rs
vendored
@@ -1,5 +1,5 @@
|
|||||||
use std::cmp::Ordering::{Equal, Greater, Less};
|
|
||||||
use super::size_hint;
|
use super::size_hint;
|
||||||
|
use std::cmp::Ordering::{Equal, Greater, Less};
|
||||||
use std::iter::{Fuse, FusedIterator};
|
use std::iter::{Fuse, FusedIterator};
|
||||||
|
|
||||||
use crate::either_or_both::EitherOrBoth;
|
use crate::either_or_both::EitherOrBoth;
|
||||||
@@ -8,6 +8,7 @@ use crate::either_or_both::EitherOrBoth;
|
|||||||
// and dedicated to itertools https://github.com/rust-lang/rust/pull/19283
|
// and dedicated to itertools https://github.com/rust-lang/rust/pull/19283
|
||||||
|
|
||||||
/// An iterator which iterates two other iterators simultaneously
|
/// An iterator which iterates two other iterators simultaneously
|
||||||
|
/// and wraps the elements in [`EitherOrBoth`].
|
||||||
///
|
///
|
||||||
/// This iterator is *fused*.
|
/// This iterator is *fused*.
|
||||||
///
|
///
|
||||||
@@ -21,8 +22,9 @@ pub struct ZipLongest<T, U> {
|
|||||||
|
|
||||||
/// Create a new `ZipLongest` iterator.
|
/// Create a new `ZipLongest` iterator.
|
||||||
pub fn zip_longest<T, U>(a: T, b: U) -> ZipLongest<T, U>
|
pub fn zip_longest<T, U>(a: T, b: U) -> ZipLongest<T, U>
|
||||||
where T: Iterator,
|
where
|
||||||
U: Iterator
|
T: Iterator,
|
||||||
|
U: Iterator,
|
||||||
{
|
{
|
||||||
ZipLongest {
|
ZipLongest {
|
||||||
a: a.fuse(),
|
a: a.fuse(),
|
||||||
@@ -31,8 +33,9 @@ pub fn zip_longest<T, U>(a: T, b: U) -> ZipLongest<T, U>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> Iterator for ZipLongest<T, U>
|
impl<T, U> Iterator for ZipLongest<T, U>
|
||||||
where T: Iterator,
|
where
|
||||||
U: Iterator
|
T: Iterator,
|
||||||
|
U: Iterator,
|
||||||
{
|
{
|
||||||
type Item = EitherOrBoth<T::Item, U::Item>;
|
type Item = EitherOrBoth<T::Item, U::Item>;
|
||||||
|
|
||||||
@@ -50,11 +53,29 @@ impl<T, U> Iterator for ZipLongest<T, U>
|
|||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
size_hint::max(self.a.size_hint(), self.b.size_hint())
|
size_hint::max(self.a.size_hint(), self.b.size_hint())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn fold<B, F>(self, init: B, mut f: F) -> B
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
let Self { mut a, mut b } = self;
|
||||||
|
let res = a.try_fold(init, |init, a| match b.next() {
|
||||||
|
Some(b) => Ok(f(init, EitherOrBoth::Both(a, b))),
|
||||||
|
None => Err(f(init, EitherOrBoth::Left(a))),
|
||||||
|
});
|
||||||
|
match res {
|
||||||
|
Ok(acc) => b.map(EitherOrBoth::Right).fold(acc, f),
|
||||||
|
Err(acc) => a.map(EitherOrBoth::Left).fold(acc, f),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> DoubleEndedIterator for ZipLongest<T, U>
|
impl<T, U> DoubleEndedIterator for ZipLongest<T, U>
|
||||||
where T: DoubleEndedIterator + ExactSizeIterator,
|
where
|
||||||
U: DoubleEndedIterator + ExactSizeIterator
|
T: DoubleEndedIterator + ExactSizeIterator,
|
||||||
|
U: DoubleEndedIterator + ExactSizeIterator,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next_back(&mut self) -> Option<Self::Item> {
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
@@ -70,14 +91,49 @@ impl<T, U> DoubleEndedIterator for ZipLongest<T, U>
|
|||||||
Less => self.b.next_back().map(EitherOrBoth::Right),
|
Less => self.b.next_back().map(EitherOrBoth::Right),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rfold<B, F>(self, mut init: B, mut f: F) -> B
|
||||||
|
where
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
let Self { mut a, mut b } = self;
|
||||||
|
let a_len = a.len();
|
||||||
|
let b_len = b.len();
|
||||||
|
match a_len.cmp(&b_len) {
|
||||||
|
Equal => {}
|
||||||
|
Greater => {
|
||||||
|
init = a
|
||||||
|
.by_ref()
|
||||||
|
.rev()
|
||||||
|
.take(a_len - b_len)
|
||||||
|
.map(EitherOrBoth::Left)
|
||||||
|
.fold(init, &mut f)
|
||||||
|
}
|
||||||
|
Less => {
|
||||||
|
init = b
|
||||||
|
.by_ref()
|
||||||
|
.rev()
|
||||||
|
.take(b_len - a_len)
|
||||||
|
.map(EitherOrBoth::Right)
|
||||||
|
.fold(init, &mut f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a.rfold(init, |acc, item_a| {
|
||||||
|
f(acc, EitherOrBoth::Both(item_a, b.next_back().unwrap()))
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> ExactSizeIterator for ZipLongest<T, U>
|
impl<T, U> ExactSizeIterator for ZipLongest<T, U>
|
||||||
where T: ExactSizeIterator,
|
where
|
||||||
U: ExactSizeIterator
|
T: ExactSizeIterator,
|
||||||
{}
|
U: ExactSizeIterator,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
impl<T, U> FusedIterator for ZipLongest<T, U>
|
impl<T, U> FusedIterator for ZipLongest<T, U>
|
||||||
where T: Iterator,
|
where
|
||||||
U: Iterator
|
T: Iterator,
|
||||||
{}
|
U: Iterator,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|||||||
13
third_party/rust/itertools/src/ziptuple.rs
vendored
13
third_party/rust/itertools/src/ziptuple.rs
vendored
@@ -7,7 +7,7 @@ pub struct Zip<T> {
|
|||||||
t: T,
|
t: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator that generalizes *.zip()* and allows running multiple iterators in lockstep.
|
/// An iterator that generalizes `.zip()` and allows running multiple iterators in lockstep.
|
||||||
///
|
///
|
||||||
/// The iterator `Zip<(I, J, ..., M)>` is formed from a tuple of iterators (or values that
|
/// The iterator `Zip<(I, J, ..., M)>` is formed from a tuple of iterators (or values that
|
||||||
/// implement [`IntoIterator`]) and yields elements
|
/// implement [`IntoIterator`]) and yields elements
|
||||||
@@ -16,11 +16,11 @@ pub struct Zip<T> {
|
|||||||
/// 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 like `(A, B, ..., E)` where `A` to `E` are the
|
||||||
/// element types of the subiterator.
|
/// element types of the subiterator.
|
||||||
///
|
///
|
||||||
/// **Note:** The result of this macro is a value of a named type (`Zip<(I, J,
|
/// **Note:** The result of this function is a value of a named type (`Zip<(I, J,
|
||||||
/// ..)>` of each component iterator `I, J, ...`) if each component iterator is
|
/// ..)>` of each component iterator `I, J, ...`) if each component iterator is
|
||||||
/// nameable.
|
/// nameable.
|
||||||
///
|
///
|
||||||
/// Prefer [`izip!()`] over `multizip` for the performance benefits of using the
|
/// Prefer [`izip!()`](crate::izip) over `multizip` for the performance benefits of using the
|
||||||
/// standard library `.zip()`. Prefer `multizip` if a nameable type is needed.
|
/// standard library `.zip()`. Prefer `multizip` if a nameable type is needed.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@@ -36,10 +36,9 @@ pub struct Zip<T> {
|
|||||||
///
|
///
|
||||||
/// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]);
|
/// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]);
|
||||||
/// ```
|
/// ```
|
||||||
/// [`izip!()`]: crate::izip
|
|
||||||
pub fn multizip<T, U>(t: U) -> Zip<T>
|
pub fn multizip<T, U>(t: U) -> Zip<T>
|
||||||
where Zip<T>: From<U>,
|
where
|
||||||
Zip<T>: Iterator,
|
Zip<T>: From<U> + Iterator,
|
||||||
{
|
{
|
||||||
Zip::from(t)
|
Zip::from(t)
|
||||||
}
|
}
|
||||||
@@ -82,7 +81,7 @@ macro_rules! impl_zip_iter {
|
|||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>)
|
fn size_hint(&self) -> (usize, Option<usize>)
|
||||||
{
|
{
|
||||||
let sh = (::std::usize::MAX, None);
|
let sh = (usize::MAX, None);
|
||||||
let ($(ref $B,)*) = self.t;
|
let ($(ref $B,)*) = self.t;
|
||||||
$(
|
$(
|
||||||
let sh = size_hint::min($B.size_hint(), sh);
|
let sh = size_hint::min($B.size_hint(), sh);
|
||||||
|
|||||||
@@ -22,9 +22,14 @@ impl Iterator for PanickingCounter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn no_collect_test<A, T>(to_adaptor: T)
|
fn no_collect_test<A, T>(to_adaptor: T)
|
||||||
where A: Iterator, T: Fn(PanickingCounter) -> A
|
where
|
||||||
|
A: Iterator,
|
||||||
|
T: Fn(PanickingCounter) -> A,
|
||||||
{
|
{
|
||||||
let counter = PanickingCounter { curr: 0, max: 10_000 };
|
let counter = PanickingCounter {
|
||||||
|
curr: 0,
|
||||||
|
max: 10_000,
|
||||||
|
};
|
||||||
let adaptor = to_adaptor(counter);
|
let adaptor = to_adaptor(counter);
|
||||||
|
|
||||||
for _ in adaptor.take(5) {}
|
for _ in adaptor.take(5) {}
|
||||||
@@ -43,4 +48,4 @@ fn combinations_no_collect() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn combinations_with_replacement_no_collect() {
|
fn combinations_with_replacement_no_collect() {
|
||||||
no_collect_test(|iter| iter.combinations_with_replacement(5))
|
no_collect_test(|iter| iter.combinations_with_replacement(5))
|
||||||
}
|
}
|
||||||
|
|||||||
283
third_party/rust/itertools/tests/laziness.rs
vendored
Normal file
283
third_party/rust/itertools/tests/laziness.rs
vendored
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
#![allow(unstable_name_collisions)]
|
||||||
|
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
|
struct Panicking;
|
||||||
|
|
||||||
|
impl Iterator for Panicking {
|
||||||
|
type Item = u8;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<u8> {
|
||||||
|
panic!("iterator adaptor is not lazy")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
(0, Some(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExactSizeIterator for Panicking {}
|
||||||
|
|
||||||
|
/// ## Usage example
|
||||||
|
/// ```compile_fail
|
||||||
|
/// must_use_tests! {
|
||||||
|
/// name {
|
||||||
|
/// Panicking.name(); // Add `let _ =` only if required (encountered error).
|
||||||
|
/// }
|
||||||
|
/// // ...
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// **TODO:** test missing `must_use` attributes better, maybe with a new lint.
|
||||||
|
macro_rules! must_use_tests {
|
||||||
|
($($(#[$attr:meta])* $name:ident $body:block)*) => {
|
||||||
|
$(
|
||||||
|
/// `#[deny(unused_must_use)]` should force us to ignore the resulting iterators
|
||||||
|
/// by adding `let _ = ...;` on every iterator.
|
||||||
|
/// If it does not, then a `must_use` attribute is missing on the associated struct.
|
||||||
|
///
|
||||||
|
/// However, it's only helpful if we don't add `let _ =` before seeing if there is an error or not.
|
||||||
|
/// And it does not protect us against removed `must_use` attributes.
|
||||||
|
/// There is no simple way to test this yet.
|
||||||
|
#[deny(unused_must_use)]
|
||||||
|
#[test]
|
||||||
|
$(#[$attr])*
|
||||||
|
fn $name() $body
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
must_use_tests! {
|
||||||
|
// Itertools trait:
|
||||||
|
interleave {
|
||||||
|
let _ = Panicking.interleave(Panicking);
|
||||||
|
}
|
||||||
|
interleave_shortest {
|
||||||
|
let _ = Panicking.interleave_shortest(Panicking);
|
||||||
|
}
|
||||||
|
intersperse {
|
||||||
|
let _ = Panicking.intersperse(0);
|
||||||
|
}
|
||||||
|
intersperse_with {
|
||||||
|
let _ = Panicking.intersperse_with(|| 0);
|
||||||
|
}
|
||||||
|
get {
|
||||||
|
let _ = Panicking.get(1..4);
|
||||||
|
let _ = Panicking.get(1..=4);
|
||||||
|
let _ = Panicking.get(1..);
|
||||||
|
let _ = Panicking.get(..4);
|
||||||
|
let _ = Panicking.get(..=4);
|
||||||
|
let _ = Panicking.get(..);
|
||||||
|
}
|
||||||
|
zip_longest {
|
||||||
|
let _ = Panicking.zip_longest(Panicking);
|
||||||
|
}
|
||||||
|
zip_eq {
|
||||||
|
let _ = Panicking.zip_eq(Panicking);
|
||||||
|
}
|
||||||
|
batching {
|
||||||
|
let _ = Panicking.batching(Iterator::next);
|
||||||
|
}
|
||||||
|
chunk_by {
|
||||||
|
// ChunkBy
|
||||||
|
let _ = Panicking.chunk_by(|x| *x);
|
||||||
|
// Groups
|
||||||
|
let _ = Panicking.chunk_by(|x| *x).into_iter();
|
||||||
|
}
|
||||||
|
chunks {
|
||||||
|
// IntoChunks
|
||||||
|
let _ = Panicking.chunks(1);
|
||||||
|
let _ = Panicking.chunks(2);
|
||||||
|
// Chunks
|
||||||
|
let _ = Panicking.chunks(1).into_iter();
|
||||||
|
let _ = Panicking.chunks(2).into_iter();
|
||||||
|
}
|
||||||
|
tuple_windows {
|
||||||
|
let _ = Panicking.tuple_windows::<(_,)>();
|
||||||
|
let _ = Panicking.tuple_windows::<(_, _)>();
|
||||||
|
let _ = Panicking.tuple_windows::<(_, _, _)>();
|
||||||
|
}
|
||||||
|
circular_tuple_windows {
|
||||||
|
let _ = Panicking.circular_tuple_windows::<(_,)>();
|
||||||
|
let _ = Panicking.circular_tuple_windows::<(_, _)>();
|
||||||
|
let _ = Panicking.circular_tuple_windows::<(_, _, _)>();
|
||||||
|
}
|
||||||
|
tuples {
|
||||||
|
let _ = Panicking.tuples::<(_,)>();
|
||||||
|
let _ = Panicking.tuples::<(_, _)>();
|
||||||
|
let _ = Panicking.tuples::<(_, _, _)>();
|
||||||
|
}
|
||||||
|
tee {
|
||||||
|
let _ = Panicking.tee();
|
||||||
|
}
|
||||||
|
map_into {
|
||||||
|
let _ = Panicking.map_into::<u16>();
|
||||||
|
}
|
||||||
|
map_ok {
|
||||||
|
let _ = Panicking.map(Ok::<u8, ()>).map_ok(|x| x + 1);
|
||||||
|
}
|
||||||
|
filter_ok {
|
||||||
|
let _ = Panicking.map(Ok::<u8, ()>).filter_ok(|x| x % 2 == 0);
|
||||||
|
}
|
||||||
|
filter_map_ok {
|
||||||
|
let _ = Panicking.map(Ok::<u8, ()>).filter_map_ok(|x| {
|
||||||
|
if x % 2 == 0 {
|
||||||
|
Some(x + 1)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
flatten_ok {
|
||||||
|
let _ = Panicking.map(|x| Ok::<_, ()>([x])).flatten_ok();
|
||||||
|
}
|
||||||
|
merge {
|
||||||
|
let _ = Panicking.merge(Panicking);
|
||||||
|
}
|
||||||
|
merge_by {
|
||||||
|
let _ = Panicking.merge_by(Panicking, |_, _| true);
|
||||||
|
}
|
||||||
|
merge_join_by {
|
||||||
|
let _ = Panicking.merge_join_by(Panicking, |_, _| true);
|
||||||
|
let _ = Panicking.merge_join_by(Panicking, Ord::cmp);
|
||||||
|
}
|
||||||
|
#[should_panic]
|
||||||
|
kmerge {
|
||||||
|
let _ = Panicking.map(|_| Panicking).kmerge();
|
||||||
|
}
|
||||||
|
#[should_panic]
|
||||||
|
kmerge_by {
|
||||||
|
let _ = Panicking.map(|_| Panicking).kmerge_by(|_, _| true);
|
||||||
|
}
|
||||||
|
cartesian_product {
|
||||||
|
let _ = Panicking.cartesian_product(Panicking);
|
||||||
|
}
|
||||||
|
multi_cartesian_product {
|
||||||
|
let _ = vec![Panicking, Panicking, Panicking].into_iter().multi_cartesian_product();
|
||||||
|
}
|
||||||
|
coalesce {
|
||||||
|
let _ = Panicking.coalesce(|x, y| if x == y { Ok(x) } else { Err((x, y)) });
|
||||||
|
}
|
||||||
|
dedup {
|
||||||
|
let _ = Panicking.dedup();
|
||||||
|
}
|
||||||
|
dedup_by {
|
||||||
|
let _ = Panicking.dedup_by(|_, _| true);
|
||||||
|
}
|
||||||
|
dedup_with_count {
|
||||||
|
let _ = Panicking.dedup_with_count();
|
||||||
|
}
|
||||||
|
dedup_by_with_count {
|
||||||
|
let _ = Panicking.dedup_by_with_count(|_, _| true);
|
||||||
|
}
|
||||||
|
duplicates {
|
||||||
|
let _ = Panicking.duplicates();
|
||||||
|
}
|
||||||
|
duplicates_by {
|
||||||
|
let _ = Panicking.duplicates_by(|x| *x);
|
||||||
|
}
|
||||||
|
unique {
|
||||||
|
let _ = Panicking.unique();
|
||||||
|
}
|
||||||
|
unique_by {
|
||||||
|
let _ = Panicking.unique_by(|x| *x);
|
||||||
|
}
|
||||||
|
peeking_take_while {
|
||||||
|
let _ = Panicking.peekable().peeking_take_while(|x| x % 2 == 0);
|
||||||
|
}
|
||||||
|
take_while_ref {
|
||||||
|
let _ = Panicking.take_while_ref(|x| x % 2 == 0);
|
||||||
|
}
|
||||||
|
take_while_inclusive {
|
||||||
|
let _ = Panicking.take_while_inclusive(|x| x % 2 == 0);
|
||||||
|
}
|
||||||
|
while_some {
|
||||||
|
let _ = Panicking.map(Some).while_some();
|
||||||
|
}
|
||||||
|
tuple_combinations1 {
|
||||||
|
let _ = Panicking.tuple_combinations::<(_,)>();
|
||||||
|
}
|
||||||
|
#[should_panic]
|
||||||
|
tuple_combinations2 {
|
||||||
|
let _ = Panicking.tuple_combinations::<(_, _)>();
|
||||||
|
}
|
||||||
|
#[should_panic]
|
||||||
|
tuple_combinations3 {
|
||||||
|
let _ = Panicking.tuple_combinations::<(_, _, _)>();
|
||||||
|
}
|
||||||
|
combinations {
|
||||||
|
let _ = Panicking.combinations(0);
|
||||||
|
let _ = Panicking.combinations(1);
|
||||||
|
let _ = Panicking.combinations(2);
|
||||||
|
}
|
||||||
|
combinations_with_replacement {
|
||||||
|
let _ = Panicking.combinations_with_replacement(0);
|
||||||
|
let _ = Panicking.combinations_with_replacement(1);
|
||||||
|
let _ = Panicking.combinations_with_replacement(2);
|
||||||
|
}
|
||||||
|
permutations {
|
||||||
|
let _ = Panicking.permutations(0);
|
||||||
|
let _ = Panicking.permutations(1);
|
||||||
|
let _ = Panicking.permutations(2);
|
||||||
|
}
|
||||||
|
powerset {
|
||||||
|
let _ = Panicking.powerset();
|
||||||
|
}
|
||||||
|
pad_using {
|
||||||
|
let _ = Panicking.pad_using(25, |_| 10);
|
||||||
|
}
|
||||||
|
with_position {
|
||||||
|
let _ = Panicking.with_position();
|
||||||
|
}
|
||||||
|
positions {
|
||||||
|
let _ = Panicking.positions(|v| v % 2 == 0);
|
||||||
|
}
|
||||||
|
update {
|
||||||
|
let _ = Panicking.update(|n| *n += 1);
|
||||||
|
}
|
||||||
|
multipeek {
|
||||||
|
let _ = Panicking.multipeek();
|
||||||
|
}
|
||||||
|
// Not iterator themselves but still lazy.
|
||||||
|
into_grouping_map {
|
||||||
|
let _ = Panicking.map(|x| (x, x + 1)).into_grouping_map();
|
||||||
|
}
|
||||||
|
into_grouping_map_by {
|
||||||
|
let _ = Panicking.into_grouping_map_by(|x| *x);
|
||||||
|
}
|
||||||
|
// Macros:
|
||||||
|
iproduct {
|
||||||
|
let _ = itertools::iproduct!(Panicking);
|
||||||
|
let _ = itertools::iproduct!(Panicking, Panicking);
|
||||||
|
let _ = itertools::iproduct!(Panicking, Panicking, Panicking);
|
||||||
|
}
|
||||||
|
izip {
|
||||||
|
let _ = itertools::izip!(Panicking);
|
||||||
|
let _ = itertools::izip!(Panicking, Panicking);
|
||||||
|
let _ = itertools::izip!(Panicking, Panicking, Panicking);
|
||||||
|
}
|
||||||
|
chain {
|
||||||
|
let _ = itertools::chain!(Panicking);
|
||||||
|
let _ = itertools::chain!(Panicking, Panicking);
|
||||||
|
let _ = itertools::chain!(Panicking, Panicking, Panicking);
|
||||||
|
}
|
||||||
|
// Free functions:
|
||||||
|
multizip {
|
||||||
|
let _ = itertools::multizip((Panicking, Panicking));
|
||||||
|
}
|
||||||
|
put_back {
|
||||||
|
let _ = itertools::put_back(Panicking);
|
||||||
|
let _ = itertools::put_back(Panicking).with_value(15);
|
||||||
|
}
|
||||||
|
peek_nth {
|
||||||
|
let _ = itertools::peek_nth(Panicking);
|
||||||
|
}
|
||||||
|
put_back_n {
|
||||||
|
let _ = itertools::put_back_n(Panicking);
|
||||||
|
}
|
||||||
|
rciter {
|
||||||
|
let _ = itertools::rciter(Panicking);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
|
mod alloc {}
|
||||||
|
mod core {}
|
||||||
|
mod either {}
|
||||||
|
mod std {}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn iproduct_hygiene() {
|
fn iproduct_hygiene() {
|
||||||
|
let _ = itertools::iproduct!();
|
||||||
let _ = itertools::iproduct!(0..6);
|
let _ = itertools::iproduct!(0..6);
|
||||||
let _ = itertools::iproduct!(0..6, 0..9);
|
let _ = itertools::iproduct!(0..6, 0..9);
|
||||||
let _ = itertools::iproduct!(0..6, 0..9, 0..12);
|
let _ = itertools::iproduct!(0..6, 0..9, 0..12);
|
||||||
@@ -11,3 +17,11 @@ fn izip_hygiene() {
|
|||||||
let _ = itertools::izip!(0..6, 0..9);
|
let _ = itertools::izip!(0..6, 0..9);
|
||||||
let _ = itertools::izip!(0..6, 0..9, 0..12);
|
let _ = itertools::izip!(0..6, 0..9, 0..12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn chain_hygiene() {
|
||||||
|
let _: ::std::iter::Empty<i32> = itertools::chain!();
|
||||||
|
let _ = itertools::chain!(0..6);
|
||||||
|
let _ = itertools::chain!(0..6, 0..9);
|
||||||
|
let _ = itertools::chain!(0..6, 0..9, 0..12);
|
||||||
|
}
|
||||||
|
|||||||
69
third_party/rust/itertools/tests/merge_join.rs
vendored
69
third_party/rust/itertools/tests/merge_join.rs
vendored
@@ -1,108 +1,101 @@
|
|||||||
use itertools::EitherOrBoth;
|
|
||||||
use itertools::free::merge_join_by;
|
use itertools::free::merge_join_by;
|
||||||
|
use itertools::EitherOrBoth;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty() {
|
fn empty() {
|
||||||
let left: Vec<u32> = vec![];
|
let left: Vec<u32> = vec![];
|
||||||
let right: Vec<u32> = vec![];
|
let right: Vec<u32> = vec![];
|
||||||
let expected_result: Vec<EitherOrBoth<u32, u32>> = vec![];
|
let expected_result: Vec<EitherOrBoth<u32>> = vec![];
|
||||||
let actual_result = merge_join_by(left, right, |l, r| l.cmp(r))
|
let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)).collect::<Vec<_>>();
|
||||||
.collect::<Vec<_>>();
|
|
||||||
assert_eq!(expected_result, actual_result);
|
assert_eq!(expected_result, actual_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn left_only() {
|
fn left_only() {
|
||||||
let left: Vec<u32> = vec![1,2,3];
|
let left: Vec<u32> = vec![1, 2, 3];
|
||||||
let right: Vec<u32> = vec![];
|
let right: Vec<u32> = vec![];
|
||||||
let expected_result: Vec<EitherOrBoth<u32, u32>> = vec![
|
let expected_result: Vec<EitherOrBoth<u32>> = vec![
|
||||||
EitherOrBoth::Left(1),
|
EitherOrBoth::Left(1),
|
||||||
EitherOrBoth::Left(2),
|
EitherOrBoth::Left(2),
|
||||||
EitherOrBoth::Left(3)
|
EitherOrBoth::Left(3),
|
||||||
];
|
];
|
||||||
let actual_result = merge_join_by(left, right, |l, r| l.cmp(r))
|
let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)).collect::<Vec<_>>();
|
||||||
.collect::<Vec<_>>();
|
|
||||||
assert_eq!(expected_result, actual_result);
|
assert_eq!(expected_result, actual_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn right_only() {
|
fn right_only() {
|
||||||
let left: Vec<u32> = vec![];
|
let left: Vec<u32> = vec![];
|
||||||
let right: Vec<u32> = vec![1,2,3];
|
let right: Vec<u32> = vec![1, 2, 3];
|
||||||
let expected_result: Vec<EitherOrBoth<u32, u32>> = vec![
|
let expected_result: Vec<EitherOrBoth<u32>> = vec![
|
||||||
EitherOrBoth::Right(1),
|
EitherOrBoth::Right(1),
|
||||||
EitherOrBoth::Right(2),
|
EitherOrBoth::Right(2),
|
||||||
EitherOrBoth::Right(3)
|
EitherOrBoth::Right(3),
|
||||||
];
|
];
|
||||||
let actual_result = merge_join_by(left, right, |l, r| l.cmp(r))
|
let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)).collect::<Vec<_>>();
|
||||||
.collect::<Vec<_>>();
|
|
||||||
assert_eq!(expected_result, actual_result);
|
assert_eq!(expected_result, actual_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn first_left_then_right() {
|
fn first_left_then_right() {
|
||||||
let left: Vec<u32> = vec![1,2,3];
|
let left: Vec<u32> = vec![1, 2, 3];
|
||||||
let right: Vec<u32> = vec![4,5,6];
|
let right: Vec<u32> = vec![4, 5, 6];
|
||||||
let expected_result: Vec<EitherOrBoth<u32, u32>> = vec![
|
let expected_result: Vec<EitherOrBoth<u32>> = vec![
|
||||||
EitherOrBoth::Left(1),
|
EitherOrBoth::Left(1),
|
||||||
EitherOrBoth::Left(2),
|
EitherOrBoth::Left(2),
|
||||||
EitherOrBoth::Left(3),
|
EitherOrBoth::Left(3),
|
||||||
EitherOrBoth::Right(4),
|
EitherOrBoth::Right(4),
|
||||||
EitherOrBoth::Right(5),
|
EitherOrBoth::Right(5),
|
||||||
EitherOrBoth::Right(6)
|
EitherOrBoth::Right(6),
|
||||||
];
|
];
|
||||||
let actual_result = merge_join_by(left, right, |l, r| l.cmp(r))
|
let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)).collect::<Vec<_>>();
|
||||||
.collect::<Vec<_>>();
|
|
||||||
assert_eq!(expected_result, actual_result);
|
assert_eq!(expected_result, actual_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn first_right_then_left() {
|
fn first_right_then_left() {
|
||||||
let left: Vec<u32> = vec![4,5,6];
|
let left: Vec<u32> = vec![4, 5, 6];
|
||||||
let right: Vec<u32> = vec![1,2,3];
|
let right: Vec<u32> = vec![1, 2, 3];
|
||||||
let expected_result: Vec<EitherOrBoth<u32, u32>> = vec![
|
let expected_result: Vec<EitherOrBoth<u32>> = vec![
|
||||||
EitherOrBoth::Right(1),
|
EitherOrBoth::Right(1),
|
||||||
EitherOrBoth::Right(2),
|
EitherOrBoth::Right(2),
|
||||||
EitherOrBoth::Right(3),
|
EitherOrBoth::Right(3),
|
||||||
EitherOrBoth::Left(4),
|
EitherOrBoth::Left(4),
|
||||||
EitherOrBoth::Left(5),
|
EitherOrBoth::Left(5),
|
||||||
EitherOrBoth::Left(6)
|
EitherOrBoth::Left(6),
|
||||||
];
|
];
|
||||||
let actual_result = merge_join_by(left, right, |l, r| l.cmp(r))
|
let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)).collect::<Vec<_>>();
|
||||||
.collect::<Vec<_>>();
|
|
||||||
assert_eq!(expected_result, actual_result);
|
assert_eq!(expected_result, actual_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn interspersed_left_and_right() {
|
fn interspersed_left_and_right() {
|
||||||
let left: Vec<u32> = vec![1,3,5];
|
let left: Vec<u32> = vec![1, 3, 5];
|
||||||
let right: Vec<u32> = vec![2,4,6];
|
let right: Vec<u32> = vec![2, 4, 6];
|
||||||
let expected_result: Vec<EitherOrBoth<u32, u32>> = vec![
|
let expected_result: Vec<EitherOrBoth<u32>> = vec![
|
||||||
EitherOrBoth::Left(1),
|
EitherOrBoth::Left(1),
|
||||||
EitherOrBoth::Right(2),
|
EitherOrBoth::Right(2),
|
||||||
EitherOrBoth::Left(3),
|
EitherOrBoth::Left(3),
|
||||||
EitherOrBoth::Right(4),
|
EitherOrBoth::Right(4),
|
||||||
EitherOrBoth::Left(5),
|
EitherOrBoth::Left(5),
|
||||||
EitherOrBoth::Right(6)
|
EitherOrBoth::Right(6),
|
||||||
];
|
];
|
||||||
let actual_result = merge_join_by(left, right, |l, r| l.cmp(r))
|
let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)).collect::<Vec<_>>();
|
||||||
.collect::<Vec<_>>();
|
|
||||||
assert_eq!(expected_result, actual_result);
|
assert_eq!(expected_result, actual_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn overlapping_left_and_right() {
|
fn overlapping_left_and_right() {
|
||||||
let left: Vec<u32> = vec![1,3,4,6];
|
let left: Vec<u32> = vec![1, 3, 4, 6];
|
||||||
let right: Vec<u32> = vec![2,3,4,5];
|
let right: Vec<u32> = vec![2, 3, 4, 5];
|
||||||
let expected_result: Vec<EitherOrBoth<u32, u32>> = vec![
|
let expected_result: Vec<EitherOrBoth<u32>> = vec![
|
||||||
EitherOrBoth::Left(1),
|
EitherOrBoth::Left(1),
|
||||||
EitherOrBoth::Right(2),
|
EitherOrBoth::Right(2),
|
||||||
EitherOrBoth::Both(3, 3),
|
EitherOrBoth::Both(3, 3),
|
||||||
EitherOrBoth::Both(4, 4),
|
EitherOrBoth::Both(4, 4),
|
||||||
EitherOrBoth::Right(5),
|
EitherOrBoth::Right(5),
|
||||||
EitherOrBoth::Left(6)
|
EitherOrBoth::Left(6),
|
||||||
];
|
];
|
||||||
let actual_result = merge_join_by(left, right, |l, r| l.cmp(r))
|
let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)).collect::<Vec<_>>();
|
||||||
.collect::<Vec<_>>();
|
|
||||||
assert_eq!(expected_result, actual_result);
|
assert_eq!(expected_result, actual_result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,3 +48,22 @@ fn peeking_take_while_slice_iter_rev() {
|
|||||||
r.peeking_take_while(|_| true).count();
|
r.peeking_take_while(|_| true).count();
|
||||||
assert_eq!(r.next(), None);
|
assert_eq!(r.next(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn peeking_take_while_nested() {
|
||||||
|
let mut xs = (0..10).peekable();
|
||||||
|
let ys: Vec<_> = xs
|
||||||
|
.peeking_take_while(|x| *x < 6)
|
||||||
|
.peeking_take_while(|x| *x != 3)
|
||||||
|
.collect();
|
||||||
|
assert_eq!(ys, vec![0, 1, 2]);
|
||||||
|
assert_eq!(xs.next(), Some(3));
|
||||||
|
|
||||||
|
let mut xs = (4..10).peekable();
|
||||||
|
let ys: Vec<_> = xs
|
||||||
|
.peeking_take_while(|x| *x != 3)
|
||||||
|
.peeking_take_while(|x| *x < 6)
|
||||||
|
.collect();
|
||||||
|
assert_eq!(ys, vec![4, 5]);
|
||||||
|
assert_eq!(xs.next(), Some(6));
|
||||||
|
}
|
||||||
|
|||||||
572
third_party/rust/itertools/tests/quick.rs
vendored
572
third_party/rust/itertools/tests/quick.rs
vendored
@@ -2,35 +2,28 @@
|
|||||||
//! and adaptors.
|
//! and adaptors.
|
||||||
//!
|
//!
|
||||||
//! In particular we test the tedious size_hint and exact size correctness.
|
//! In particular we test the tedious size_hint and exact size correctness.
|
||||||
|
//!
|
||||||
|
//! **NOTE:** Due to performance limitations, these tests are not run with miri!
|
||||||
|
//! They cannot be relied upon to discover soundness issues.
|
||||||
|
|
||||||
|
#![cfg(not(miri))]
|
||||||
|
#![allow(deprecated, unstable_name_collisions)]
|
||||||
|
|
||||||
|
use itertools::free::{
|
||||||
|
cloned, enumerate, multipeek, peek_nth, put_back, put_back_n, rciter, zip, zip_eq,
|
||||||
|
};
|
||||||
|
use itertools::Itertools;
|
||||||
|
use itertools::{iproduct, izip, multizip, EitherOrBoth};
|
||||||
use quickcheck as qc;
|
use quickcheck as qc;
|
||||||
|
use std::cmp::{max, min, Ordering};
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::num::Wrapping;
|
use std::num::Wrapping;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::cmp::{max, min, Ordering};
|
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
use itertools::Itertools;
|
|
||||||
use itertools::{
|
|
||||||
multizip,
|
|
||||||
EitherOrBoth,
|
|
||||||
iproduct,
|
|
||||||
izip,
|
|
||||||
};
|
|
||||||
use itertools::free::{
|
|
||||||
cloned,
|
|
||||||
enumerate,
|
|
||||||
multipeek,
|
|
||||||
peek_nth,
|
|
||||||
put_back,
|
|
||||||
put_back_n,
|
|
||||||
rciter,
|
|
||||||
zip,
|
|
||||||
zip_eq,
|
|
||||||
};
|
|
||||||
|
|
||||||
use rand::Rng;
|
|
||||||
use rand::seq::SliceRandom;
|
|
||||||
use quickcheck::TestResult;
|
use quickcheck::TestResult;
|
||||||
|
use rand::seq::SliceRandom;
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
/// Trait for size hint modifier types
|
/// Trait for size hint modifier types
|
||||||
trait HintKind: Copy + Send + qc::Arbitrary {
|
trait HintKind: Copy + Send + qc::Arbitrary {
|
||||||
@@ -49,7 +42,7 @@ impl HintKind for Exact {
|
|||||||
|
|
||||||
impl qc::Arbitrary for Exact {
|
impl qc::Arbitrary for Exact {
|
||||||
fn arbitrary<G: qc::Gen>(_: &mut G) -> Self {
|
fn arbitrary<G: qc::Gen>(_: &mut G) -> Self {
|
||||||
Exact {}
|
Self {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,8 +59,10 @@ struct Inexact {
|
|||||||
impl HintKind for Inexact {
|
impl HintKind for Inexact {
|
||||||
fn loosen_bounds(&self, org_hint: (usize, Option<usize>)) -> (usize, Option<usize>) {
|
fn loosen_bounds(&self, org_hint: (usize, Option<usize>)) -> (usize, Option<usize>) {
|
||||||
let (org_lower, org_upper) = org_hint;
|
let (org_lower, org_upper) = org_hint;
|
||||||
(org_lower.saturating_sub(self.underestimate),
|
(
|
||||||
org_upper.and_then(move |x| x.checked_add(self.overestimate)))
|
org_lower.saturating_sub(self.underestimate),
|
||||||
|
org_upper.and_then(move |x| x.checked_add(self.overestimate)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,27 +71,23 @@ impl qc::Arbitrary for Inexact {
|
|||||||
let ue_value = usize::arbitrary(g);
|
let ue_value = usize::arbitrary(g);
|
||||||
let oe_value = usize::arbitrary(g);
|
let oe_value = usize::arbitrary(g);
|
||||||
// Compensate for quickcheck using extreme values too rarely
|
// Compensate for quickcheck using extreme values too rarely
|
||||||
let ue_choices = &[0, ue_value, usize::max_value()];
|
let ue_choices = &[0, ue_value, usize::MAX];
|
||||||
let oe_choices = &[0, oe_value, usize::max_value()];
|
let oe_choices = &[0, oe_value, usize::MAX];
|
||||||
Inexact {
|
Self {
|
||||||
underestimate: *ue_choices.choose(g).unwrap(),
|
underestimate: *ue_choices.choose(g).unwrap(),
|
||||||
overestimate: *oe_choices.choose(g).unwrap(),
|
overestimate: *oe_choices.choose(g).unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shrink(&self) -> Box<dyn Iterator<Item=Self>> {
|
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
||||||
let underestimate_value = self.underestimate;
|
let underestimate_value = self.underestimate;
|
||||||
let overestimate_value = self.overestimate;
|
let overestimate_value = self.overestimate;
|
||||||
Box::new(
|
Box::new(underestimate_value.shrink().flat_map(move |ue_value| {
|
||||||
underestimate_value.shrink().flat_map(move |ue_value|
|
overestimate_value.shrink().map(move |oe_value| Self {
|
||||||
overestimate_value.shrink().map(move |oe_value|
|
underestimate: ue_value,
|
||||||
Inexact {
|
overestimate: oe_value,
|
||||||
underestimate: ue_value,
|
})
|
||||||
overestimate: oe_value,
|
}))
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,10 +107,12 @@ struct Iter<T, SK: HintKind = Inexact> {
|
|||||||
hint_kind: SK,
|
hint_kind: SK,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, HK> Iter<T, HK> where HK: HintKind
|
impl<T, HK> Iter<T, HK>
|
||||||
|
where
|
||||||
|
HK: HintKind,
|
||||||
{
|
{
|
||||||
fn new(it: Range<T>, hint_kind: HK) -> Self {
|
fn new(it: Range<T>, hint_kind: HK) -> Self {
|
||||||
Iter {
|
Self {
|
||||||
iterator: it,
|
iterator: it,
|
||||||
fuse_flag: 0,
|
fuse_flag: 0,
|
||||||
hint_kind,
|
hint_kind,
|
||||||
@@ -128,64 +121,66 @@ impl<T, HK> Iter<T, HK> where HK: HintKind
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T, HK> Iterator for Iter<T, HK>
|
impl<T, HK> Iterator for Iter<T, HK>
|
||||||
where Range<T>: Iterator,
|
where
|
||||||
<Range<T> as Iterator>::Item: Default,
|
Range<T>: Iterator,
|
||||||
HK: HintKind,
|
<Range<T> as Iterator>::Item: Default,
|
||||||
|
HK: HintKind,
|
||||||
{
|
{
|
||||||
type Item = <Range<T> as Iterator>::Item;
|
type Item = <Range<T> as Iterator>::Item;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item>
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
{
|
|
||||||
let elt = self.iterator.next();
|
let elt = self.iterator.next();
|
||||||
if elt.is_none() {
|
if elt.is_none() {
|
||||||
self.fuse_flag += 1;
|
self.fuse_flag += 1;
|
||||||
// check fuse flag
|
// check fuse flag
|
||||||
if self.fuse_flag == 2 {
|
if self.fuse_flag == 2 {
|
||||||
return Some(Default::default())
|
return Some(Default::default());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elt
|
elt
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>)
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
{
|
|
||||||
let org_hint = self.iterator.size_hint();
|
let org_hint = self.iterator.size_hint();
|
||||||
self.hint_kind.loosen_bounds(org_hint)
|
self.hint_kind.loosen_bounds(org_hint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, HK> DoubleEndedIterator for Iter<T, HK>
|
impl<T, HK> DoubleEndedIterator for Iter<T, HK>
|
||||||
where Range<T>: DoubleEndedIterator,
|
where
|
||||||
<Range<T> as Iterator>::Item: Default,
|
Range<T>: DoubleEndedIterator,
|
||||||
HK: HintKind
|
<Range<T> as Iterator>::Item: Default,
|
||||||
|
HK: HintKind,
|
||||||
{
|
{
|
||||||
fn next_back(&mut self) -> Option<Self::Item> { self.iterator.next_back() }
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
self.iterator.next_back()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ExactSizeIterator for Iter<T, Exact> where Range<T>: ExactSizeIterator,
|
impl<T> ExactSizeIterator for Iter<T, Exact>
|
||||||
|
where
|
||||||
|
Range<T>: ExactSizeIterator,
|
||||||
<Range<T> as Iterator>::Item: Default,
|
<Range<T> as Iterator>::Item: Default,
|
||||||
{ }
|
{
|
||||||
|
}
|
||||||
|
|
||||||
impl<T, HK> qc::Arbitrary for Iter<T, HK>
|
impl<T, HK> qc::Arbitrary for Iter<T, HK>
|
||||||
where T: qc::Arbitrary,
|
where
|
||||||
HK: HintKind,
|
T: qc::Arbitrary,
|
||||||
|
HK: HintKind,
|
||||||
{
|
{
|
||||||
fn arbitrary<G: qc::Gen>(g: &mut G) -> Self
|
fn arbitrary<G: qc::Gen>(g: &mut G) -> Self {
|
||||||
{
|
Self::new(T::arbitrary(g)..T::arbitrary(g), HK::arbitrary(g))
|
||||||
Iter::new(T::arbitrary(g)..T::arbitrary(g), HK::arbitrary(g))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shrink(&self) -> Box<dyn Iterator<Item=Iter<T, HK>>>
|
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
||||||
{
|
|
||||||
let r = self.iterator.clone();
|
let r = self.iterator.clone();
|
||||||
let hint_kind = self.hint_kind;
|
let hint_kind = self.hint_kind;
|
||||||
Box::new(
|
Box::new(r.start.shrink().flat_map(move |a| {
|
||||||
r.start.shrink().flat_map(move |a|
|
r.end
|
||||||
r.end.shrink().map(move |b|
|
.shrink()
|
||||||
Iter::new(a.clone()..b, hint_kind)
|
.map(move |b| Self::new(a.clone()..b, hint_kind))
|
||||||
)
|
}))
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +196,10 @@ struct ShiftRange<HK = Inexact> {
|
|||||||
hint_kind: HK,
|
hint_kind: HK,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<HK> Iterator for ShiftRange<HK> where HK: HintKind {
|
impl<HK> Iterator for ShiftRange<HK>
|
||||||
|
where
|
||||||
|
HK: HintKind,
|
||||||
|
{
|
||||||
type Item = Iter<i32, HK>;
|
type Item = Iter<i32, HK>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
@@ -219,10 +217,11 @@ impl<HK> Iterator for ShiftRange<HK> where HK: HintKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExactSizeIterator for ShiftRange<Exact> { }
|
impl ExactSizeIterator for ShiftRange<Exact> {}
|
||||||
|
|
||||||
impl<HK> qc::Arbitrary for ShiftRange<HK>
|
impl<HK> qc::Arbitrary for ShiftRange<HK>
|
||||||
where HK: HintKind
|
where
|
||||||
|
HK: HintKind,
|
||||||
{
|
{
|
||||||
fn arbitrary<G: qc::Gen>(g: &mut G) -> Self {
|
fn arbitrary<G: qc::Gen>(g: &mut G) -> Self {
|
||||||
const MAX_STARTING_RANGE_DIFF: i32 = 32;
|
const MAX_STARTING_RANGE_DIFF: i32 = 32;
|
||||||
@@ -236,7 +235,7 @@ impl<HK> qc::Arbitrary for ShiftRange<HK>
|
|||||||
let iter_count = g.gen_range(0, MAX_ITER_COUNT + 1);
|
let iter_count = g.gen_range(0, MAX_ITER_COUNT + 1);
|
||||||
let hint_kind = qc::Arbitrary::arbitrary(g);
|
let hint_kind = qc::Arbitrary::arbitrary(g);
|
||||||
|
|
||||||
ShiftRange {
|
Self {
|
||||||
range_start,
|
range_start,
|
||||||
range_end,
|
range_end,
|
||||||
start_step,
|
start_step,
|
||||||
@@ -250,7 +249,7 @@ impl<HK> qc::Arbitrary for ShiftRange<HK>
|
|||||||
fn correct_count<I, F>(get_it: F) -> bool
|
fn correct_count<I, F>(get_it: F) -> bool
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
F: Fn() -> I
|
F: Fn() -> I,
|
||||||
{
|
{
|
||||||
let mut counts = vec![get_it().count()];
|
let mut counts = vec![get_it().count()];
|
||||||
|
|
||||||
@@ -258,7 +257,6 @@ where
|
|||||||
let mut it = get_it();
|
let mut it = get_it();
|
||||||
|
|
||||||
for _ in 0..(counts.len() - 1) {
|
for _ in 0..(counts.len() - 1) {
|
||||||
#[allow(clippy::manual_assert)]
|
|
||||||
if it.next().is_none() {
|
if it.next().is_none() {
|
||||||
panic!("Iterator shouldn't be finished, may not be deterministic");
|
panic!("Iterator shouldn't be finished, may not be deterministic");
|
||||||
}
|
}
|
||||||
@@ -276,7 +274,10 @@ where
|
|||||||
for (i, returned_count) in counts.into_iter().enumerate() {
|
for (i, returned_count) in counts.into_iter().enumerate() {
|
||||||
let actual_count = total_actual_count - i;
|
let actual_count = total_actual_count - i;
|
||||||
if actual_count != returned_count {
|
if actual_count != returned_count {
|
||||||
println!("Total iterations: {} True count: {} returned count: {}", i, actual_count, returned_count);
|
println!(
|
||||||
|
"Total iterations: {} True count: {} returned count: {}",
|
||||||
|
i, actual_count, returned_count
|
||||||
|
);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -299,12 +300,10 @@ fn correct_size_hint<I: Iterator>(mut it: I) -> bool {
|
|||||||
// check all the size hints
|
// check all the size hints
|
||||||
for &(low, hi) in &hints {
|
for &(low, hi) in &hints {
|
||||||
true_count -= 1;
|
true_count -= 1;
|
||||||
if low > true_count ||
|
if low > true_count || (hi.is_some() && hi.unwrap() < true_count) {
|
||||||
(hi.is_some() && hi.unwrap() < true_count)
|
|
||||||
{
|
|
||||||
println!("True size: {:?}, size hint: {:?}", true_count, (low, hi));
|
println!("True size: {:?}, size hint: {:?}", true_count, (low, hi));
|
||||||
//println!("All hints: {:?}", hints);
|
//println!("All hints: {:?}", hints);
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
@@ -313,13 +312,19 @@ fn correct_size_hint<I: Iterator>(mut it: I) -> bool {
|
|||||||
fn exact_size<I: ExactSizeIterator>(mut it: I) -> bool {
|
fn exact_size<I: ExactSizeIterator>(mut it: I) -> bool {
|
||||||
// check every iteration
|
// check every iteration
|
||||||
let (mut low, mut hi) = it.size_hint();
|
let (mut low, mut hi) = it.size_hint();
|
||||||
if Some(low) != hi { return false; }
|
if Some(low) != hi {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
while let Some(_) = it.next() {
|
while let Some(_) = it.next() {
|
||||||
let (xlow, xhi) = it.size_hint();
|
let (xlow, xhi) = it.size_hint();
|
||||||
if low != xlow + 1 { return false; }
|
if low != xlow + 1 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
low = xlow;
|
low = xlow;
|
||||||
hi = xhi;
|
hi = xhi;
|
||||||
if Some(low) != hi { return false; }
|
if Some(low) != hi {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let (low, hi) = it.size_hint();
|
let (low, hi) = it.size_hint();
|
||||||
low == 0 && hi == Some(0)
|
low == 0 && hi == Some(0)
|
||||||
@@ -329,13 +334,19 @@ fn exact_size<I: ExactSizeIterator>(mut it: I) -> bool {
|
|||||||
fn exact_size_for_this<I: Iterator>(mut it: I) -> bool {
|
fn exact_size_for_this<I: Iterator>(mut it: I) -> bool {
|
||||||
// check every iteration
|
// check every iteration
|
||||||
let (mut low, mut hi) = it.size_hint();
|
let (mut low, mut hi) = it.size_hint();
|
||||||
if Some(low) != hi { return false; }
|
if Some(low) != hi {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
while let Some(_) = it.next() {
|
while let Some(_) = it.next() {
|
||||||
let (xlow, xhi) = it.size_hint();
|
let (xlow, xhi) = it.size_hint();
|
||||||
if low != xlow + 1 { return false; }
|
if low != xlow + 1 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
low = xlow;
|
low = xlow;
|
||||||
hi = xhi;
|
hi = xhi;
|
||||||
if Some(low) != hi { return false; }
|
if Some(low) != hi {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let (low, hi) = it.size_hint();
|
let (low, hi) = it.size_hint();
|
||||||
low == 0 && hi == Some(0)
|
low == 0 && hi == Some(0)
|
||||||
@@ -442,43 +453,10 @@ quickcheck! {
|
|||||||
assert_eq!(answer.into_iter().last(), a.multi_cartesian_product().last());
|
assert_eq!(answer.into_iter().last(), a.multi_cartesian_product().last());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(deprecated)]
|
fn correct_empty_multi_product() -> () {
|
||||||
fn size_step(a: Iter<i16, Exact>, s: usize) -> bool {
|
let empty = Vec::<std::vec::IntoIter<i32>>::new().into_iter().multi_cartesian_product();
|
||||||
let mut s = s;
|
assert!(correct_size_hint(empty.clone()));
|
||||||
if s == 0 {
|
itertools::assert_equal(empty, std::iter::once(Vec::new()))
|
||||||
s += 1; // never zero
|
|
||||||
}
|
|
||||||
let filt = a.clone().dedup();
|
|
||||||
correct_size_hint(filt.step(s)) &&
|
|
||||||
exact_size(a.step(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(deprecated)]
|
|
||||||
fn equal_step(a: Iter<i16>, s: usize) -> bool {
|
|
||||||
let mut s = s;
|
|
||||||
if s == 0 {
|
|
||||||
s += 1; // never zero
|
|
||||||
}
|
|
||||||
let mut i = 0;
|
|
||||||
itertools::equal(a.clone().step(s), a.filter(|_| {
|
|
||||||
let keep = i % s == 0;
|
|
||||||
i += 1;
|
|
||||||
keep
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(deprecated)]
|
|
||||||
fn equal_step_vec(a: Vec<i16>, s: usize) -> bool {
|
|
||||||
let mut s = s;
|
|
||||||
if s == 0 {
|
|
||||||
s += 1; // never zero
|
|
||||||
}
|
|
||||||
let mut i = 0;
|
|
||||||
itertools::equal(a.iter().step(s), a.iter().filter(|_| {
|
|
||||||
let keep = i % s == 0;
|
|
||||||
i += 1;
|
|
||||||
keep
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_multipeek(a: Iter<u16, Exact>, s: u8) -> bool {
|
fn size_multipeek(a: Iter<u16, Exact>, s: u8) -> bool {
|
||||||
@@ -596,6 +574,20 @@ quickcheck! {
|
|||||||
let b = &b[..len];
|
let b = &b[..len];
|
||||||
itertools::equal(zip_eq(a, b), zip(a, b))
|
itertools::equal(zip_eq(a, b), zip(a, b))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[should_panic]
|
||||||
|
fn zip_eq_panics(a: Vec<u8>, b: Vec<u8>) -> TestResult {
|
||||||
|
if a.len() == b.len() { return TestResult::discard(); }
|
||||||
|
zip_eq(a.iter(), b.iter()).for_each(|_| {});
|
||||||
|
TestResult::passed() // won't come here
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equal_positions(a: Vec<i32>) -> bool {
|
||||||
|
let with_pos = a.iter().positions(|v| v % 2 == 0);
|
||||||
|
let without = a.iter().enumerate().filter(|(_, v)| *v % 2 == 0).map(|(i, _)| i);
|
||||||
|
itertools::equal(with_pos.clone(), without.clone())
|
||||||
|
&& itertools::equal(with_pos.rev(), without.rev())
|
||||||
|
}
|
||||||
fn size_zip_longest(a: Iter<i16, Exact>, b: Iter<i16, Exact>) -> bool {
|
fn size_zip_longest(a: Iter<i16, Exact>, b: Iter<i16, Exact>) -> bool {
|
||||||
let filt = a.clone().dedup();
|
let filt = a.clone().dedup();
|
||||||
let filt2 = b.clone().dedup();
|
let filt2 = b.clone().dedup();
|
||||||
@@ -750,6 +742,56 @@ quickcheck! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn correct_peek_nth(mut a: Vec<u16>) -> () {
|
||||||
|
let mut it = peek_nth(a.clone());
|
||||||
|
for start_pos in 0..a.len() + 2 {
|
||||||
|
for real_idx in start_pos..a.len() + 2 {
|
||||||
|
let peek_idx = real_idx - start_pos;
|
||||||
|
assert_eq!(it.peek_nth(peek_idx), a.get(real_idx));
|
||||||
|
assert_eq!(it.peek_nth_mut(peek_idx), a.get_mut(real_idx));
|
||||||
|
}
|
||||||
|
assert_eq!(it.next(), a.get(start_pos).copied());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek_nth_mut_replace(a: Vec<u16>, b: Vec<u16>) -> () {
|
||||||
|
let mut it = peek_nth(a.iter());
|
||||||
|
for (i, m) in b.iter().enumerate().take(a.len().min(b.len())) {
|
||||||
|
*it.peek_nth_mut(i).unwrap() = m;
|
||||||
|
}
|
||||||
|
for (i, m) in a.iter().enumerate() {
|
||||||
|
assert_eq!(it.next().unwrap(), b.get(i).unwrap_or(m));
|
||||||
|
}
|
||||||
|
assert_eq!(it.next(), None);
|
||||||
|
assert_eq!(it.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek_nth_next_if(a: Vec<u8>) -> () {
|
||||||
|
let mut it = peek_nth(a.clone());
|
||||||
|
for (idx, mut value) in a.iter().copied().enumerate() {
|
||||||
|
let should_be_none = it.next_if(|x| x != &value);
|
||||||
|
assert_eq!(should_be_none, None);
|
||||||
|
if value % 5 == 0 {
|
||||||
|
// Sometimes, peek up to 3 further.
|
||||||
|
let n = value as usize % 3;
|
||||||
|
let nth = it.peek_nth(n);
|
||||||
|
assert_eq!(nth, a.get(idx + n));
|
||||||
|
} else if value % 5 == 1 {
|
||||||
|
// Sometimes, peek next element mutably.
|
||||||
|
if let Some(v) = it.peek_mut() {
|
||||||
|
*v = v.wrapping_sub(1);
|
||||||
|
let should_be_none = it.next_if_eq(&value);
|
||||||
|
assert_eq!(should_be_none, None);
|
||||||
|
value = value.wrapping_sub(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let eq = it.next_if_eq(&value);
|
||||||
|
assert_eq!(eq, Some(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
fn dedup_via_coalesce(a: Vec<i32>) -> bool {
|
fn dedup_via_coalesce(a: Vec<i32>) -> bool {
|
||||||
let mut b = a.clone();
|
let mut b = a.clone();
|
||||||
@@ -811,9 +853,8 @@ quickcheck! {
|
|||||||
quickcheck! {
|
quickcheck! {
|
||||||
fn size_put_back(a: Vec<u8>, x: Option<u8>) -> bool {
|
fn size_put_back(a: Vec<u8>, x: Option<u8>) -> bool {
|
||||||
let mut it = put_back(a.into_iter());
|
let mut it = put_back(a.into_iter());
|
||||||
match x {
|
if let Some(t) = x {
|
||||||
Some(t) => it.put_back(t),
|
it.put_back(t);
|
||||||
None => {}
|
|
||||||
}
|
}
|
||||||
correct_size_hint(it)
|
correct_size_hint(it)
|
||||||
}
|
}
|
||||||
@@ -829,6 +870,31 @@ quickcheck! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn merge_join_by_ordering_vs_bool(a: Vec<u8>, b: Vec<u8>) -> bool {
|
||||||
|
use either::Either;
|
||||||
|
use itertools::free::merge_join_by;
|
||||||
|
let mut has_equal = false;
|
||||||
|
let it_ord = merge_join_by(a.clone(), b.clone(), Ord::cmp).flat_map(|v| match v {
|
||||||
|
EitherOrBoth::Both(l, r) => {
|
||||||
|
has_equal = true;
|
||||||
|
vec![Either::Left(l), Either::Right(r)]
|
||||||
|
}
|
||||||
|
EitherOrBoth::Left(l) => vec![Either::Left(l)],
|
||||||
|
EitherOrBoth::Right(r) => vec![Either::Right(r)],
|
||||||
|
});
|
||||||
|
let it_bool = merge_join_by(a, b, PartialOrd::le);
|
||||||
|
itertools::equal(it_ord, it_bool) || has_equal
|
||||||
|
}
|
||||||
|
fn merge_join_by_bool_unwrapped_is_merge_by(a: Vec<u8>, b: Vec<u8>) -> bool {
|
||||||
|
use either::Either;
|
||||||
|
use itertools::free::merge_join_by;
|
||||||
|
let it = a.clone().into_iter().merge_by(b.clone(), PartialOrd::ge);
|
||||||
|
let it_join = merge_join_by(a, b, PartialOrd::ge).map(Either::into_inner);
|
||||||
|
itertools::equal(it, it_join)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
fn size_tee(a: Vec<u8>) -> bool {
|
fn size_tee(a: Vec<u8>) -> bool {
|
||||||
let (mut t1, mut t2) = a.iter().tee();
|
let (mut t1, mut t2) = a.iter().tee();
|
||||||
@@ -870,8 +936,31 @@ quickcheck! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
fn size_combinations(it: Iter<i16>) -> bool {
|
fn size_combinations(a: Iter<i16>) -> bool {
|
||||||
correct_size_hint(it.tuple_combinations::<(_, _)>())
|
let it = a.clone().tuple_combinations::<(_, _)>();
|
||||||
|
correct_size_hint(it.clone()) && it.count() == binomial(a.count(), 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exact_size_combinations_1(a: Vec<u8>) -> bool {
|
||||||
|
let it = a.iter().tuple_combinations::<(_,)>();
|
||||||
|
exact_size_for_this(it.clone()) && it.count() == binomial(a.len(), 1)
|
||||||
|
}
|
||||||
|
fn exact_size_combinations_2(a: Vec<u8>) -> bool {
|
||||||
|
let it = a.iter().tuple_combinations::<(_, _)>();
|
||||||
|
exact_size_for_this(it.clone()) && it.count() == binomial(a.len(), 2)
|
||||||
|
}
|
||||||
|
fn exact_size_combinations_3(mut a: Vec<u8>) -> bool {
|
||||||
|
a.truncate(15);
|
||||||
|
let it = a.iter().tuple_combinations::<(_, _, _)>();
|
||||||
|
exact_size_for_this(it.clone()) && it.count() == binomial(a.len(), 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn binomial(n: usize, k: usize) -> usize {
|
||||||
|
if k > n {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
(n - k + 1..=n).product::<usize>() / (1..=k).product::<usize>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -887,7 +976,7 @@ quickcheck! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmb.next() == None
|
cmb.next().is_none()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -936,63 +1025,74 @@ quickcheck! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
fn fuzz_group_by_lazy_1(it: Iter<u8>) -> bool {
|
fn fuzz_chunk_by_lazy_1(it: Iter<u8>) -> bool {
|
||||||
let jt = it.clone();
|
let jt = it.clone();
|
||||||
let groups = it.group_by(|k| *k);
|
let chunks = it.chunk_by(|k| *k);
|
||||||
itertools::equal(jt, groups.into_iter().flat_map(|(_, x)| x))
|
itertools::equal(jt, chunks.into_iter().flat_map(|(_, x)| x))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
fn fuzz_group_by_lazy_2(data: Vec<u8>) -> bool {
|
fn fuzz_chunk_by_lazy_2(data: Vec<u8>) -> bool {
|
||||||
let groups = data.iter().group_by(|k| *k / 10);
|
let chunks = data.iter().chunk_by(|k| *k / 10);
|
||||||
let res = itertools::equal(data.iter(), groups.into_iter().flat_map(|(_, x)| x));
|
let res = itertools::equal(data.iter(), chunks.into_iter().flat_map(|(_, x)| x));
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
fn fuzz_group_by_lazy_3(data: Vec<u8>) -> bool {
|
fn fuzz_chunk_by_lazy_3(data: Vec<u8>) -> bool {
|
||||||
let grouper = data.iter().group_by(|k| *k / 10);
|
let grouper = data.iter().chunk_by(|k| *k / 10);
|
||||||
let groups = grouper.into_iter().collect_vec();
|
let chunks = grouper.into_iter().collect_vec();
|
||||||
let res = itertools::equal(data.iter(), groups.into_iter().flat_map(|(_, x)| x));
|
let res = itertools::equal(data.iter(), chunks.into_iter().flat_map(|(_, x)| x));
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
fn fuzz_group_by_lazy_duo(data: Vec<u8>, order: Vec<(bool, bool)>) -> bool {
|
fn fuzz_chunk_by_lazy_duo(data: Vec<u8>, order: Vec<(bool, bool)>) -> bool {
|
||||||
let grouper = data.iter().group_by(|k| *k / 3);
|
let grouper = data.iter().chunk_by(|k| *k / 3);
|
||||||
let mut groups1 = grouper.into_iter();
|
let mut chunks1 = grouper.into_iter();
|
||||||
let mut groups2 = grouper.into_iter();
|
let mut chunks2 = grouper.into_iter();
|
||||||
let mut elts = Vec::<&u8>::new();
|
let mut elts = Vec::<&u8>::new();
|
||||||
let mut old_groups = Vec::new();
|
let mut old_chunks = Vec::new();
|
||||||
|
|
||||||
let tup1 = |(_, b)| b;
|
let tup1 = |(_, b)| b;
|
||||||
for &(ord, consume_now) in &order {
|
for &(ord, consume_now) in &order {
|
||||||
let iter = &mut [&mut groups1, &mut groups2][ord as usize];
|
let iter = &mut [&mut chunks1, &mut chunks2][ord as usize];
|
||||||
match iter.next() {
|
match iter.next() {
|
||||||
Some((_, gr)) => if consume_now {
|
Some((_, gr)) => if consume_now {
|
||||||
for og in old_groups.drain(..) {
|
for og in old_chunks.drain(..) {
|
||||||
elts.extend(og);
|
elts.extend(og);
|
||||||
}
|
}
|
||||||
elts.extend(gr);
|
elts.extend(gr);
|
||||||
} else {
|
} else {
|
||||||
old_groups.push(gr);
|
old_chunks.push(gr);
|
||||||
},
|
},
|
||||||
None => break,
|
None => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for og in old_groups.drain(..) {
|
for og in old_chunks.drain(..) {
|
||||||
elts.extend(og);
|
elts.extend(og);
|
||||||
}
|
}
|
||||||
for gr in groups1.map(&tup1) { elts.extend(gr); }
|
for gr in chunks1.map(&tup1) { elts.extend(gr); }
|
||||||
for gr in groups2.map(&tup1) { elts.extend(gr); }
|
for gr in chunks2.map(&tup1) { elts.extend(gr); }
|
||||||
itertools::assert_equal(&data, elts);
|
itertools::assert_equal(&data, elts);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quickcheck! {
|
||||||
|
fn chunk_clone_equal(a: Vec<u8>, size: u8) -> () {
|
||||||
|
let mut size = size;
|
||||||
|
if size == 0 {
|
||||||
|
size += 1;
|
||||||
|
}
|
||||||
|
let it = a.chunks(size as usize);
|
||||||
|
itertools::assert_equal(it.clone(), it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
fn equal_chunks_lazy(a: Vec<u8>, size: u8) -> bool {
|
fn equal_chunks_lazy(a: Vec<u8>, size: u8) -> bool {
|
||||||
let mut size = size;
|
let mut size = size;
|
||||||
@@ -1010,7 +1110,75 @@ quickcheck! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tuple iterators
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
|
fn equal_circular_tuple_windows_1(a: Vec<u8>) -> bool {
|
||||||
|
let x = a.iter().map(|e| (e,) );
|
||||||
|
let y = a.iter().circular_tuple_windows::<(_,)>();
|
||||||
|
itertools::assert_equal(x,y);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equal_circular_tuple_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_tuple_windows::<(_, _)>();
|
||||||
|
itertools::assert_equal(x,y);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equal_circular_tuple_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_tuple_windows::<(_, _, _)>();
|
||||||
|
itertools::assert_equal(x,y);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equal_circular_tuple_windows_4(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()],
|
||||||
|
&a[(start_idx + 3) % a.len()],
|
||||||
|
));
|
||||||
|
let y = a.iter().circular_tuple_windows::<(_, _, _, _)>();
|
||||||
|
itertools::assert_equal(x,y);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equal_cloned_circular_tuple_windows(a: Vec<u8>) -> bool {
|
||||||
|
let x = a.iter().circular_tuple_windows::<(_, _, _, _)>();
|
||||||
|
let y = x.clone();
|
||||||
|
itertools::assert_equal(x,y);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equal_cloned_circular_tuple_windows_noninitial(a: Vec<u8>) -> bool {
|
||||||
|
let mut x = a.iter().circular_tuple_windows::<(_, _, _, _)>();
|
||||||
|
let _ = x.next();
|
||||||
|
let y = x.clone();
|
||||||
|
itertools::assert_equal(x,y);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equal_cloned_circular_tuple_windows_complete(a: Vec<u8>) -> bool {
|
||||||
|
let mut x = a.iter().circular_tuple_windows::<(_, _, _, _)>();
|
||||||
|
for _ in x.by_ref() {}
|
||||||
|
let y = x.clone();
|
||||||
|
itertools::assert_equal(x,y);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn circular_tuple_windows_exact_size(a: Vec<u8>) -> bool {
|
||||||
|
exact_size(a.iter().circular_tuple_windows::<(_, _, _, _)>())
|
||||||
|
}
|
||||||
|
|
||||||
fn equal_tuple_windows_1(a: Vec<u8>) -> bool {
|
fn equal_tuple_windows_1(a: Vec<u8>) -> bool {
|
||||||
let x = a.windows(1).map(|s| (&s[0], ));
|
let x = a.windows(1).map(|s| (&s[0], ));
|
||||||
let y = a.iter().tuple_windows::<(_,)>();
|
let y = a.iter().tuple_windows::<(_,)>();
|
||||||
@@ -1035,6 +1203,14 @@ quickcheck! {
|
|||||||
itertools::equal(x, y)
|
itertools::equal(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tuple_windows_exact_size_1(a: Vec<u8>) -> bool {
|
||||||
|
exact_size(a.iter().tuple_windows::<(_,)>())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tuple_windows_exact_size_4(a: Vec<u8>) -> bool {
|
||||||
|
exact_size(a.iter().tuple_windows::<(_, _, _, _)>())
|
||||||
|
}
|
||||||
|
|
||||||
fn equal_tuples_1(a: Vec<u8>) -> bool {
|
fn equal_tuples_1(a: Vec<u8>) -> bool {
|
||||||
let x = a.chunks(1).map(|s| (&s[0], ));
|
let x = a.chunks(1).map(|s| (&s[0], ));
|
||||||
let y = a.iter().tuples::<(_,)>();
|
let y = a.iter().tuples::<(_,)>();
|
||||||
@@ -1066,6 +1242,18 @@ quickcheck! {
|
|||||||
assert_eq!(buffer.len(), a.len() % 4);
|
assert_eq!(buffer.len(), a.len() % 4);
|
||||||
exact_size(buffer)
|
exact_size(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tuples_size_hint_inexact(a: Iter<u8>) -> bool {
|
||||||
|
correct_size_hint(a.clone().tuples::<(_,)>())
|
||||||
|
&& correct_size_hint(a.clone().tuples::<(_, _)>())
|
||||||
|
&& correct_size_hint(a.tuples::<(_, _, _, _)>())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tuples_size_hint_exact(a: Iter<u8, Exact>) -> bool {
|
||||||
|
exact_size(a.clone().tuples::<(_,)>())
|
||||||
|
&& exact_size(a.clone().tuples::<(_, _)>())
|
||||||
|
&& exact_size(a.tuples::<(_, _, _, _)>())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// with_position
|
// with_position
|
||||||
@@ -1097,14 +1285,14 @@ quickcheck! {
|
|||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
struct Val(u32, u32);
|
struct Val(u32, u32);
|
||||||
|
|
||||||
impl PartialOrd<Val> for Val {
|
impl PartialOrd<Self> for Val {
|
||||||
fn partial_cmp(&self, other: &Val) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
self.0.partial_cmp(&other.0)
|
Some(self.cmp(other))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for Val {
|
impl Ord for Val {
|
||||||
fn cmp(&self, other: &Val) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
self.0.cmp(&other.0)
|
self.0.cmp(&other.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1112,10 +1300,10 @@ impl Ord for Val {
|
|||||||
impl qc::Arbitrary for Val {
|
impl qc::Arbitrary for Val {
|
||||||
fn arbitrary<G: qc::Gen>(g: &mut G) -> Self {
|
fn arbitrary<G: qc::Gen>(g: &mut G) -> Self {
|
||||||
let (x, y) = <(u32, u32)>::arbitrary(g);
|
let (x, y) = <(u32, u32)>::arbitrary(g);
|
||||||
Val(x, y)
|
Self(x, y)
|
||||||
}
|
}
|
||||||
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
||||||
Box::new((self.0, self.1).shrink().map(|(x, y)| Val(x, y)))
|
Box::new((self.0, self.1).shrink().map(|(x, y)| Self(x, y)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1157,13 +1345,12 @@ quickcheck! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
#[allow(deprecated)]
|
fn tree_reduce_f64(mut a: Vec<f64>) -> TestResult {
|
||||||
fn tree_fold1_f64(mut a: Vec<f64>) -> TestResult {
|
|
||||||
fn collapse_adjacent<F>(x: Vec<f64>, mut f: F) -> Vec<f64>
|
fn collapse_adjacent<F>(x: Vec<f64>, mut f: F) -> Vec<f64>
|
||||||
where F: FnMut(f64, f64) -> f64
|
where F: FnMut(f64, f64) -> f64
|
||||||
{
|
{
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
for i in (0..x.len()).step(2) {
|
for i in (0..x.len()).step_by(2) {
|
||||||
if i == x.len()-1 {
|
if i == x.len()-1 {
|
||||||
out.push(x[i])
|
out.push(x[i])
|
||||||
} else {
|
} else {
|
||||||
@@ -1177,7 +1364,7 @@ quickcheck! {
|
|||||||
return TestResult::discard();
|
return TestResult::discard();
|
||||||
}
|
}
|
||||||
|
|
||||||
let actual = a.iter().cloned().tree_fold1(f64::atan2);
|
let actual = a.iter().cloned().tree_reduce(f64::atan2);
|
||||||
|
|
||||||
while a.len() > 1 {
|
while a.len() > 1 {
|
||||||
a = collapse_adjacent(a, f64::atan2);
|
a = collapse_adjacent(a, f64::atan2);
|
||||||
@@ -1202,7 +1389,7 @@ quickcheck! {
|
|||||||
fn at_most_one_i32(a: Vec<i32>) -> TestResult {
|
fn at_most_one_i32(a: Vec<i32>) -> TestResult {
|
||||||
let ret = a.iter().cloned().at_most_one();
|
let ret = a.iter().cloned().at_most_one();
|
||||||
match a.len() {
|
match a.len() {
|
||||||
0 => TestResult::from_bool(ret.unwrap() == None),
|
0 => TestResult::from_bool(ret.unwrap().is_none()),
|
||||||
1 => TestResult::from_bool(ret.unwrap() == Some(a[0])),
|
1 => TestResult::from_bool(ret.unwrap() == Some(a[0])),
|
||||||
_ => TestResult::from_bool(ret.unwrap_err().eq(a.iter().cloned())),
|
_ => TestResult::from_bool(ret.unwrap_err().eq(a.iter().cloned())),
|
||||||
}
|
}
|
||||||
@@ -1232,7 +1419,7 @@ quickcheck! {
|
|||||||
Some(acc.unwrap_or(0) + val)
|
Some(acc.unwrap_or(0) + val)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let group_map_lookup = a.iter()
|
let group_map_lookup = a.iter()
|
||||||
.map(|&b| b as u64)
|
.map(|&b| b as u64)
|
||||||
.map(|i| (i % modulo, i))
|
.map(|i| (i % modulo, i))
|
||||||
@@ -1252,7 +1439,7 @@ quickcheck! {
|
|||||||
|
|
||||||
for m in 0..modulo {
|
for m in 0..modulo {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
lookup.get(&m).copied(),
|
lookup.get(&m).copied(),
|
||||||
a.iter()
|
a.iter()
|
||||||
.map(|&b| b as u64)
|
.map(|&b| b as u64)
|
||||||
.filter(|&val| val % modulo == m)
|
.filter(|&val| val % modulo == m)
|
||||||
@@ -1267,6 +1454,35 @@ quickcheck! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn correct_grouping_map_by_fold_with_modulo_key(a: Vec<u8>, modulo: u8) -> () {
|
||||||
|
#[derive(Debug, Default, PartialEq)]
|
||||||
|
struct Accumulator {
|
||||||
|
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
|
||||||
|
.into_grouping_map_by(|i| i % modulo)
|
||||||
|
.fold_with(|_key, _val| Default::default(), |Accumulator { acc }, &key, val| {
|
||||||
|
assert!(val % modulo == key);
|
||||||
|
let acc = acc + val;
|
||||||
|
Accumulator { acc }
|
||||||
|
});
|
||||||
|
|
||||||
|
let group_map_lookup = a.iter()
|
||||||
|
.map(|&b| b as u64)
|
||||||
|
.map(|i| (i % modulo, i))
|
||||||
|
.into_group_map()
|
||||||
|
.into_iter()
|
||||||
|
.map(|(key, vals)| (key, vals.into_iter().sum())).map(|(key, acc)| (key,Accumulator { acc }))
|
||||||
|
.collect::<HashMap<_,_>>();
|
||||||
|
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>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn correct_grouping_map_by_fold_modulo_key(a: Vec<u8>, modulo: u8) -> () {
|
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 modulo = if modulo == 0 { 1 } else { modulo } as u64; // Avoid `% 0`
|
||||||
let lookup = a.iter().map(|&b| b as u64) // Avoid overflows
|
let lookup = a.iter().map(|&b| b as u64) // Avoid overflows
|
||||||
@@ -1290,22 +1506,21 @@ quickcheck! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn correct_grouping_map_by_fold_first_modulo_key(a: Vec<u8>, modulo: u8) -> () {
|
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 modulo = if modulo == 0 { 1 } else { modulo } as u64; // Avoid `% 0`
|
||||||
let lookup = a.iter().map(|&b| b as u64) // Avoid overflows
|
let lookup = a.iter().map(|&b| b as u64) // Avoid overflows
|
||||||
.into_grouping_map_by(|i| i % modulo)
|
.into_grouping_map_by(|i| i % modulo)
|
||||||
.fold_first(|acc, &key, val| {
|
.reduce(|acc, &key, val| {
|
||||||
assert!(val % modulo == key);
|
assert!(val % modulo == key);
|
||||||
acc + val
|
acc + val
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Swap `fold1` with stdlib's `fold_first` when it's stabilized
|
|
||||||
let group_map_lookup = a.iter()
|
let group_map_lookup = a.iter()
|
||||||
.map(|&b| b as u64)
|
.map(|&b| b as u64)
|
||||||
.map(|i| (i % modulo, i))
|
.map(|i| (i % modulo, i))
|
||||||
.into_group_map()
|
.into_group_map()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(key, vals)| (key, vals.into_iter().fold1(|acc, val| acc + val).unwrap()))
|
.map(|(key, vals)| (key, vals.into_iter().reduce(|acc, val| acc + val).unwrap()))
|
||||||
.collect::<HashMap<_,_>>();
|
.collect::<HashMap<_,_>>();
|
||||||
assert_eq!(lookup, group_map_lookup);
|
assert_eq!(lookup, group_map_lookup);
|
||||||
|
|
||||||
@@ -1372,7 +1587,7 @@ quickcheck! {
|
|||||||
assert_eq!(Some(max), a.iter().copied().filter(|&val| val % modulo == key).max_by_key(|&val| val));
|
assert_eq!(Some(max), a.iter().copied().filter(|&val| val % modulo == key).max_by_key(|&val| val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn correct_grouping_map_by_min_modulo_key(a: Vec<u8>, modulo: u8) -> () {
|
fn correct_grouping_map_by_min_modulo_key(a: Vec<u8>, modulo: u8) -> () {
|
||||||
let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0`
|
let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0`
|
||||||
let lookup = a.iter().copied().into_grouping_map_by(|i| i % modulo).min();
|
let lookup = a.iter().copied().into_grouping_map_by(|i| i % modulo).min();
|
||||||
@@ -1423,7 +1638,7 @@ quickcheck! {
|
|||||||
assert_eq!(Some(min), a.iter().copied().filter(|&val| val % modulo == key).min_by_key(|&val| val));
|
assert_eq!(Some(min), a.iter().copied().filter(|&val| val % modulo == key).min_by_key(|&val| val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn correct_grouping_map_by_minmax_modulo_key(a: Vec<u8>, modulo: u8) -> () {
|
fn correct_grouping_map_by_minmax_modulo_key(a: Vec<u8>, modulo: u8) -> () {
|
||||||
let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0`
|
let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0`
|
||||||
let lookup = a.iter().copied().into_grouping_map_by(|i| i % modulo).minmax();
|
let lookup = a.iter().copied().into_grouping_map_by(|i| i % modulo).minmax();
|
||||||
@@ -1536,7 +1751,7 @@ quickcheck! {
|
|||||||
.min_by(|_, _, _| Ordering::Equal);
|
.min_by(|_, _, _| Ordering::Equal);
|
||||||
|
|
||||||
assert_eq!(lookup[&0], 0);
|
assert_eq!(lookup[&0], 0);
|
||||||
|
|
||||||
let lookup = (0..=10)
|
let lookup = (0..=10)
|
||||||
.into_grouping_map_by(|_| 0)
|
.into_grouping_map_by(|_| 0)
|
||||||
.minmax_by(|_, _, _| Ordering::Equal);
|
.minmax_by(|_, _, _| Ordering::Equal);
|
||||||
@@ -1594,12 +1809,10 @@ quickcheck! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_fused<I: Iterator>(mut it: I) -> bool {
|
||||||
fn is_fused<I: Iterator>(mut it: I) -> bool
|
|
||||||
{
|
|
||||||
for _ in it.by_ref() {}
|
for _ in it.by_ref() {}
|
||||||
for _ in 0..10{
|
for _ in 0..10 {
|
||||||
if it.next().is_some(){
|
if it.next().is_some() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1640,7 +1853,7 @@ quickcheck! {
|
|||||||
!is_fused(a.clone().interleave_shortest(b.clone())) &&
|
!is_fused(a.clone().interleave_shortest(b.clone())) &&
|
||||||
is_fused(a.fuse().interleave_shortest(b.fuse()))
|
is_fused(a.fuse().interleave_shortest(b.fuse()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fused_product(a: Iter<i16>, b: Iter<i16>) -> bool
|
fn fused_product(a: Iter<i16>, b: Iter<i16>) -> bool
|
||||||
{
|
{
|
||||||
is_fused(a.fuse().cartesian_product(b.fuse()))
|
is_fused(a.fuse().cartesian_product(b.fuse()))
|
||||||
@@ -1746,4 +1959,11 @@ quickcheck! {
|
|||||||
result_set.is_empty()
|
result_set.is_empty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tail(v: Vec<i32>, n: u8) -> bool {
|
||||||
|
let n = n as usize;
|
||||||
|
let result = &v[v.len().saturating_sub(n)..];
|
||||||
|
itertools::equal(v.iter().tail(n), result)
|
||||||
|
&& itertools::equal(v.iter().filter(|_| true).tail(n), result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
498
third_party/rust/itertools/tests/specializations.rs
vendored
498
third_party/rust/itertools/tests/specializations.rs
vendored
@@ -1,8 +1,20 @@
|
|||||||
|
//! Test specializations of methods with default impls match the behavior of the
|
||||||
|
//! default impls.
|
||||||
|
//!
|
||||||
|
//! **NOTE:** Due to performance limitations, these tests are not run with miri!
|
||||||
|
//! They cannot be relied upon to discover soundness issues.
|
||||||
|
|
||||||
|
#![cfg(not(miri))]
|
||||||
|
#![allow(unstable_name_collisions)]
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use quickcheck::Arbitrary;
|
||||||
|
use quickcheck::{quickcheck, TestResult};
|
||||||
|
use rand::Rng;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use quickcheck::quickcheck;
|
|
||||||
|
|
||||||
struct Unspecialized<I>(I);
|
struct Unspecialized<I>(I);
|
||||||
|
|
||||||
impl<I> Iterator for Unspecialized<I>
|
impl<I> Iterator for Unspecialized<I>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
@@ -15,30 +27,41 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! check_specialized {
|
impl<I> DoubleEndedIterator for Unspecialized<I>
|
||||||
($src:expr, |$it:pat| $closure:expr) => {
|
where
|
||||||
let $it = $src.clone();
|
I: DoubleEndedIterator,
|
||||||
let v1 = $closure;
|
{
|
||||||
|
#[inline(always)]
|
||||||
let $it = Unspecialized($src.clone());
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
let v2 = $closure;
|
self.0.next_back()
|
||||||
|
|
||||||
assert_eq!(v1, v2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_specializations<IterItem, Iter>(
|
fn test_specializations<I>(it: &I)
|
||||||
it: &Iter,
|
where
|
||||||
) where
|
I::Item: Eq + Debug + Clone,
|
||||||
IterItem: Eq + Debug + Clone,
|
I: Iterator + Clone,
|
||||||
Iter: Iterator<Item = IterItem> + Clone,
|
|
||||||
{
|
{
|
||||||
|
macro_rules! check_specialized {
|
||||||
|
($src:expr, |$it:pat| $closure:expr) => {
|
||||||
|
// Many iterators special-case the first elements, so we test specializations for iterators that have already been advanced.
|
||||||
|
let mut src = $src.clone();
|
||||||
|
for _ in 0..5 {
|
||||||
|
let $it = src.clone();
|
||||||
|
let v1 = $closure;
|
||||||
|
let $it = Unspecialized(src.clone());
|
||||||
|
let v2 = $closure;
|
||||||
|
assert_eq!(v1, v2);
|
||||||
|
src.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
check_specialized!(it, |i| i.count());
|
check_specialized!(it, |i| i.count());
|
||||||
check_specialized!(it, |i| i.last());
|
check_specialized!(it, |i| i.last());
|
||||||
check_specialized!(it, |i| i.collect::<Vec<_>>());
|
check_specialized!(it, |i| i.collect::<Vec<_>>());
|
||||||
check_specialized!(it, |i| {
|
check_specialized!(it, |i| {
|
||||||
let mut parameters_from_fold = vec![];
|
let mut parameters_from_fold = vec![];
|
||||||
let fold_result = i.fold(vec![], |mut acc, v: IterItem| {
|
let fold_result = i.fold(vec![], |mut acc, v: I::Item| {
|
||||||
parameters_from_fold.push((acc.clone(), v.clone()));
|
parameters_from_fold.push((acc.clone(), v.clone()));
|
||||||
acc.push(v);
|
acc.push(v);
|
||||||
acc
|
acc
|
||||||
@@ -50,7 +73,7 @@ fn test_specializations<IterItem, Iter>(
|
|||||||
let first = i.next();
|
let first = i.next();
|
||||||
let all_result = i.all(|x| {
|
let all_result = i.all(|x| {
|
||||||
parameters_from_all.push(x.clone());
|
parameters_from_all.push(x.clone());
|
||||||
Some(x)==first
|
Some(x) == first
|
||||||
});
|
});
|
||||||
(parameters_from_all, all_result)
|
(parameters_from_all, all_result)
|
||||||
});
|
});
|
||||||
@@ -72,10 +95,270 @@ fn test_specializations<IterItem, Iter>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_double_ended_specializations<I>(it: &I)
|
||||||
|
where
|
||||||
|
I::Item: Eq + Debug + Clone,
|
||||||
|
I: DoubleEndedIterator + Clone,
|
||||||
|
{
|
||||||
|
macro_rules! check_specialized {
|
||||||
|
($src:expr, |$it:pat| $closure:expr) => {
|
||||||
|
// Many iterators special-case the first elements, so we test specializations for iterators that have already been advanced.
|
||||||
|
let mut src = $src.clone();
|
||||||
|
for step in 0..8 {
|
||||||
|
let $it = src.clone();
|
||||||
|
let v1 = $closure;
|
||||||
|
let $it = Unspecialized(src.clone());
|
||||||
|
let v2 = $closure;
|
||||||
|
assert_eq!(v1, v2);
|
||||||
|
if step % 2 == 0 {
|
||||||
|
src.next();
|
||||||
|
} else {
|
||||||
|
src.next_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check_specialized!(it, |i| {
|
||||||
|
let mut parameters_from_rfold = vec![];
|
||||||
|
let rfold_result = i.rfold(vec![], |mut acc, v: I::Item| {
|
||||||
|
parameters_from_rfold.push((acc.clone(), v.clone()));
|
||||||
|
acc.push(v);
|
||||||
|
acc
|
||||||
|
});
|
||||||
|
(parameters_from_rfold, rfold_result)
|
||||||
|
});
|
||||||
|
let size = it.clone().count();
|
||||||
|
for n in 0..size + 2 {
|
||||||
|
check_specialized!(it, |mut i| i.nth_back(n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
|
fn interleave(v: Vec<u8>, w: Vec<u8>) -> () {
|
||||||
|
test_specializations(&v.iter().interleave(w.iter()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interleave_shortest(v: Vec<u8>, w: Vec<u8>) -> () {
|
||||||
|
test_specializations(&v.iter().interleave_shortest(w.iter()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn batching(v: Vec<u8>) -> () {
|
||||||
|
test_specializations(&v.iter().batching(Iterator::next));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tuple_windows(v: Vec<u8>) -> () {
|
||||||
|
test_specializations(&v.iter().tuple_windows::<(_,)>());
|
||||||
|
test_specializations(&v.iter().tuple_windows::<(_, _)>());
|
||||||
|
test_specializations(&v.iter().tuple_windows::<(_, _, _)>());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn circular_tuple_windows(v: Vec<u8>) -> () {
|
||||||
|
test_specializations(&v.iter().circular_tuple_windows::<(_,)>());
|
||||||
|
test_specializations(&v.iter().circular_tuple_windows::<(_, _)>());
|
||||||
|
test_specializations(&v.iter().circular_tuple_windows::<(_, _, _)>());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tuples(v: Vec<u8>) -> () {
|
||||||
|
test_specializations(&v.iter().tuples::<(_,)>());
|
||||||
|
test_specializations(&v.iter().tuples::<(_, _)>());
|
||||||
|
test_specializations(&v.iter().tuples::<(_, _, _)>());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cartesian_product(a: Vec<u8>, b: Vec<u8>) -> TestResult {
|
||||||
|
if a.len() * b.len() > 100 {
|
||||||
|
return TestResult::discard();
|
||||||
|
}
|
||||||
|
test_specializations(&a.iter().cartesian_product(&b));
|
||||||
|
TestResult::passed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn multi_cartesian_product(a: Vec<u8>, b: Vec<u8>, c: Vec<u8>) -> TestResult {
|
||||||
|
if a.len() * b.len() * c.len() > 100 {
|
||||||
|
return TestResult::discard();
|
||||||
|
}
|
||||||
|
test_specializations(&vec![a, b, c].into_iter().multi_cartesian_product());
|
||||||
|
TestResult::passed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn coalesce(v: Vec<u8>) -> () {
|
||||||
|
test_specializations(&v.iter().coalesce(|x, y| if x == y { Ok(x) } else { Err((x, y)) }))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dedup(v: Vec<u8>) -> () {
|
||||||
|
test_specializations(&v.iter().dedup())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dedup_by(v: Vec<u8>) -> () {
|
||||||
|
test_specializations(&v.iter().dedup_by(PartialOrd::ge))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dedup_with_count(v: Vec<u8>) -> () {
|
||||||
|
test_specializations(&v.iter().dedup_with_count())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dedup_by_with_count(v: Vec<u8>) -> () {
|
||||||
|
test_specializations(&v.iter().dedup_by_with_count(PartialOrd::ge))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn duplicates(v: Vec<u8>) -> () {
|
||||||
|
let it = v.iter().duplicates();
|
||||||
|
test_specializations(&it);
|
||||||
|
test_double_ended_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn duplicates_by(v: Vec<u8>) -> () {
|
||||||
|
let it = v.iter().duplicates_by(|x| *x % 10);
|
||||||
|
test_specializations(&it);
|
||||||
|
test_double_ended_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unique(v: Vec<u8>) -> () {
|
||||||
|
let it = v.iter().unique();
|
||||||
|
test_specializations(&it);
|
||||||
|
test_double_ended_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unique_by(v: Vec<u8>) -> () {
|
||||||
|
let it = v.iter().unique_by(|x| *x % 50);
|
||||||
|
test_specializations(&it);
|
||||||
|
test_double_ended_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_while_inclusive(v: Vec<u8>) -> () {
|
||||||
|
test_specializations(&v.iter().copied().take_while_inclusive(|&x| x < 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn while_some(v: Vec<u8>) -> () {
|
||||||
|
test_specializations(&v.iter().map(|&x| if x < 100 { Some(2 * x) } else { None }).while_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pad_using(v: Vec<u8>) -> () {
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
let it = v.iter().copied().pad_using(10, |i| u8::try_from(5 * i).unwrap_or(u8::MAX));
|
||||||
|
test_specializations(&it);
|
||||||
|
test_double_ended_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_position(v: Vec<u8>) -> () {
|
||||||
|
test_specializations(&v.iter().with_position());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn positions(v: Vec<u8>) -> () {
|
||||||
|
let it = v.iter().positions(|x| x % 5 == 0);
|
||||||
|
test_specializations(&it);
|
||||||
|
test_double_ended_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(v: Vec<u8>) -> () {
|
||||||
|
let it = v.iter().copied().update(|x| *x = x.wrapping_mul(7));
|
||||||
|
test_specializations(&it);
|
||||||
|
test_double_ended_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tuple_combinations(v: Vec<u8>) -> TestResult {
|
||||||
|
if v.len() > 10 {
|
||||||
|
return TestResult::discard();
|
||||||
|
}
|
||||||
|
test_specializations(&v.iter().tuple_combinations::<(_,)>());
|
||||||
|
test_specializations(&v.iter().tuple_combinations::<(_, _)>());
|
||||||
|
test_specializations(&v.iter().tuple_combinations::<(_, _, _)>());
|
||||||
|
TestResult::passed()
|
||||||
|
}
|
||||||
|
|
||||||
fn intersperse(v: Vec<u8>) -> () {
|
fn intersperse(v: Vec<u8>) -> () {
|
||||||
test_specializations(&v.into_iter().intersperse(0));
|
test_specializations(&v.into_iter().intersperse(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn intersperse_with(v: Vec<u8>) -> () {
|
||||||
|
test_specializations(&v.into_iter().intersperse_with(|| 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn array_combinations(v: Vec<u8>) -> TestResult {
|
||||||
|
if v.len() > 10 {
|
||||||
|
return TestResult::discard();
|
||||||
|
}
|
||||||
|
test_specializations(&v.iter().array_combinations::<1>());
|
||||||
|
test_specializations(&v.iter().array_combinations::<2>());
|
||||||
|
test_specializations(&v.iter().array_combinations::<3>());
|
||||||
|
TestResult::passed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn combinations(a: Vec<u8>, n: u8) -> TestResult {
|
||||||
|
if n > 3 || a.len() > 8 {
|
||||||
|
return TestResult::discard();
|
||||||
|
}
|
||||||
|
test_specializations(&a.iter().combinations(n as usize));
|
||||||
|
TestResult::passed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn combinations_with_replacement(a: Vec<u8>, n: u8) -> TestResult {
|
||||||
|
if n > 3 || a.len() > 7 {
|
||||||
|
return TestResult::discard();
|
||||||
|
}
|
||||||
|
test_specializations(&a.iter().combinations_with_replacement(n as usize));
|
||||||
|
TestResult::passed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn permutations(a: Vec<u8>, n: u8) -> TestResult {
|
||||||
|
if n > 3 || a.len() > 8 {
|
||||||
|
return TestResult::discard();
|
||||||
|
}
|
||||||
|
test_specializations(&a.iter().permutations(n as usize));
|
||||||
|
TestResult::passed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn powerset(a: Vec<u8>) -> TestResult {
|
||||||
|
if a.len() > 6 {
|
||||||
|
return TestResult::discard();
|
||||||
|
}
|
||||||
|
test_specializations(&a.iter().powerset());
|
||||||
|
TestResult::passed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zip_longest(a: Vec<u8>, b: Vec<u8>) -> () {
|
||||||
|
let it = a.into_iter().zip_longest(b);
|
||||||
|
test_specializations(&it);
|
||||||
|
test_double_ended_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zip_eq(a: Vec<u8>) -> () {
|
||||||
|
test_specializations(&a.iter().zip_eq(a.iter().rev()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn multizip(a: Vec<u8>) -> () {
|
||||||
|
let it = itertools::multizip((a.iter(), a.iter().rev(), a.iter().take(50)));
|
||||||
|
test_specializations(&it);
|
||||||
|
test_double_ended_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn izip(a: Vec<u8>, b: Vec<u8>) -> () {
|
||||||
|
test_specializations(&itertools::izip!(b.iter(), a, b.iter().rev()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iproduct(a: Vec<u8>, b: Vec<u8>, c: Vec<u8>) -> TestResult {
|
||||||
|
if a.len() * b.len() * c.len() > 200 {
|
||||||
|
return TestResult::discard();
|
||||||
|
}
|
||||||
|
test_specializations(&itertools::iproduct!(a, b.iter(), c));
|
||||||
|
TestResult::passed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn repeat_n(element: i8, n: u8) -> () {
|
||||||
|
let it = itertools::repeat_n(element, n as usize);
|
||||||
|
test_specializations(&it);
|
||||||
|
test_double_ended_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exactly_one_error(v: Vec<u8>) -> TestResult {
|
||||||
|
// Use `at_most_one` would be similar.
|
||||||
|
match v.iter().exactly_one() {
|
||||||
|
Ok(_) => TestResult::discard(),
|
||||||
|
Err(it) => {
|
||||||
|
test_specializations(&it);
|
||||||
|
TestResult::passed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
@@ -85,32 +368,128 @@ quickcheck! {
|
|||||||
pb.put_back(1);
|
pb.put_back(1);
|
||||||
test_specializations(&pb);
|
test_specializations(&pb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn put_back_n(v: Vec<u8>, n: u8) -> () {
|
||||||
|
let mut it = itertools::put_back_n(v);
|
||||||
|
for k in 0..n {
|
||||||
|
it.put_back(k);
|
||||||
|
}
|
||||||
|
test_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn multipeek(v: Vec<u8>, n: u8) -> () {
|
||||||
|
let mut it = v.into_iter().multipeek();
|
||||||
|
for _ in 0..n {
|
||||||
|
it.peek();
|
||||||
|
}
|
||||||
|
test_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek_nth_with_peek(v: Vec<u8>, n: u8) -> () {
|
||||||
|
let mut it = itertools::peek_nth(v);
|
||||||
|
for _ in 0..n {
|
||||||
|
it.peek();
|
||||||
|
}
|
||||||
|
test_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek_nth_with_peek_nth(v: Vec<u8>, n: u8) -> () {
|
||||||
|
let mut it = itertools::peek_nth(v);
|
||||||
|
it.peek_nth(n as usize);
|
||||||
|
test_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek_nth_with_peek_mut(v: Vec<u8>, n: u8) -> () {
|
||||||
|
let mut it = itertools::peek_nth(v);
|
||||||
|
for _ in 0..n {
|
||||||
|
if let Some(x) = it.peek_mut() {
|
||||||
|
*x = x.wrapping_add(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek_nth_with_peek_nth_mut(v: Vec<u8>, n: u8) -> () {
|
||||||
|
let mut it = itertools::peek_nth(v);
|
||||||
|
if let Some(x) = it.peek_nth_mut(n as usize) {
|
||||||
|
*x = x.wrapping_add(50);
|
||||||
|
}
|
||||||
|
test_specializations(&it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
fn merge_join_by_qc(i1: Vec<usize>, i2: Vec<usize>) -> () {
|
fn merge(a: Vec<u8>, b: Vec<u8>) -> () {
|
||||||
test_specializations(&i1.into_iter().merge_join_by(i2.into_iter(), std::cmp::Ord::cmp));
|
test_specializations(&a.into_iter().merge(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merge_by(a: Vec<u8>, b: Vec<u8>) -> () {
|
||||||
|
test_specializations(&a.into_iter().merge_by(b, PartialOrd::ge))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merge_join_by_ordering(i1: Vec<u8>, i2: Vec<u8>) -> () {
|
||||||
|
test_specializations(&i1.into_iter().merge_join_by(i2, Ord::cmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merge_join_by_bool(i1: Vec<u8>, i2: Vec<u8>) -> () {
|
||||||
|
test_specializations(&i1.into_iter().merge_join_by(i2, PartialOrd::ge));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kmerge(a: Vec<i8>, b: Vec<i8>, c: Vec<i8>) -> () {
|
||||||
|
test_specializations(&vec![a, b, c]
|
||||||
|
.into_iter()
|
||||||
|
.map(|v| v.into_iter().sorted())
|
||||||
|
.kmerge());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kmerge_by(a: Vec<i8>, b: Vec<i8>, c: Vec<i8>) -> () {
|
||||||
|
test_specializations(&vec![a, b, c]
|
||||||
|
.into_iter()
|
||||||
|
.map(|v| v.into_iter().sorted_by_key(|a| a.abs()))
|
||||||
|
.kmerge_by(|a, b| a.abs() < b.abs()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
fn map_into(v: Vec<u8>) -> () {
|
fn map_into(v: Vec<u8>) -> () {
|
||||||
test_specializations(&v.into_iter().map_into::<u32>());
|
let it = v.into_iter().map_into::<u32>();
|
||||||
|
test_specializations(&it);
|
||||||
|
test_double_ended_specializations(&it);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
quickcheck! {
|
|
||||||
fn map_ok(v: Vec<Result<u8, char>>) -> () {
|
fn map_ok(v: Vec<Result<u8, char>>) -> () {
|
||||||
test_specializations(&v.into_iter().map_ok(|u| u.checked_add(1)));
|
let it = v.into_iter().map_ok(|u| u.checked_add(1));
|
||||||
|
test_specializations(&it);
|
||||||
|
test_double_ended_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filter_ok(v: Vec<Result<u8, char>>) -> () {
|
||||||
|
let it = v.into_iter().filter_ok(|&i| i < 20);
|
||||||
|
test_specializations(&it);
|
||||||
|
test_double_ended_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filter_map_ok(v: Vec<Result<u8, char>>) -> () {
|
||||||
|
let it = v.into_iter().filter_map_ok(|i| if i < 20 { Some(i * 2) } else { None });
|
||||||
|
test_specializations(&it);
|
||||||
|
test_double_ended_specializations(&it);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `SmallIter2<u8>` because `Vec<u8>` is too slow and we get bad coverage from a singleton like Option<u8>
|
||||||
|
fn flatten_ok(v: Vec<Result<SmallIter2<u8>, char>>) -> () {
|
||||||
|
let it = v.into_iter().flatten_ok();
|
||||||
|
test_specializations(&it);
|
||||||
|
test_double_ended_specializations(&it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
|
// TODO Replace this function by a normal call to test_specializations
|
||||||
fn process_results(v: Vec<Result<u8, u8>>) -> () {
|
fn process_results(v: Vec<Result<u8, u8>>) -> () {
|
||||||
helper(v.iter().copied());
|
helper(v.iter().copied());
|
||||||
helper(v.iter().copied().filter(Result::is_ok));
|
helper(v.iter().copied().filter(Result::is_ok));
|
||||||
|
|
||||||
fn helper(it: impl Iterator<Item = Result<u8, u8>> + Clone) {
|
fn helper(it: impl DoubleEndedIterator<Item = Result<u8, u8>> + Clone) {
|
||||||
macro_rules! check_results_specialized {
|
macro_rules! check_results_specialized {
|
||||||
($src:expr, |$it:pat| $closure:expr) => {
|
($src:expr, |$it:pat| $closure:expr) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -126,6 +505,7 @@ quickcheck! {
|
|||||||
check_results_specialized!(it, |i| i.count());
|
check_results_specialized!(it, |i| i.count());
|
||||||
check_results_specialized!(it, |i| i.last());
|
check_results_specialized!(it, |i| i.last());
|
||||||
check_results_specialized!(it, |i| i.collect::<Vec<_>>());
|
check_results_specialized!(it, |i| i.collect::<Vec<_>>());
|
||||||
|
check_results_specialized!(it, |i| i.rev().collect::<Vec<_>>());
|
||||||
check_results_specialized!(it, |i| {
|
check_results_specialized!(it, |i| {
|
||||||
let mut parameters_from_fold = vec![];
|
let mut parameters_from_fold = vec![];
|
||||||
let fold_result = i.fold(vec![], |mut acc, v| {
|
let fold_result = i.fold(vec![], |mut acc, v| {
|
||||||
@@ -135,6 +515,15 @@ quickcheck! {
|
|||||||
});
|
});
|
||||||
(parameters_from_fold, fold_result)
|
(parameters_from_fold, fold_result)
|
||||||
});
|
});
|
||||||
|
check_results_specialized!(it, |i| {
|
||||||
|
let mut parameters_from_rfold = vec![];
|
||||||
|
let rfold_result = i.rfold(vec![], |mut acc, v| {
|
||||||
|
parameters_from_rfold.push((acc.clone(), v));
|
||||||
|
acc.push(v);
|
||||||
|
acc
|
||||||
|
});
|
||||||
|
(parameters_from_rfold, rfold_result)
|
||||||
|
});
|
||||||
check_results_specialized!(it, |mut i| {
|
check_results_specialized!(it, |mut i| {
|
||||||
let mut parameters_from_all = vec![];
|
let mut parameters_from_all = vec![];
|
||||||
let first = i.next();
|
let first = i.next();
|
||||||
@@ -148,6 +537,67 @@ quickcheck! {
|
|||||||
for n in 0..size + 2 {
|
for n in 0..size + 2 {
|
||||||
check_results_specialized!(it, |mut i| i.nth(n));
|
check_results_specialized!(it, |mut i| i.nth(n));
|
||||||
}
|
}
|
||||||
|
for n in 0..size + 2 {
|
||||||
|
check_results_specialized!(it, |mut i| i.nth_back(n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like `VecIntoIter<T>` with maximum 2 elements.
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
enum SmallIter2<T> {
|
||||||
|
#[default]
|
||||||
|
Zero,
|
||||||
|
One(T),
|
||||||
|
Two(T, T),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Arbitrary> Arbitrary for SmallIter2<T> {
|
||||||
|
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
|
||||||
|
match g.gen_range(0u8, 3) {
|
||||||
|
0 => Self::Zero,
|
||||||
|
1 => Self::One(T::arbitrary(g)),
|
||||||
|
2 => Self::Two(T::arbitrary(g), T::arbitrary(g)),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// maybe implement shrink too, maybe not
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Iterator for SmallIter2<T> {
|
||||||
|
type Item = T;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
match std::mem::take(self) {
|
||||||
|
Self::Zero => None,
|
||||||
|
Self::One(val) => Some(val),
|
||||||
|
Self::Two(val, second) => {
|
||||||
|
*self = Self::One(second);
|
||||||
|
Some(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
let len = match self {
|
||||||
|
Self::Zero => 0,
|
||||||
|
Self::One(_) => 1,
|
||||||
|
Self::Two(_, _) => 2,
|
||||||
|
};
|
||||||
|
(len, Some(len))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DoubleEndedIterator for SmallIter2<T> {
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
match std::mem::take(self) {
|
||||||
|
Self::Zero => None,
|
||||||
|
Self::One(val) => Some(val),
|
||||||
|
Self::Two(first, val) => {
|
||||||
|
*self = Self::One(first);
|
||||||
|
Some(val)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
180
third_party/rust/itertools/tests/test_core.rs
vendored
180
third_party/rust/itertools/tests/test_core.rs
vendored
@@ -4,18 +4,71 @@
|
|||||||
//! option. This file may not be copied, modified, or distributed
|
//! option. This file may not be copied, modified, or distributed
|
||||||
//! except according to those terms.
|
//! except according to those terms.
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
#![allow(deprecated)]
|
||||||
|
|
||||||
use core::iter;
|
use crate::it::chain;
|
||||||
use itertools as it;
|
use crate::it::free::put_back;
|
||||||
use crate::it::Itertools;
|
|
||||||
use crate::it::interleave;
|
use crate::it::interleave;
|
||||||
use crate::it::intersperse;
|
use crate::it::intersperse;
|
||||||
use crate::it::intersperse_with;
|
use crate::it::intersperse_with;
|
||||||
use crate::it::multizip;
|
|
||||||
use crate::it::free::put_back;
|
|
||||||
use crate::it::iproduct;
|
use crate::it::iproduct;
|
||||||
use crate::it::izip;
|
use crate::it::izip;
|
||||||
use crate::it::chain;
|
use crate::it::multizip;
|
||||||
|
use crate::it::Itertools;
|
||||||
|
use core::iter;
|
||||||
|
use itertools as it;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn get_esi_then_esi<I: ExactSizeIterator + Clone>(it: I) {
|
||||||
|
fn is_esi(_: impl ExactSizeIterator) {}
|
||||||
|
is_esi(it.clone().get(1..4));
|
||||||
|
is_esi(it.clone().get(1..=4));
|
||||||
|
is_esi(it.clone().get(1..));
|
||||||
|
is_esi(it.clone().get(..4));
|
||||||
|
is_esi(it.clone().get(..=4));
|
||||||
|
is_esi(it.get(..));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn get_dei_esi_then_dei_esi<I: DoubleEndedIterator + ExactSizeIterator + Clone>(it: I) {
|
||||||
|
fn is_dei_esi(_: impl DoubleEndedIterator + ExactSizeIterator) {}
|
||||||
|
is_dei_esi(it.clone().get(1..4));
|
||||||
|
is_dei_esi(it.clone().get(1..=4));
|
||||||
|
is_dei_esi(it.clone().get(1..));
|
||||||
|
is_dei_esi(it.clone().get(..4));
|
||||||
|
is_dei_esi(it.clone().get(..=4));
|
||||||
|
is_dei_esi(it.get(..));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_1_max() {
|
||||||
|
let mut it = (0..5).get(1..=usize::MAX);
|
||||||
|
assert_eq!(it.next(), Some(1));
|
||||||
|
assert_eq!(it.next_back(), Some(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn get_full_range_inclusive() {
|
||||||
|
let _it = (0..5).get(0..=usize::MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn product0() {
|
||||||
|
let mut prod = iproduct!();
|
||||||
|
assert_eq!(prod.next(), Some(()));
|
||||||
|
assert!(prod.next().is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn iproduct1() {
|
||||||
|
let s = "αβ";
|
||||||
|
|
||||||
|
let mut prod = iproduct!(s.chars());
|
||||||
|
assert_eq!(prod.next(), Some(('α',)));
|
||||||
|
assert_eq!(prod.next(), Some(('β',)));
|
||||||
|
assert!(prod.next().is_none());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn product2() {
|
fn product2() {
|
||||||
@@ -26,7 +79,7 @@ fn product2() {
|
|||||||
assert!(prod.next() == Some(('α', 1)));
|
assert!(prod.next() == Some(('α', 1)));
|
||||||
assert!(prod.next() == Some(('β', 0)));
|
assert!(prod.next() == Some(('β', 0)));
|
||||||
assert!(prod.next() == Some(('β', 1)));
|
assert!(prod.next() == Some(('β', 1)));
|
||||||
assert!(prod.next() == None);
|
assert!(prod.next().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -34,13 +87,12 @@ fn product_temporary() {
|
|||||||
for (_x, _y, _z) in iproduct!(
|
for (_x, _y, _z) in iproduct!(
|
||||||
[0, 1, 2].iter().cloned(),
|
[0, 1, 2].iter().cloned(),
|
||||||
[0, 1, 2].iter().cloned(),
|
[0, 1, 2].iter().cloned(),
|
||||||
[0, 1, 2].iter().cloned())
|
[0, 1, 2].iter().cloned()
|
||||||
{
|
) {
|
||||||
// ok
|
// ok
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn izip_macro() {
|
fn izip_macro() {
|
||||||
let mut zip = izip!(2..3);
|
let mut zip = izip!(2..3);
|
||||||
@@ -61,7 +113,7 @@ fn izip_macro() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn izip2() {
|
fn izip2() {
|
||||||
let _zip1: iter::Zip<_, _> = izip!(1.., 2..);
|
let _zip1: iter::Zip<_, _> = izip!(1.., 2..);
|
||||||
let _zip2: iter::Zip<_, _> = izip!(1.., 2.., );
|
let _zip2: iter::Zip<_, _> = izip!(1.., 2..,);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -109,7 +161,7 @@ fn chain_macro() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn chain2() {
|
fn chain2() {
|
||||||
let _ = chain!(1.., 2..);
|
let _ = chain!(1.., 2..);
|
||||||
let _ = chain!(1.., 2.., );
|
let _ = chain!(1.., 2..,);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -127,7 +179,7 @@ fn write_to() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_interleave() {
|
fn test_interleave() {
|
||||||
let xs: [u8; 0] = [];
|
let xs: [u8; 0] = [];
|
||||||
let ys = [7u8, 9, 8, 10];
|
let ys = [7u8, 9, 8, 10];
|
||||||
let zs = [2u8, 77];
|
let zs = [2u8, 77];
|
||||||
let it = interleave(xs.iter(), ys.iter());
|
let it = interleave(xs.iter(), ys.iter());
|
||||||
@@ -155,15 +207,6 @@ fn test_intersperse_with() {
|
|||||||
it::assert_equal(it, ys.iter());
|
it::assert_equal(it, ys.iter());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(deprecated)]
|
|
||||||
#[test]
|
|
||||||
fn foreach() {
|
|
||||||
let xs = [1i32, 2, 3];
|
|
||||||
let mut sum = 0;
|
|
||||||
xs.iter().foreach(|elt| sum += *elt);
|
|
||||||
assert!(sum == 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dropping() {
|
fn dropping() {
|
||||||
let xs = [1, 2, 3];
|
let xs = [1, 2, 3];
|
||||||
@@ -197,21 +240,11 @@ fn test_put_back() {
|
|||||||
it::assert_equal(pb, xs.iter().cloned());
|
it::assert_equal(pb, xs.iter().cloned());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(deprecated)]
|
|
||||||
#[test]
|
|
||||||
fn step() {
|
|
||||||
it::assert_equal((0..10).step(1), 0..10);
|
|
||||||
it::assert_equal((0..10).step(2), (0..10).filter(|x: &i32| *x % 2 == 0));
|
|
||||||
it::assert_equal((0..10).step(10), 0..1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(deprecated)]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn merge() {
|
fn merge() {
|
||||||
it::assert_equal((0..10).step(2).merge((1..10).step(2)), 0..10);
|
it::assert_equal((0..10).step_by(2).merge((1..10).step_by(2)), 0..10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn repeatn() {
|
fn repeatn() {
|
||||||
let s = "α";
|
let s = "α";
|
||||||
@@ -231,29 +264,33 @@ fn count_clones() {
|
|||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
struct Foo {
|
struct Foo {
|
||||||
n: Cell<usize>
|
n: Cell<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for Foo
|
impl Clone for Foo {
|
||||||
{
|
fn clone(&self) -> Self {
|
||||||
fn clone(&self) -> Self
|
|
||||||
{
|
|
||||||
let n = self.n.get();
|
let n = self.n.get();
|
||||||
self.n.set(n + 1);
|
self.n.set(n + 1);
|
||||||
Foo { n: Cell::new(n + 1) }
|
Self {
|
||||||
|
n: Cell::new(n + 1),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for n in 0..10 {
|
for n in 0..10 {
|
||||||
let f = Foo{n: Cell::new(0)};
|
let f = Foo { n: Cell::new(0) };
|
||||||
let it = it::repeat_n(f, n);
|
let it = it::repeat_n(f, n);
|
||||||
// drain it
|
// drain it
|
||||||
let last = it.last();
|
let last = it.last();
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
assert_eq!(last, None);
|
assert_eq!(last, None);
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(last, Some(Foo{n: Cell::new(n - 1)}));
|
assert_eq!(
|
||||||
|
last,
|
||||||
|
Some(Foo {
|
||||||
|
n: Cell::new(n - 1)
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -276,25 +313,45 @@ fn part() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tree_fold1() {
|
fn tree_reduce() {
|
||||||
for i in 0..100 {
|
for i in 0..100 {
|
||||||
assert_eq!((0..i).tree_fold1(|x, y| x + y), (0..i).fold1(|x, y| x + y));
|
assert_eq!((0..i).tree_reduce(|x, y| x + y), (0..i).fold1(|x, y| x + y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exactly_one() {
|
fn exactly_one() {
|
||||||
assert_eq!((0..10).filter(|&x| x == 2).exactly_one().unwrap(), 2);
|
assert_eq!((0..10).filter(|&x| x == 2).exactly_one().unwrap(), 2);
|
||||||
assert!((0..10).filter(|&x| x > 1 && x < 4).exactly_one().unwrap_err().eq(2..4));
|
assert!((0..10)
|
||||||
assert!((0..10).filter(|&x| x > 1 && x < 5).exactly_one().unwrap_err().eq(2..5));
|
.filter(|&x| x > 1 && x < 4)
|
||||||
assert!((0..10).filter(|&_| false).exactly_one().unwrap_err().eq(0..0));
|
.exactly_one()
|
||||||
|
.unwrap_err()
|
||||||
|
.eq(2..4));
|
||||||
|
assert!((0..10)
|
||||||
|
.filter(|&x| x > 1 && x < 5)
|
||||||
|
.exactly_one()
|
||||||
|
.unwrap_err()
|
||||||
|
.eq(2..5));
|
||||||
|
assert!((0..10)
|
||||||
|
.filter(|&_| false)
|
||||||
|
.exactly_one()
|
||||||
|
.unwrap_err()
|
||||||
|
.eq(0..0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn at_most_one() {
|
fn at_most_one() {
|
||||||
assert_eq!((0..10).filter(|&x| x == 2).at_most_one().unwrap(), Some(2));
|
assert_eq!((0..10).filter(|&x| x == 2).at_most_one().unwrap(), Some(2));
|
||||||
assert!((0..10).filter(|&x| x > 1 && x < 4).at_most_one().unwrap_err().eq(2..4));
|
assert!((0..10)
|
||||||
assert!((0..10).filter(|&x| x > 1 && x < 5).at_most_one().unwrap_err().eq(2..5));
|
.filter(|&x| x > 1 && x < 4)
|
||||||
|
.at_most_one()
|
||||||
|
.unwrap_err()
|
||||||
|
.eq(2..4));
|
||||||
|
assert!((0..10)
|
||||||
|
.filter(|&x| x > 1 && x < 5)
|
||||||
|
.at_most_one()
|
||||||
|
.unwrap_err()
|
||||||
|
.eq(2..5));
|
||||||
assert_eq!((0..10).filter(|&_| false).at_most_one().unwrap(), None);
|
assert_eq!((0..10).filter(|&_| false).at_most_one().unwrap(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,3 +372,28 @@ fn product1() {
|
|||||||
assert_eq!(v[1..3].iter().cloned().product1::<i32>(), Some(2));
|
assert_eq!(v[1..3].iter().cloned().product1::<i32>(), Some(2));
|
||||||
assert_eq!(v[1..5].iter().cloned().product1::<i32>(), Some(24));
|
assert_eq!(v[1..5].iter().cloned().product1::<i32>(), Some(24));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn next_array() {
|
||||||
|
let v = [1, 2, 3, 4, 5];
|
||||||
|
let mut iter = v.iter();
|
||||||
|
assert_eq!(iter.next_array(), Some([]));
|
||||||
|
assert_eq!(iter.next_array().map(|[&x, &y]| [x, y]), Some([1, 2]));
|
||||||
|
assert_eq!(iter.next_array().map(|[&x, &y]| [x, y]), Some([3, 4]));
|
||||||
|
assert_eq!(iter.next_array::<2>(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn collect_array() {
|
||||||
|
let v = [1, 2];
|
||||||
|
let iter = v.iter().cloned();
|
||||||
|
assert_eq!(iter.collect_array(), Some([1, 2]));
|
||||||
|
|
||||||
|
let v = [1];
|
||||||
|
let iter = v.iter().cloned();
|
||||||
|
assert_eq!(iter.collect_array::<2>(), None);
|
||||||
|
|
||||||
|
let v = [1, 2, 3];
|
||||||
|
let iter = v.iter().cloned();
|
||||||
|
assert_eq!(iter.collect_array::<2>(), None);
|
||||||
|
}
|
||||||
|
|||||||
831
third_party/rust/itertools/tests/test_std.rs
vendored
831
third_party/rust/itertools/tests/test_std.rs
vendored
File diff suppressed because it is too large
Load Diff
35
third_party/rust/itertools/tests/zip.rs
vendored
35
third_party/rust/itertools/tests/zip.rs
vendored
@@ -1,17 +1,17 @@
|
|||||||
use itertools::Itertools;
|
|
||||||
use itertools::EitherOrBoth::{Both, Left, Right};
|
|
||||||
use itertools::free::zip_eq;
|
|
||||||
use itertools::multizip;
|
use itertools::multizip;
|
||||||
|
use itertools::EitherOrBoth::{Both, Left, Right};
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn zip_longest_fused() {
|
fn zip_longest_fused() {
|
||||||
let a = [Some(1), None, Some(3), Some(4)];
|
let a = [Some(1), None, Some(3), Some(4)];
|
||||||
let b = [1, 2, 3];
|
let b = [1, 2, 3];
|
||||||
|
|
||||||
let unfused = a.iter().batching(|it| *it.next().unwrap())
|
let unfused = a
|
||||||
|
.iter()
|
||||||
|
.batching(|it| *it.next().unwrap())
|
||||||
.zip_longest(b.iter().cloned());
|
.zip_longest(b.iter().cloned());
|
||||||
itertools::assert_equal(unfused,
|
itertools::assert_equal(unfused, vec![Both(1, 1), Right(2), Right(3)]);
|
||||||
vec![Both(1, 1), Right(2), Right(3)]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -20,7 +20,7 @@ fn test_zip_longest_size_hint() {
|
|||||||
let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
let v2 = &[10, 11, 12];
|
let v2 = &[10, 11, 12];
|
||||||
|
|
||||||
assert_eq!(c.zip_longest(v.iter()).size_hint(), (std::usize::MAX, None));
|
assert_eq!(c.zip_longest(v.iter()).size_hint(), (usize::MAX, None));
|
||||||
|
|
||||||
assert_eq!(v.iter().zip_longest(v2.iter()).size_hint(), (10, Some(10)));
|
assert_eq!(v.iter().zip_longest(v2.iter()).size_hint(), (10, Some(10)));
|
||||||
}
|
}
|
||||||
@@ -54,24 +54,3 @@ fn test_double_ended_zip() {
|
|||||||
assert_eq!(it.next_back(), Some((1, 1)));
|
assert_eq!(it.next_back(), Some((1, 1)));
|
||||||
assert_eq!(it.next_back(), None);
|
assert_eq!(it.next_back(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[should_panic]
|
|
||||||
#[test]
|
|
||||||
fn zip_eq_panic1()
|
|
||||||
{
|
|
||||||
let a = [1, 2];
|
|
||||||
let b = [1, 2, 3];
|
|
||||||
|
|
||||||
zip_eq(&a, &b).count();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[should_panic]
|
|
||||||
#[test]
|
|
||||||
fn zip_eq_panic2()
|
|
||||||
{
|
|
||||||
let a: [i32; 0] = [];
|
|
||||||
let b = [1, 2, 3];
|
|
||||||
|
|
||||||
zip_eq(&a, &b).count();
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user