Bug 1933199 - update Rust rayon crate to v1.10.0 r=kershaw,supply-chain-reviewers,valentin
[mozilla/neqo#2135](https://github.com/mozilla/neqo/pull/2135) adds `mtu` crate to `neqo-*`. `mtu` crate depends on `windows-bindgen`. `windows-bindgen` depends on `rayon` `1.7`. On the other hand mozilla-central depends on [`rayon` `v1.6.1`](https://searchfox.org/mozilla-central/rev/7987501f2c2ed1914e5c682bd328ace9c4a7c6cd/Cargo.lock#5149-5157). Given that mozilla-central allows at most one version of each crate, let's update mozilla-central to `rayon` `1.10.0`, i.e. the most recent version. See https://github.com/mozilla/neqo/pull/2135#issuecomment-2497077670 for details. Differential Revision: https://phabricator.services.mozilla.com/D230127
This commit is contained in:
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -5158,9 +5158,9 @@ checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "1.6.1"
|
version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7"
|
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
"rayon-core",
|
"rayon-core",
|
||||||
@@ -5168,9 +5168,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon-core"
|
name = "rayon-core"
|
||||||
version = "1.12.0"
|
version = "1.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
|
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-deque",
|
"crossbeam-deque",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
|
|||||||
@@ -1668,15 +1668,35 @@ who = "David Cook <dcook@divviup.org>"
|
|||||||
criteria = "safe-to-deploy"
|
criteria = "safe-to-deploy"
|
||||||
version = "0.6.3"
|
version = "0.6.3"
|
||||||
|
|
||||||
[[audits.isrg.audits.rayon-core]]
|
[[audits.isrg.audits.rayon]]
|
||||||
who = "Brandon Pitman <bran@bran.land>"
|
who = "Brandon Pitman <bran@bran.land>"
|
||||||
criteria = "safe-to-deploy"
|
criteria = "safe-to-deploy"
|
||||||
delta = "1.10.2 -> 1.11.0"
|
delta = "1.6.1 -> 1.7.0"
|
||||||
|
|
||||||
[[audits.isrg.audits.rayon-core]]
|
[[audits.isrg.audits.rayon]]
|
||||||
who = "David Cook <dcook@divviup.org>"
|
who = "David Cook <dcook@divviup.org>"
|
||||||
criteria = "safe-to-deploy"
|
criteria = "safe-to-deploy"
|
||||||
delta = "1.11.0 -> 1.12.0"
|
delta = "1.7.0 -> 1.8.0"
|
||||||
|
|
||||||
|
[[audits.isrg.audits.rayon]]
|
||||||
|
who = "Ameer Ghani <inahga@divviup.org>"
|
||||||
|
criteria = "safe-to-deploy"
|
||||||
|
delta = "1.8.0 -> 1.8.1"
|
||||||
|
|
||||||
|
[[audits.isrg.audits.rayon]]
|
||||||
|
who = "Brandon Pitman <bran@bran.land>"
|
||||||
|
criteria = "safe-to-deploy"
|
||||||
|
delta = "1.8.1 -> 1.9.0"
|
||||||
|
|
||||||
|
[[audits.isrg.audits.rayon]]
|
||||||
|
who = "Brandon Pitman <bran@bran.land>"
|
||||||
|
criteria = "safe-to-deploy"
|
||||||
|
delta = "1.9.0 -> 1.10.0"
|
||||||
|
|
||||||
|
[[audits.isrg.audits.rayon-core]]
|
||||||
|
who = "Ameer Ghani <inahga@divviup.org>"
|
||||||
|
criteria = "safe-to-deploy"
|
||||||
|
version = "1.12.1"
|
||||||
|
|
||||||
[[audits.isrg.audits.sha2]]
|
[[audits.isrg.audits.sha2]]
|
||||||
who = "David Cook <dcook@divviup.org>"
|
who = "David Cook <dcook@divviup.org>"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"files":{"Cargo.toml":"c25083c4b0fc46e0f63b88b4bc346a1c034698c16ece8f04ce72dd2af9cc7ffb","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","README.md":"7281273bea1d5fdc57731513cf9f0e3b911d06ac9905b03a8375a1324951c35b","build.rs":"fa31cb198b772600d100a7c403ddedccef637d2e6b2da431fa7f02ca41307fc6","src/broadcast/mod.rs":"2c9a84e7e6e5e8d8e23e28d6f2703825d7d6af59f0a16bc6125d5f0d25bd7598","src/broadcast/test.rs":"fe50fc868e67d855a9f71e078b0c3a7780e789652abb4b586accb4ccf035e872","src/compile_fail/mod.rs":"4d70256295bd64691a8c1994b323559cda1888e85f0b45ca55711541c257dcb6","src/compile_fail/quicksort_race1.rs":"35f498cda38f4eb6e00117f78ed68e0fe5a3fa61c25303d9c08a19bda345bc6c","src/compile_fail/quicksort_race2.rs":"cbb40030c7867cae34bb373b6ec5d97c2ac6de39bc917f47879b30eb423924bc","src/compile_fail/quicksort_race3.rs":"8403643e64c969306b1a9b1243378e6ccdd313b57e1878dbd31393618082fd35","src/compile_fail/rc_return.rs":"197894803d8df58fc8005d90c86b90cd98f1972f1a4b57438516a565df35903f","src/compile_fail/rc_upvar.rs":"42d110429621f407ef0dada1306dab116583d2c782a99894204dd8e0ccd2312f","src/compile_fail/scope_join_bad.rs":"892959949f77cadfc07458473e7a290301182027ca64428df5a8ce887be0892b","src/job.rs":"06de0c2add2e303b6383bf11f5f0d75775c1efe6aa7bc16de3992117f1012f09","src/join/mod.rs":"7638c0fc1da1a2d2b14673c8a2e0f87d26c24232cebee26fd334bdc2caa80886","src/join/test.rs":"157db5306e8df89a8eea19dbba499f26c2f44d9803cb36a796c852a9a695821e","src/latch.rs":"81da563b29b03455cd22073d243eaed081e953873c14ac202f6605cd3dac09a5","src/lib.rs":"53bb01b167d56c6ace035666b570fff648eedf03a5c8c415ec37136a0ef35697","src/private.rs":"152f6d65ce4741616a1dec796b9442f78a018d38bb040f76c4cd85008333a3bb","src/registry.rs":"c464c4fdb36c85cfe2a10d6196802b036bb76985d737ab9a67d708f908877672","src/scope/mod.rs":"421a5561093928b1d0081d34c2bff78377055d8f6de0689088f52fe476d3a56a","src/scope/test.rs":"d4f068cae4ee4483b41bd3054582d96e74ced46eb57361e7510ef62d4318d340","src/sleep/README.md":"e1ac1a5556cf257f38b7654feb0615c208d9186fefbe52a584d4fe6545d7c373","src/sleep/counters.rs":"e9eccc7d76d17415156c12d30cc7bf89a5c64ca5742965bb4e6c1ce23c2782e9","src/sleep/mod.rs":"23a9116f84653a5f68ab21c910f1dea5314a5332fdc9473a87710974f4b2c717","src/spawn/mod.rs":"745494a18fc4901c37ea2f45a1324abf5bd2a4d9c840620956e6633755116d88","src/spawn/test.rs":"a28f8943f28a4cef642b6429c538b1df879c9eb1db9927ce69b97c686bf81173","src/test.rs":"7d0dee06fcf41bddf77449a85cece44133f966a0622a31cf3ed110fbe83e094e","src/thread_pool/mod.rs":"392ad78a209826c4fb7257288dc082ace380220893d44559480045587e279202","src/thread_pool/test.rs":"657b1938993eb98fb5f3fd1d02a77728e37d0e833390b4ba82926b9107ce3170","src/unwind.rs":"7baa4511467d008b14856ea8de7ced92b9251c9df4854f69c81f7efc3cf0cd6c","tests/double_init_fail.rs":"8c208ce45e83ab1dfc5890353d5b2f06fc8005684ae622827a65d05abb35a072","tests/init_zero_threads.rs":"5c7f7e0e13e9ead3733253e30d6b52ac5ee66fd6c105999d096bdf31cfccaf95","tests/scope_join.rs":"56f570c4b6a01704aacf93e7f17f89fe0f40f46ed6f9ede517abfe9adaf91f83","tests/scoped_threadpool.rs":"24d1293fe65ad5f194bbff9d1ef0486c3440d0a3783f04eaaaae4929adef5cb8","tests/simple_panic.rs":"916d40d36c1a0fad3e1dfb31550f0672641feab4b03d480f039143dbe2f2445f","tests/stack_overflow_crash.rs":"87b962c66f301ac44f808d992d4e8b861305db0c282f256761a5075c9f018243","tests/use_current_thread.rs":"fe1b981e77e422e616c09502731a70fb2f1c023d2386ef32c9d47e5a6f5bc162"},"package":"5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"}
|
{"files":{"Cargo.toml":"60f04aab82c6489c779cf19535fddf0ec1a673edc07f523c66c10996806d2fbe","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","README.md":"7281273bea1d5fdc57731513cf9f0e3b911d06ac9905b03a8375a1324951c35b","build.rs":"fa31cb198b772600d100a7c403ddedccef637d2e6b2da431fa7f02ca41307fc6","src/broadcast/mod.rs":"2c9a84e7e6e5e8d8e23e28d6f2703825d7d6af59f0a16bc6125d5f0d25bd7598","src/broadcast/test.rs":"fe50fc868e67d855a9f71e078b0c3a7780e789652abb4b586accb4ccf035e872","src/compile_fail/mod.rs":"4d70256295bd64691a8c1994b323559cda1888e85f0b45ca55711541c257dcb6","src/compile_fail/quicksort_race1.rs":"35f498cda38f4eb6e00117f78ed68e0fe5a3fa61c25303d9c08a19bda345bc6c","src/compile_fail/quicksort_race2.rs":"cbb40030c7867cae34bb373b6ec5d97c2ac6de39bc917f47879b30eb423924bc","src/compile_fail/quicksort_race3.rs":"8403643e64c969306b1a9b1243378e6ccdd313b57e1878dbd31393618082fd35","src/compile_fail/rc_return.rs":"197894803d8df58fc8005d90c86b90cd98f1972f1a4b57438516a565df35903f","src/compile_fail/rc_upvar.rs":"42d110429621f407ef0dada1306dab116583d2c782a99894204dd8e0ccd2312f","src/compile_fail/scope_join_bad.rs":"892959949f77cadfc07458473e7a290301182027ca64428df5a8ce887be0892b","src/job.rs":"06de0c2add2e303b6383bf11f5f0d75775c1efe6aa7bc16de3992117f1012f09","src/join/mod.rs":"7638c0fc1da1a2d2b14673c8a2e0f87d26c24232cebee26fd334bdc2caa80886","src/join/test.rs":"157db5306e8df89a8eea19dbba499f26c2f44d9803cb36a796c852a9a695821e","src/latch.rs":"3f5c73cc6998d7cea177c19a3c7ce0d4a5667c65d77f744a2159872f09e8fba6","src/lib.rs":"d34f6cbaba40293d3b3e095bd2eae989cce3467fe686835a37e80652ca8133df","src/private.rs":"152f6d65ce4741616a1dec796b9442f78a018d38bb040f76c4cd85008333a3bb","src/registry.rs":"bcfedc6d51eade2bedc30271ab8b21e98700e45f74bd8967d02ae6fe17f73a94","src/scope/mod.rs":"421a5561093928b1d0081d34c2bff78377055d8f6de0689088f52fe476d3a56a","src/scope/test.rs":"d4f068cae4ee4483b41bd3054582d96e74ced46eb57361e7510ef62d4318d340","src/sleep/README.md":"e1ac1a5556cf257f38b7654feb0615c208d9186fefbe52a584d4fe6545d7c373","src/sleep/counters.rs":"e9eccc7d76d17415156c12d30cc7bf89a5c64ca5742965bb4e6c1ce23c2782e9","src/sleep/mod.rs":"7576bc0a54c30f35b10c63a6fd23f2e33774ba994352634ea1ca7865818fb2a4","src/spawn/mod.rs":"087d2a3e5fd5dd22a780c14d71509f9eea0bac92ccfa35d9933c0b39b3e269e1","src/spawn/test.rs":"a28f8943f28a4cef642b6429c538b1df879c9eb1db9927ce69b97c686bf81173","src/test.rs":"7d0dee06fcf41bddf77449a85cece44133f966a0622a31cf3ed110fbe83e094e","src/thread_pool/mod.rs":"4c85b46eb8ba05631b658996f0d6c64247a05575c89621e0a54a1fc056cc447f","src/thread_pool/test.rs":"657b1938993eb98fb5f3fd1d02a77728e37d0e833390b4ba82926b9107ce3170","src/unwind.rs":"7baa4511467d008b14856ea8de7ced92b9251c9df4854f69c81f7efc3cf0cd6c","tests/double_init_fail.rs":"8c208ce45e83ab1dfc5890353d5b2f06fc8005684ae622827a65d05abb35a072","tests/init_zero_threads.rs":"5c7f7e0e13e9ead3733253e30d6b52ac5ee66fd6c105999d096bdf31cfccaf95","tests/scope_join.rs":"56f570c4b6a01704aacf93e7f17f89fe0f40f46ed6f9ede517abfe9adaf91f83","tests/scoped_threadpool.rs":"24d1293fe65ad5f194bbff9d1ef0486c3440d0a3783f04eaaaae4929adef5cb8","tests/simple_panic.rs":"916d40d36c1a0fad3e1dfb31550f0672641feab4b03d480f039143dbe2f2445f","tests/stack_overflow_crash.rs":"87b962c66f301ac44f808d992d4e8b861305db0c282f256761a5075c9f018243","tests/use_current_thread.rs":"fe1b981e77e422e616c09502731a70fb2f1c023d2386ef32c9d47e5a6f5bc162"},"package":"1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"}
|
||||||
9
third_party/rust/rayon-core/Cargo.toml
vendored
9
third_party/rust/rayon-core/Cargo.toml
vendored
@@ -13,7 +13,7 @@
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.63"
|
rust-version = "1.63"
|
||||||
name = "rayon-core"
|
name = "rayon-core"
|
||||||
version = "1.12.0"
|
version = "1.12.1"
|
||||||
authors = [
|
authors = [
|
||||||
"Niko Matsakis <niko@alum.mit.edu>",
|
"Niko Matsakis <niko@alum.mit.edu>",
|
||||||
"Josh Stone <cuviper@gmail.com>",
|
"Josh Stone <cuviper@gmail.com>",
|
||||||
@@ -68,6 +68,10 @@ version = "0.8.1"
|
|||||||
[dependencies.crossbeam-utils]
|
[dependencies.crossbeam-utils]
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
|
||||||
|
[dependencies.wasm_sync]
|
||||||
|
version = "0.1.0"
|
||||||
|
optional = true
|
||||||
|
|
||||||
[dev-dependencies.rand]
|
[dev-dependencies.rand]
|
||||||
version = "0.8"
|
version = "0.8"
|
||||||
|
|
||||||
@@ -77,5 +81,8 @@ version = "0.3"
|
|||||||
[dev-dependencies.scoped-tls]
|
[dev-dependencies.scoped-tls]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
web_spin_lock = ["dep:wasm_sync"]
|
||||||
|
|
||||||
[target."cfg(unix)".dev-dependencies.libc]
|
[target."cfg(unix)".dev-dependencies.libc]
|
||||||
version = "0.2"
|
version = "0.2"
|
||||||
|
|||||||
3
third_party/rust/rayon-core/src/latch.rs
vendored
3
third_party/rust/rayon-core/src/latch.rs
vendored
@@ -1,10 +1,11 @@
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::sync::{Arc, Condvar, Mutex};
|
use std::sync::Arc;
|
||||||
use std::usize;
|
use std::usize;
|
||||||
|
|
||||||
use crate::registry::{Registry, WorkerThread};
|
use crate::registry::{Registry, WorkerThread};
|
||||||
|
use crate::sync::{Condvar, Mutex};
|
||||||
|
|
||||||
/// We define various kinds of latches, which are all a primitive signaling
|
/// We define various kinds of latches, which are all a primitive signaling
|
||||||
/// mechanism. A latch starts as false. Eventually someone calls `set()` and
|
/// mechanism. A latch starts as false. Eventually someone calls `set()` and
|
||||||
|
|||||||
6
third_party/rust/rayon-core/src/lib.rs
vendored
6
third_party/rust/rayon-core/src/lib.rs
vendored
@@ -103,6 +103,12 @@ pub use self::thread_pool::current_thread_index;
|
|||||||
pub use self::thread_pool::ThreadPool;
|
pub use self::thread_pool::ThreadPool;
|
||||||
pub use self::thread_pool::{yield_local, yield_now, Yield};
|
pub use self::thread_pool::{yield_local, yield_now, Yield};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "web_spin_lock"))]
|
||||||
|
use std::sync;
|
||||||
|
|
||||||
|
#[cfg(feature = "web_spin_lock")]
|
||||||
|
use wasm_sync as sync;
|
||||||
|
|
||||||
use self::registry::{CustomSpawn, DefaultSpawn, ThreadSpawn};
|
use self::registry::{CustomSpawn, DefaultSpawn, ThreadSpawn};
|
||||||
|
|
||||||
/// Returns the maximum number of threads that Rayon supports in a single thread-pool.
|
/// Returns the maximum number of threads that Rayon supports in a single thread-pool.
|
||||||
|
|||||||
3
third_party/rust/rayon-core/src/registry.rs
vendored
3
third_party/rust/rayon-core/src/registry.rs
vendored
@@ -1,6 +1,7 @@
|
|||||||
use crate::job::{JobFifo, JobRef, StackJob};
|
use crate::job::{JobFifo, JobRef, StackJob};
|
||||||
use crate::latch::{AsCoreLatch, CoreLatch, Latch, LatchRef, LockLatch, OnceLatch, SpinLatch};
|
use crate::latch::{AsCoreLatch, CoreLatch, Latch, LatchRef, LockLatch, OnceLatch, SpinLatch};
|
||||||
use crate::sleep::Sleep;
|
use crate::sleep::Sleep;
|
||||||
|
use crate::sync::Mutex;
|
||||||
use crate::unwind;
|
use crate::unwind;
|
||||||
use crate::{
|
use crate::{
|
||||||
ErrorKind, ExitHandler, PanicHandler, StartHandler, ThreadPoolBuildError, ThreadPoolBuilder,
|
ErrorKind, ExitHandler, PanicHandler, StartHandler, ThreadPoolBuildError, ThreadPoolBuilder,
|
||||||
@@ -15,7 +16,7 @@ use std::io;
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::sync::{Arc, Mutex, Once};
|
use std::sync::{Arc, Once};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::usize;
|
use std::usize;
|
||||||
|
|
||||||
|
|||||||
2
third_party/rust/rayon-core/src/sleep/mod.rs
vendored
2
third_party/rust/rayon-core/src/sleep/mod.rs
vendored
@@ -2,9 +2,9 @@
|
|||||||
//! for an overview.
|
//! for an overview.
|
||||||
|
|
||||||
use crate::latch::CoreLatch;
|
use crate::latch::CoreLatch;
|
||||||
|
use crate::sync::{Condvar, Mutex};
|
||||||
use crossbeam_utils::CachePadded;
|
use crossbeam_utils::CachePadded;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
use std::sync::{Condvar, Mutex};
|
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::usize;
|
use std::usize;
|
||||||
|
|
||||||
|
|||||||
4
third_party/rust/rayon-core/src/spawn/mod.rs
vendored
4
third_party/rust/rayon-core/src/spawn/mod.rs
vendored
@@ -4,8 +4,8 @@ use crate::unwind;
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Fires off a task into the Rayon threadpool in the "static" or
|
/// Puts the task into the Rayon threadpool's job queue in the "static"
|
||||||
/// "global" scope. Just like a standard thread, this task is not
|
/// or "global" scope. Just like a standard thread, this task is not
|
||||||
/// tied to the current stack frame, and hence it cannot hold any
|
/// tied to the current stack frame, and hence it cannot hold any
|
||||||
/// references other than those with `'static` lifetime. If you want
|
/// references other than those with `'static` lifetime. If you want
|
||||||
/// to spawn a task that references stack data, use [the `scope()`
|
/// to spawn a task that references stack data, use [the `scope()`
|
||||||
|
|||||||
@@ -80,6 +80,43 @@ impl ThreadPool {
|
|||||||
/// thread-local data from the current thread will not be
|
/// thread-local data from the current thread will not be
|
||||||
/// accessible.
|
/// accessible.
|
||||||
///
|
///
|
||||||
|
/// # Warning: execution order
|
||||||
|
///
|
||||||
|
/// If the current thread is part of a different thread pool, it will try to
|
||||||
|
/// keep busy while the `op` completes in its target pool, similar to
|
||||||
|
/// calling [`ThreadPool::yield_now()`] in a loop. Therefore, it may
|
||||||
|
/// potentially schedule other tasks to run on the current thread in the
|
||||||
|
/// meantime. For example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use rayon_core as rayon;
|
||||||
|
/// fn main() {
|
||||||
|
/// rayon::ThreadPoolBuilder::new().num_threads(1).build_global().unwrap();
|
||||||
|
/// let pool = rayon_core::ThreadPoolBuilder::default().build().unwrap();
|
||||||
|
/// let do_it = || {
|
||||||
|
/// print!("one ");
|
||||||
|
/// pool.install(||{});
|
||||||
|
/// print!("two ");
|
||||||
|
/// };
|
||||||
|
/// rayon::join(|| do_it(), || do_it());
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Since we configured just one thread in the global pool, one might
|
||||||
|
/// expect `do_it()` to run sequentially, producing:
|
||||||
|
///
|
||||||
|
/// ```ascii
|
||||||
|
/// one two one two
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// However each call to `install()` yields implicitly, allowing rayon to
|
||||||
|
/// run multiple instances of `do_it()` concurrently on the single, global
|
||||||
|
/// thread. The following output would be equally valid:
|
||||||
|
///
|
||||||
|
/// ```ascii
|
||||||
|
/// one one two two
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// If `op` should panic, that panic will be propagated.
|
/// If `op` should panic, that panic will be propagated.
|
||||||
|
|||||||
2
third_party/rust/rayon/.cargo-checksum.json
vendored
2
third_party/rust/rayon/.cargo-checksum.json
vendored
File diff suppressed because one or more lines are too long
18
third_party/rust/rayon/Cargo.toml
vendored
18
third_party/rust/rayon/Cargo.toml
vendored
@@ -11,9 +11,9 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.56"
|
rust-version = "1.63"
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "1.6.1"
|
version = "1.10.0"
|
||||||
authors = [
|
authors = [
|
||||||
"Niko Matsakis <niko@alum.mit.edu>",
|
"Niko Matsakis <niko@alum.mit.edu>",
|
||||||
"Josh Stone <cuviper@gmail.com>",
|
"Josh Stone <cuviper@gmail.com>",
|
||||||
@@ -22,7 +22,6 @@ exclude = [
|
|||||||
"/ci/*",
|
"/ci/*",
|
||||||
"/scripts/*",
|
"/scripts/*",
|
||||||
"/.github/*",
|
"/.github/*",
|
||||||
"/bors.toml",
|
|
||||||
]
|
]
|
||||||
description = "Simple work-stealing parallelism for Rust"
|
description = "Simple work-stealing parallelism for Rust"
|
||||||
documentation = "https://docs.rs/rayon/"
|
documentation = "https://docs.rs/rayon/"
|
||||||
@@ -43,13 +42,20 @@ version = "1.0"
|
|||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[dependencies.rayon-core]
|
[dependencies.rayon-core]
|
||||||
version = "1.10.0"
|
version = "1.12.1"
|
||||||
|
|
||||||
[dev-dependencies.lazy_static]
|
[dependencies.wasm_sync]
|
||||||
version = "1"
|
version = "0.1.0"
|
||||||
|
optional = true
|
||||||
|
|
||||||
[dev-dependencies.rand]
|
[dev-dependencies.rand]
|
||||||
version = "0.8"
|
version = "0.8"
|
||||||
|
|
||||||
[dev-dependencies.rand_xorshift]
|
[dev-dependencies.rand_xorshift]
|
||||||
version = "0.3"
|
version = "0.3"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
web_spin_lock = [
|
||||||
|
"dep:wasm_sync",
|
||||||
|
"rayon-core/web_spin_lock",
|
||||||
|
]
|
||||||
|
|||||||
44
third_party/rust/rayon/README.md
vendored
44
third_party/rust/rayon/README.md
vendored
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
[](https://crates.io/crates/rayon)
|
[](https://crates.io/crates/rayon)
|
||||||
[](https://docs.rs/rayon)
|
[](https://docs.rs/rayon)
|
||||||

|

|
||||||
[](https://github.com/rayon-rs/rayon/actions)
|
[](https://github.com/rayon-rs/rayon/actions)
|
||||||
[](https://gitter.im/rayon-rs/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://gitter.im/rayon-rs/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
Rayon is a data-parallelism library for Rust. It is extremely
|
Rayon is a data-parallelism library for Rust. It is extremely
|
||||||
@@ -13,7 +13,7 @@ enjoy [this blog post][blog] about Rayon, which gives more background
|
|||||||
and details about how it works, or [this video][video], from the Rust
|
and details about how it works, or [this video][video], from the Rust
|
||||||
Belt Rust conference.) Rayon is
|
Belt Rust conference.) Rayon is
|
||||||
[available on crates.io](https://crates.io/crates/rayon), and
|
[available on crates.io](https://crates.io/crates/rayon), and
|
||||||
[API Documentation is available on docs.rs](https://docs.rs/rayon/).
|
[API documentation is available on docs.rs](https://docs.rs/rayon).
|
||||||
|
|
||||||
[blog]: https://smallcultfollowing.com/babysteps/blog/2015/12/18/rayon-data-parallelism-in-rust/
|
[blog]: https://smallcultfollowing.com/babysteps/blog/2015/12/18/rayon-data-parallelism-in-rust/
|
||||||
[video]: https://www.youtube.com/watch?v=gof_OEv71Aw
|
[video]: https://www.youtube.com/watch?v=gof_OEv71Aw
|
||||||
@@ -71,10 +71,10 @@ as:
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rayon = "1.5"
|
rayon = "1.8"
|
||||||
```
|
```
|
||||||
|
|
||||||
To use the Parallel Iterator APIs, a number of traits have to be in
|
To use the parallel iterator APIs, a number of traits have to be in
|
||||||
scope. The easiest way to bring those things into scope is to use the
|
scope. The easiest way to bring those things into scope is to use the
|
||||||
[Rayon prelude](https://docs.rs/rayon/*/rayon/prelude/index.html). In
|
[Rayon prelude](https://docs.rs/rayon/*/rayon/prelude/index.html). In
|
||||||
each module where you would like to use the parallel iterator APIs,
|
each module where you would like to use the parallel iterator APIs,
|
||||||
@@ -84,26 +84,44 @@ just add:
|
|||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
```
|
```
|
||||||
|
|
||||||
Rayon currently requires `rustc 1.56.0` or greater.
|
Rayon currently requires `rustc 1.63.0` or greater.
|
||||||
|
|
||||||
### Usage with WebAssembly
|
### Usage with WebAssembly
|
||||||
|
|
||||||
Rayon can work on the Web via WebAssembly, but requires an adapter
|
By default, when building to WebAssembly, Rayon will treat it as any
|
||||||
and some project configuration to account for differences between
|
other platform without multithreading support and will fall back to
|
||||||
WebAssembly threads and threads on the other platforms.
|
sequential iteration. This allows existing code to compile and run
|
||||||
|
successfully with no changes necessary, but it will run slower as it
|
||||||
|
will only use a single CPU core.
|
||||||
|
|
||||||
Check out [wasm-bindgen-rayon](https://github.com/GoogleChromeLabs/wasm-bindgen-rayon)
|
You can build Rayon-based projects with proper multithreading support
|
||||||
|
for the Web, but you'll need an adapter and some project configuration
|
||||||
|
to account for differences between WebAssembly threads and threads
|
||||||
|
on the other platforms.
|
||||||
|
|
||||||
|
Check out the
|
||||||
|
[wasm-bindgen-rayon](https://github.com/RReverser/wasm-bindgen-rayon)
|
||||||
docs for more details.
|
docs for more details.
|
||||||
|
|
||||||
## Contribution
|
## Contribution
|
||||||
|
|
||||||
Rayon is an open source project! If you'd like to contribute to Rayon, check out [the list of "help wanted" issues](https://github.com/rayon-rs/rayon/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22). These are all (or should be) issues that are suitable for getting started, and they generally include a detailed set of instructions for what to do. Please ask questions if anything is unclear! Also, check out the [Guide to Development](https://github.com/rayon-rs/rayon/wiki/Guide-to-Development) page on the wiki. Note that all code submitted in PRs to Rayon is assumed to [be licensed under Rayon's dual MIT/Apache2 licensing](https://github.com/rayon-rs/rayon/blob/master/README.md#license).
|
Rayon is an open source project! If you'd like to contribute to Rayon,
|
||||||
|
check out
|
||||||
|
[the list of "help wanted" issues](https://github.com/rayon-rs/rayon/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22).
|
||||||
|
These are all (or should be) issues that are suitable for getting
|
||||||
|
started, and they generally include a detailed set of instructions for
|
||||||
|
what to do. Please ask questions if anything is unclear! Also, check
|
||||||
|
out the
|
||||||
|
[Guide to Development](https://github.com/rayon-rs/rayon/wiki/Guide-to-Development)
|
||||||
|
page on the wiki. Note that all code submitted in PRs to Rayon is
|
||||||
|
assumed to
|
||||||
|
[be licensed under Rayon's dual MIT/Apache 2.0 licensing](https://github.com/rayon-rs/rayon/blob/main/README.md#license).
|
||||||
|
|
||||||
## Quick demo
|
## Quick demo
|
||||||
|
|
||||||
To see Rayon in action, check out the `rayon-demo` directory, which
|
To see Rayon in action, check out the `rayon-demo` directory, which
|
||||||
includes a number of demos of code using Rayon. For example, run this
|
includes a number of demos of code using Rayon. For example, run this
|
||||||
command to get a visualization of an nbody simulation. To see the
|
command to get a visualization of an N-body simulation. To see the
|
||||||
effect of using Rayon, press `s` to run sequentially and `p` to run in
|
effect of using Rayon, press `s` to run sequentially and `p` to run in
|
||||||
parallel.
|
parallel.
|
||||||
|
|
||||||
@@ -123,7 +141,7 @@ For more information on demos, try:
|
|||||||
|
|
||||||
See [the Rayon FAQ][faq].
|
See [the Rayon FAQ][faq].
|
||||||
|
|
||||||
[faq]: https://github.com/rayon-rs/rayon/blob/master/FAQ.md
|
[faq]: https://github.com/rayon-rs/rayon/blob/main/FAQ.md
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
70
third_party/rust/rayon/RELEASES.md
vendored
70
third_party/rust/rayon/RELEASES.md
vendored
@@ -1,3 +1,69 @@
|
|||||||
|
# Release rayon 1.10.0 (2024-03-23)
|
||||||
|
|
||||||
|
- The new methods `ParallelSlice::par_chunk_by` and
|
||||||
|
`ParallelSliceMut::par_chunk_by_mut` work like the slice methods `chunk_by`
|
||||||
|
and `chunk_by_mut` added in Rust 1.77.
|
||||||
|
|
||||||
|
# Release rayon 1.9.0 (2024-02-27)
|
||||||
|
|
||||||
|
- The new methods `IndexedParallelIterator::by_exponential_blocks` and
|
||||||
|
`by_uniform_blocks` allow processing items in smaller groups at a time.
|
||||||
|
- The new `iter::walk_tree`, `walk_tree_prefix`, and `walk_tree_postfix`
|
||||||
|
functions enable custom parallel iteration over tree-like structures.
|
||||||
|
- The new method `ParallelIterator::collect_vec_list` returns items as a linked
|
||||||
|
list of vectors, which is an efficient mode of parallel collection used by
|
||||||
|
many of the internal implementations of `collect`.
|
||||||
|
- The new methods `ParallelSliceMut::par_split_inclusive_mut`,
|
||||||
|
`ParallelSlice::par_split_inclusive`, and
|
||||||
|
`ParallelString::par_split_inclusive` all work like a normal split but
|
||||||
|
keeping the separator as part of the left slice.
|
||||||
|
- The new `ParallelString::par_split_ascii_whitespace` splits only on ASCII
|
||||||
|
whitespace, which is faster than including Unicode multi-byte whitespace.
|
||||||
|
- `OsString` now implements `FromParallelIterator<_>` and `ParallelExtend<_>`
|
||||||
|
for a few item types similar to the standard `FromIterator` and `Extend`.
|
||||||
|
- The internal `Pattern` trait for string methods is now implemented for
|
||||||
|
`[char; N]` and `&[char; N]`, matching any of the given characters.
|
||||||
|
|
||||||
|
# Release rayon 1.8.1 / rayon-core 1.12.1 (2024-01-17)
|
||||||
|
|
||||||
|
- The new `"web_spin_lock"` crate feature makes mutexes spin on the main
|
||||||
|
browser thread in WebAssembly, rather than suffer an error about forbidden
|
||||||
|
`atomics.wait` if they were to block in that context. Thanks @RReverser!
|
||||||
|
|
||||||
|
# Release rayon 1.8.0 / rayon-core 1.12.0 (2023-09-20)
|
||||||
|
|
||||||
|
- The minimum supported `rustc` is now 1.63.
|
||||||
|
- Added `ThreadPoolBuilder::use_current_thread` to use the builder thread as
|
||||||
|
part of the new thread pool. That thread does not run the pool's main loop,
|
||||||
|
but it may participate in work-stealing if it yields to rayon in some way.
|
||||||
|
- Implemented `FromParallelIterator<T>` for `Box<[T]>`, `Rc<[T]>`, and
|
||||||
|
`Arc<[T]>`, as well as `FromParallelIterator<Box<str>>` and
|
||||||
|
`ParallelExtend<Box<str>>` for `String`.
|
||||||
|
- `ThreadPoolBuilder::build_scoped` now uses `std::thread::scope`.
|
||||||
|
- The default number of threads is now determined using
|
||||||
|
`std::thread::available_parallelism` instead of the `num_cpus` crate.
|
||||||
|
- The internal logging facility has been removed, reducing bloat for all users.
|
||||||
|
- Many smaller performance tweaks and documentation updates.
|
||||||
|
|
||||||
|
# Release rayon 1.7.0 / rayon-core 1.11.0 (2023-03-03)
|
||||||
|
|
||||||
|
- The minimum supported `rustc` is now 1.59.
|
||||||
|
- Added a fallback when threading is unsupported.
|
||||||
|
- The new `ParallelIterator::take_any` and `skip_any` methods work like
|
||||||
|
unordered `IndexedParallelIterator::take` and `skip`, counting items in
|
||||||
|
whatever order they are visited in parallel.
|
||||||
|
- The new `ParallelIterator::take_any_while` and `skip_any_while` methods work
|
||||||
|
like unordered `Iterator::take_while` and `skip_while`, which previously had
|
||||||
|
no parallel equivalent. The "while" condition may be satisfied from anywhere
|
||||||
|
in the parallel iterator, affecting all future items regardless of position.
|
||||||
|
- The new `yield_now` and `yield_local` functions will cooperatively yield
|
||||||
|
execution to Rayon, either trying to execute pending work from the entire
|
||||||
|
pool or from just the local deques of the current thread, respectively.
|
||||||
|
|
||||||
|
# Release rayon-core 1.10.2 (2023-01-22)
|
||||||
|
|
||||||
|
- Fixed miri-reported UB for SharedReadOnly tags protected by a call.
|
||||||
|
|
||||||
# Release rayon 1.6.1 (2022-12-09)
|
# Release rayon 1.6.1 (2022-12-09)
|
||||||
|
|
||||||
- Simplified `par_bridge` to only pull one item at a time from the iterator,
|
- Simplified `par_bridge` to only pull one item at a time from the iterator,
|
||||||
@@ -303,8 +369,8 @@ Thanks to all of the contributors for this release!
|
|||||||
- @seanchen1991
|
- @seanchen1991
|
||||||
- @yegeun542
|
- @yegeun542
|
||||||
|
|
||||||
[RFC 1]: https://github.com/rayon-rs/rfcs/blob/master/accepted/rfc0001-scope-scheduling.md
|
[RFC 1]: https://github.com/rayon-rs/rfcs/blob/main/accepted/rfc0001-scope-scheduling.md
|
||||||
[RFC 3]: https://github.com/rayon-rs/rfcs/blob/master/accepted/rfc0003-minimum-rustc.md
|
[RFC 3]: https://github.com/rayon-rs/rfcs/blob/main/accepted/rfc0003-minimum-rustc.md
|
||||||
|
|
||||||
|
|
||||||
# Release rayon 1.0.3 (2018-11-02)
|
# Release rayon 1.0.3 (2018-11-02)
|
||||||
|
|||||||
3
third_party/rust/rayon/src/array.rs
vendored
3
third_party/rust/rayon/src/array.rs
vendored
@@ -78,7 +78,8 @@ impl<T: Send, const N: usize> IndexedParallelIterator for IntoIter<T, N> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
// Drain every item, and then the local array can just fall out of scope.
|
// Drain every item, and then the local array can just fall out of scope.
|
||||||
let mut array = ManuallyDrop::new(self.array);
|
let mut array = ManuallyDrop::new(self.array);
|
||||||
callback.callback(DrainProducer::new(&mut *array))
|
let producer = DrainProducer::new(array.as_mut_slice());
|
||||||
|
callback.callback(producer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ macro_rules! must_use {
|
|||||||
}
|
}
|
||||||
|
|
||||||
must_use! {
|
must_use! {
|
||||||
|
by_exponential_blocks /** v.par_iter().by_exponential_blocks(); */
|
||||||
|
by_uniform_blocks /** v.par_iter().by_uniform_blocks(2); */
|
||||||
step_by /** v.par_iter().step_by(2); */
|
step_by /** v.par_iter().step_by(2); */
|
||||||
chain /** v.par_iter().chain(&v); */
|
chain /** v.par_iter().chain(&v); */
|
||||||
chunks /** v.par_iter().chunks(2); */
|
chunks /** v.par_iter().chunks(2); */
|
||||||
|
|||||||
131
third_party/rust/rayon/src/iter/blocks.rs
vendored
Normal file
131
third_party/rust/rayon/src/iter/blocks.rs
vendored
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
use super::plumbing::*;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
struct BlocksCallback<S, C> {
|
||||||
|
sizes: S,
|
||||||
|
consumer: C,
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, S, C> ProducerCallback<T> for BlocksCallback<S, C>
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<T>,
|
||||||
|
S: Iterator<Item = usize>,
|
||||||
|
{
|
||||||
|
type Output = C::Result;
|
||||||
|
|
||||||
|
fn callback<P: Producer<Item = T>>(mut self, mut producer: P) -> Self::Output {
|
||||||
|
let mut remaining_len = self.len;
|
||||||
|
let mut consumer = self.consumer;
|
||||||
|
|
||||||
|
// we need a local variable for the accumulated results
|
||||||
|
// we call the reducer's identity by splitting at 0
|
||||||
|
let (left_consumer, right_consumer, _) = consumer.split_at(0);
|
||||||
|
let mut leftmost_res = left_consumer.into_folder().complete();
|
||||||
|
consumer = right_consumer;
|
||||||
|
|
||||||
|
// now we loop on each block size
|
||||||
|
while remaining_len > 0 && !consumer.full() {
|
||||||
|
// we compute the next block's size
|
||||||
|
let size = self.sizes.next().unwrap_or(std::usize::MAX);
|
||||||
|
let capped_size = remaining_len.min(size);
|
||||||
|
remaining_len -= capped_size;
|
||||||
|
|
||||||
|
// split the producer
|
||||||
|
let (left_producer, right_producer) = producer.split_at(capped_size);
|
||||||
|
producer = right_producer;
|
||||||
|
|
||||||
|
// split the consumer
|
||||||
|
let (left_consumer, right_consumer, _) = consumer.split_at(capped_size);
|
||||||
|
consumer = right_consumer;
|
||||||
|
|
||||||
|
leftmost_res = consumer.to_reducer().reduce(
|
||||||
|
leftmost_res,
|
||||||
|
bridge_producer_consumer(capped_size, left_producer, left_consumer),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
leftmost_res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `ExponentialBlocks` is a parallel iterator that consumes itself as a sequence
|
||||||
|
/// of parallel blocks of increasing sizes (exponentially).
|
||||||
|
///
|
||||||
|
/// This struct is created by the [`by_exponential_blocks()`] method on [`IndexedParallelIterator`]
|
||||||
|
///
|
||||||
|
/// [`by_exponential_blocks()`]: trait.IndexedParallelIterator.html#method.by_exponential_blocks
|
||||||
|
/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
|
||||||
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ExponentialBlocks<I> {
|
||||||
|
base: I,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> ExponentialBlocks<I> {
|
||||||
|
pub(super) fn new(base: I) -> Self {
|
||||||
|
Self { base }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> ParallelIterator for ExponentialBlocks<I>
|
||||||
|
where
|
||||||
|
I: IndexedParallelIterator,
|
||||||
|
{
|
||||||
|
type Item = I::Item;
|
||||||
|
|
||||||
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<Self::Item>,
|
||||||
|
{
|
||||||
|
let first = crate::current_num_threads();
|
||||||
|
let callback = BlocksCallback {
|
||||||
|
consumer,
|
||||||
|
sizes: std::iter::successors(Some(first), exponential_size),
|
||||||
|
len: self.base.len(),
|
||||||
|
};
|
||||||
|
self.base.with_producer(callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exponential_size(size: &usize) -> Option<usize> {
|
||||||
|
Some(size.saturating_mul(2))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `UniformBlocks` is a parallel iterator that consumes itself as a sequence
|
||||||
|
/// of parallel blocks of constant sizes.
|
||||||
|
///
|
||||||
|
/// This struct is created by the [`by_uniform_blocks()`] method on [`IndexedParallelIterator`]
|
||||||
|
///
|
||||||
|
/// [`by_uniform_blocks()`]: trait.IndexedParallelIterator.html#method.by_uniform_blocks
|
||||||
|
/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
|
||||||
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct UniformBlocks<I> {
|
||||||
|
base: I,
|
||||||
|
block_size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> UniformBlocks<I> {
|
||||||
|
pub(super) fn new(base: I, block_size: usize) -> Self {
|
||||||
|
Self { base, block_size }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> ParallelIterator for UniformBlocks<I>
|
||||||
|
where
|
||||||
|
I: IndexedParallelIterator,
|
||||||
|
{
|
||||||
|
type Item = I::Item;
|
||||||
|
|
||||||
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<Self::Item>,
|
||||||
|
{
|
||||||
|
let callback = BlocksCallback {
|
||||||
|
consumer,
|
||||||
|
sizes: std::iter::repeat(self.block_size),
|
||||||
|
len: self.base.len(),
|
||||||
|
};
|
||||||
|
self.base.with_producer(callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
5
third_party/rust/rayon/src/iter/chain.rs
vendored
5
third_party/rust/rayon/src/iter/chain.rs
vendored
@@ -1,7 +1,6 @@
|
|||||||
use super::plumbing::*;
|
use super::plumbing::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
use rayon_core::join;
|
use rayon_core::join;
|
||||||
use std::cmp;
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
/// `Chain` is an iterator that joins `b` after `a` in one continuous iterator.
|
/// `Chain` is an iterator that joins `b` after `a` in one continuous iterator.
|
||||||
@@ -178,11 +177,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn min_len(&self) -> usize {
|
fn min_len(&self) -> usize {
|
||||||
cmp::max(self.a.min_len(), self.b.min_len())
|
Ord::max(self.a.min_len(), self.b.min_len())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn max_len(&self) -> usize {
|
fn max_len(&self) -> usize {
|
||||||
cmp::min(self.a.max_len(), self.b.max_len())
|
Ord::min(self.a.max_len(), self.b.max_len())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn split_at(self, index: usize) -> (Self, Self) {
|
fn split_at(self, index: usize) -> (Self, Self) {
|
||||||
|
|||||||
4
third_party/rust/rayon/src/iter/chunks.rs
vendored
4
third_party/rust/rayon/src/iter/chunks.rs
vendored
@@ -1,5 +1,3 @@
|
|||||||
use std::cmp::min;
|
|
||||||
|
|
||||||
use super::plumbing::*;
|
use super::plumbing::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::math::div_round_up;
|
use crate::math::div_round_up;
|
||||||
@@ -133,7 +131,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn split_at(self, index: usize) -> (Self, Self) {
|
fn split_at(self, index: usize) -> (Self, Self) {
|
||||||
let elem_index = min(index * self.chunk_size, self.len);
|
let elem_index = Ord::min(index * self.chunk_size, self.len);
|
||||||
let (left, right) = self.base.split_at(elem_index);
|
let (left, right) = self.base.split_at(elem_index);
|
||||||
(
|
(
|
||||||
ChunkProducer {
|
ChunkProducer {
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ fn right_produces_items_with_no_complete() {
|
|||||||
|
|
||||||
// Complete is not called by the consumer. Hence,the collection vector is not fully initialized.
|
// Complete is not called by the consumer. Hence,the collection vector is not fully initialized.
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(not(panic = "unwind"), ignore)]
|
||||||
fn produces_items_with_no_complete() {
|
fn produces_items_with_no_complete() {
|
||||||
let counter = DropCounter::default();
|
let counter = DropCounter::default();
|
||||||
let mut v = vec![];
|
let mut v = vec![];
|
||||||
@@ -273,6 +274,7 @@ fn right_panics() {
|
|||||||
// The left consumer produces fewer items while the right
|
// The left consumer produces fewer items while the right
|
||||||
// consumer produces correct number; check that created elements are dropped
|
// consumer produces correct number; check that created elements are dropped
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(not(panic = "unwind"), ignore)]
|
||||||
fn left_produces_fewer_items_drops() {
|
fn left_produces_fewer_items_drops() {
|
||||||
let counter = DropCounter::default();
|
let counter = DropCounter::default();
|
||||||
let mut v = vec![];
|
let mut v = vec![];
|
||||||
|
|||||||
233
third_party/rust/rayon/src/iter/extend.rs
vendored
233
third_party/rust/rayon/src/iter/extend.rs
vendored
@@ -2,26 +2,83 @@ use super::noop::NoopConsumer;
|
|||||||
use super::plumbing::{Consumer, Folder, Reducer, UnindexedConsumer};
|
use super::plumbing::{Consumer, Folder, Reducer, UnindexedConsumer};
|
||||||
use super::{IntoParallelIterator, ParallelExtend, ParallelIterator};
|
use super::{IntoParallelIterator, ParallelExtend, ParallelIterator};
|
||||||
|
|
||||||
|
use either::Either;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::LinkedList;
|
use std::collections::LinkedList;
|
||||||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||||
use std::collections::{BinaryHeap, VecDeque};
|
use std::collections::{BinaryHeap, VecDeque};
|
||||||
|
use std::ffi::{OsStr, OsString};
|
||||||
use std::hash::{BuildHasher, Hash};
|
use std::hash::{BuildHasher, Hash};
|
||||||
|
|
||||||
/// Performs a generic `par_extend` by collecting to a `LinkedList<Vec<_>>` in
|
/// Performs a generic `par_extend` by collecting to a `LinkedList<Vec<_>>` in
|
||||||
/// parallel, then extending the collection sequentially.
|
/// parallel, then extending the collection sequentially.
|
||||||
macro_rules! extend {
|
macro_rules! extend {
|
||||||
($self:ident, $par_iter:ident, $extend:ident) => {
|
($self:ident, $par_iter:ident) => {
|
||||||
$extend(
|
extend!($self <- fast_collect($par_iter))
|
||||||
$self,
|
};
|
||||||
$par_iter.into_par_iter().drive_unindexed(ListVecConsumer),
|
($self:ident <- $vecs:expr) => {
|
||||||
);
|
match $vecs {
|
||||||
|
Either::Left(vec) => $self.extend(vec),
|
||||||
|
Either::Right(list) => {
|
||||||
|
for vec in list {
|
||||||
|
$self.extend(vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! extend_reserved {
|
||||||
|
($self:ident, $par_iter:ident, $len:ident) => {
|
||||||
|
let vecs = fast_collect($par_iter);
|
||||||
|
$self.reserve($len(&vecs));
|
||||||
|
extend!($self <- vecs)
|
||||||
|
};
|
||||||
|
($self:ident, $par_iter:ident) => {
|
||||||
|
extend_reserved!($self, $par_iter, len)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the total length of a `LinkedList<Vec<_>>`.
|
/// Computes the total length of a `fast_collect` result.
|
||||||
fn len<T>(list: &LinkedList<Vec<T>>) -> usize {
|
fn len<T>(vecs: &Either<Vec<T>, LinkedList<Vec<T>>>) -> usize {
|
||||||
list.iter().map(Vec::len).sum()
|
match vecs {
|
||||||
|
Either::Left(vec) => vec.len(),
|
||||||
|
Either::Right(list) => list.iter().map(Vec::len).sum(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Computes the total string length of a `fast_collect` result.
|
||||||
|
fn string_len<T: AsRef<str>>(vecs: &Either<Vec<T>, LinkedList<Vec<T>>>) -> usize {
|
||||||
|
let strs = match vecs {
|
||||||
|
Either::Left(vec) => Either::Left(vec.iter()),
|
||||||
|
Either::Right(list) => Either::Right(list.iter().flatten()),
|
||||||
|
};
|
||||||
|
strs.map(AsRef::as_ref).map(str::len).sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Computes the total OS-string length of a `fast_collect` result.
|
||||||
|
fn osstring_len<T: AsRef<OsStr>>(vecs: &Either<Vec<T>, LinkedList<Vec<T>>>) -> usize {
|
||||||
|
let osstrs = match vecs {
|
||||||
|
Either::Left(vec) => Either::Left(vec.iter()),
|
||||||
|
Either::Right(list) => Either::Right(list.iter().flatten()),
|
||||||
|
};
|
||||||
|
osstrs.map(AsRef::as_ref).map(OsStr::len).sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn fast_collect<I, T>(pi: I) -> Either<Vec<T>, LinkedList<Vec<T>>>
|
||||||
|
where
|
||||||
|
I: IntoParallelIterator<Item = T>,
|
||||||
|
T: Send,
|
||||||
|
{
|
||||||
|
let par_iter = pi.into_par_iter();
|
||||||
|
match par_iter.opt_len() {
|
||||||
|
Some(len) => {
|
||||||
|
// Pseudo-specialization. See impl of ParallelExtend for Vec for more details.
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
super::collect::special_extend(par_iter, len, &mut vec);
|
||||||
|
Either::Left(vec)
|
||||||
|
}
|
||||||
|
None => Either::Right(par_iter.drive_unindexed(ListVecConsumer)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ListVecConsumer;
|
struct ListVecConsumer;
|
||||||
@@ -87,16 +144,6 @@ impl<T> Folder<T> for ListVecFolder<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn heap_extend<T, Item>(heap: &mut BinaryHeap<T>, list: LinkedList<Vec<Item>>)
|
|
||||||
where
|
|
||||||
BinaryHeap<T>: Extend<Item>,
|
|
||||||
{
|
|
||||||
heap.reserve(len(&list));
|
|
||||||
for vec in list {
|
|
||||||
heap.extend(vec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extends a binary heap with items from a parallel iterator.
|
/// Extends a binary heap with items from a parallel iterator.
|
||||||
impl<T> ParallelExtend<T> for BinaryHeap<T>
|
impl<T> ParallelExtend<T> for BinaryHeap<T>
|
||||||
where
|
where
|
||||||
@@ -106,7 +153,7 @@ where
|
|||||||
where
|
where
|
||||||
I: IntoParallelIterator<Item = T>,
|
I: IntoParallelIterator<Item = T>,
|
||||||
{
|
{
|
||||||
extend!(self, par_iter, heap_extend);
|
extend_reserved!(self, par_iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,16 +166,7 @@ where
|
|||||||
where
|
where
|
||||||
I: IntoParallelIterator<Item = &'a T>,
|
I: IntoParallelIterator<Item = &'a T>,
|
||||||
{
|
{
|
||||||
extend!(self, par_iter, heap_extend);
|
extend_reserved!(self, par_iter);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn btree_map_extend<K, V, Item>(map: &mut BTreeMap<K, V>, list: LinkedList<Vec<Item>>)
|
|
||||||
where
|
|
||||||
BTreeMap<K, V>: Extend<Item>,
|
|
||||||
{
|
|
||||||
for vec in list {
|
|
||||||
map.extend(vec);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +180,7 @@ where
|
|||||||
where
|
where
|
||||||
I: IntoParallelIterator<Item = (K, V)>,
|
I: IntoParallelIterator<Item = (K, V)>,
|
||||||
{
|
{
|
||||||
extend!(self, par_iter, btree_map_extend);
|
extend!(self, par_iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,16 +194,7 @@ where
|
|||||||
where
|
where
|
||||||
I: IntoParallelIterator<Item = (&'a K, &'a V)>,
|
I: IntoParallelIterator<Item = (&'a K, &'a V)>,
|
||||||
{
|
{
|
||||||
extend!(self, par_iter, btree_map_extend);
|
extend!(self, par_iter);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn btree_set_extend<T, Item>(set: &mut BTreeSet<T>, list: LinkedList<Vec<Item>>)
|
|
||||||
where
|
|
||||||
BTreeSet<T>: Extend<Item>,
|
|
||||||
{
|
|
||||||
for vec in list {
|
|
||||||
set.extend(vec);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +207,7 @@ where
|
|||||||
where
|
where
|
||||||
I: IntoParallelIterator<Item = T>,
|
I: IntoParallelIterator<Item = T>,
|
||||||
{
|
{
|
||||||
extend!(self, par_iter, btree_set_extend);
|
extend!(self, par_iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,19 +220,7 @@ where
|
|||||||
where
|
where
|
||||||
I: IntoParallelIterator<Item = &'a T>,
|
I: IntoParallelIterator<Item = &'a T>,
|
||||||
{
|
{
|
||||||
extend!(self, par_iter, btree_set_extend);
|
extend!(self, par_iter);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hash_map_extend<K, V, S, Item>(map: &mut HashMap<K, V, S>, list: LinkedList<Vec<Item>>)
|
|
||||||
where
|
|
||||||
HashMap<K, V, S>: Extend<Item>,
|
|
||||||
K: Eq + Hash,
|
|
||||||
S: BuildHasher,
|
|
||||||
{
|
|
||||||
map.reserve(len(&list));
|
|
||||||
for vec in list {
|
|
||||||
map.extend(vec);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +236,7 @@ where
|
|||||||
I: IntoParallelIterator<Item = (K, V)>,
|
I: IntoParallelIterator<Item = (K, V)>,
|
||||||
{
|
{
|
||||||
// See the map_collect benchmarks in rayon-demo for different strategies.
|
// See the map_collect benchmarks in rayon-demo for different strategies.
|
||||||
extend!(self, par_iter, hash_map_extend);
|
extend_reserved!(self, par_iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,19 +251,7 @@ where
|
|||||||
where
|
where
|
||||||
I: IntoParallelIterator<Item = (&'a K, &'a V)>,
|
I: IntoParallelIterator<Item = (&'a K, &'a V)>,
|
||||||
{
|
{
|
||||||
extend!(self, par_iter, hash_map_extend);
|
extend_reserved!(self, par_iter);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hash_set_extend<T, S, Item>(set: &mut HashSet<T, S>, list: LinkedList<Vec<Item>>)
|
|
||||||
where
|
|
||||||
HashSet<T, S>: Extend<Item>,
|
|
||||||
T: Eq + Hash,
|
|
||||||
S: BuildHasher,
|
|
||||||
{
|
|
||||||
set.reserve(len(&list));
|
|
||||||
for vec in list {
|
|
||||||
set.extend(vec);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,7 +265,7 @@ where
|
|||||||
where
|
where
|
||||||
I: IntoParallelIterator<Item = T>,
|
I: IntoParallelIterator<Item = T>,
|
||||||
{
|
{
|
||||||
extend!(self, par_iter, hash_set_extend);
|
extend_reserved!(self, par_iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,7 +279,7 @@ where
|
|||||||
where
|
where
|
||||||
I: IntoParallelIterator<Item = &'a T>,
|
I: IntoParallelIterator<Item = &'a T>,
|
||||||
{
|
{
|
||||||
extend!(self, par_iter, hash_set_extend);
|
extend_reserved!(self, par_iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,9 +380,34 @@ impl<T> Reducer<LinkedList<T>> for ListReducer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flat_string_extend(string: &mut String, list: LinkedList<String>) {
|
/// Extends an OS-string with string slices from a parallel iterator.
|
||||||
string.reserve(list.iter().map(String::len).sum());
|
impl<'a> ParallelExtend<&'a OsStr> for OsString {
|
||||||
string.extend(list);
|
fn par_extend<I>(&mut self, par_iter: I)
|
||||||
|
where
|
||||||
|
I: IntoParallelIterator<Item = &'a OsStr>,
|
||||||
|
{
|
||||||
|
extend_reserved!(self, par_iter, osstring_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extends an OS-string with strings from a parallel iterator.
|
||||||
|
impl ParallelExtend<OsString> for OsString {
|
||||||
|
fn par_extend<I>(&mut self, par_iter: I)
|
||||||
|
where
|
||||||
|
I: IntoParallelIterator<Item = OsString>,
|
||||||
|
{
|
||||||
|
extend_reserved!(self, par_iter, osstring_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extends an OS-string with string slices from a parallel iterator.
|
||||||
|
impl<'a> ParallelExtend<Cow<'a, OsStr>> for OsString {
|
||||||
|
fn par_extend<I>(&mut self, par_iter: I)
|
||||||
|
where
|
||||||
|
I: IntoParallelIterator<Item = Cow<'a, OsStr>>,
|
||||||
|
{
|
||||||
|
extend_reserved!(self, par_iter, osstring_len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extends a string with characters from a parallel iterator.
|
/// Extends a string with characters from a parallel iterator.
|
||||||
@@ -389,7 +419,8 @@ impl ParallelExtend<char> for String {
|
|||||||
// This is like `extend`, but `Vec<char>` is less efficient to deal
|
// This is like `extend`, but `Vec<char>` is less efficient to deal
|
||||||
// with than `String`, so instead collect to `LinkedList<String>`.
|
// with than `String`, so instead collect to `LinkedList<String>`.
|
||||||
let list = par_iter.into_par_iter().drive_unindexed(ListStringConsumer);
|
let list = par_iter.into_par_iter().drive_unindexed(ListStringConsumer);
|
||||||
flat_string_extend(self, list);
|
self.reserve(list.iter().map(String::len).sum());
|
||||||
|
self.extend(list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,25 +499,13 @@ impl Folder<char> for ListStringFolder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn string_extend<Item>(string: &mut String, list: LinkedList<Vec<Item>>)
|
|
||||||
where
|
|
||||||
String: Extend<Item>,
|
|
||||||
Item: AsRef<str>,
|
|
||||||
{
|
|
||||||
let len = list.iter().flatten().map(Item::as_ref).map(str::len).sum();
|
|
||||||
string.reserve(len);
|
|
||||||
for vec in list {
|
|
||||||
string.extend(vec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extends a string with string slices from a parallel iterator.
|
/// Extends a string with string slices from a parallel iterator.
|
||||||
impl<'a> ParallelExtend<&'a str> for String {
|
impl<'a> ParallelExtend<&'a str> for String {
|
||||||
fn par_extend<I>(&mut self, par_iter: I)
|
fn par_extend<I>(&mut self, par_iter: I)
|
||||||
where
|
where
|
||||||
I: IntoParallelIterator<Item = &'a str>,
|
I: IntoParallelIterator<Item = &'a str>,
|
||||||
{
|
{
|
||||||
extend!(self, par_iter, string_extend);
|
extend_reserved!(self, par_iter, string_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,7 +515,17 @@ impl ParallelExtend<String> for String {
|
|||||||
where
|
where
|
||||||
I: IntoParallelIterator<Item = String>,
|
I: IntoParallelIterator<Item = String>,
|
||||||
{
|
{
|
||||||
extend!(self, par_iter, string_extend);
|
extend_reserved!(self, par_iter, string_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extends a string with boxed strings from a parallel iterator.
|
||||||
|
impl ParallelExtend<Box<str>> for String {
|
||||||
|
fn par_extend<I>(&mut self, par_iter: I)
|
||||||
|
where
|
||||||
|
I: IntoParallelIterator<Item = Box<str>>,
|
||||||
|
{
|
||||||
|
extend_reserved!(self, par_iter, string_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,17 +535,7 @@ impl<'a> ParallelExtend<Cow<'a, str>> for String {
|
|||||||
where
|
where
|
||||||
I: IntoParallelIterator<Item = Cow<'a, str>>,
|
I: IntoParallelIterator<Item = Cow<'a, str>>,
|
||||||
{
|
{
|
||||||
extend!(self, par_iter, string_extend);
|
extend_reserved!(self, par_iter, string_len);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deque_extend<T, Item>(deque: &mut VecDeque<T>, list: LinkedList<Vec<Item>>)
|
|
||||||
where
|
|
||||||
VecDeque<T>: Extend<Item>,
|
|
||||||
{
|
|
||||||
deque.reserve(len(&list));
|
|
||||||
for vec in list {
|
|
||||||
deque.extend(vec);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,7 +548,7 @@ where
|
|||||||
where
|
where
|
||||||
I: IntoParallelIterator<Item = T>,
|
I: IntoParallelIterator<Item = T>,
|
||||||
{
|
{
|
||||||
extend!(self, par_iter, deque_extend);
|
extend_reserved!(self, par_iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -542,14 +561,7 @@ where
|
|||||||
where
|
where
|
||||||
I: IntoParallelIterator<Item = &'a T>,
|
I: IntoParallelIterator<Item = &'a T>,
|
||||||
{
|
{
|
||||||
extend!(self, par_iter, deque_extend);
|
extend_reserved!(self, par_iter);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vec_append<T>(vec: &mut Vec<T>, list: LinkedList<Vec<T>>) {
|
|
||||||
vec.reserve(len(&list));
|
|
||||||
for mut other in list {
|
|
||||||
vec.append(&mut other);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,7 +586,10 @@ where
|
|||||||
None => {
|
None => {
|
||||||
// This works like `extend`, but `Vec::append` is more efficient.
|
// This works like `extend`, but `Vec::append` is more efficient.
|
||||||
let list = par_iter.drive_unindexed(ListVecConsumer);
|
let list = par_iter.drive_unindexed(ListVecConsumer);
|
||||||
vec_append(self, list);
|
self.reserve(list.iter().map(Vec::len).sum());
|
||||||
|
for mut other in list {
|
||||||
|
self.append(&mut other);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,25 +181,17 @@ impl<'p, P: 'p + Fn(&T) -> bool, T> Folder<T> for FindFolder<'p, T, P> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if !found_best_in_range && (self.find_op)(&item) {
|
if !found_best_in_range && (self.find_op)(&item) {
|
||||||
// Continuously try to set best_found until we succeed or we
|
// Update the best found index if ours is better.
|
||||||
// discover a better match was already found.
|
let update =
|
||||||
let mut current = self.best_found.load(Ordering::Relaxed);
|
self.best_found
|
||||||
loop {
|
.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |current| {
|
||||||
if better_position(current, self.boundary, self.match_position) {
|
better_position(self.boundary, current, self.match_position)
|
||||||
break;
|
.then_some(self.boundary)
|
||||||
}
|
});
|
||||||
match self.best_found.compare_exchange_weak(
|
|
||||||
current,
|
// Save this item if our index was better or equal.
|
||||||
self.boundary,
|
if update.is_ok() || update == Err(self.boundary) {
|
||||||
Ordering::Relaxed,
|
|
||||||
Ordering::Relaxed,
|
|
||||||
) {
|
|
||||||
Ok(_) => {
|
|
||||||
self.item = Some(item);
|
self.item = Some(item);
|
||||||
break;
|
|
||||||
}
|
|
||||||
Err(v) => current = v,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use std::sync::atomic::AtomicUsize;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn same_range_first_consumers_return_correct_answer() {
|
fn same_range_first_consumers_return_correct_answer() {
|
||||||
|
|||||||
@@ -201,16 +201,16 @@ mod test {
|
|||||||
assert_eq!(4, (0..8).into_par_iter().fold_chunks(2, id, sum).len());
|
assert_eq!(4, (0..8).into_par_iter().fold_chunks(2, id, sum).len());
|
||||||
assert_eq!(3, (0..9).into_par_iter().fold_chunks(3, id, sum).len());
|
assert_eq!(3, (0..9).into_par_iter().fold_chunks(3, id, sum).len());
|
||||||
assert_eq!(3, (0..8).into_par_iter().fold_chunks(3, id, sum).len());
|
assert_eq!(3, (0..8).into_par_iter().fold_chunks(3, id, sum).len());
|
||||||
assert_eq!(1, (&[1]).par_iter().fold_chunks(3, id, sum).len());
|
assert_eq!(1, [1].par_iter().fold_chunks(3, id, sum).len());
|
||||||
assert_eq!(0, (0..0).into_par_iter().fold_chunks(3, id, sum).len());
|
assert_eq!(0, (0..0).into_par_iter().fold_chunks(3, id, sum).len());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_fold_chunks_uneven() {
|
fn check_fold_chunks_uneven() {
|
||||||
let cases: Vec<(Vec<u32>, usize, Vec<u32>)> = vec![
|
let cases: Vec<(Vec<u32>, usize, Vec<u32>)> = vec![
|
||||||
((0..5).collect(), 3, vec![0 + 1 + 2, 3 + 4]),
|
((0..5).collect(), 3, vec![1 + 2, 3 + 4]),
|
||||||
(vec![1], 5, vec![1]),
|
(vec![1], 5, vec![1]),
|
||||||
((0..4).collect(), 3, vec![0 + 1 + 2, 3]),
|
((0..4).collect(), 3, vec![1 + 2, 3]),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (i, (v, n, expected)) in cases.into_iter().enumerate() {
|
for (i, (v, n, expected)) in cases.into_iter().enumerate() {
|
||||||
|
|||||||
@@ -196,16 +196,16 @@ mod test {
|
|||||||
assert_eq!(4, (0..8).into_par_iter().fold_chunks_with(2, 0, sum).len());
|
assert_eq!(4, (0..8).into_par_iter().fold_chunks_with(2, 0, sum).len());
|
||||||
assert_eq!(3, (0..9).into_par_iter().fold_chunks_with(3, 0, sum).len());
|
assert_eq!(3, (0..9).into_par_iter().fold_chunks_with(3, 0, sum).len());
|
||||||
assert_eq!(3, (0..8).into_par_iter().fold_chunks_with(3, 0, sum).len());
|
assert_eq!(3, (0..8).into_par_iter().fold_chunks_with(3, 0, sum).len());
|
||||||
assert_eq!(1, (&[1]).par_iter().fold_chunks_with(3, 0, sum).len());
|
assert_eq!(1, [1].par_iter().fold_chunks_with(3, 0, sum).len());
|
||||||
assert_eq!(0, (0..0).into_par_iter().fold_chunks_with(3, 0, sum).len());
|
assert_eq!(0, (0..0).into_par_iter().fold_chunks_with(3, 0, sum).len());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_fold_chunks_uneven() {
|
fn check_fold_chunks_uneven() {
|
||||||
let cases: Vec<(Vec<u32>, usize, Vec<u32>)> = vec![
|
let cases: Vec<(Vec<u32>, usize, Vec<u32>)> = vec![
|
||||||
((0..5).collect(), 3, vec![0 + 1 + 2, 3 + 4]),
|
((0..5).collect(), 3, vec![1 + 2, 3 + 4]),
|
||||||
(vec![1], 5, vec![1]),
|
(vec![1], 5, vec![1]),
|
||||||
((0..4).collect(), 3, vec![0 + 1 + 2, 3]),
|
((0..4).collect(), 3, vec![1 + 2, 3]),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (i, (v, n, expected)) in cases.into_iter().enumerate() {
|
for (i, (v, n, expected)) in cases.into_iter().enumerate() {
|
||||||
|
|||||||
82
third_party/rust/rayon/src/iter/from_par_iter.rs
vendored
82
third_party/rust/rayon/src/iter/from_par_iter.rs
vendored
@@ -5,7 +5,10 @@ use std::borrow::Cow;
|
|||||||
use std::collections::LinkedList;
|
use std::collections::LinkedList;
|
||||||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||||
use std::collections::{BinaryHeap, VecDeque};
|
use std::collections::{BinaryHeap, VecDeque};
|
||||||
|
use std::ffi::{OsStr, OsString};
|
||||||
use std::hash::{BuildHasher, Hash};
|
use std::hash::{BuildHasher, Hash};
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Creates an empty default collection and extends it.
|
/// Creates an empty default collection and extends it.
|
||||||
fn collect_extended<C, I>(par_iter: I) -> C
|
fn collect_extended<C, I>(par_iter: I) -> C
|
||||||
@@ -31,6 +34,45 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Collects items from a parallel iterator into a boxed slice.
|
||||||
|
impl<T> FromParallelIterator<T> for Box<[T]>
|
||||||
|
where
|
||||||
|
T: Send,
|
||||||
|
{
|
||||||
|
fn from_par_iter<I>(par_iter: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoParallelIterator<Item = T>,
|
||||||
|
{
|
||||||
|
Vec::from_par_iter(par_iter).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collects items from a parallel iterator into a reference-counted slice.
|
||||||
|
impl<T> FromParallelIterator<T> for Rc<[T]>
|
||||||
|
where
|
||||||
|
T: Send,
|
||||||
|
{
|
||||||
|
fn from_par_iter<I>(par_iter: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoParallelIterator<Item = T>,
|
||||||
|
{
|
||||||
|
Vec::from_par_iter(par_iter).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collects items from a parallel iterator into an atomically-reference-counted slice.
|
||||||
|
impl<T> FromParallelIterator<T> for Arc<[T]>
|
||||||
|
where
|
||||||
|
T: Send,
|
||||||
|
{
|
||||||
|
fn from_par_iter<I>(par_iter: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoParallelIterator<Item = T>,
|
||||||
|
{
|
||||||
|
Vec::from_par_iter(par_iter).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Collects items from a parallel iterator into a vecdeque.
|
/// Collects items from a parallel iterator into a vecdeque.
|
||||||
impl<T> FromParallelIterator<T> for VecDeque<T>
|
impl<T> FromParallelIterator<T> for VecDeque<T>
|
||||||
where
|
where
|
||||||
@@ -174,6 +216,16 @@ impl FromParallelIterator<String> for String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Collects boxed strings from a parallel iterator into one large string.
|
||||||
|
impl FromParallelIterator<Box<str>> for String {
|
||||||
|
fn from_par_iter<I>(par_iter: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoParallelIterator<Item = Box<str>>,
|
||||||
|
{
|
||||||
|
collect_extended(par_iter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Collects string slices from a parallel iterator into a string.
|
/// Collects string slices from a parallel iterator into a string.
|
||||||
impl<'a> FromParallelIterator<Cow<'a, str>> for String {
|
impl<'a> FromParallelIterator<Cow<'a, str>> for String {
|
||||||
fn from_par_iter<I>(par_iter: I) -> Self
|
fn from_par_iter<I>(par_iter: I) -> Self
|
||||||
@@ -184,6 +236,36 @@ impl<'a> FromParallelIterator<Cow<'a, str>> for String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Collects OS-string slices from a parallel iterator into an OS-string.
|
||||||
|
impl<'a> FromParallelIterator<&'a OsStr> for OsString {
|
||||||
|
fn from_par_iter<I>(par_iter: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoParallelIterator<Item = &'a OsStr>,
|
||||||
|
{
|
||||||
|
collect_extended(par_iter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collects OS-strings from a parallel iterator into one large OS-string.
|
||||||
|
impl FromParallelIterator<OsString> for OsString {
|
||||||
|
fn from_par_iter<I>(par_iter: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoParallelIterator<Item = OsString>,
|
||||||
|
{
|
||||||
|
collect_extended(par_iter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collects OS-string slices from a parallel iterator into an OS-string.
|
||||||
|
impl<'a> FromParallelIterator<Cow<'a, OsStr>> for OsString {
|
||||||
|
fn from_par_iter<I>(par_iter: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoParallelIterator<Item = Cow<'a, OsStr>>,
|
||||||
|
{
|
||||||
|
collect_extended(par_iter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Collects an arbitrary `Cow` collection.
|
/// Collects an arbitrary `Cow` collection.
|
||||||
///
|
///
|
||||||
/// Note, the standard library only has `FromIterator` for `Cow<'a, str>` and
|
/// Note, the standard library only has `FromIterator` for `Cow<'a, str>` and
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use super::plumbing::*;
|
use super::plumbing::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::cmp;
|
|
||||||
use std::iter::Fuse;
|
use std::iter::Fuse;
|
||||||
|
|
||||||
/// `Interleave` is an iterator that interleaves elements of iterators
|
/// `Interleave` is an iterator that interleaves elements of iterators
|
||||||
@@ -185,11 +184,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn min_len(&self) -> usize {
|
fn min_len(&self) -> usize {
|
||||||
cmp::max(self.i.min_len(), self.j.min_len())
|
Ord::max(self.i.min_len(), self.j.min_len())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn max_len(&self) -> usize {
|
fn max_len(&self) -> usize {
|
||||||
cmp::min(self.i.max_len(), self.j.max_len())
|
Ord::min(self.i.max_len(), self.j.max_len())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We know 0 < index <= self.i_len + self.j_len
|
/// We know 0 < index <= self.i_len + self.j_len
|
||||||
|
|||||||
5
third_party/rust/rayon/src/iter/len.rs
vendored
5
third_party/rust/rayon/src/iter/len.rs
vendored
@@ -1,6 +1,5 @@
|
|||||||
use super::plumbing::*;
|
use super::plumbing::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::cmp;
|
|
||||||
|
|
||||||
/// `MinLen` is an iterator that imposes a minimum length on iterator splits.
|
/// `MinLen` is an iterator that imposes a minimum length on iterator splits.
|
||||||
/// This struct is created by the [`with_min_len()`] method on [`IndexedParallelIterator`]
|
/// This struct is created by the [`with_min_len()`] method on [`IndexedParallelIterator`]
|
||||||
@@ -107,7 +106,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn min_len(&self) -> usize {
|
fn min_len(&self) -> usize {
|
||||||
cmp::max(self.min, self.base.min_len())
|
Ord::max(self.min, self.base.min_len())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn max_len(&self) -> usize {
|
fn max_len(&self) -> usize {
|
||||||
@@ -245,7 +244,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn max_len(&self) -> usize {
|
fn max_len(&self) -> usize {
|
||||||
cmp::min(self.max, self.base.max_len())
|
Ord::min(self.max, self.base.max_len())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn split_at(self, index: usize) -> (Self, Self) {
|
fn split_at(self, index: usize) -> (Self, Self) {
|
||||||
|
|||||||
303
third_party/rust/rayon/src/iter/mod.rs
vendored
303
third_party/rust/rayon/src/iter/mod.rs
vendored
@@ -82,7 +82,8 @@
|
|||||||
use self::plumbing::*;
|
use self::plumbing::*;
|
||||||
use self::private::Try;
|
use self::private::Try;
|
||||||
pub use either::Either;
|
pub use either::Either;
|
||||||
use std::cmp::{self, Ordering};
|
use std::cmp::Ordering;
|
||||||
|
use std::collections::LinkedList;
|
||||||
use std::iter::{Product, Sum};
|
use std::iter::{Product, Sum};
|
||||||
use std::ops::{Fn, RangeBounds};
|
use std::ops::{Fn, RangeBounds};
|
||||||
|
|
||||||
@@ -102,6 +103,7 @@ mod test;
|
|||||||
// e.g. `find::find()`, are always used **prefixed**, so that they
|
// e.g. `find::find()`, are always used **prefixed**, so that they
|
||||||
// can be readily distinguished.
|
// can be readily distinguished.
|
||||||
|
|
||||||
|
mod blocks;
|
||||||
mod chain;
|
mod chain;
|
||||||
mod chunks;
|
mod chunks;
|
||||||
mod cloned;
|
mod cloned;
|
||||||
@@ -141,20 +143,26 @@ mod reduce;
|
|||||||
mod repeat;
|
mod repeat;
|
||||||
mod rev;
|
mod rev;
|
||||||
mod skip;
|
mod skip;
|
||||||
|
mod skip_any;
|
||||||
|
mod skip_any_while;
|
||||||
mod splitter;
|
mod splitter;
|
||||||
mod step_by;
|
mod step_by;
|
||||||
mod sum;
|
mod sum;
|
||||||
mod take;
|
mod take;
|
||||||
|
mod take_any;
|
||||||
|
mod take_any_while;
|
||||||
mod try_fold;
|
mod try_fold;
|
||||||
mod try_reduce;
|
mod try_reduce;
|
||||||
mod try_reduce_with;
|
mod try_reduce_with;
|
||||||
mod unzip;
|
mod unzip;
|
||||||
mod update;
|
mod update;
|
||||||
|
mod walk_tree;
|
||||||
mod while_some;
|
mod while_some;
|
||||||
mod zip;
|
mod zip;
|
||||||
mod zip_eq;
|
mod zip_eq;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
|
blocks::{ExponentialBlocks, UniformBlocks},
|
||||||
chain::Chain,
|
chain::Chain,
|
||||||
chunks::Chunks,
|
chunks::Chunks,
|
||||||
cloned::Cloned,
|
cloned::Cloned,
|
||||||
@@ -185,11 +193,18 @@ pub use self::{
|
|||||||
repeat::{repeat, repeatn, Repeat, RepeatN},
|
repeat::{repeat, repeatn, Repeat, RepeatN},
|
||||||
rev::Rev,
|
rev::Rev,
|
||||||
skip::Skip,
|
skip::Skip,
|
||||||
|
skip_any::SkipAny,
|
||||||
|
skip_any_while::SkipAnyWhile,
|
||||||
splitter::{split, Split},
|
splitter::{split, Split},
|
||||||
step_by::StepBy,
|
step_by::StepBy,
|
||||||
take::Take,
|
take::Take,
|
||||||
|
take_any::TakeAny,
|
||||||
|
take_any_while::TakeAnyWhile,
|
||||||
try_fold::{TryFold, TryFoldWith},
|
try_fold::{TryFold, TryFoldWith},
|
||||||
update::Update,
|
update::Update,
|
||||||
|
walk_tree::{
|
||||||
|
walk_tree, walk_tree_postfix, walk_tree_prefix, WalkTree, WalkTreePostfix, WalkTreePrefix,
|
||||||
|
},
|
||||||
while_some::WhileSome,
|
while_some::WhileSome,
|
||||||
zip::Zip,
|
zip::Zip,
|
||||||
zip_eq::ZipEq,
|
zip_eq::ZipEq,
|
||||||
@@ -1417,7 +1432,7 @@ pub trait ParallelIterator: Sized + Send {
|
|||||||
/// specified, so if the `Ord` impl is not truly associative, then
|
/// specified, so if the `Ord` impl is not truly associative, then
|
||||||
/// the results are not deterministic.
|
/// the results are not deterministic.
|
||||||
///
|
///
|
||||||
/// Basically equivalent to `self.reduce_with(|a, b| cmp::min(a, b))`.
|
/// Basically equivalent to `self.reduce_with(|a, b| Ord::min(a, b))`.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@@ -1436,7 +1451,7 @@ pub trait ParallelIterator: Sized + Send {
|
|||||||
where
|
where
|
||||||
Self::Item: Ord,
|
Self::Item: Ord,
|
||||||
{
|
{
|
||||||
self.reduce_with(cmp::min)
|
self.reduce_with(Ord::min)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the minimum of all the items in the iterator with respect to
|
/// Computes the minimum of all the items in the iterator with respect to
|
||||||
@@ -1515,7 +1530,7 @@ pub trait ParallelIterator: Sized + Send {
|
|||||||
/// specified, so if the `Ord` impl is not truly associative, then
|
/// specified, so if the `Ord` impl is not truly associative, then
|
||||||
/// the results are not deterministic.
|
/// the results are not deterministic.
|
||||||
///
|
///
|
||||||
/// Basically equivalent to `self.reduce_with(|a, b| cmp::max(a, b))`.
|
/// Basically equivalent to `self.reduce_with(|a, b| Ord::max(a, b))`.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@@ -1534,12 +1549,12 @@ pub trait ParallelIterator: Sized + Send {
|
|||||||
where
|
where
|
||||||
Self::Item: Ord,
|
Self::Item: Ord,
|
||||||
{
|
{
|
||||||
self.reduce_with(cmp::max)
|
self.reduce_with(Ord::max)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the maximum of all the items in the iterator with respect to
|
/// Computes the maximum of all the items in the iterator with respect to
|
||||||
/// the given comparison function. If the iterator is empty, `None` is
|
/// the given comparison function. If the iterator is empty, `None` is
|
||||||
/// returned; otherwise, `Some(min)` is returned.
|
/// returned; otherwise, `Some(max)` is returned.
|
||||||
///
|
///
|
||||||
/// Note that the order in which the items will be reduced is not
|
/// Note that the order in which the items will be reduced is not
|
||||||
/// specified, so if the comparison function is not associative, then
|
/// specified, so if the comparison function is not associative, then
|
||||||
@@ -1665,6 +1680,9 @@ pub trait ParallelIterator: Sized + Send {
|
|||||||
/// will be stopped, while attempts to the left must continue in case
|
/// will be stopped, while attempts to the left must continue in case
|
||||||
/// an earlier match is found.
|
/// an earlier match is found.
|
||||||
///
|
///
|
||||||
|
/// For added performance, you might consider using `find_first` in conjunction with
|
||||||
|
/// [`by_exponential_blocks()`][IndexedParallelIterator::by_exponential_blocks].
|
||||||
|
///
|
||||||
/// Note that not all parallel iterators have a useful order, much like
|
/// Note that not all parallel iterators have a useful order, much like
|
||||||
/// sequential `HashMap` iteration, so "first" may be nebulous. If you
|
/// sequential `HashMap` iteration, so "first" may be nebulous. If you
|
||||||
/// just want the first match that discovered anywhere in the iterator,
|
/// just want the first match that discovered anywhere in the iterator,
|
||||||
@@ -1953,6 +1971,9 @@ pub trait ParallelIterator: Sized + Send {
|
|||||||
/// of how many elements the iterator contains, and even allows you to reuse
|
/// of how many elements the iterator contains, and even allows you to reuse
|
||||||
/// an existing vector's backing store rather than allocating a fresh vector.
|
/// an existing vector's backing store rather than allocating a fresh vector.
|
||||||
///
|
///
|
||||||
|
/// See also [`collect_vec_list()`][Self::collect_vec_list] for collecting
|
||||||
|
/// into a `LinkedList<Vec<T>>`.
|
||||||
|
///
|
||||||
/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
|
/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
|
||||||
/// [`collect_into_vec()`]:
|
/// [`collect_into_vec()`]:
|
||||||
/// trait.IndexedParallelIterator.html#method.collect_into_vec
|
/// trait.IndexedParallelIterator.html#method.collect_into_vec
|
||||||
@@ -2194,6 +2215,188 @@ pub trait ParallelIterator: Sized + Send {
|
|||||||
Intersperse::new(self, element)
|
Intersperse::new(self, element)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates an iterator that yields `n` elements from *anywhere* in the original iterator.
|
||||||
|
///
|
||||||
|
/// This is similar to [`IndexedParallelIterator::take`] without being
|
||||||
|
/// constrained to the "first" `n` of the original iterator order. The
|
||||||
|
/// taken items will still maintain their relative order where that is
|
||||||
|
/// visible in `collect`, `reduce`, and similar outputs.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
///
|
||||||
|
/// let result: Vec<_> = (0..100)
|
||||||
|
/// .into_par_iter()
|
||||||
|
/// .filter(|&x| x % 2 == 0)
|
||||||
|
/// .take_any(5)
|
||||||
|
/// .collect();
|
||||||
|
///
|
||||||
|
/// assert_eq!(result.len(), 5);
|
||||||
|
/// assert!(result.windows(2).all(|w| w[0] < w[1]));
|
||||||
|
/// ```
|
||||||
|
fn take_any(self, n: usize) -> TakeAny<Self> {
|
||||||
|
TakeAny::new(self, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an iterator that skips `n` elements from *anywhere* in the original iterator.
|
||||||
|
///
|
||||||
|
/// This is similar to [`IndexedParallelIterator::skip`] without being
|
||||||
|
/// constrained to the "first" `n` of the original iterator order. The
|
||||||
|
/// remaining items will still maintain their relative order where that is
|
||||||
|
/// visible in `collect`, `reduce`, and similar outputs.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
///
|
||||||
|
/// let result: Vec<_> = (0..100)
|
||||||
|
/// .into_par_iter()
|
||||||
|
/// .filter(|&x| x % 2 == 0)
|
||||||
|
/// .skip_any(5)
|
||||||
|
/// .collect();
|
||||||
|
///
|
||||||
|
/// assert_eq!(result.len(), 45);
|
||||||
|
/// assert!(result.windows(2).all(|w| w[0] < w[1]));
|
||||||
|
/// ```
|
||||||
|
fn skip_any(self, n: usize) -> SkipAny<Self> {
|
||||||
|
SkipAny::new(self, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an iterator that takes elements from *anywhere* in the original iterator
|
||||||
|
/// until the given `predicate` returns `false`.
|
||||||
|
///
|
||||||
|
/// The `predicate` may be anything -- e.g. it could be checking a fact about the item, a
|
||||||
|
/// global condition unrelated to the item itself, or some combination thereof.
|
||||||
|
///
|
||||||
|
/// If parallel calls to the `predicate` race and give different results, then the
|
||||||
|
/// `true` results will still take those particular items, while respecting the `false`
|
||||||
|
/// result from elsewhere to skip any further items.
|
||||||
|
///
|
||||||
|
/// This is similar to [`Iterator::take_while`] without being constrained to the original
|
||||||
|
/// iterator order. The taken items will still maintain their relative order where that is
|
||||||
|
/// visible in `collect`, `reduce`, and similar outputs.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
///
|
||||||
|
/// let result: Vec<_> = (0..100)
|
||||||
|
/// .into_par_iter()
|
||||||
|
/// .take_any_while(|x| *x < 50)
|
||||||
|
/// .collect();
|
||||||
|
///
|
||||||
|
/// assert!(result.len() <= 50);
|
||||||
|
/// assert!(result.windows(2).all(|w| w[0] < w[1]));
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
/// use std::sync::atomic::AtomicUsize;
|
||||||
|
/// use std::sync::atomic::Ordering::Relaxed;
|
||||||
|
///
|
||||||
|
/// // Collect any group of items that sum <= 1000
|
||||||
|
/// let quota = AtomicUsize::new(1000);
|
||||||
|
/// let result: Vec<_> = (0_usize..100)
|
||||||
|
/// .into_par_iter()
|
||||||
|
/// .take_any_while(|&x| {
|
||||||
|
/// quota.fetch_update(Relaxed, Relaxed, |q| q.checked_sub(x))
|
||||||
|
/// .is_ok()
|
||||||
|
/// })
|
||||||
|
/// .collect();
|
||||||
|
///
|
||||||
|
/// let sum = result.iter().sum::<usize>();
|
||||||
|
/// assert!(matches!(sum, 902..=1000));
|
||||||
|
/// ```
|
||||||
|
fn take_any_while<P>(self, predicate: P) -> TakeAnyWhile<Self, P>
|
||||||
|
where
|
||||||
|
P: Fn(&Self::Item) -> bool + Sync + Send,
|
||||||
|
{
|
||||||
|
TakeAnyWhile::new(self, predicate)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an iterator that skips elements from *anywhere* in the original iterator
|
||||||
|
/// until the given `predicate` returns `false`.
|
||||||
|
///
|
||||||
|
/// The `predicate` may be anything -- e.g. it could be checking a fact about the item, a
|
||||||
|
/// global condition unrelated to the item itself, or some combination thereof.
|
||||||
|
///
|
||||||
|
/// If parallel calls to the `predicate` race and give different results, then the
|
||||||
|
/// `true` results will still skip those particular items, while respecting the `false`
|
||||||
|
/// result from elsewhere to skip any further items.
|
||||||
|
///
|
||||||
|
/// This is similar to [`Iterator::skip_while`] without being constrained to the original
|
||||||
|
/// iterator order. The remaining items will still maintain their relative order where that is
|
||||||
|
/// visible in `collect`, `reduce`, and similar outputs.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
///
|
||||||
|
/// let result: Vec<_> = (0..100)
|
||||||
|
/// .into_par_iter()
|
||||||
|
/// .skip_any_while(|x| *x < 50)
|
||||||
|
/// .collect();
|
||||||
|
///
|
||||||
|
/// assert!(result.len() >= 50);
|
||||||
|
/// assert!(result.windows(2).all(|w| w[0] < w[1]));
|
||||||
|
/// ```
|
||||||
|
fn skip_any_while<P>(self, predicate: P) -> SkipAnyWhile<Self, P>
|
||||||
|
where
|
||||||
|
P: Fn(&Self::Item) -> bool + Sync + Send,
|
||||||
|
{
|
||||||
|
SkipAnyWhile::new(self, predicate)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collects this iterator into a linked list of vectors.
|
||||||
|
///
|
||||||
|
/// This is useful when you need to condense a parallel iterator into a collection,
|
||||||
|
/// but have no specific requirements for what that collection should be. If you
|
||||||
|
/// plan to store the collection longer-term, `Vec<T>` is, as always, likely the
|
||||||
|
/// best default choice, despite the overhead that comes from concatenating each
|
||||||
|
/// vector. Or, if this is an `IndexedParallelIterator`, you should also prefer to
|
||||||
|
/// just collect to a `Vec<T>`.
|
||||||
|
///
|
||||||
|
/// Internally, most [`FromParallelIterator`]/[`ParallelExtend`] implementations
|
||||||
|
/// use this strategy; each job collecting their chunk of the iterator to a `Vec<T>`
|
||||||
|
/// and those chunks getting merged into a `LinkedList`, before then extending the
|
||||||
|
/// collection with each vector. This is a very efficient way to collect an
|
||||||
|
/// unindexed parallel iterator, without much intermediate data movement.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use std::collections::LinkedList;
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
///
|
||||||
|
/// let result: LinkedList<Vec<_>> = (0..=100)
|
||||||
|
/// .into_par_iter()
|
||||||
|
/// .filter(|x| x % 2 == 0)
|
||||||
|
/// .flat_map(|x| 0..x)
|
||||||
|
/// .collect_vec_list();
|
||||||
|
///
|
||||||
|
/// // `par_iter.collect_vec_list().into_iter().flatten()` turns
|
||||||
|
/// // a parallel iterator into a serial one
|
||||||
|
/// let total_len = result.into_iter().flatten().count();
|
||||||
|
/// assert_eq!(total_len, 2550);
|
||||||
|
/// ```
|
||||||
|
fn collect_vec_list(self) -> LinkedList<Vec<Self::Item>> {
|
||||||
|
match extend::fast_collect(self) {
|
||||||
|
Either::Left(vec) => {
|
||||||
|
let mut list = LinkedList::new();
|
||||||
|
if !vec.is_empty() {
|
||||||
|
list.push_back(vec);
|
||||||
|
}
|
||||||
|
list
|
||||||
|
}
|
||||||
|
Either::Right(list) => list,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Internal method used to define the behavior of this parallel
|
/// Internal method used to define the behavior of this parallel
|
||||||
/// iterator. You should not need to call this directly.
|
/// iterator. You should not need to call this directly.
|
||||||
///
|
///
|
||||||
@@ -2205,7 +2408,7 @@ pub trait ParallelIterator: Sized + Send {
|
|||||||
/// See the [README] for more details on the internals of parallel
|
/// See the [README] for more details on the internals of parallel
|
||||||
/// iterators.
|
/// iterators.
|
||||||
///
|
///
|
||||||
/// [README]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md
|
/// [README]: https://github.com/rayon-rs/rayon/blob/main/src/iter/plumbing/README.md
|
||||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
where
|
where
|
||||||
C: UnindexedConsumer<Self::Item>;
|
C: UnindexedConsumer<Self::Item>;
|
||||||
@@ -2246,8 +2449,72 @@ impl<T: ParallelIterator> IntoParallelIterator for T {
|
|||||||
// Waiting for `ExactSizeIterator::is_empty` to be stabilized. See rust-lang/rust#35428
|
// Waiting for `ExactSizeIterator::is_empty` to be stabilized. See rust-lang/rust#35428
|
||||||
#[allow(clippy::len_without_is_empty)]
|
#[allow(clippy::len_without_is_empty)]
|
||||||
pub trait IndexedParallelIterator: ParallelIterator {
|
pub trait IndexedParallelIterator: ParallelIterator {
|
||||||
|
/// Divides an iterator into sequential blocks of exponentially-increasing size.
|
||||||
|
///
|
||||||
|
/// Normally, parallel iterators are recursively divided into tasks in parallel.
|
||||||
|
/// This adaptor changes the default behavior by splitting the iterator into a **sequence**
|
||||||
|
/// of parallel iterators of increasing sizes.
|
||||||
|
/// Sizes grow exponentially in order to avoid creating
|
||||||
|
/// too many blocks. This also allows to balance the current block with all previous ones.
|
||||||
|
///
|
||||||
|
/// This can have many applications but the most notable ones are:
|
||||||
|
/// - better performance with [`find_first()`][ParallelIterator::find_first]
|
||||||
|
/// - more predictable performance with [`find_any()`][ParallelIterator::find_any]
|
||||||
|
/// or any interruptible computation
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
/// assert_eq!((0..10_000).into_par_iter()
|
||||||
|
/// .by_exponential_blocks()
|
||||||
|
/// .find_first(|&e| e==4_999), Some(4_999))
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// In this example, without blocks, rayon will split the initial range into two but all work
|
||||||
|
/// on the right hand side (from 5,000 onwards) is **useless** since the sequential algorithm
|
||||||
|
/// never goes there. This means that if two threads are used there will be **no** speedup **at
|
||||||
|
/// all**.
|
||||||
|
///
|
||||||
|
/// `by_exponential_blocks` on the other hand will start with the leftmost range from 0
|
||||||
|
/// to `p` (threads number), continue with p to 3p, the 3p to 7p...
|
||||||
|
///
|
||||||
|
/// Each subrange is treated in parallel, while all subranges are treated sequentially.
|
||||||
|
/// We therefore ensure a logarithmic number of blocks (and overhead) while guaranteeing
|
||||||
|
/// we stop at the first block containing the searched data.
|
||||||
|
fn by_exponential_blocks(self) -> ExponentialBlocks<Self> {
|
||||||
|
ExponentialBlocks::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Divides an iterator into sequential blocks of the given size.
|
||||||
|
///
|
||||||
|
/// Normally, parallel iterators are recursively divided into tasks in parallel.
|
||||||
|
/// This adaptor changes the default behavior by splitting the iterator into a **sequence**
|
||||||
|
/// of parallel iterators of given `block_size`.
|
||||||
|
/// The main application is to obtain better
|
||||||
|
/// memory locality (especially if the reduce operation re-use folded data).
|
||||||
|
///
|
||||||
|
/// **Panics** if `block_size` is 0.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
/// // during most reductions v1 and v2 fit the cache
|
||||||
|
/// let v = (0u32..10_000_000)
|
||||||
|
/// .into_par_iter()
|
||||||
|
/// .by_uniform_blocks(1_000_000)
|
||||||
|
/// .fold(Vec::new, |mut v, e| { v.push(e); v})
|
||||||
|
/// .reduce(Vec::new, |mut v1, mut v2| { v1.append(&mut v2); v1});
|
||||||
|
/// assert_eq!(v, (0u32..10_000_000).collect::<Vec<u32>>());
|
||||||
|
/// ```
|
||||||
|
#[track_caller]
|
||||||
|
fn by_uniform_blocks(self, block_size: usize) -> UniformBlocks<Self> {
|
||||||
|
assert!(block_size != 0, "block_size must not be zero");
|
||||||
|
UniformBlocks::new(self, block_size)
|
||||||
|
}
|
||||||
|
|
||||||
/// Collects the results of the iterator into the specified
|
/// Collects the results of the iterator into the specified
|
||||||
/// vector. The vector is always truncated before execution
|
/// vector. The vector is always cleared before execution
|
||||||
/// begins. If possible, reusing the vector across calls can lead
|
/// begins. If possible, reusing the vector across calls can lead
|
||||||
/// to better performance since it reuses the same backing buffer.
|
/// to better performance since it reuses the same backing buffer.
|
||||||
///
|
///
|
||||||
@@ -2256,7 +2523,7 @@ pub trait IndexedParallelIterator: ParallelIterator {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use rayon::prelude::*;
|
/// use rayon::prelude::*;
|
||||||
///
|
///
|
||||||
/// // any prior data will be truncated
|
/// // any prior data will be cleared
|
||||||
/// let mut vec = vec![-1, -2, -3];
|
/// let mut vec = vec![-1, -2, -3];
|
||||||
///
|
///
|
||||||
/// (0..5).into_par_iter()
|
/// (0..5).into_par_iter()
|
||||||
@@ -2269,7 +2536,7 @@ pub trait IndexedParallelIterator: ParallelIterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Unzips the results of the iterator into the specified
|
/// Unzips the results of the iterator into the specified
|
||||||
/// vectors. The vectors are always truncated before execution
|
/// vectors. The vectors are always cleared before execution
|
||||||
/// begins. If possible, reusing the vectors across calls can lead
|
/// begins. If possible, reusing the vectors across calls can lead
|
||||||
/// to better performance since they reuse the same backing buffer.
|
/// to better performance since they reuse the same backing buffer.
|
||||||
///
|
///
|
||||||
@@ -2278,7 +2545,7 @@ pub trait IndexedParallelIterator: ParallelIterator {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use rayon::prelude::*;
|
/// use rayon::prelude::*;
|
||||||
///
|
///
|
||||||
/// // any prior data will be truncated
|
/// // any prior data will be cleared
|
||||||
/// let mut left = vec![42; 10];
|
/// let mut left = vec![42; 10];
|
||||||
/// let mut right = vec![-1; 10];
|
/// let mut right = vec![-1; 10];
|
||||||
///
|
///
|
||||||
@@ -2411,6 +2678,8 @@ pub trait IndexedParallelIterator: ParallelIterator {
|
|||||||
/// [`par_chunks()`]: ../slice/trait.ParallelSlice.html#method.par_chunks
|
/// [`par_chunks()`]: ../slice/trait.ParallelSlice.html#method.par_chunks
|
||||||
/// [`par_chunks_mut()`]: ../slice/trait.ParallelSliceMut.html#method.par_chunks_mut
|
/// [`par_chunks_mut()`]: ../slice/trait.ParallelSliceMut.html#method.par_chunks_mut
|
||||||
///
|
///
|
||||||
|
/// **Panics** if `chunk_size` is 0.
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@@ -2419,6 +2688,7 @@ pub trait IndexedParallelIterator: ParallelIterator {
|
|||||||
/// let r: Vec<Vec<i32>> = a.into_par_iter().chunks(3).collect();
|
/// let r: Vec<Vec<i32>> = a.into_par_iter().chunks(3).collect();
|
||||||
/// assert_eq!(r, vec![vec![1,2,3], vec![4,5,6], vec![7,8,9], vec![10]]);
|
/// assert_eq!(r, vec![vec![1,2,3], vec![4,5,6], vec![7,8,9], vec![10]]);
|
||||||
/// ```
|
/// ```
|
||||||
|
#[track_caller]
|
||||||
fn chunks(self, chunk_size: usize) -> Chunks<Self> {
|
fn chunks(self, chunk_size: usize) -> Chunks<Self> {
|
||||||
assert!(chunk_size != 0, "chunk_size must not be zero");
|
assert!(chunk_size != 0, "chunk_size must not be zero");
|
||||||
Chunks::new(self, chunk_size)
|
Chunks::new(self, chunk_size)
|
||||||
@@ -2977,7 +3247,7 @@ pub trait IndexedParallelIterator: ParallelIterator {
|
|||||||
/// See the [README] for more details on the internals of parallel
|
/// See the [README] for more details on the internals of parallel
|
||||||
/// iterators.
|
/// iterators.
|
||||||
///
|
///
|
||||||
/// [README]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md
|
/// [README]: https://github.com/rayon-rs/rayon/blob/main/src/iter/plumbing/README.md
|
||||||
fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result;
|
fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result;
|
||||||
|
|
||||||
/// Internal method used to define the behavior of this parallel
|
/// Internal method used to define the behavior of this parallel
|
||||||
@@ -2994,7 +3264,7 @@ pub trait IndexedParallelIterator: ParallelIterator {
|
|||||||
/// See the [README] for more details on the internals of parallel
|
/// See the [README] for more details on the internals of parallel
|
||||||
/// iterators.
|
/// iterators.
|
||||||
///
|
///
|
||||||
/// [README]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md
|
/// [README]: https://github.com/rayon-rs/rayon/blob/main/src/iter/plumbing/README.md
|
||||||
fn with_producer<CB: ProducerCallback<Self::Item>>(self, callback: CB) -> CB::Output;
|
fn with_producer<CB: ProducerCallback<Self::Item>>(self, callback: CB) -> CB::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3042,14 +3312,15 @@ where
|
|||||||
///
|
///
|
||||||
/// If your collection is not naturally parallel, the easiest (and
|
/// If your collection is not naturally parallel, the easiest (and
|
||||||
/// fastest) way to do this is often to collect `par_iter` into a
|
/// fastest) way to do this is often to collect `par_iter` into a
|
||||||
/// [`LinkedList`] or other intermediate data structure and then
|
/// [`LinkedList`] (via [`collect_vec_list`]) or another intermediate
|
||||||
/// sequentially extend your collection. However, a more 'native'
|
/// data structure and then sequentially extend your collection. However,
|
||||||
/// technique is to use the [`par_iter.fold`] or
|
/// a more 'native' technique is to use the [`par_iter.fold`] or
|
||||||
/// [`par_iter.fold_with`] methods to create the collection.
|
/// [`par_iter.fold_with`] methods to create the collection.
|
||||||
/// Alternatively, if your collection is 'natively' parallel, you
|
/// Alternatively, if your collection is 'natively' parallel, you
|
||||||
/// can use `par_iter.for_each` to process each element in turn.
|
/// can use `par_iter.for_each` to process each element in turn.
|
||||||
///
|
///
|
||||||
/// [`LinkedList`]: https://doc.rust-lang.org/std/collections/struct.LinkedList.html
|
/// [`LinkedList`]: https://doc.rust-lang.org/std/collections/struct.LinkedList.html
|
||||||
|
/// [`collect_vec_list`]: ParallelIterator::collect_vec_list
|
||||||
/// [`par_iter.fold`]: trait.ParallelIterator.html#method.fold
|
/// [`par_iter.fold`]: trait.ParallelIterator.html#method.fold
|
||||||
/// [`par_iter.fold_with`]: trait.ParallelIterator.html#method.fold_with
|
/// [`par_iter.fold_with`]: trait.ParallelIterator.html#method.fold_with
|
||||||
/// [`par_iter.for_each`]: trait.ParallelIterator.html#method.for_each
|
/// [`par_iter.for_each`]: trait.ParallelIterator.html#method.for_each
|
||||||
|
|||||||
33
third_party/rust/rayon/src/iter/par_bridge.rs
vendored
33
third_party/rust/rayon/src/iter/par_bridge.rs
vendored
@@ -1,6 +1,11 @@
|
|||||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
#[cfg(not(feature = "web_spin_lock"))]
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
#[cfg(feature = "web_spin_lock")]
|
||||||
|
use wasm_sync::Mutex;
|
||||||
|
|
||||||
|
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||||
|
|
||||||
use crate::iter::plumbing::{bridge_unindexed, Folder, UnindexedConsumer, UnindexedProducer};
|
use crate::iter::plumbing::{bridge_unindexed, Folder, UnindexedConsumer, UnindexedProducer};
|
||||||
use crate::iter::ParallelIterator;
|
use crate::iter::ParallelIterator;
|
||||||
use crate::{current_num_threads, current_thread_index};
|
use crate::{current_num_threads, current_thread_index};
|
||||||
@@ -13,6 +18,11 @@ use crate::{current_num_threads, current_thread_index};
|
|||||||
/// `par_iter` instead. However, it can still be useful for iterators that are difficult to
|
/// `par_iter` instead. However, it can still be useful for iterators that are difficult to
|
||||||
/// parallelize by other means, like channels or file or network I/O.
|
/// parallelize by other means, like channels or file or network I/O.
|
||||||
///
|
///
|
||||||
|
/// Iterator items are pulled by `next()` one at a time, synchronized from each thread that is
|
||||||
|
/// ready for work, so this may become a bottleneck if the serial iterator can't keep up with the
|
||||||
|
/// parallel demand. The items are not buffered by `IterBridge`, so it's fine to use this with
|
||||||
|
/// large or even unbounded iterators.
|
||||||
|
///
|
||||||
/// The resulting iterator is not guaranteed to keep the order of the original iterator.
|
/// The resulting iterator is not guaranteed to keep the order of the original iterator.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
@@ -99,24 +109,11 @@ impl<Iter: Iterator + Send> UnindexedProducer for &IterParallelProducer<'_, Iter
|
|||||||
type Item = Iter::Item;
|
type Item = Iter::Item;
|
||||||
|
|
||||||
fn split(self) -> (Self, Option<Self>) {
|
fn split(self) -> (Self, Option<Self>) {
|
||||||
let mut count = self.split_count.load(Ordering::SeqCst);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
// Check if the iterator is exhausted
|
// Check if the iterator is exhausted
|
||||||
if let Some(new_count) = count.checked_sub(1) {
|
let update = self
|
||||||
match self.split_count.compare_exchange_weak(
|
.split_count
|
||||||
count,
|
.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |c| c.checked_sub(1));
|
||||||
new_count,
|
(self, update.is_ok().then_some(self))
|
||||||
Ordering::SeqCst,
|
|
||||||
Ordering::SeqCst,
|
|
||||||
) {
|
|
||||||
Ok(_) => return (self, Some(self)),
|
|
||||||
Err(last_count) => count = last_count,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return (self, None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_with<F>(self, mut folder: F) -> F
|
fn fold_with<F>(self, mut folder: F) -> F
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ modes (which is why there are two):
|
|||||||
more like a `for_each` call: each time a new item is produced, the
|
more like a `for_each` call: each time a new item is produced, the
|
||||||
`consume` method is called with that item. (The traits themselves are
|
`consume` method is called with that item. (The traits themselves are
|
||||||
a bit more complex, as they support state that can be threaded
|
a bit more complex, as they support state that can be threaded
|
||||||
through and ultimately reduced.) Unlike producers, there are two
|
through and ultimately reduced.) Like producers, there are two
|
||||||
variants of consumers. The difference is how the split is performed:
|
variants of consumers which differ in how the split is performed:
|
||||||
- in the `Consumer` trait, splitting is done with `split_at`, which
|
- in the `Consumer` trait, splitting is done with `split_at`, which
|
||||||
accepts an index where the split should be performed. All
|
accepts an index where the split should be performed. All
|
||||||
iterators can work in this mode. The resulting halves thus have an
|
iterators can work in this mode. The resulting halves thus have an
|
||||||
|
|||||||
17
third_party/rust/rayon/src/iter/plumbing/mod.rs
vendored
17
third_party/rust/rayon/src/iter/plumbing/mod.rs
vendored
@@ -2,20 +2,19 @@
|
|||||||
//! low-level details -- users of parallel iterators should not need to
|
//! low-level details -- users of parallel iterators should not need to
|
||||||
//! interact with them directly. See [the `plumbing` README][r] for a general overview.
|
//! interact with them directly. See [the `plumbing` README][r] for a general overview.
|
||||||
//!
|
//!
|
||||||
//! [r]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md
|
//! [r]: https://github.com/rayon-rs/rayon/blob/main/src/iter/plumbing/README.md
|
||||||
|
|
||||||
use crate::join_context;
|
use crate::join_context;
|
||||||
|
|
||||||
use super::IndexedParallelIterator;
|
use super::IndexedParallelIterator;
|
||||||
|
|
||||||
use std::cmp;
|
|
||||||
use std::usize;
|
use std::usize;
|
||||||
|
|
||||||
/// The `ProducerCallback` trait is a kind of generic closure,
|
/// The `ProducerCallback` trait is a kind of generic closure,
|
||||||
/// [analogous to `FnOnce`][FnOnce]. See [the corresponding section in
|
/// [analogous to `FnOnce`][FnOnce]. See [the corresponding section in
|
||||||
/// the plumbing README][r] for more details.
|
/// the plumbing README][r] for more details.
|
||||||
///
|
///
|
||||||
/// [r]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md#producer-callback
|
/// [r]: https://github.com/rayon-rs/rayon/blob/main/src/iter/plumbing/README.md#producer-callback
|
||||||
/// [FnOnce]: https://doc.rust-lang.org/std/ops/trait.FnOnce.html
|
/// [FnOnce]: https://doc.rust-lang.org/std/ops/trait.FnOnce.html
|
||||||
pub trait ProducerCallback<T> {
|
pub trait ProducerCallback<T> {
|
||||||
/// The type of value returned by this callback. Analogous to
|
/// The type of value returned by this callback. Analogous to
|
||||||
@@ -54,7 +53,7 @@ pub trait ProducerCallback<T> {
|
|||||||
/// constraints on a required IntoIterator trait, so we inline
|
/// constraints on a required IntoIterator trait, so we inline
|
||||||
/// IntoIterator here until that issue is fixed.
|
/// IntoIterator here until that issue is fixed.
|
||||||
///
|
///
|
||||||
/// [r]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md
|
/// [r]: https://github.com/rayon-rs/rayon/blob/main/src/iter/plumbing/README.md
|
||||||
/// [20671]: https://github.com/rust-lang/rust/issues/20671
|
/// [20671]: https://github.com/rust-lang/rust/issues/20671
|
||||||
pub trait Producer: Send + Sized {
|
pub trait Producer: Send + Sized {
|
||||||
/// The type of item that will be produced by this producer once
|
/// The type of item that will be produced by this producer once
|
||||||
@@ -121,7 +120,7 @@ pub trait Producer: Send + Sized {
|
|||||||
/// combine their two results into one. See [the `plumbing`
|
/// combine their two results into one. See [the `plumbing`
|
||||||
/// README][r] for further details.
|
/// README][r] for further details.
|
||||||
///
|
///
|
||||||
/// [r]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md
|
/// [r]: https://github.com/rayon-rs/rayon/blob/main/src/iter/plumbing/README.md
|
||||||
/// [fold]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.fold
|
/// [fold]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.fold
|
||||||
/// [`Folder`]: trait.Folder.html
|
/// [`Folder`]: trait.Folder.html
|
||||||
/// [`Producer`]: trait.Producer.html
|
/// [`Producer`]: trait.Producer.html
|
||||||
@@ -198,7 +197,7 @@ pub trait Folder<Item>: Sized {
|
|||||||
/// used to combine those two results into one. See [the `plumbing`
|
/// used to combine those two results into one. See [the `plumbing`
|
||||||
/// README][r] for further details.
|
/// README][r] for further details.
|
||||||
///
|
///
|
||||||
/// [r]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md
|
/// [r]: https://github.com/rayon-rs/rayon/blob/main/src/iter/plumbing/README.md
|
||||||
pub trait Reducer<Result> {
|
pub trait Reducer<Result> {
|
||||||
/// Reduce two final results into one; this is executed after a
|
/// Reduce two final results into one; this is executed after a
|
||||||
/// split.
|
/// split.
|
||||||
@@ -275,7 +274,7 @@ impl Splitter {
|
|||||||
if stolen {
|
if stolen {
|
||||||
// This job was stolen! Reset the number of desired splits to the
|
// This job was stolen! Reset the number of desired splits to the
|
||||||
// thread count, if that's more than we had remaining anyway.
|
// thread count, if that's more than we had remaining anyway.
|
||||||
self.splits = cmp::max(crate::current_num_threads(), self.splits / 2);
|
self.splits = Ord::max(crate::current_num_threads(), self.splits / 2);
|
||||||
true
|
true
|
||||||
} else if splits > 0 {
|
} else if splits > 0 {
|
||||||
// We have splits remaining, make it so.
|
// We have splits remaining, make it so.
|
||||||
@@ -313,14 +312,14 @@ impl LengthSplitter {
|
|||||||
fn new(min: usize, max: usize, len: usize) -> LengthSplitter {
|
fn new(min: usize, max: usize, len: usize) -> LengthSplitter {
|
||||||
let mut splitter = LengthSplitter {
|
let mut splitter = LengthSplitter {
|
||||||
inner: Splitter::new(),
|
inner: Splitter::new(),
|
||||||
min: cmp::max(min, 1),
|
min: Ord::max(min, 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Divide the given length by the max working length to get the minimum
|
// Divide the given length by the max working length to get the minimum
|
||||||
// number of splits we need to get under that max. This rounds down,
|
// number of splits we need to get under that max. This rounds down,
|
||||||
// but the splitter actually gives `next_power_of_two()` pieces anyway.
|
// but the splitter actually gives `next_power_of_two()` pieces anyway.
|
||||||
// e.g. len 12345 / max 100 = 123 min_splits -> 128 pieces.
|
// e.g. len 12345 / max 100 = 123 min_splits -> 128 pieces.
|
||||||
let min_splits = len / cmp::max(max, 1);
|
let min_splits = len / Ord::max(max, 1);
|
||||||
|
|
||||||
// Only update the value if it's not splitting enough already.
|
// Only update the value if it's not splitting enough already.
|
||||||
if min_splits > splitter.inner.splits {
|
if min_splits > splitter.inner.splits {
|
||||||
|
|||||||
2
third_party/rust/rayon/src/iter/product.rs
vendored
2
third_party/rust/rayon/src/iter/product.rs
vendored
@@ -13,7 +13,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn mul<T: Product>(left: T, right: T) -> T {
|
fn mul<T: Product>(left: T, right: T) -> T {
|
||||||
iter::once(left).chain(iter::once(right)).product()
|
[left, right].into_iter().product()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProductConsumer<P: Send> {
|
struct ProductConsumer<P: Send> {
|
||||||
|
|||||||
3
third_party/rust/rayon/src/iter/skip.rs
vendored
3
third_party/rust/rayon/src/iter/skip.rs
vendored
@@ -1,7 +1,6 @@
|
|||||||
use super::noop::NoopConsumer;
|
use super::noop::NoopConsumer;
|
||||||
use super::plumbing::*;
|
use super::plumbing::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::cmp::min;
|
|
||||||
|
|
||||||
/// `Skip` is an iterator that skips over the first `n` elements.
|
/// `Skip` is an iterator that skips over the first `n` elements.
|
||||||
/// This struct is created by the [`skip()`] method on [`IndexedParallelIterator`]
|
/// This struct is created by the [`skip()`] method on [`IndexedParallelIterator`]
|
||||||
@@ -21,7 +20,7 @@ where
|
|||||||
{
|
{
|
||||||
/// Creates a new `Skip` iterator.
|
/// Creates a new `Skip` iterator.
|
||||||
pub(super) fn new(base: I, n: usize) -> Self {
|
pub(super) fn new(base: I, n: usize) -> Self {
|
||||||
let n = min(base.len(), n);
|
let n = Ord::min(base.len(), n);
|
||||||
Skip { base, n }
|
Skip { base, n }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
144
third_party/rust/rayon/src/iter/skip_any.rs
vendored
Normal file
144
third_party/rust/rayon/src/iter/skip_any.rs
vendored
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
use super::plumbing::*;
|
||||||
|
use super::*;
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
|
/// `SkipAny` is an iterator that skips over `n` elements from anywhere in `I`.
|
||||||
|
/// This struct is created by the [`skip_any()`] method on [`ParallelIterator`]
|
||||||
|
///
|
||||||
|
/// [`skip_any()`]: trait.ParallelIterator.html#method.skip_any
|
||||||
|
/// [`ParallelIterator`]: trait.ParallelIterator.html
|
||||||
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct SkipAny<I: ParallelIterator> {
|
||||||
|
base: I,
|
||||||
|
count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> SkipAny<I>
|
||||||
|
where
|
||||||
|
I: ParallelIterator,
|
||||||
|
{
|
||||||
|
/// Creates a new `SkipAny` iterator.
|
||||||
|
pub(super) fn new(base: I, count: usize) -> Self {
|
||||||
|
SkipAny { base, count }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> ParallelIterator for SkipAny<I>
|
||||||
|
where
|
||||||
|
I: ParallelIterator,
|
||||||
|
{
|
||||||
|
type Item = I::Item;
|
||||||
|
|
||||||
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<Self::Item>,
|
||||||
|
{
|
||||||
|
let consumer1 = SkipAnyConsumer {
|
||||||
|
base: consumer,
|
||||||
|
count: &AtomicUsize::new(self.count),
|
||||||
|
};
|
||||||
|
self.base.drive_unindexed(consumer1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Consumer implementation
|
||||||
|
|
||||||
|
struct SkipAnyConsumer<'f, C> {
|
||||||
|
base: C,
|
||||||
|
count: &'f AtomicUsize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'f, T, C> Consumer<T> for SkipAnyConsumer<'f, C>
|
||||||
|
where
|
||||||
|
C: Consumer<T>,
|
||||||
|
T: Send,
|
||||||
|
{
|
||||||
|
type Folder = SkipAnyFolder<'f, C::Folder>;
|
||||||
|
type Reducer = C::Reducer;
|
||||||
|
type Result = C::Result;
|
||||||
|
|
||||||
|
fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
|
||||||
|
let (left, right, reducer) = self.base.split_at(index);
|
||||||
|
(
|
||||||
|
SkipAnyConsumer { base: left, ..self },
|
||||||
|
SkipAnyConsumer {
|
||||||
|
base: right,
|
||||||
|
..self
|
||||||
|
},
|
||||||
|
reducer,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_folder(self) -> Self::Folder {
|
||||||
|
SkipAnyFolder {
|
||||||
|
base: self.base.into_folder(),
|
||||||
|
count: self.count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn full(&self) -> bool {
|
||||||
|
self.base.full()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'f, T, C> UnindexedConsumer<T> for SkipAnyConsumer<'f, C>
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<T>,
|
||||||
|
T: Send,
|
||||||
|
{
|
||||||
|
fn split_off_left(&self) -> Self {
|
||||||
|
SkipAnyConsumer {
|
||||||
|
base: self.base.split_off_left(),
|
||||||
|
..*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_reducer(&self) -> Self::Reducer {
|
||||||
|
self.base.to_reducer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SkipAnyFolder<'f, C> {
|
||||||
|
base: C,
|
||||||
|
count: &'f AtomicUsize,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn checked_decrement(u: &AtomicUsize) -> bool {
|
||||||
|
u.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |u| u.checked_sub(1))
|
||||||
|
.is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'f, T, C> Folder<T> for SkipAnyFolder<'f, C>
|
||||||
|
where
|
||||||
|
C: Folder<T>,
|
||||||
|
{
|
||||||
|
type Result = C::Result;
|
||||||
|
|
||||||
|
fn consume(mut self, item: T) -> Self {
|
||||||
|
if !checked_decrement(self.count) {
|
||||||
|
self.base = self.base.consume(item);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn consume_iter<I>(mut self, iter: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = T>,
|
||||||
|
{
|
||||||
|
self.base = self.base.consume_iter(
|
||||||
|
iter.into_iter()
|
||||||
|
.skip_while(move |_| checked_decrement(self.count)),
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete(self) -> C::Result {
|
||||||
|
self.base.complete()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn full(&self) -> bool {
|
||||||
|
self.base.full()
|
||||||
|
}
|
||||||
|
}
|
||||||
166
third_party/rust/rayon/src/iter/skip_any_while.rs
vendored
Normal file
166
third_party/rust/rayon/src/iter/skip_any_while.rs
vendored
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
use super::plumbing::*;
|
||||||
|
use super::*;
|
||||||
|
use std::fmt;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
|
/// `SkipAnyWhile` is an iterator that skips over elements from anywhere in `I`
|
||||||
|
/// until the callback returns `false`.
|
||||||
|
/// This struct is created by the [`skip_any_while()`] method on [`ParallelIterator`]
|
||||||
|
///
|
||||||
|
/// [`skip_any_while()`]: trait.ParallelIterator.html#method.skip_any_while
|
||||||
|
/// [`ParallelIterator`]: trait.ParallelIterator.html
|
||||||
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SkipAnyWhile<I: ParallelIterator, P> {
|
||||||
|
base: I,
|
||||||
|
predicate: P,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: ParallelIterator + fmt::Debug, P> fmt::Debug for SkipAnyWhile<I, P> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("SkipAnyWhile")
|
||||||
|
.field("base", &self.base)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, P> SkipAnyWhile<I, P>
|
||||||
|
where
|
||||||
|
I: ParallelIterator,
|
||||||
|
{
|
||||||
|
/// Creates a new `SkipAnyWhile` iterator.
|
||||||
|
pub(super) fn new(base: I, predicate: P) -> Self {
|
||||||
|
SkipAnyWhile { base, predicate }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, P> ParallelIterator for SkipAnyWhile<I, P>
|
||||||
|
where
|
||||||
|
I: ParallelIterator,
|
||||||
|
P: Fn(&I::Item) -> bool + Sync + Send,
|
||||||
|
{
|
||||||
|
type Item = I::Item;
|
||||||
|
|
||||||
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<Self::Item>,
|
||||||
|
{
|
||||||
|
let consumer1 = SkipAnyWhileConsumer {
|
||||||
|
base: consumer,
|
||||||
|
predicate: &self.predicate,
|
||||||
|
skipping: &AtomicBool::new(true),
|
||||||
|
};
|
||||||
|
self.base.drive_unindexed(consumer1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Consumer implementation
|
||||||
|
|
||||||
|
struct SkipAnyWhileConsumer<'p, C, P> {
|
||||||
|
base: C,
|
||||||
|
predicate: &'p P,
|
||||||
|
skipping: &'p AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p, T, C, P> Consumer<T> for SkipAnyWhileConsumer<'p, C, P>
|
||||||
|
where
|
||||||
|
C: Consumer<T>,
|
||||||
|
P: Fn(&T) -> bool + Sync,
|
||||||
|
{
|
||||||
|
type Folder = SkipAnyWhileFolder<'p, C::Folder, P>;
|
||||||
|
type Reducer = C::Reducer;
|
||||||
|
type Result = C::Result;
|
||||||
|
|
||||||
|
fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
|
||||||
|
let (left, right, reducer) = self.base.split_at(index);
|
||||||
|
(
|
||||||
|
SkipAnyWhileConsumer { base: left, ..self },
|
||||||
|
SkipAnyWhileConsumer {
|
||||||
|
base: right,
|
||||||
|
..self
|
||||||
|
},
|
||||||
|
reducer,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_folder(self) -> Self::Folder {
|
||||||
|
SkipAnyWhileFolder {
|
||||||
|
base: self.base.into_folder(),
|
||||||
|
predicate: self.predicate,
|
||||||
|
skipping: self.skipping,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn full(&self) -> bool {
|
||||||
|
self.base.full()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p, T, C, P> UnindexedConsumer<T> for SkipAnyWhileConsumer<'p, C, P>
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<T>,
|
||||||
|
P: Fn(&T) -> bool + Sync,
|
||||||
|
{
|
||||||
|
fn split_off_left(&self) -> Self {
|
||||||
|
SkipAnyWhileConsumer {
|
||||||
|
base: self.base.split_off_left(),
|
||||||
|
..*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_reducer(&self) -> Self::Reducer {
|
||||||
|
self.base.to_reducer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SkipAnyWhileFolder<'p, C, P> {
|
||||||
|
base: C,
|
||||||
|
predicate: &'p P,
|
||||||
|
skipping: &'p AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn skip<T>(item: &T, skipping: &AtomicBool, predicate: &impl Fn(&T) -> bool) -> bool {
|
||||||
|
if !skipping.load(Ordering::Relaxed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if predicate(item) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
skipping.store(false, Ordering::Relaxed);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p, T, C, P> Folder<T> for SkipAnyWhileFolder<'p, C, P>
|
||||||
|
where
|
||||||
|
C: Folder<T>,
|
||||||
|
P: Fn(&T) -> bool + 'p,
|
||||||
|
{
|
||||||
|
type Result = C::Result;
|
||||||
|
|
||||||
|
fn consume(mut self, item: T) -> Self {
|
||||||
|
if !skip(&item, self.skipping, self.predicate) {
|
||||||
|
self.base = self.base.consume(item);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn consume_iter<I>(mut self, iter: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = T>,
|
||||||
|
{
|
||||||
|
self.base = self.base.consume_iter(
|
||||||
|
iter.into_iter()
|
||||||
|
.skip_while(move |x| skip(x, self.skipping, self.predicate)),
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete(self) -> C::Result {
|
||||||
|
self.base.complete()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn full(&self) -> bool {
|
||||||
|
self.base.full()
|
||||||
|
}
|
||||||
|
}
|
||||||
4
third_party/rust/rayon/src/iter/step_by.rs
vendored
4
third_party/rust/rayon/src/iter/step_by.rs
vendored
@@ -1,5 +1,3 @@
|
|||||||
use std::cmp::min;
|
|
||||||
|
|
||||||
use super::plumbing::*;
|
use super::plumbing::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::math::div_round_up;
|
use crate::math::div_round_up;
|
||||||
@@ -116,7 +114,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn split_at(self, index: usize) -> (Self, Self) {
|
fn split_at(self, index: usize) -> (Self, Self) {
|
||||||
let elem_index = min(index * self.step, self.len);
|
let elem_index = Ord::min(index * self.step, self.len);
|
||||||
|
|
||||||
let (left, right) = self.base.split_at(elem_index);
|
let (left, right) = self.base.split_at(elem_index);
|
||||||
(
|
(
|
||||||
|
|||||||
2
third_party/rust/rayon/src/iter/sum.rs
vendored
2
third_party/rust/rayon/src/iter/sum.rs
vendored
@@ -13,7 +13,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn add<T: Sum>(left: T, right: T) -> T {
|
fn add<T: Sum>(left: T, right: T) -> T {
|
||||||
iter::once(left).chain(iter::once(right)).sum()
|
[left, right].into_iter().sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SumConsumer<S: Send> {
|
struct SumConsumer<S: Send> {
|
||||||
|
|||||||
3
third_party/rust/rayon/src/iter/take.rs
vendored
3
third_party/rust/rayon/src/iter/take.rs
vendored
@@ -1,6 +1,5 @@
|
|||||||
use super::plumbing::*;
|
use super::plumbing::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::cmp::min;
|
|
||||||
|
|
||||||
/// `Take` is an iterator that iterates over the first `n` elements.
|
/// `Take` is an iterator that iterates over the first `n` elements.
|
||||||
/// This struct is created by the [`take()`] method on [`IndexedParallelIterator`]
|
/// This struct is created by the [`take()`] method on [`IndexedParallelIterator`]
|
||||||
@@ -20,7 +19,7 @@ where
|
|||||||
{
|
{
|
||||||
/// Creates a new `Take` iterator.
|
/// Creates a new `Take` iterator.
|
||||||
pub(super) fn new(base: I, n: usize) -> Self {
|
pub(super) fn new(base: I, n: usize) -> Self {
|
||||||
let n = min(base.len(), n);
|
let n = Ord::min(base.len(), n);
|
||||||
Take { base, n }
|
Take { base, n }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
144
third_party/rust/rayon/src/iter/take_any.rs
vendored
Normal file
144
third_party/rust/rayon/src/iter/take_any.rs
vendored
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
use super::plumbing::*;
|
||||||
|
use super::*;
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
|
/// `TakeAny` is an iterator that iterates over `n` elements from anywhere in `I`.
|
||||||
|
/// This struct is created by the [`take_any()`] method on [`ParallelIterator`]
|
||||||
|
///
|
||||||
|
/// [`take_any()`]: trait.ParallelIterator.html#method.take_any
|
||||||
|
/// [`ParallelIterator`]: trait.ParallelIterator.html
|
||||||
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct TakeAny<I: ParallelIterator> {
|
||||||
|
base: I,
|
||||||
|
count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> TakeAny<I>
|
||||||
|
where
|
||||||
|
I: ParallelIterator,
|
||||||
|
{
|
||||||
|
/// Creates a new `TakeAny` iterator.
|
||||||
|
pub(super) fn new(base: I, count: usize) -> Self {
|
||||||
|
TakeAny { base, count }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> ParallelIterator for TakeAny<I>
|
||||||
|
where
|
||||||
|
I: ParallelIterator,
|
||||||
|
{
|
||||||
|
type Item = I::Item;
|
||||||
|
|
||||||
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<Self::Item>,
|
||||||
|
{
|
||||||
|
let consumer1 = TakeAnyConsumer {
|
||||||
|
base: consumer,
|
||||||
|
count: &AtomicUsize::new(self.count),
|
||||||
|
};
|
||||||
|
self.base.drive_unindexed(consumer1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Consumer implementation
|
||||||
|
|
||||||
|
struct TakeAnyConsumer<'f, C> {
|
||||||
|
base: C,
|
||||||
|
count: &'f AtomicUsize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'f, T, C> Consumer<T> for TakeAnyConsumer<'f, C>
|
||||||
|
where
|
||||||
|
C: Consumer<T>,
|
||||||
|
T: Send,
|
||||||
|
{
|
||||||
|
type Folder = TakeAnyFolder<'f, C::Folder>;
|
||||||
|
type Reducer = C::Reducer;
|
||||||
|
type Result = C::Result;
|
||||||
|
|
||||||
|
fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
|
||||||
|
let (left, right, reducer) = self.base.split_at(index);
|
||||||
|
(
|
||||||
|
TakeAnyConsumer { base: left, ..self },
|
||||||
|
TakeAnyConsumer {
|
||||||
|
base: right,
|
||||||
|
..self
|
||||||
|
},
|
||||||
|
reducer,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_folder(self) -> Self::Folder {
|
||||||
|
TakeAnyFolder {
|
||||||
|
base: self.base.into_folder(),
|
||||||
|
count: self.count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn full(&self) -> bool {
|
||||||
|
self.count.load(Ordering::Relaxed) == 0 || self.base.full()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'f, T, C> UnindexedConsumer<T> for TakeAnyConsumer<'f, C>
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<T>,
|
||||||
|
T: Send,
|
||||||
|
{
|
||||||
|
fn split_off_left(&self) -> Self {
|
||||||
|
TakeAnyConsumer {
|
||||||
|
base: self.base.split_off_left(),
|
||||||
|
..*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_reducer(&self) -> Self::Reducer {
|
||||||
|
self.base.to_reducer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TakeAnyFolder<'f, C> {
|
||||||
|
base: C,
|
||||||
|
count: &'f AtomicUsize,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn checked_decrement(u: &AtomicUsize) -> bool {
|
||||||
|
u.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |u| u.checked_sub(1))
|
||||||
|
.is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'f, T, C> Folder<T> for TakeAnyFolder<'f, C>
|
||||||
|
where
|
||||||
|
C: Folder<T>,
|
||||||
|
{
|
||||||
|
type Result = C::Result;
|
||||||
|
|
||||||
|
fn consume(mut self, item: T) -> Self {
|
||||||
|
if checked_decrement(self.count) {
|
||||||
|
self.base = self.base.consume(item);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn consume_iter<I>(mut self, iter: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = T>,
|
||||||
|
{
|
||||||
|
self.base = self.base.consume_iter(
|
||||||
|
iter.into_iter()
|
||||||
|
.take_while(move |_| checked_decrement(self.count)),
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete(self) -> C::Result {
|
||||||
|
self.base.complete()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn full(&self) -> bool {
|
||||||
|
self.count.load(Ordering::Relaxed) == 0 || self.base.full()
|
||||||
|
}
|
||||||
|
}
|
||||||
166
third_party/rust/rayon/src/iter/take_any_while.rs
vendored
Normal file
166
third_party/rust/rayon/src/iter/take_any_while.rs
vendored
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
use super::plumbing::*;
|
||||||
|
use super::*;
|
||||||
|
use std::fmt;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
|
/// `TakeAnyWhile` is an iterator that iterates over elements from anywhere in `I`
|
||||||
|
/// until the callback returns `false`.
|
||||||
|
/// This struct is created by the [`take_any_while()`] method on [`ParallelIterator`]
|
||||||
|
///
|
||||||
|
/// [`take_any_while()`]: trait.ParallelIterator.html#method.take_any_while
|
||||||
|
/// [`ParallelIterator`]: trait.ParallelIterator.html
|
||||||
|
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct TakeAnyWhile<I: ParallelIterator, P> {
|
||||||
|
base: I,
|
||||||
|
predicate: P,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: ParallelIterator + fmt::Debug, P> fmt::Debug for TakeAnyWhile<I, P> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("TakeAnyWhile")
|
||||||
|
.field("base", &self.base)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, P> TakeAnyWhile<I, P>
|
||||||
|
where
|
||||||
|
I: ParallelIterator,
|
||||||
|
{
|
||||||
|
/// Creates a new `TakeAnyWhile` iterator.
|
||||||
|
pub(super) fn new(base: I, predicate: P) -> Self {
|
||||||
|
TakeAnyWhile { base, predicate }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, P> ParallelIterator for TakeAnyWhile<I, P>
|
||||||
|
where
|
||||||
|
I: ParallelIterator,
|
||||||
|
P: Fn(&I::Item) -> bool + Sync + Send,
|
||||||
|
{
|
||||||
|
type Item = I::Item;
|
||||||
|
|
||||||
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<Self::Item>,
|
||||||
|
{
|
||||||
|
let consumer1 = TakeAnyWhileConsumer {
|
||||||
|
base: consumer,
|
||||||
|
predicate: &self.predicate,
|
||||||
|
taking: &AtomicBool::new(true),
|
||||||
|
};
|
||||||
|
self.base.drive_unindexed(consumer1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ////////////////////////////////////////////////////////////////////////
|
||||||
|
/// Consumer implementation
|
||||||
|
|
||||||
|
struct TakeAnyWhileConsumer<'p, C, P> {
|
||||||
|
base: C,
|
||||||
|
predicate: &'p P,
|
||||||
|
taking: &'p AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p, T, C, P> Consumer<T> for TakeAnyWhileConsumer<'p, C, P>
|
||||||
|
where
|
||||||
|
C: Consumer<T>,
|
||||||
|
P: Fn(&T) -> bool + Sync,
|
||||||
|
{
|
||||||
|
type Folder = TakeAnyWhileFolder<'p, C::Folder, P>;
|
||||||
|
type Reducer = C::Reducer;
|
||||||
|
type Result = C::Result;
|
||||||
|
|
||||||
|
fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
|
||||||
|
let (left, right, reducer) = self.base.split_at(index);
|
||||||
|
(
|
||||||
|
TakeAnyWhileConsumer { base: left, ..self },
|
||||||
|
TakeAnyWhileConsumer {
|
||||||
|
base: right,
|
||||||
|
..self
|
||||||
|
},
|
||||||
|
reducer,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_folder(self) -> Self::Folder {
|
||||||
|
TakeAnyWhileFolder {
|
||||||
|
base: self.base.into_folder(),
|
||||||
|
predicate: self.predicate,
|
||||||
|
taking: self.taking,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn full(&self) -> bool {
|
||||||
|
!self.taking.load(Ordering::Relaxed) || self.base.full()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p, T, C, P> UnindexedConsumer<T> for TakeAnyWhileConsumer<'p, C, P>
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<T>,
|
||||||
|
P: Fn(&T) -> bool + Sync,
|
||||||
|
{
|
||||||
|
fn split_off_left(&self) -> Self {
|
||||||
|
TakeAnyWhileConsumer {
|
||||||
|
base: self.base.split_off_left(),
|
||||||
|
..*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_reducer(&self) -> Self::Reducer {
|
||||||
|
self.base.to_reducer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TakeAnyWhileFolder<'p, C, P> {
|
||||||
|
base: C,
|
||||||
|
predicate: &'p P,
|
||||||
|
taking: &'p AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take<T>(item: &T, taking: &AtomicBool, predicate: &impl Fn(&T) -> bool) -> bool {
|
||||||
|
if !taking.load(Ordering::Relaxed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if predicate(item) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
taking.store(false, Ordering::Relaxed);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p, T, C, P> Folder<T> for TakeAnyWhileFolder<'p, C, P>
|
||||||
|
where
|
||||||
|
C: Folder<T>,
|
||||||
|
P: Fn(&T) -> bool + 'p,
|
||||||
|
{
|
||||||
|
type Result = C::Result;
|
||||||
|
|
||||||
|
fn consume(mut self, item: T) -> Self {
|
||||||
|
if take(&item, self.taking, self.predicate) {
|
||||||
|
self.base = self.base.consume(item);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn consume_iter<I>(mut self, iter: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = T>,
|
||||||
|
{
|
||||||
|
self.base = self.base.consume_iter(
|
||||||
|
iter.into_iter()
|
||||||
|
.take_while(move |x| take(x, self.taking, self.predicate)),
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete(self) -> C::Result {
|
||||||
|
self.base.complete()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn full(&self) -> bool {
|
||||||
|
!self.taking.load(Ordering::Relaxed) || self.base.full()
|
||||||
|
}
|
||||||
|
}
|
||||||
170
third_party/rust/rayon/src/iter/test.rs
vendored
170
third_party/rust/rayon/src/iter/test.rs
vendored
@@ -7,10 +7,10 @@ use rayon_core::*;
|
|||||||
use rand::distributions::Standard;
|
use rand::distributions::Standard;
|
||||||
use rand::{Rng, SeedableRng};
|
use rand::{Rng, SeedableRng};
|
||||||
use rand_xorshift::XorShiftRng;
|
use rand_xorshift::XorShiftRng;
|
||||||
use std::collections::LinkedList;
|
|
||||||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||||
use std::collections::{BinaryHeap, VecDeque};
|
use std::collections::{BinaryHeap, VecDeque};
|
||||||
use std::f64;
|
use std::f64;
|
||||||
|
use std::ffi::OsStr;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::usize;
|
use std::usize;
|
||||||
@@ -60,8 +60,7 @@ fn execute_unindexed_range() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn execute_pseudo_indexed_range() {
|
fn execute_pseudo_indexed_range() {
|
||||||
use std::i128::MAX;
|
let range = i128::MAX - 1024..i128::MAX;
|
||||||
let range = MAX - 1024..MAX;
|
|
||||||
|
|
||||||
// Given `Some` length, collecting `Vec` will try to act indexed.
|
// Given `Some` length, collecting `Vec` will try to act indexed.
|
||||||
let a = range.clone().into_par_iter();
|
let a = range.clone().into_par_iter();
|
||||||
@@ -278,6 +277,7 @@ fn check_skip() {
|
|||||||
|
|
||||||
let mut v1 = Vec::new();
|
let mut v1 = Vec::new();
|
||||||
a.par_iter().skip(0).collect_into_vec(&mut v1);
|
a.par_iter().skip(0).collect_into_vec(&mut v1);
|
||||||
|
#[allow(clippy::iter_skip_zero)]
|
||||||
let v2 = a.iter().skip(0).collect::<Vec<_>>();
|
let v2 = a.iter().skip(0).collect::<Vec<_>>();
|
||||||
assert_eq!(v1, v2);
|
assert_eq!(v1, v2);
|
||||||
|
|
||||||
@@ -468,6 +468,7 @@ fn check_cmp_gt_to_seq() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
|
||||||
fn check_cmp_short_circuit() {
|
fn check_cmp_short_circuit() {
|
||||||
// We only use a single thread in order to make the short-circuit behavior deterministic.
|
// We only use a single thread in order to make the short-circuit behavior deterministic.
|
||||||
let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
|
let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
|
||||||
@@ -497,6 +498,7 @@ fn check_cmp_short_circuit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
|
||||||
fn check_partial_cmp_short_circuit() {
|
fn check_partial_cmp_short_circuit() {
|
||||||
// We only use a single thread to make the short-circuit behavior deterministic.
|
// We only use a single thread to make the short-circuit behavior deterministic.
|
||||||
let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
|
let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
|
||||||
@@ -526,6 +528,7 @@ fn check_partial_cmp_short_circuit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
|
||||||
fn check_partial_cmp_nan_short_circuit() {
|
fn check_partial_cmp_nan_short_circuit() {
|
||||||
// We only use a single thread to make the short-circuit behavior deterministic.
|
// We only use a single thread to make the short-circuit behavior deterministic.
|
||||||
let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
|
let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
|
||||||
@@ -626,7 +629,7 @@ fn check_partial_cmp_none_direct() {
|
|||||||
|
|
||||||
let result = a.par_iter().partial_cmp(b.par_iter());
|
let result = a.par_iter().partial_cmp(b.par_iter());
|
||||||
|
|
||||||
assert!(result == None);
|
assert!(result.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -651,7 +654,7 @@ fn check_partial_cmp_late_nan_direct() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_partial_cmp_late_nane_to_seq() {
|
fn check_partial_cmp_late_nan_to_seq() {
|
||||||
let a = vec![0.0, f64::NAN];
|
let a = vec![0.0, f64::NAN];
|
||||||
let b = vec![1.0, 1.0];
|
let b = vec![1.0, 1.0];
|
||||||
|
|
||||||
@@ -980,6 +983,25 @@ fn check_slice_split() {
|
|||||||
assert_eq!(v, &[&slice[..1], &slice[..0], &slice[3..]]);
|
assert_eq!(v, &[&slice[..1], &slice[..0], &slice[3..]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_slice_split_inclusive() {
|
||||||
|
let v: Vec<_> = (0..1000).collect();
|
||||||
|
for m in 1..100 {
|
||||||
|
let a: Vec<_> = v.split_inclusive(|x| x % m == 0).collect();
|
||||||
|
let b: Vec<_> = v.par_split_inclusive(|x| x % m == 0).collect();
|
||||||
|
assert_eq!(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// same as std::slice::split_inclusive() examples
|
||||||
|
let slice = [10, 40, 33, 20];
|
||||||
|
let v: Vec<_> = slice.par_split_inclusive(|num| num % 3 == 0).collect();
|
||||||
|
assert_eq!(v, &[&slice[..3], &slice[3..]]);
|
||||||
|
|
||||||
|
let slice = [3, 10, 40, 33];
|
||||||
|
let v: Vec<_> = slice.par_split_inclusive(|num| num % 3 == 0).collect();
|
||||||
|
assert_eq!(v, &[&slice[..1], &slice[1..]]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_slice_split_mut() {
|
fn check_slice_split_mut() {
|
||||||
let mut v1: Vec<_> = (0..1000).collect();
|
let mut v1: Vec<_> = (0..1000).collect();
|
||||||
@@ -998,6 +1020,26 @@ fn check_slice_split_mut() {
|
|||||||
assert_eq!(v, [1, 40, 30, 1, 60, 1]);
|
assert_eq!(v, [1, 40, 30, 1, 60, 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_slice_split_inclusive_mut() {
|
||||||
|
let mut v1: Vec<_> = (0..1000).collect();
|
||||||
|
let mut v2 = v1.clone();
|
||||||
|
for m in 1..100 {
|
||||||
|
let a: Vec<_> = v1.split_inclusive_mut(|x| x % m == 0).collect();
|
||||||
|
let b: Vec<_> = v2.par_split_inclusive_mut(|x| x % m == 0).collect();
|
||||||
|
assert_eq!(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// same as std::slice::split_inclusive_mut() example
|
||||||
|
let mut v = [10, 40, 30, 20, 60, 50];
|
||||||
|
v.par_split_inclusive_mut(|num| num % 3 == 0)
|
||||||
|
.for_each(|group| {
|
||||||
|
let terminator_idx = group.len() - 1;
|
||||||
|
group[terminator_idx] = 1;
|
||||||
|
});
|
||||||
|
assert_eq!(v, [10, 40, 1, 20, 1, 1]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_chunks() {
|
fn check_chunks() {
|
||||||
let a: Vec<i32> = vec![1, 5, 10, 4, 100, 3, 1000, 2, 10000, 1];
|
let a: Vec<i32> = vec![1, 5, 10, 4, 100, 3, 1000, 2, 10000, 1];
|
||||||
@@ -1526,13 +1568,27 @@ fn par_iter_collect_cows() {
|
|||||||
assert_eq!(a, b);
|
assert_eq!(a, b);
|
||||||
|
|
||||||
// Collects `str` into a `String`
|
// Collects `str` into a `String`
|
||||||
let a: Cow<'_, str> = s.split_whitespace().collect();
|
let sw = s.split_whitespace();
|
||||||
let b: Cow<'_, str> = s.par_split_whitespace().collect();
|
let psw = s.par_split_whitespace();
|
||||||
|
let a: Cow<'_, str> = sw.clone().collect();
|
||||||
|
let b: Cow<'_, str> = psw.clone().collect();
|
||||||
assert_eq!(a, b);
|
assert_eq!(a, b);
|
||||||
|
|
||||||
// Collects `String` into a `String`
|
// Collects `String` into a `String`
|
||||||
let a: Cow<'_, str> = s.split_whitespace().map(str::to_owned).collect();
|
let a: Cow<'_, str> = sw.map(str::to_owned).collect();
|
||||||
let b: Cow<'_, str> = s.par_split_whitespace().map(str::to_owned).collect();
|
let b: Cow<'_, str> = psw.map(str::to_owned).collect();
|
||||||
|
assert_eq!(a, b);
|
||||||
|
|
||||||
|
// Collects `OsStr` into a `OsString`
|
||||||
|
let sw = s.split_whitespace().map(OsStr::new);
|
||||||
|
let psw = s.par_split_whitespace().map(OsStr::new);
|
||||||
|
let a: Cow<'_, OsStr> = Cow::Owned(sw.clone().collect());
|
||||||
|
let b: Cow<'_, OsStr> = psw.clone().collect();
|
||||||
|
assert_eq!(a, b);
|
||||||
|
|
||||||
|
// Collects `OsString` into a `OsString`
|
||||||
|
let a: Cow<'_, OsStr> = Cow::Owned(sw.map(OsStr::to_owned).collect());
|
||||||
|
let b: Cow<'_, OsStr> = psw.map(OsStr::to_owned).collect();
|
||||||
assert_eq!(a, b);
|
assert_eq!(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1651,8 +1707,8 @@ fn check_lengths() {
|
|||||||
let range = 0..1024 * 1024;
|
let range = 0..1024 * 1024;
|
||||||
|
|
||||||
// Check against normalized values.
|
// Check against normalized values.
|
||||||
let min_check = cmp::min(cmp::max(min, 1), range.len());
|
let min_check = Ord::min(Ord::max(min, 1), range.len());
|
||||||
let max_check = cmp::max(max, min_check.saturating_add(min_check - 1));
|
let max_check = Ord::max(max, min_check.saturating_add(min_check - 1));
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
range
|
range
|
||||||
@@ -2183,3 +2239,95 @@ fn check_update() {
|
|||||||
|
|
||||||
assert_eq!(v, vec![vec![1, 0], vec![3, 2, 1, 0]]);
|
assert_eq!(v, vec![vec![1, 0], vec![3, 2, 1, 0]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn walk_tree_prefix() {
|
||||||
|
let v: Vec<u32> = crate::iter::walk_tree_prefix(0u32..100, |r| {
|
||||||
|
// root is smallest
|
||||||
|
let mid = (r.start + 1 + r.end) / 2;
|
||||||
|
// small indices to the left, large to the right
|
||||||
|
std::iter::once((r.start + 1)..mid)
|
||||||
|
.chain(std::iter::once(mid..r.end))
|
||||||
|
.filter(|r| !r.is_empty())
|
||||||
|
})
|
||||||
|
.map(|r| r.start)
|
||||||
|
.collect();
|
||||||
|
assert!(v.into_iter().eq(0..100));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn walk_tree_postfix() {
|
||||||
|
let v: Vec<_> = crate::iter::walk_tree_postfix(0u64..100, |r| {
|
||||||
|
// root is largest
|
||||||
|
let mid = (r.start + r.end - 1) / 2;
|
||||||
|
// small indices to the left, large to the right
|
||||||
|
std::iter::once(r.start..mid)
|
||||||
|
.chain(std::iter::once(mid..(r.end - 1)))
|
||||||
|
.filter(|r| !r.is_empty())
|
||||||
|
})
|
||||||
|
.map(|r| r.end - 1)
|
||||||
|
.collect();
|
||||||
|
assert!(v.into_iter().eq(0..100));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn walk_flat_tree_prefix() {
|
||||||
|
let v: Vec<_> =
|
||||||
|
crate::iter::walk_tree_prefix(0, |&e| if e < 99 { Some(e + 1) } else { None }).collect();
|
||||||
|
assert!(v.into_iter().eq(0..100));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn walk_flat_tree_postfix() {
|
||||||
|
let v: Vec<_> =
|
||||||
|
crate::iter::walk_tree_postfix(99, |&e| if e > 0 { Some(e - 1) } else { None }).collect();
|
||||||
|
assert!(v.into_iter().eq(0..100));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn walk_tree_prefix_degree5() {
|
||||||
|
let depth = 5;
|
||||||
|
let nodes_number = (1 - 5i32.pow(depth)) / (1 - 5);
|
||||||
|
let nodes = (0..nodes_number).collect::<Vec<_>>();
|
||||||
|
let v: Vec<i32> = crate::iter::walk_tree_prefix(nodes.as_slice(), |&r| {
|
||||||
|
r.split_first()
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(_, r)| if r.is_empty() { None } else { Some(r) })
|
||||||
|
.flat_map(|r| r.chunks(r.len() / 5))
|
||||||
|
})
|
||||||
|
.filter_map(|r| r.first().copied())
|
||||||
|
.collect();
|
||||||
|
assert_eq!(v, nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn walk_tree_postfix_degree5() {
|
||||||
|
let depth = 5;
|
||||||
|
let nodes_number = (1 - 5i32.pow(depth)) / (1 - 5);
|
||||||
|
let nodes = (0..nodes_number).collect::<Vec<_>>();
|
||||||
|
let v: Vec<i32> = crate::iter::walk_tree_postfix(nodes.as_slice(), |&r| {
|
||||||
|
r.split_last()
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(_, r)| if r.is_empty() { None } else { Some(r) })
|
||||||
|
.flat_map(|r| r.chunks(r.len() / 5))
|
||||||
|
})
|
||||||
|
.filter_map(|r| r.last().copied())
|
||||||
|
.collect();
|
||||||
|
assert_eq!(v, nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn blocks() {
|
||||||
|
let count = AtomicUsize::new(0);
|
||||||
|
let v: Vec<usize> = (0..1000)
|
||||||
|
.into_par_iter()
|
||||||
|
.map(|_| count.fetch_add(1, Ordering::Relaxed))
|
||||||
|
.by_uniform_blocks(100)
|
||||||
|
.collect();
|
||||||
|
let m = v
|
||||||
|
.chunks(100)
|
||||||
|
.map(|c| c.iter().max().copied().unwrap())
|
||||||
|
.collect::<Vec<usize>>();
|
||||||
|
assert!(m.windows(2).all(|w| w[0].lt(&w[1])));
|
||||||
|
assert_eq!(v.len(), 1000);
|
||||||
|
}
|
||||||
|
|||||||
529
third_party/rust/rayon/src/iter/walk_tree.rs
vendored
Normal file
529
third_party/rust/rayon/src/iter/walk_tree.rs
vendored
Normal file
@@ -0,0 +1,529 @@
|
|||||||
|
use crate::iter::plumbing::{bridge_unindexed, Folder, UnindexedConsumer, UnindexedProducer};
|
||||||
|
use crate::prelude::*;
|
||||||
|
use std::iter::once;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct WalkTreePrefixProducer<'b, S, B> {
|
||||||
|
to_explore: Vec<S>, // nodes (and subtrees) we have to process
|
||||||
|
seen: Vec<S>, // nodes which have already been explored
|
||||||
|
children_of: &'b B, // function generating children
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, B, I> UnindexedProducer for WalkTreePrefixProducer<'_, S, B>
|
||||||
|
where
|
||||||
|
S: Send,
|
||||||
|
B: Fn(&S) -> I + Send + Sync,
|
||||||
|
I: IntoIterator<Item = S>,
|
||||||
|
I::IntoIter: DoubleEndedIterator,
|
||||||
|
{
|
||||||
|
type Item = S;
|
||||||
|
|
||||||
|
fn split(mut self) -> (Self, Option<Self>) {
|
||||||
|
// explore while front is of size one.
|
||||||
|
while self.to_explore.len() == 1 {
|
||||||
|
let front_node = self.to_explore.pop().unwrap();
|
||||||
|
self.to_explore
|
||||||
|
.extend((self.children_of)(&front_node).into_iter().rev());
|
||||||
|
self.seen.push(front_node);
|
||||||
|
}
|
||||||
|
// now take half of the front.
|
||||||
|
let right_children = split_vec(&mut self.to_explore);
|
||||||
|
let right = right_children
|
||||||
|
.map(|mut c| {
|
||||||
|
std::mem::swap(&mut c, &mut self.to_explore);
|
||||||
|
WalkTreePrefixProducer {
|
||||||
|
to_explore: c,
|
||||||
|
seen: Vec::new(),
|
||||||
|
children_of: self.children_of,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
// we can still try to divide 'seen'
|
||||||
|
let right_seen = split_vec(&mut self.seen);
|
||||||
|
right_seen.map(|s| WalkTreePrefixProducer {
|
||||||
|
to_explore: Default::default(),
|
||||||
|
seen: s,
|
||||||
|
children_of: self.children_of,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
(self, right)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_with<F>(mut self, mut folder: F) -> F
|
||||||
|
where
|
||||||
|
F: Folder<Self::Item>,
|
||||||
|
{
|
||||||
|
// start by consuming everything seen
|
||||||
|
folder = folder.consume_iter(self.seen);
|
||||||
|
if folder.full() {
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
// now do all remaining explorations
|
||||||
|
while let Some(e) = self.to_explore.pop() {
|
||||||
|
self.to_explore
|
||||||
|
.extend((self.children_of)(&e).into_iter().rev());
|
||||||
|
folder = folder.consume(e);
|
||||||
|
if folder.full() {
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
folder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ParallelIterator for arbitrary tree-shaped patterns.
|
||||||
|
/// Returned by the [`walk_tree_prefix()`] function.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WalkTreePrefix<S, B> {
|
||||||
|
initial_state: S,
|
||||||
|
children_of: B,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, B, I> ParallelIterator for WalkTreePrefix<S, B>
|
||||||
|
where
|
||||||
|
S: Send,
|
||||||
|
B: Fn(&S) -> I + Send + Sync,
|
||||||
|
I: IntoIterator<Item = S>,
|
||||||
|
I::IntoIter: DoubleEndedIterator,
|
||||||
|
{
|
||||||
|
type Item = S;
|
||||||
|
|
||||||
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<Self::Item>,
|
||||||
|
{
|
||||||
|
let producer = WalkTreePrefixProducer {
|
||||||
|
to_explore: once(self.initial_state).collect(),
|
||||||
|
seen: Vec::new(),
|
||||||
|
children_of: &self.children_of,
|
||||||
|
};
|
||||||
|
bridge_unindexed(producer, consumer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a tree-like prefix parallel iterator from an initial root node.
|
||||||
|
/// The `children_of` function should take a node and return an iterator over its child nodes.
|
||||||
|
/// The best parallelization is obtained when the tree is balanced
|
||||||
|
/// but we should also be able to handle harder cases.
|
||||||
|
///
|
||||||
|
/// # Ordering
|
||||||
|
///
|
||||||
|
/// This function guarantees a prefix ordering. See also [`walk_tree_postfix`],
|
||||||
|
/// which guarantees a postfix order.
|
||||||
|
/// If you don't care about ordering, you should use [`walk_tree`],
|
||||||
|
/// which will use whatever is believed to be fastest.
|
||||||
|
/// For example a perfect binary tree of 7 nodes will reduced in the following order:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// a
|
||||||
|
/// / \
|
||||||
|
/// / \
|
||||||
|
/// b c
|
||||||
|
/// / \ / \
|
||||||
|
/// d e f g
|
||||||
|
///
|
||||||
|
/// reduced as a,b,d,e,c,f,g
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// 4
|
||||||
|
/// / \
|
||||||
|
/// / \
|
||||||
|
/// 2 3
|
||||||
|
/// / \
|
||||||
|
/// 1 2
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::iter::walk_tree_prefix;
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
///
|
||||||
|
/// let par_iter = walk_tree_prefix(4, |&e| {
|
||||||
|
/// if e <= 2 {
|
||||||
|
/// Vec::new()
|
||||||
|
/// } else {
|
||||||
|
/// vec![e / 2, e / 2 + 1]
|
||||||
|
/// }
|
||||||
|
/// });
|
||||||
|
/// assert_eq!(par_iter.sum::<u32>(), 12);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
/// use rayon::iter::walk_tree_prefix;
|
||||||
|
///
|
||||||
|
/// struct Node {
|
||||||
|
/// content: u32,
|
||||||
|
/// left: Option<Box<Node>>,
|
||||||
|
/// right: Option<Box<Node>>,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Here we loop on the following tree:
|
||||||
|
/// //
|
||||||
|
/// // 10
|
||||||
|
/// // / \
|
||||||
|
/// // / \
|
||||||
|
/// // 3 14
|
||||||
|
/// // \
|
||||||
|
/// // \
|
||||||
|
/// // 18
|
||||||
|
///
|
||||||
|
/// let root = Node {
|
||||||
|
/// content: 10,
|
||||||
|
/// left: Some(Box::new(Node {
|
||||||
|
/// content: 3,
|
||||||
|
/// left: None,
|
||||||
|
/// right: None,
|
||||||
|
/// })),
|
||||||
|
/// right: Some(Box::new(Node {
|
||||||
|
/// content: 14,
|
||||||
|
/// left: None,
|
||||||
|
/// right: Some(Box::new(Node {
|
||||||
|
/// content: 18,
|
||||||
|
/// left: None,
|
||||||
|
/// right: None,
|
||||||
|
/// })),
|
||||||
|
/// })),
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// let mut v: Vec<u32> = walk_tree_prefix(&root, |r| {
|
||||||
|
/// r.left
|
||||||
|
/// .as_ref()
|
||||||
|
/// .into_iter()
|
||||||
|
/// .chain(r.right.as_ref())
|
||||||
|
/// .map(|n| &**n)
|
||||||
|
/// })
|
||||||
|
/// .map(|node| node.content)
|
||||||
|
/// .collect();
|
||||||
|
/// assert_eq!(v, vec![10, 3, 14, 18]);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn walk_tree_prefix<S, B, I>(root: S, children_of: B) -> WalkTreePrefix<S, B>
|
||||||
|
where
|
||||||
|
S: Send,
|
||||||
|
B: Fn(&S) -> I + Send + Sync,
|
||||||
|
I: IntoIterator<Item = S>,
|
||||||
|
I::IntoIter: DoubleEndedIterator,
|
||||||
|
{
|
||||||
|
WalkTreePrefix {
|
||||||
|
initial_state: root,
|
||||||
|
children_of,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// post fix
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct WalkTreePostfixProducer<'b, S, B> {
|
||||||
|
to_explore: Vec<S>, // nodes (and subtrees) we have to process
|
||||||
|
seen: Vec<S>, // nodes which have already been explored
|
||||||
|
children_of: &'b B, // function generating children
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, B, I> UnindexedProducer for WalkTreePostfixProducer<'_, S, B>
|
||||||
|
where
|
||||||
|
S: Send,
|
||||||
|
B: Fn(&S) -> I + Send + Sync,
|
||||||
|
I: IntoIterator<Item = S>,
|
||||||
|
{
|
||||||
|
type Item = S;
|
||||||
|
|
||||||
|
fn split(mut self) -> (Self, Option<Self>) {
|
||||||
|
// explore while front is of size one.
|
||||||
|
while self.to_explore.len() == 1 {
|
||||||
|
let front_node = self.to_explore.pop().unwrap();
|
||||||
|
self.to_explore
|
||||||
|
.extend((self.children_of)(&front_node).into_iter());
|
||||||
|
self.seen.push(front_node);
|
||||||
|
}
|
||||||
|
// now take half of the front.
|
||||||
|
let right_children = split_vec(&mut self.to_explore);
|
||||||
|
let right = right_children
|
||||||
|
.map(|c| {
|
||||||
|
let right_seen = std::mem::take(&mut self.seen); // postfix -> upper nodes are processed last
|
||||||
|
WalkTreePostfixProducer {
|
||||||
|
to_explore: c,
|
||||||
|
seen: right_seen,
|
||||||
|
children_of: self.children_of,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
// we can still try to divide 'seen'
|
||||||
|
let right_seen = split_vec(&mut self.seen);
|
||||||
|
right_seen.map(|mut s| {
|
||||||
|
std::mem::swap(&mut self.seen, &mut s);
|
||||||
|
WalkTreePostfixProducer {
|
||||||
|
to_explore: Default::default(),
|
||||||
|
seen: s,
|
||||||
|
children_of: self.children_of,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
(self, right)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_with<F>(self, mut folder: F) -> F
|
||||||
|
where
|
||||||
|
F: Folder<Self::Item>,
|
||||||
|
{
|
||||||
|
// now do all remaining explorations
|
||||||
|
for e in self.to_explore {
|
||||||
|
folder = consume_rec_postfix(&self.children_of, e, folder);
|
||||||
|
if folder.full() {
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end by consuming everything seen
|
||||||
|
folder.consume_iter(self.seen.into_iter().rev())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn consume_rec_postfix<F, S, B, I>(children_of: &B, s: S, mut folder: F) -> F
|
||||||
|
where
|
||||||
|
F: Folder<S>,
|
||||||
|
B: Fn(&S) -> I,
|
||||||
|
I: IntoIterator<Item = S>,
|
||||||
|
{
|
||||||
|
let children = (children_of)(&s).into_iter();
|
||||||
|
for child in children {
|
||||||
|
folder = consume_rec_postfix(children_of, child, folder);
|
||||||
|
if folder.full() {
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
folder.consume(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ParallelIterator for arbitrary tree-shaped patterns.
|
||||||
|
/// Returned by the [`walk_tree_postfix()`] function.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WalkTreePostfix<S, B> {
|
||||||
|
initial_state: S,
|
||||||
|
children_of: B,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, B, I> ParallelIterator for WalkTreePostfix<S, B>
|
||||||
|
where
|
||||||
|
S: Send,
|
||||||
|
B: Fn(&S) -> I + Send + Sync,
|
||||||
|
I: IntoIterator<Item = S>,
|
||||||
|
{
|
||||||
|
type Item = S;
|
||||||
|
|
||||||
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<Self::Item>,
|
||||||
|
{
|
||||||
|
let producer = WalkTreePostfixProducer {
|
||||||
|
to_explore: once(self.initial_state).collect(),
|
||||||
|
seen: Vec::new(),
|
||||||
|
children_of: &self.children_of,
|
||||||
|
};
|
||||||
|
bridge_unindexed(producer, consumer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Divide given vector in two equally sized vectors.
|
||||||
|
/// Return `None` if initial size is <=1.
|
||||||
|
/// We return the first half and keep the last half in `v`.
|
||||||
|
fn split_vec<T>(v: &mut Vec<T>) -> Option<Vec<T>> {
|
||||||
|
if v.len() <= 1 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let n = v.len() / 2;
|
||||||
|
Some(v.split_off(n))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a tree like postfix parallel iterator from an initial root node.
|
||||||
|
/// The `children_of` function should take a node and iterate on all of its child nodes.
|
||||||
|
/// The best parallelization is obtained when the tree is balanced
|
||||||
|
/// but we should also be able to handle harder cases.
|
||||||
|
///
|
||||||
|
/// # Ordering
|
||||||
|
///
|
||||||
|
/// This function guarantees a postfix ordering. See also [`walk_tree_prefix`] which guarantees a
|
||||||
|
/// prefix order. If you don't care about ordering, you should use [`walk_tree`], which will use
|
||||||
|
/// whatever is believed to be fastest.
|
||||||
|
///
|
||||||
|
/// Between siblings, children are reduced in order -- that is first children are reduced first.
|
||||||
|
///
|
||||||
|
/// For example a perfect binary tree of 7 nodes will reduced in the following order:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// a
|
||||||
|
/// / \
|
||||||
|
/// / \
|
||||||
|
/// b c
|
||||||
|
/// / \ / \
|
||||||
|
/// d e f g
|
||||||
|
///
|
||||||
|
/// reduced as d,e,b,f,g,c,a
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// 4
|
||||||
|
/// / \
|
||||||
|
/// / \
|
||||||
|
/// 2 3
|
||||||
|
/// / \
|
||||||
|
/// 1 2
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::iter::walk_tree_postfix;
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
///
|
||||||
|
/// let par_iter = walk_tree_postfix(4, |&e| {
|
||||||
|
/// if e <= 2 {
|
||||||
|
/// Vec::new()
|
||||||
|
/// } else {
|
||||||
|
/// vec![e / 2, e / 2 + 1]
|
||||||
|
/// }
|
||||||
|
/// });
|
||||||
|
/// assert_eq!(par_iter.sum::<u32>(), 12);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
/// use rayon::iter::walk_tree_postfix;
|
||||||
|
///
|
||||||
|
/// struct Node {
|
||||||
|
/// content: u32,
|
||||||
|
/// left: Option<Box<Node>>,
|
||||||
|
/// right: Option<Box<Node>>,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Here we loop on the following tree:
|
||||||
|
/// //
|
||||||
|
/// // 10
|
||||||
|
/// // / \
|
||||||
|
/// // / \
|
||||||
|
/// // 3 14
|
||||||
|
/// // \
|
||||||
|
/// // \
|
||||||
|
/// // 18
|
||||||
|
///
|
||||||
|
/// let root = Node {
|
||||||
|
/// content: 10,
|
||||||
|
/// left: Some(Box::new(Node {
|
||||||
|
/// content: 3,
|
||||||
|
/// left: None,
|
||||||
|
/// right: None,
|
||||||
|
/// })),
|
||||||
|
/// right: Some(Box::new(Node {
|
||||||
|
/// content: 14,
|
||||||
|
/// left: None,
|
||||||
|
/// right: Some(Box::new(Node {
|
||||||
|
/// content: 18,
|
||||||
|
/// left: None,
|
||||||
|
/// right: None,
|
||||||
|
/// })),
|
||||||
|
/// })),
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// let mut v: Vec<u32> = walk_tree_postfix(&root, |r| {
|
||||||
|
/// r.left
|
||||||
|
/// .as_ref()
|
||||||
|
/// .into_iter()
|
||||||
|
/// .chain(r.right.as_ref())
|
||||||
|
/// .map(|n| &**n)
|
||||||
|
/// })
|
||||||
|
/// .map(|node| node.content)
|
||||||
|
/// .collect();
|
||||||
|
/// assert_eq!(v, vec![3, 18, 14, 10]);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn walk_tree_postfix<S, B, I>(root: S, children_of: B) -> WalkTreePostfix<S, B>
|
||||||
|
where
|
||||||
|
S: Send,
|
||||||
|
B: Fn(&S) -> I + Send + Sync,
|
||||||
|
I: IntoIterator<Item = S>,
|
||||||
|
{
|
||||||
|
WalkTreePostfix {
|
||||||
|
initial_state: root,
|
||||||
|
children_of,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ParallelIterator for arbitrary tree-shaped patterns.
|
||||||
|
/// Returned by the [`walk_tree()`] function.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WalkTree<S, B>(WalkTreePostfix<S, B>);
|
||||||
|
|
||||||
|
/// Create a tree like parallel iterator from an initial root node.
|
||||||
|
/// The `children_of` function should take a node and iterate on all of its child nodes.
|
||||||
|
/// The best parallelization is obtained when the tree is balanced
|
||||||
|
/// but we should also be able to handle harder cases.
|
||||||
|
///
|
||||||
|
/// # Ordering
|
||||||
|
///
|
||||||
|
/// This function does not guarantee any ordering but will
|
||||||
|
/// use whatever algorithm is thought to achieve the fastest traversal.
|
||||||
|
/// See also [`walk_tree_prefix`] which guarantees a
|
||||||
|
/// prefix order and [`walk_tree_postfix`] which guarantees a postfix order.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// 4
|
||||||
|
/// / \
|
||||||
|
/// / \
|
||||||
|
/// 2 3
|
||||||
|
/// / \
|
||||||
|
/// 1 2
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::iter::walk_tree;
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
///
|
||||||
|
/// let par_iter = walk_tree(4, |&e| {
|
||||||
|
/// if e <= 2 {
|
||||||
|
/// Vec::new()
|
||||||
|
/// } else {
|
||||||
|
/// vec![e / 2, e / 2 + 1]
|
||||||
|
/// }
|
||||||
|
/// });
|
||||||
|
/// assert_eq!(par_iter.sum::<u32>(), 12);
|
||||||
|
/// ```
|
||||||
|
pub fn walk_tree<S, B, I>(root: S, children_of: B) -> WalkTree<S, B>
|
||||||
|
where
|
||||||
|
S: Send,
|
||||||
|
B: Fn(&S) -> I + Send + Sync,
|
||||||
|
I: IntoIterator<Item = S>,
|
||||||
|
I::IntoIter: DoubleEndedIterator,
|
||||||
|
{
|
||||||
|
let walker = WalkTreePostfix {
|
||||||
|
initial_state: root,
|
||||||
|
children_of,
|
||||||
|
};
|
||||||
|
WalkTree(walker)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, B, I> ParallelIterator for WalkTree<S, B>
|
||||||
|
where
|
||||||
|
S: Send,
|
||||||
|
B: Fn(&S) -> I + Send + Sync,
|
||||||
|
I: IntoIterator<Item = S> + Send,
|
||||||
|
I::IntoIter: DoubleEndedIterator,
|
||||||
|
{
|
||||||
|
type Item = S;
|
||||||
|
|
||||||
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<Self::Item>,
|
||||||
|
{
|
||||||
|
self.0.drive_unindexed(consumer)
|
||||||
|
}
|
||||||
|
}
|
||||||
7
third_party/rust/rayon/src/iter/zip.rs
vendored
7
third_party/rust/rayon/src/iter/zip.rs
vendored
@@ -1,6 +1,5 @@
|
|||||||
use super::plumbing::*;
|
use super::plumbing::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::cmp;
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
/// `Zip` is an iterator that zips up `a` and `b` into a single iterator
|
/// `Zip` is an iterator that zips up `a` and `b` into a single iterator
|
||||||
@@ -59,7 +58,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
cmp::min(self.a.len(), self.b.len())
|
Ord::min(self.a.len(), self.b.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_producer<CB>(self, callback: CB) -> CB::Output
|
fn with_producer<CB>(self, callback: CB) -> CB::Output
|
||||||
@@ -135,11 +134,11 @@ impl<A: Producer, B: Producer> Producer for ZipProducer<A, B> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn min_len(&self) -> usize {
|
fn min_len(&self) -> usize {
|
||||||
cmp::max(self.a.min_len(), self.b.min_len())
|
Ord::max(self.a.min_len(), self.b.min_len())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn max_len(&self) -> usize {
|
fn max_len(&self) -> usize {
|
||||||
cmp::min(self.a.max_len(), self.b.max_len())
|
Ord::min(self.a.max_len(), self.b.max_len())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn split_at(self, index: usize) -> (Self, Self) {
|
fn split_at(self, index: usize) -> (Self, Self) {
|
||||||
|
|||||||
16
third_party/rust/rayon/src/lib.rs
vendored
16
third_party/rust/rayon/src/lib.rs
vendored
@@ -3,10 +3,10 @@
|
|||||||
#![deny(unreachable_pub)]
|
#![deny(unreachable_pub)]
|
||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
|
|
||||||
//! Data-parallelism library that makes it easy to convert sequential
|
//! Rayon is a data-parallelism library that makes it easy to convert sequential
|
||||||
//! computations into parallel
|
//! computations into parallel.
|
||||||
//!
|
//!
|
||||||
//! Rayon is lightweight and convenient for introducing parallelism into existing
|
//! It is lightweight and convenient for introducing parallelism into existing
|
||||||
//! code. It guarantees data-race free executions and takes advantage of
|
//! code. It guarantees data-race free executions and takes advantage of
|
||||||
//! parallelism when sensible, based on work-load at runtime.
|
//! parallelism when sensible, based on work-load at runtime.
|
||||||
//!
|
//!
|
||||||
@@ -76,11 +76,16 @@
|
|||||||
//! [the `collections` from `std`]: https://doc.rust-lang.org/std/collections/index.html
|
//! [the `collections` from `std`]: https://doc.rust-lang.org/std/collections/index.html
|
||||||
//! [`std`]: https://doc.rust-lang.org/std/
|
//! [`std`]: https://doc.rust-lang.org/std/
|
||||||
//!
|
//!
|
||||||
|
//! # Targets without threading
|
||||||
|
//!
|
||||||
|
//! Rayon has limited support for targets without `std` threading implementations.
|
||||||
|
//! See the [`rayon_core`] documentation for more information about its global fallback.
|
||||||
|
//!
|
||||||
//! # Other questions?
|
//! # Other questions?
|
||||||
//!
|
//!
|
||||||
//! See [the Rayon FAQ][faq].
|
//! See [the Rayon FAQ][faq].
|
||||||
//!
|
//!
|
||||||
//! [faq]: https://github.com/rayon-rs/rayon/blob/master/FAQ.md
|
//! [faq]: https://github.com/rayon-rs/rayon/blob/main/FAQ.md
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod delegate;
|
mod delegate;
|
||||||
@@ -119,6 +124,7 @@ pub use rayon_core::{in_place_scope, scope, Scope};
|
|||||||
pub use rayon_core::{in_place_scope_fifo, scope_fifo, ScopeFifo};
|
pub use rayon_core::{in_place_scope_fifo, scope_fifo, ScopeFifo};
|
||||||
pub use rayon_core::{join, join_context};
|
pub use rayon_core::{join, join_context};
|
||||||
pub use rayon_core::{spawn, spawn_fifo};
|
pub use rayon_core::{spawn, spawn_fifo};
|
||||||
|
pub use rayon_core::{yield_local, yield_now, Yield};
|
||||||
|
|
||||||
/// We need to transmit raw pointers across threads. It is possible to do this
|
/// We need to transmit raw pointers across threads. It is possible to do this
|
||||||
/// without any unsafe code by converting pointers to usize or to AtomicPtr<T>
|
/// without any unsafe code by converting pointers to usize or to AtomicPtr<T>
|
||||||
@@ -146,7 +152,7 @@ impl<T> SendPtr<T> {
|
|||||||
// Implement Clone without the T: Clone bound from the derive
|
// Implement Clone without the T: Clone bound from the derive
|
||||||
impl<T> Clone for SendPtr<T> {
|
impl<T> Clone for SendPtr<T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self(self.0)
|
*self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
8
third_party/rust/rayon/src/range.rs
vendored
8
third_party/rust/rayon/src/range.rs
vendored
@@ -18,10 +18,7 @@
|
|||||||
|
|
||||||
use crate::iter::plumbing::*;
|
use crate::iter::plumbing::*;
|
||||||
use crate::iter::*;
|
use crate::iter::*;
|
||||||
use std::char;
|
|
||||||
use std::convert::TryFrom;
|
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::usize;
|
|
||||||
|
|
||||||
/// Parallel iterator over a range, implemented for all integer types and `char`.
|
/// Parallel iterator over a range, implemented for all integer types and `char`.
|
||||||
///
|
///
|
||||||
@@ -379,8 +376,6 @@ fn check_range_split_at_overflow() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_i128_len_doesnt_overflow() {
|
fn test_i128_len_doesnt_overflow() {
|
||||||
use std::{i128, u128};
|
|
||||||
|
|
||||||
// Using parse because some versions of rust don't allow long literals
|
// Using parse because some versions of rust don't allow long literals
|
||||||
let octillion: i128 = "1000000000000000000000000000".parse().unwrap();
|
let octillion: i128 = "1000000000000000000000000000".parse().unwrap();
|
||||||
let producer = IterProducer {
|
let producer = IterProducer {
|
||||||
@@ -396,7 +391,6 @@ fn test_i128_len_doesnt_overflow() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_u64_opt_len() {
|
fn test_u64_opt_len() {
|
||||||
use std::{u64, usize};
|
|
||||||
assert_eq!(Some(100), (0..100u64).into_par_iter().opt_len());
|
assert_eq!(Some(100), (0..100u64).into_par_iter().opt_len());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(usize::MAX),
|
Some(usize::MAX),
|
||||||
@@ -415,7 +409,6 @@ fn test_u64_opt_len() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_u128_opt_len() {
|
fn test_u128_opt_len() {
|
||||||
use std::{u128, usize};
|
|
||||||
assert_eq!(Some(100), (0..100u128).into_par_iter().opt_len());
|
assert_eq!(Some(100), (0..100u128).into_par_iter().opt_len());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(usize::MAX),
|
Some(usize::MAX),
|
||||||
@@ -431,7 +424,6 @@ fn test_u128_opt_len() {
|
|||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
fn test_usize_i64_overflow() {
|
fn test_usize_i64_overflow() {
|
||||||
use crate::ThreadPoolBuilder;
|
use crate::ThreadPoolBuilder;
|
||||||
use std::i64;
|
|
||||||
|
|
||||||
let iter = (-2..i64::MAX).into_par_iter();
|
let iter = (-2..i64::MAX).into_par_iter();
|
||||||
assert_eq!(iter.opt_len(), Some(i64::MAX as usize + 2));
|
assert_eq!(iter.opt_len(), Some(i64::MAX as usize + 2));
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
use crate::iter::plumbing::*;
|
use crate::iter::plumbing::*;
|
||||||
use crate::iter::*;
|
use crate::iter::*;
|
||||||
use std::char;
|
|
||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
/// Parallel iterator over an inclusive range, implemented for all integer types and `char`.
|
/// Parallel iterator over an inclusive range, implemented for all integer types and `char`.
|
||||||
@@ -313,7 +312,6 @@ impl IndexedParallelIterator for Iter<char> {
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
fn test_u32_opt_len() {
|
fn test_u32_opt_len() {
|
||||||
use std::u32;
|
|
||||||
assert_eq!(Some(101), (0..=100u32).into_par_iter().opt_len());
|
assert_eq!(Some(101), (0..=100u32).into_par_iter().opt_len());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(u32::MAX as usize),
|
Some(u32::MAX as usize),
|
||||||
@@ -327,7 +325,6 @@ fn test_u32_opt_len() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_u64_opt_len() {
|
fn test_u64_opt_len() {
|
||||||
use std::{u64, usize};
|
|
||||||
assert_eq!(Some(101), (0..=100u64).into_par_iter().opt_len());
|
assert_eq!(Some(101), (0..=100u64).into_par_iter().opt_len());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(usize::MAX),
|
Some(usize::MAX),
|
||||||
@@ -339,7 +336,6 @@ fn test_u64_opt_len() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_u128_opt_len() {
|
fn test_u128_opt_len() {
|
||||||
use std::{u128, usize};
|
|
||||||
assert_eq!(Some(101), (0..=100u128).into_par_iter().opt_len());
|
assert_eq!(Some(101), (0..=100u128).into_par_iter().opt_len());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(usize::MAX),
|
Some(usize::MAX),
|
||||||
@@ -355,7 +351,6 @@ fn test_u128_opt_len() {
|
|||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
fn test_usize_i64_overflow() {
|
fn test_usize_i64_overflow() {
|
||||||
use crate::ThreadPoolBuilder;
|
use crate::ThreadPoolBuilder;
|
||||||
use std::i64;
|
|
||||||
|
|
||||||
let iter = (-2..=i64::MAX).into_par_iter();
|
let iter = (-2..=i64::MAX).into_par_iter();
|
||||||
assert_eq!(iter.opt_len(), Some(i64::MAX as usize + 3));
|
assert_eq!(iter.opt_len(), Some(i64::MAX as usize + 3));
|
||||||
|
|||||||
244
third_party/rust/rayon/src/slice/chunk_by.rs
vendored
Normal file
244
third_party/rust/rayon/src/slice/chunk_by.rs
vendored
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
use crate::iter::plumbing::*;
|
||||||
|
use crate::iter::*;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::{fmt, mem};
|
||||||
|
|
||||||
|
trait ChunkBySlice<T>: AsRef<[T]> + Default + Send {
|
||||||
|
fn split(self, index: usize) -> (Self, Self);
|
||||||
|
|
||||||
|
fn find(&self, pred: &impl Fn(&T, &T) -> bool, start: usize, end: usize) -> Option<usize> {
|
||||||
|
self.as_ref()[start..end]
|
||||||
|
.windows(2)
|
||||||
|
.position(move |w| !pred(&w[0], &w[1]))
|
||||||
|
.map(|i| i + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rfind(&self, pred: &impl Fn(&T, &T) -> bool, end: usize) -> Option<usize> {
|
||||||
|
self.as_ref()[..end]
|
||||||
|
.windows(2)
|
||||||
|
.rposition(move |w| !pred(&w[0], &w[1]))
|
||||||
|
.map(|i| i + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Sync> ChunkBySlice<T> for &[T] {
|
||||||
|
fn split(self, index: usize) -> (Self, Self) {
|
||||||
|
self.split_at(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Send> ChunkBySlice<T> for &mut [T] {
|
||||||
|
fn split(self, index: usize) -> (Self, Self) {
|
||||||
|
self.split_at_mut(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ChunkByProducer<'p, T, Slice, Pred> {
|
||||||
|
slice: Slice,
|
||||||
|
pred: &'p Pred,
|
||||||
|
tail: usize,
|
||||||
|
marker: PhantomData<fn(&T)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: this implementation is very similar to `SplitProducer`.
|
||||||
|
impl<T, Slice, Pred> UnindexedProducer for ChunkByProducer<'_, T, Slice, Pred>
|
||||||
|
where
|
||||||
|
Slice: ChunkBySlice<T>,
|
||||||
|
Pred: Fn(&T, &T) -> bool + Send + Sync,
|
||||||
|
{
|
||||||
|
type Item = Slice;
|
||||||
|
|
||||||
|
fn split(self) -> (Self, Option<Self>) {
|
||||||
|
if self.tail < 2 {
|
||||||
|
return (Self { tail: 0, ..self }, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look forward for the separator, and failing that look backward.
|
||||||
|
let mid = self.tail / 2;
|
||||||
|
let index = match self.slice.find(self.pred, mid, self.tail) {
|
||||||
|
Some(i) => Some(mid + i),
|
||||||
|
None => self.slice.rfind(self.pred, mid + 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(index) = index {
|
||||||
|
let (left, right) = self.slice.split(index);
|
||||||
|
|
||||||
|
let (left_tail, right_tail) = if index <= mid {
|
||||||
|
// If we scanned backwards to find the separator, everything in
|
||||||
|
// the right side is exhausted, with no separators left to find.
|
||||||
|
(index, 0)
|
||||||
|
} else {
|
||||||
|
(mid + 1, self.tail - index)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create the left split before the separator.
|
||||||
|
let left = Self {
|
||||||
|
slice: left,
|
||||||
|
tail: left_tail,
|
||||||
|
..self
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create the right split following the separator.
|
||||||
|
let right = Self {
|
||||||
|
slice: right,
|
||||||
|
tail: right_tail,
|
||||||
|
..self
|
||||||
|
};
|
||||||
|
|
||||||
|
(left, Some(right))
|
||||||
|
} else {
|
||||||
|
// The search is exhausted, no more separators...
|
||||||
|
(Self { tail: 0, ..self }, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_with<F>(self, mut folder: F) -> F
|
||||||
|
where
|
||||||
|
F: Folder<Self::Item>,
|
||||||
|
{
|
||||||
|
let Self {
|
||||||
|
slice, pred, tail, ..
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
let (slice, tail) = if tail == slice.as_ref().len() {
|
||||||
|
// No tail section, so just let `consume_iter` do it all.
|
||||||
|
(Some(slice), None)
|
||||||
|
} else if let Some(index) = slice.rfind(pred, tail) {
|
||||||
|
// We found the last separator to complete the tail, so
|
||||||
|
// end with that slice after `consume_iter` finds the rest.
|
||||||
|
let (left, right) = slice.split(index);
|
||||||
|
(Some(left), Some(right))
|
||||||
|
} else {
|
||||||
|
// We know there are no separators at all, so it's all "tail".
|
||||||
|
(None, Some(slice))
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(mut slice) = slice {
|
||||||
|
// TODO (MSRV 1.77) use either:
|
||||||
|
// folder.consume_iter(slice.chunk_by(pred))
|
||||||
|
// folder.consume_iter(slice.chunk_by_mut(pred))
|
||||||
|
|
||||||
|
folder = folder.consume_iter(std::iter::from_fn(move || {
|
||||||
|
let len = slice.as_ref().len();
|
||||||
|
if len > 0 {
|
||||||
|
let i = slice.find(pred, 0, len).unwrap_or(len);
|
||||||
|
let (head, tail) = mem::take(&mut slice).split(i);
|
||||||
|
slice = tail;
|
||||||
|
Some(head)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(tail) = tail {
|
||||||
|
folder = folder.consume(tail);
|
||||||
|
}
|
||||||
|
|
||||||
|
folder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parallel iterator over slice in (non-overlapping) chunks separated by a predicate.
|
||||||
|
///
|
||||||
|
/// This struct is created by the [`par_chunk_by`] method on `&[T]`.
|
||||||
|
///
|
||||||
|
/// [`par_chunk_by`]: trait.ParallelSlice.html#method.par_chunk_by
|
||||||
|
pub struct ChunkBy<'data, T, P> {
|
||||||
|
pred: P,
|
||||||
|
slice: &'data [T],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'data, T, P: Clone> Clone for ChunkBy<'data, T, P> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
ChunkBy {
|
||||||
|
pred: self.pred.clone(),
|
||||||
|
slice: self.slice,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'data, T: fmt::Debug, P> fmt::Debug for ChunkBy<'data, T, P> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("ChunkBy")
|
||||||
|
.field("slice", &self.slice)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'data, T, P> ChunkBy<'data, T, P> {
|
||||||
|
pub(super) fn new(slice: &'data [T], pred: P) -> Self {
|
||||||
|
Self { pred, slice }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'data, T, P> ParallelIterator for ChunkBy<'data, T, P>
|
||||||
|
where
|
||||||
|
T: Sync,
|
||||||
|
P: Fn(&T, &T) -> bool + Send + Sync,
|
||||||
|
{
|
||||||
|
type Item = &'data [T];
|
||||||
|
|
||||||
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<Self::Item>,
|
||||||
|
{
|
||||||
|
bridge_unindexed(
|
||||||
|
ChunkByProducer {
|
||||||
|
tail: self.slice.len(),
|
||||||
|
slice: self.slice,
|
||||||
|
pred: &self.pred,
|
||||||
|
marker: PhantomData,
|
||||||
|
},
|
||||||
|
consumer,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parallel iterator over slice in (non-overlapping) mutable chunks
|
||||||
|
/// separated by a predicate.
|
||||||
|
///
|
||||||
|
/// This struct is created by the [`par_chunk_by_mut`] method on `&mut [T]`.
|
||||||
|
///
|
||||||
|
/// [`par_chunk_by_mut`]: trait.ParallelSliceMut.html#method.par_chunk_by_mut
|
||||||
|
pub struct ChunkByMut<'data, T, P> {
|
||||||
|
pred: P,
|
||||||
|
slice: &'data mut [T],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'data, T: fmt::Debug, P> fmt::Debug for ChunkByMut<'data, T, P> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("ChunkByMut")
|
||||||
|
.field("slice", &self.slice)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'data, T, P> ChunkByMut<'data, T, P> {
|
||||||
|
pub(super) fn new(slice: &'data mut [T], pred: P) -> Self {
|
||||||
|
Self { pred, slice }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'data, T, P> ParallelIterator for ChunkByMut<'data, T, P>
|
||||||
|
where
|
||||||
|
T: Send,
|
||||||
|
P: Fn(&T, &T) -> bool + Send + Sync,
|
||||||
|
{
|
||||||
|
type Item = &'data mut [T];
|
||||||
|
|
||||||
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<Self::Item>,
|
||||||
|
{
|
||||||
|
bridge_unindexed(
|
||||||
|
ChunkByProducer {
|
||||||
|
tail: self.slice.len(),
|
||||||
|
slice: self.slice,
|
||||||
|
pred: &self.pred,
|
||||||
|
marker: PhantomData,
|
||||||
|
},
|
||||||
|
consumer,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
5
third_party/rust/rayon/src/slice/chunks.rs
vendored
5
third_party/rust/rayon/src/slice/chunks.rs
vendored
@@ -1,7 +1,6 @@
|
|||||||
use crate::iter::plumbing::*;
|
use crate::iter::plumbing::*;
|
||||||
use crate::iter::*;
|
use crate::iter::*;
|
||||||
use crate::math::div_round_up;
|
use crate::math::div_round_up;
|
||||||
use std::cmp;
|
|
||||||
|
|
||||||
/// Parallel iterator over immutable non-overlapping chunks of a slice
|
/// Parallel iterator over immutable non-overlapping chunks of a slice
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -74,7 +73,7 @@ impl<'data, T: 'data + Sync> Producer for ChunksProducer<'data, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn split_at(self, index: usize) -> (Self, Self) {
|
fn split_at(self, index: usize) -> (Self, Self) {
|
||||||
let elem_index = cmp::min(index * self.chunk_size, self.slice.len());
|
let elem_index = Ord::min(index * self.chunk_size, self.slice.len());
|
||||||
let (left, right) = self.slice.split_at(elem_index);
|
let (left, right) = self.slice.split_at(elem_index);
|
||||||
(
|
(
|
||||||
ChunksProducer {
|
ChunksProducer {
|
||||||
@@ -255,7 +254,7 @@ impl<'data, T: 'data + Send> Producer for ChunksMutProducer<'data, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn split_at(self, index: usize) -> (Self, Self) {
|
fn split_at(self, index: usize) -> (Self, Self) {
|
||||||
let elem_index = cmp::min(index * self.chunk_size, self.slice.len());
|
let elem_index = Ord::min(index * self.chunk_size, self.slice.len());
|
||||||
let (left, right) = self.slice.split_at_mut(elem_index);
|
let (left, right) = self.slice.split_at_mut(elem_index);
|
||||||
(
|
(
|
||||||
ChunksMutProducer {
|
ChunksMutProducer {
|
||||||
|
|||||||
205
third_party/rust/rayon/src/slice/mod.rs
vendored
205
third_party/rust/rayon/src/slice/mod.rs
vendored
@@ -5,6 +5,7 @@
|
|||||||
//!
|
//!
|
||||||
//! [std::slice]: https://doc.rust-lang.org/stable/std/slice/
|
//! [std::slice]: https://doc.rust-lang.org/stable/std/slice/
|
||||||
|
|
||||||
|
mod chunk_by;
|
||||||
mod chunks;
|
mod chunks;
|
||||||
mod mergesort;
|
mod mergesort;
|
||||||
mod quicksort;
|
mod quicksort;
|
||||||
@@ -17,11 +18,12 @@ use self::quicksort::par_quicksort;
|
|||||||
use crate::iter::plumbing::*;
|
use crate::iter::plumbing::*;
|
||||||
use crate::iter::*;
|
use crate::iter::*;
|
||||||
use crate::split_producer::*;
|
use crate::split_producer::*;
|
||||||
use std::cmp;
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
pub use self::chunk_by::{ChunkBy, ChunkByMut};
|
||||||
pub use self::chunks::{Chunks, ChunksExact, ChunksExactMut, ChunksMut};
|
pub use self::chunks::{Chunks, ChunksExact, ChunksExactMut, ChunksMut};
|
||||||
pub use self::rchunks::{RChunks, RChunksExact, RChunksExactMut, RChunksMut};
|
pub use self::rchunks::{RChunks, RChunksExact, RChunksExactMut, RChunksMut};
|
||||||
|
|
||||||
@@ -38,11 +40,11 @@ pub trait ParallelSlice<T: Sync> {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use rayon::prelude::*;
|
/// use rayon::prelude::*;
|
||||||
/// let smallest = [1, 2, 3, 0, 2, 4, 8, 0, 3, 6, 9]
|
/// let products: Vec<_> = [1, 2, 3, 0, 2, 4, 8, 0, 3, 6, 9]
|
||||||
/// .par_split(|i| *i == 0)
|
/// .par_split(|i| *i == 0)
|
||||||
/// .map(|numbers| numbers.iter().min().unwrap())
|
/// .map(|numbers| numbers.iter().product::<i32>())
|
||||||
/// .min();
|
/// .collect();
|
||||||
/// assert_eq!(Some(&1), smallest);
|
/// assert_eq!(products, [6, 64, 162]);
|
||||||
/// ```
|
/// ```
|
||||||
fn par_split<P>(&self, separator: P) -> Split<'_, T, P>
|
fn par_split<P>(&self, separator: P) -> Split<'_, T, P>
|
||||||
where
|
where
|
||||||
@@ -54,6 +56,29 @@ pub trait ParallelSlice<T: Sync> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a parallel iterator over subslices separated by elements that
|
||||||
|
/// match the separator, including the matched part as a terminator.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
/// let lengths: Vec<_> = [1, 2, 3, 0, 2, 4, 8, 0, 3, 6, 9]
|
||||||
|
/// .par_split_inclusive(|i| *i == 0)
|
||||||
|
/// .map(|numbers| numbers.len())
|
||||||
|
/// .collect();
|
||||||
|
/// assert_eq!(lengths, [4, 4, 3]);
|
||||||
|
/// ```
|
||||||
|
fn par_split_inclusive<P>(&self, separator: P) -> SplitInclusive<'_, T, P>
|
||||||
|
where
|
||||||
|
P: Fn(&T) -> bool + Sync + Send,
|
||||||
|
{
|
||||||
|
SplitInclusive {
|
||||||
|
slice: self.as_parallel_slice(),
|
||||||
|
separator,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a parallel iterator over all contiguous windows of length
|
/// Returns a parallel iterator over all contiguous windows of length
|
||||||
/// `window_size`. The windows overlap.
|
/// `window_size`. The windows overlap.
|
||||||
///
|
///
|
||||||
@@ -150,6 +175,29 @@ pub trait ParallelSlice<T: Sync> {
|
|||||||
assert!(chunk_size != 0, "chunk_size must not be zero");
|
assert!(chunk_size != 0, "chunk_size must not be zero");
|
||||||
RChunksExact::new(chunk_size, self.as_parallel_slice())
|
RChunksExact::new(chunk_size, self.as_parallel_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a parallel iterator over the slice producing non-overlapping runs
|
||||||
|
/// of elements using the predicate to separate them.
|
||||||
|
///
|
||||||
|
/// The predicate is called on two elements following themselves,
|
||||||
|
/// it means the predicate is called on `slice[0]` and `slice[1]`
|
||||||
|
/// then on `slice[1]` and `slice[2]` and so on.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
/// let chunks: Vec<_> = [1, 2, 2, 3, 3, 3].par_chunk_by(|&x, &y| x == y).collect();
|
||||||
|
/// assert_eq!(chunks[0], &[1]);
|
||||||
|
/// assert_eq!(chunks[1], &[2, 2]);
|
||||||
|
/// assert_eq!(chunks[2], &[3, 3, 3]);
|
||||||
|
/// ```
|
||||||
|
fn par_chunk_by<F>(&self, pred: F) -> ChunkBy<'_, T, F>
|
||||||
|
where
|
||||||
|
F: Fn(&T, &T) -> bool + Send + Sync,
|
||||||
|
{
|
||||||
|
ChunkBy::new(self.as_parallel_slice(), pred)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Sync> ParallelSlice<T> for [T] {
|
impl<T: Sync> ParallelSlice<T> for [T] {
|
||||||
@@ -187,6 +235,28 @@ pub trait ParallelSliceMut<T: Send> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a parallel iterator over mutable subslices separated by elements
|
||||||
|
/// that match the separator, including the matched part as a terminator.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
/// let mut array = [1, 2, 3, 0, 2, 4, 8, 0, 3, 6, 9];
|
||||||
|
/// array.par_split_inclusive_mut(|i| *i == 0)
|
||||||
|
/// .for_each(|slice| slice.reverse());
|
||||||
|
/// assert_eq!(array, [0, 3, 2, 1, 0, 8, 4, 2, 9, 6, 3]);
|
||||||
|
/// ```
|
||||||
|
fn par_split_inclusive_mut<P>(&mut self, separator: P) -> SplitInclusiveMut<'_, T, P>
|
||||||
|
where
|
||||||
|
P: Fn(&T) -> bool + Sync + Send,
|
||||||
|
{
|
||||||
|
SplitInclusiveMut {
|
||||||
|
slice: self.as_parallel_slice_mut(),
|
||||||
|
separator,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a parallel iterator over at most `chunk_size` elements of
|
/// Returns a parallel iterator over at most `chunk_size` elements of
|
||||||
/// `self` at a time. The chunks are mutable and do not overlap.
|
/// `self` at a time. The chunks are mutable and do not overlap.
|
||||||
///
|
///
|
||||||
@@ -659,6 +729,30 @@ pub trait ParallelSliceMut<T: Send> {
|
|||||||
{
|
{
|
||||||
par_quicksort(self.as_parallel_slice_mut(), |a, b| f(a).lt(&f(b)));
|
par_quicksort(self.as_parallel_slice_mut(), |a, b| f(a).lt(&f(b)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a parallel iterator over the slice producing non-overlapping mutable
|
||||||
|
/// runs of elements using the predicate to separate them.
|
||||||
|
///
|
||||||
|
/// The predicate is called on two elements following themselves,
|
||||||
|
/// it means the predicate is called on `slice[0]` and `slice[1]`
|
||||||
|
/// then on `slice[1]` and `slice[2]` and so on.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
/// let mut xs = [1, 2, 2, 3, 3, 3];
|
||||||
|
/// let chunks: Vec<_> = xs.par_chunk_by_mut(|&x, &y| x == y).collect();
|
||||||
|
/// assert_eq!(chunks[0], &mut [1]);
|
||||||
|
/// assert_eq!(chunks[1], &mut [2, 2]);
|
||||||
|
/// assert_eq!(chunks[2], &mut [3, 3, 3]);
|
||||||
|
/// ```
|
||||||
|
fn par_chunk_by_mut<F>(&mut self, pred: F) -> ChunkByMut<'_, T, F>
|
||||||
|
where
|
||||||
|
F: Fn(&T, &T) -> bool + Send + Sync,
|
||||||
|
{
|
||||||
|
ChunkByMut::new(self.as_parallel_slice_mut(), pred)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Send> ParallelSliceMut<T> for [T] {
|
impl<T: Send> ParallelSliceMut<T> for [T] {
|
||||||
@@ -817,7 +911,7 @@ impl<'data, T: 'data + Sync> Producer for WindowsProducer<'data, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn split_at(self, index: usize) -> (Self, Self) {
|
fn split_at(self, index: usize) -> (Self, Self) {
|
||||||
let left_index = cmp::min(self.slice.len(), index + (self.window_size - 1));
|
let left_index = Ord::min(self.slice.len(), index + (self.window_size - 1));
|
||||||
let left = &self.slice[..left_index];
|
let left = &self.slice[..left_index];
|
||||||
let right = &self.slice[index..];
|
let right = &self.slice[index..];
|
||||||
(
|
(
|
||||||
@@ -932,6 +1026,46 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parallel iterator over slices separated by a predicate,
|
||||||
|
/// including the matched part as a terminator.
|
||||||
|
pub struct SplitInclusive<'data, T, P> {
|
||||||
|
slice: &'data [T],
|
||||||
|
separator: P,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'data, T, P: Clone> Clone for SplitInclusive<'data, T, P> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
SplitInclusive {
|
||||||
|
separator: self.separator.clone(),
|
||||||
|
..*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'data, T: Debug, P> Debug for SplitInclusive<'data, T, P> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("SplitInclusive")
|
||||||
|
.field("slice", &self.slice)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'data, T, P> ParallelIterator for SplitInclusive<'data, T, P>
|
||||||
|
where
|
||||||
|
P: Fn(&T) -> bool + Sync + Send,
|
||||||
|
T: Sync,
|
||||||
|
{
|
||||||
|
type Item = &'data [T];
|
||||||
|
|
||||||
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<Self::Item>,
|
||||||
|
{
|
||||||
|
let producer = SplitInclusiveProducer::new_incl(self.slice, &self.separator);
|
||||||
|
bridge_unindexed(producer, consumer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Implement support for `SplitProducer`.
|
/// Implement support for `SplitProducer`.
|
||||||
impl<'data, T, P> Fissile<P> for &'data [T]
|
impl<'data, T, P> Fissile<P> for &'data [T]
|
||||||
where
|
where
|
||||||
@@ -953,16 +1087,25 @@ where
|
|||||||
self[..end].iter().rposition(separator)
|
self[..end].iter().rposition(separator)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn split_once(self, index: usize) -> (Self, Self) {
|
fn split_once<const INCL: bool>(self, index: usize) -> (Self, Self) {
|
||||||
|
if INCL {
|
||||||
|
// include the separator in the left side
|
||||||
|
self.split_at(index + 1)
|
||||||
|
} else {
|
||||||
let (left, right) = self.split_at(index);
|
let (left, right) = self.split_at(index);
|
||||||
(left, &right[1..]) // skip the separator
|
(left, &right[1..]) // skip the separator
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn fold_splits<F>(self, separator: &P, folder: F, skip_last: bool) -> F
|
fn fold_splits<F, const INCL: bool>(self, separator: &P, folder: F, skip_last: bool) -> F
|
||||||
where
|
where
|
||||||
F: Folder<Self>,
|
F: Folder<Self>,
|
||||||
Self: Send,
|
Self: Send,
|
||||||
{
|
{
|
||||||
|
if INCL {
|
||||||
|
debug_assert!(!skip_last);
|
||||||
|
folder.consume_iter(self.split_inclusive(separator))
|
||||||
|
} else {
|
||||||
let mut split = self.split(separator);
|
let mut split = self.split(separator);
|
||||||
if skip_last {
|
if skip_last {
|
||||||
split.next_back();
|
split.next_back();
|
||||||
@@ -970,6 +1113,7 @@ where
|
|||||||
folder.consume_iter(split)
|
folder.consume_iter(split)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parallel iterator over mutable slices separated by a predicate
|
/// Parallel iterator over mutable slices separated by a predicate
|
||||||
pub struct SplitMut<'data, T, P> {
|
pub struct SplitMut<'data, T, P> {
|
||||||
@@ -1001,6 +1145,37 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parallel iterator over mutable slices separated by a predicate,
|
||||||
|
/// including the matched part as a terminator.
|
||||||
|
pub struct SplitInclusiveMut<'data, T, P> {
|
||||||
|
slice: &'data mut [T],
|
||||||
|
separator: P,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'data, T: Debug, P> Debug for SplitInclusiveMut<'data, T, P> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("SplitInclusiveMut")
|
||||||
|
.field("slice", &self.slice)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'data, T, P> ParallelIterator for SplitInclusiveMut<'data, T, P>
|
||||||
|
where
|
||||||
|
P: Fn(&T) -> bool + Sync + Send,
|
||||||
|
T: Send,
|
||||||
|
{
|
||||||
|
type Item = &'data mut [T];
|
||||||
|
|
||||||
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<Self::Item>,
|
||||||
|
{
|
||||||
|
let producer = SplitInclusiveProducer::new_incl(self.slice, &self.separator);
|
||||||
|
bridge_unindexed(producer, consumer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Implement support for `SplitProducer`.
|
/// Implement support for `SplitProducer`.
|
||||||
impl<'data, T, P> Fissile<P> for &'data mut [T]
|
impl<'data, T, P> Fissile<P> for &'data mut [T]
|
||||||
where
|
where
|
||||||
@@ -1022,16 +1197,25 @@ where
|
|||||||
self[..end].iter().rposition(separator)
|
self[..end].iter().rposition(separator)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn split_once(self, index: usize) -> (Self, Self) {
|
fn split_once<const INCL: bool>(self, index: usize) -> (Self, Self) {
|
||||||
|
if INCL {
|
||||||
|
// include the separator in the left side
|
||||||
|
self.split_at_mut(index + 1)
|
||||||
|
} else {
|
||||||
let (left, right) = self.split_at_mut(index);
|
let (left, right) = self.split_at_mut(index);
|
||||||
(left, &mut right[1..]) // skip the separator
|
(left, &mut right[1..]) // skip the separator
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn fold_splits<F>(self, separator: &P, folder: F, skip_last: bool) -> F
|
fn fold_splits<F, const INCL: bool>(self, separator: &P, folder: F, skip_last: bool) -> F
|
||||||
where
|
where
|
||||||
F: Folder<Self>,
|
F: Folder<Self>,
|
||||||
Self: Send,
|
Self: Send,
|
||||||
{
|
{
|
||||||
|
if INCL {
|
||||||
|
debug_assert!(!skip_last);
|
||||||
|
folder.consume_iter(self.split_inclusive_mut(separator))
|
||||||
|
} else {
|
||||||
let mut split = self.split_mut(separator);
|
let mut split = self.split_mut(separator);
|
||||||
if skip_last {
|
if skip_last {
|
||||||
split.next_back();
|
split.next_back();
|
||||||
@@ -1039,3 +1223,4 @@ where
|
|||||||
folder.consume_iter(split)
|
folder.consume_iter(split)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
49
third_party/rust/rayon/src/slice/quicksort.rs
vendored
49
third_party/rust/rayon/src/slice/quicksort.rs
vendored
@@ -4,17 +4,34 @@
|
|||||||
//! The only difference from the original is that calls to `recurse` are executed in parallel using
|
//! The only difference from the original is that calls to `recurse` are executed in parallel using
|
||||||
//! `rayon_core::join`.
|
//! `rayon_core::join`.
|
||||||
|
|
||||||
use std::cmp;
|
use std::marker::PhantomData;
|
||||||
use std::mem::{self, MaybeUninit};
|
use std::mem::{self, MaybeUninit};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
/// When dropped, copies from `src` into `dest`.
|
/// When dropped, copies from `src` into `dest`.
|
||||||
struct CopyOnDrop<T> {
|
#[must_use]
|
||||||
|
struct CopyOnDrop<'a, T> {
|
||||||
src: *const T,
|
src: *const T,
|
||||||
dest: *mut T,
|
dest: *mut T,
|
||||||
|
/// `src` is often a local pointer here, make sure we have appropriate
|
||||||
|
/// PhantomData so that dropck can protect us.
|
||||||
|
marker: PhantomData<&'a mut T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Drop for CopyOnDrop<T> {
|
impl<'a, T> CopyOnDrop<'a, T> {
|
||||||
|
/// Construct from a source pointer and a destination
|
||||||
|
/// Assumes dest lives longer than src, since there is no easy way to
|
||||||
|
/// copy down lifetime information from another pointer
|
||||||
|
unsafe fn new(src: &'a T, dest: *mut T) -> Self {
|
||||||
|
CopyOnDrop {
|
||||||
|
src,
|
||||||
|
dest,
|
||||||
|
marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Drop for CopyOnDrop<'_, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// SAFETY: This is a helper class.
|
// SAFETY: This is a helper class.
|
||||||
// Please refer to its usage for correctness.
|
// Please refer to its usage for correctness.
|
||||||
@@ -54,10 +71,7 @@ where
|
|||||||
// into the slice.
|
// into the slice.
|
||||||
let tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0)));
|
let tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0)));
|
||||||
let v = v.as_mut_ptr();
|
let v = v.as_mut_ptr();
|
||||||
let mut hole = CopyOnDrop {
|
let mut hole = CopyOnDrop::new(&*tmp, v.add(1));
|
||||||
src: &*tmp,
|
|
||||||
dest: v.add(1),
|
|
||||||
};
|
|
||||||
ptr::copy_nonoverlapping(v.add(1), v.add(0), 1);
|
ptr::copy_nonoverlapping(v.add(1), v.add(0), 1);
|
||||||
|
|
||||||
for i in 2..len {
|
for i in 2..len {
|
||||||
@@ -103,10 +117,7 @@ where
|
|||||||
// into the slice.
|
// into the slice.
|
||||||
let tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1)));
|
let tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1)));
|
||||||
let v = v.as_mut_ptr();
|
let v = v.as_mut_ptr();
|
||||||
let mut hole = CopyOnDrop {
|
let mut hole = CopyOnDrop::new(&*tmp, v.add(len - 2));
|
||||||
src: &*tmp,
|
|
||||||
dest: v.add(len - 2),
|
|
||||||
};
|
|
||||||
ptr::copy_nonoverlapping(v.add(len - 2), v.add(len - 1), 1);
|
ptr::copy_nonoverlapping(v.add(len - 2), v.add(len - 1), 1);
|
||||||
|
|
||||||
for i in (0..len - 2).rev() {
|
for i in (0..len - 2).rev() {
|
||||||
@@ -366,7 +377,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Number of out-of-order elements to swap between the left and right side.
|
// Number of out-of-order elements to swap between the left and right side.
|
||||||
let count = cmp::min(width(start_l, end_l), width(start_r, end_r));
|
let count = Ord::min(width(start_l, end_l), width(start_r, end_r));
|
||||||
|
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
macro_rules! left {
|
macro_rules! left {
|
||||||
@@ -510,10 +521,7 @@ where
|
|||||||
|
|
||||||
// SAFETY: `pivot` is a reference to the first element of `v`, so `ptr::read` is safe.
|
// SAFETY: `pivot` is a reference to the first element of `v`, so `ptr::read` is safe.
|
||||||
let tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
|
let tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
|
||||||
let _pivot_guard = CopyOnDrop {
|
let _pivot_guard = unsafe { CopyOnDrop::new(&*tmp, pivot) };
|
||||||
src: &*tmp,
|
|
||||||
dest: pivot,
|
|
||||||
};
|
|
||||||
let pivot = &*tmp;
|
let pivot = &*tmp;
|
||||||
|
|
||||||
// Find the first pair of out-of-order elements.
|
// Find the first pair of out-of-order elements.
|
||||||
@@ -569,10 +577,7 @@ where
|
|||||||
// operation panics, the pivot will be automatically written back into the slice.
|
// operation panics, the pivot will be automatically written back into the slice.
|
||||||
// SAFETY: The pointer here is valid because it is obtained from a reference to a slice.
|
// SAFETY: The pointer here is valid because it is obtained from a reference to a slice.
|
||||||
let tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
|
let tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
|
||||||
let _pivot_guard = CopyOnDrop {
|
let _pivot_guard = unsafe { CopyOnDrop::new(&*tmp, pivot) };
|
||||||
src: &*tmp,
|
|
||||||
dest: pivot,
|
|
||||||
};
|
|
||||||
let pivot = &*tmp;
|
let pivot = &*tmp;
|
||||||
|
|
||||||
// Now partition the slice.
|
// Now partition the slice.
|
||||||
@@ -805,7 +810,7 @@ where
|
|||||||
|
|
||||||
// Partition the slice.
|
// Partition the slice.
|
||||||
let (mid, was_p) = partition(v, pivot, is_less);
|
let (mid, was_p) = partition(v, pivot, is_less);
|
||||||
was_balanced = cmp::min(mid, len - mid) >= len / 8;
|
was_balanced = Ord::min(mid, len - mid) >= len / 8;
|
||||||
was_partitioned = was_p;
|
was_partitioned = was_p;
|
||||||
|
|
||||||
// Split the slice into `left`, `pivot`, and `right`.
|
// Split the slice into `left`, `pivot`, and `right`.
|
||||||
@@ -813,7 +818,7 @@ where
|
|||||||
let (pivot, right) = right.split_at_mut(1);
|
let (pivot, right) = right.split_at_mut(1);
|
||||||
let pivot = &mut pivot[0];
|
let pivot = &mut pivot[0];
|
||||||
|
|
||||||
if cmp::max(left.len(), right.len()) <= MAX_SEQUENTIAL {
|
if Ord::max(left.len(), right.len()) <= MAX_SEQUENTIAL {
|
||||||
// Recurse into the shorter side only in order to minimize the total number of recursive
|
// Recurse into the shorter side only in order to minimize the total number of recursive
|
||||||
// calls and consume less stack space. Then just continue with the longer side (this is
|
// calls and consume less stack space. Then just continue with the longer side (this is
|
||||||
// akin to tail recursion).
|
// akin to tail recursion).
|
||||||
|
|||||||
46
third_party/rust/rayon/src/slice/test.rs
vendored
46
third_party/rust/rayon/src/slice/test.rs
vendored
@@ -5,6 +5,7 @@ use rand::distributions::Uniform;
|
|||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
use std::cmp::Ordering::{Equal, Greater, Less};
|
use std::cmp::Ordering::{Equal, Greater, Less};
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
|
||||||
|
|
||||||
macro_rules! sort {
|
macro_rules! sort {
|
||||||
($f:ident, $name:ident) => {
|
($f:ident, $name:ident) => {
|
||||||
@@ -168,3 +169,48 @@ fn test_par_rchunks_exact_mut_remainder() {
|
|||||||
assert_eq!(c.take_remainder(), &[]);
|
assert_eq!(c.take_remainder(), &[]);
|
||||||
assert_eq!(c.len(), 2);
|
assert_eq!(c.len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn slice_chunk_by() {
|
||||||
|
let v: Vec<_> = (0..1000).collect();
|
||||||
|
assert_eq!(v[..0].par_chunk_by(|_, _| todo!()).count(), 0);
|
||||||
|
assert_eq!(v[..1].par_chunk_by(|_, _| todo!()).count(), 1);
|
||||||
|
assert_eq!(v[..2].par_chunk_by(|_, _| true).count(), 1);
|
||||||
|
assert_eq!(v[..2].par_chunk_by(|_, _| false).count(), 2);
|
||||||
|
|
||||||
|
let count = AtomicUsize::new(0);
|
||||||
|
let par: Vec<_> = v
|
||||||
|
.par_chunk_by(|x, y| {
|
||||||
|
count.fetch_add(1, Relaxed);
|
||||||
|
(x % 10 < 3) == (y % 10 < 3)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
assert_eq!(count.into_inner(), v.len() - 1);
|
||||||
|
|
||||||
|
let seq: Vec<_> = v.chunk_by(|x, y| (x % 10 < 3) == (y % 10 < 3)).collect();
|
||||||
|
assert_eq!(par, seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn slice_chunk_by_mut() {
|
||||||
|
let mut v: Vec<_> = (0..1000).collect();
|
||||||
|
assert_eq!(v[..0].par_chunk_by_mut(|_, _| todo!()).count(), 0);
|
||||||
|
assert_eq!(v[..1].par_chunk_by_mut(|_, _| todo!()).count(), 1);
|
||||||
|
assert_eq!(v[..2].par_chunk_by_mut(|_, _| true).count(), 1);
|
||||||
|
assert_eq!(v[..2].par_chunk_by_mut(|_, _| false).count(), 2);
|
||||||
|
|
||||||
|
let mut v2 = v.clone();
|
||||||
|
let count = AtomicUsize::new(0);
|
||||||
|
let par: Vec<_> = v
|
||||||
|
.par_chunk_by_mut(|x, y| {
|
||||||
|
count.fetch_add(1, Relaxed);
|
||||||
|
(x % 10 < 3) == (y % 10 < 3)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
assert_eq!(count.into_inner(), v2.len() - 1);
|
||||||
|
|
||||||
|
let seq: Vec<_> = v2
|
||||||
|
.chunk_by_mut(|x, y| (x % 10 < 3) == (y % 10 < 3))
|
||||||
|
.collect();
|
||||||
|
assert_eq!(par, seq);
|
||||||
|
}
|
||||||
|
|||||||
36
third_party/rust/rayon/src/split_producer.rs
vendored
36
third_party/rust/rayon/src/split_producer.rs
vendored
@@ -5,7 +5,7 @@
|
|||||||
use crate::iter::plumbing::{Folder, UnindexedProducer};
|
use crate::iter::plumbing::{Folder, UnindexedProducer};
|
||||||
|
|
||||||
/// Common producer for splitting on a predicate.
|
/// Common producer for splitting on a predicate.
|
||||||
pub(super) struct SplitProducer<'p, P, V> {
|
pub(super) struct SplitProducer<'p, P, V, const INCL: bool = false> {
|
||||||
data: V,
|
data: V,
|
||||||
separator: &'p P,
|
separator: &'p P,
|
||||||
|
|
||||||
@@ -13,14 +13,16 @@ pub(super) struct SplitProducer<'p, P, V> {
|
|||||||
tail: usize,
|
tail: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) type SplitInclusiveProducer<'p, P, V> = SplitProducer<'p, P, V, true>;
|
||||||
|
|
||||||
/// Helper trait so `&str`, `&[T]`, and `&mut [T]` can share `SplitProducer`.
|
/// Helper trait so `&str`, `&[T]`, and `&mut [T]` can share `SplitProducer`.
|
||||||
pub(super) trait Fissile<P>: Sized {
|
pub(super) trait Fissile<P>: Sized {
|
||||||
fn length(&self) -> usize;
|
fn length(&self) -> usize;
|
||||||
fn midpoint(&self, end: usize) -> usize;
|
fn midpoint(&self, end: usize) -> usize;
|
||||||
fn find(&self, separator: &P, start: usize, end: usize) -> Option<usize>;
|
fn find(&self, separator: &P, start: usize, end: usize) -> Option<usize>;
|
||||||
fn rfind(&self, separator: &P, end: usize) -> Option<usize>;
|
fn rfind(&self, separator: &P, end: usize) -> Option<usize>;
|
||||||
fn split_once(self, index: usize) -> (Self, Self);
|
fn split_once<const INCL: bool>(self, index: usize) -> (Self, Self);
|
||||||
fn fold_splits<F>(self, separator: &P, folder: F, skip_last: bool) -> F
|
fn fold_splits<F, const INCL: bool>(self, separator: &P, folder: F, skip_last: bool) -> F
|
||||||
where
|
where
|
||||||
F: Folder<Self>,
|
F: Folder<Self>,
|
||||||
Self: Send;
|
Self: Send;
|
||||||
@@ -37,7 +39,25 @@ where
|
|||||||
separator,
|
separator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p, P, V> SplitInclusiveProducer<'p, P, V>
|
||||||
|
where
|
||||||
|
V: Fissile<P> + Send,
|
||||||
|
{
|
||||||
|
pub(super) fn new_incl(data: V, separator: &'p P) -> Self {
|
||||||
|
SplitProducer {
|
||||||
|
tail: data.length(),
|
||||||
|
data,
|
||||||
|
separator,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p, P, V, const INCL: bool> SplitProducer<'p, P, V, INCL>
|
||||||
|
where
|
||||||
|
V: Fissile<P> + Send,
|
||||||
|
{
|
||||||
/// Common `fold_with` implementation, integrating `SplitTerminator`'s
|
/// Common `fold_with` implementation, integrating `SplitTerminator`'s
|
||||||
/// need to sometimes skip its final empty item.
|
/// need to sometimes skip its final empty item.
|
||||||
pub(super) fn fold_with<F>(self, folder: F, skip_last: bool) -> F
|
pub(super) fn fold_with<F>(self, folder: F, skip_last: bool) -> F
|
||||||
@@ -52,12 +72,12 @@ where
|
|||||||
|
|
||||||
if tail == data.length() {
|
if tail == data.length() {
|
||||||
// No tail section, so just let `fold_splits` handle it.
|
// No tail section, so just let `fold_splits` handle it.
|
||||||
data.fold_splits(separator, folder, skip_last)
|
data.fold_splits::<F, INCL>(separator, folder, skip_last)
|
||||||
} else if let Some(index) = data.rfind(separator, tail) {
|
} else if let Some(index) = data.rfind(separator, tail) {
|
||||||
// We found the last separator to complete the tail, so
|
// We found the last separator to complete the tail, so
|
||||||
// end with that slice after `fold_splits` finds the rest.
|
// end with that slice after `fold_splits` finds the rest.
|
||||||
let (left, right) = data.split_once(index);
|
let (left, right) = data.split_once::<INCL>(index);
|
||||||
let folder = left.fold_splits(separator, folder, false);
|
let folder = left.fold_splits::<F, INCL>(separator, folder, false);
|
||||||
if skip_last || folder.full() {
|
if skip_last || folder.full() {
|
||||||
folder
|
folder
|
||||||
} else {
|
} else {
|
||||||
@@ -74,7 +94,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'p, P, V> UnindexedProducer for SplitProducer<'p, P, V>
|
impl<'p, P, V, const INCL: bool> UnindexedProducer for SplitProducer<'p, P, V, INCL>
|
||||||
where
|
where
|
||||||
V: Fissile<P> + Send,
|
V: Fissile<P> + Send,
|
||||||
P: Sync,
|
P: Sync,
|
||||||
@@ -91,7 +111,7 @@ where
|
|||||||
|
|
||||||
if let Some(index) = index {
|
if let Some(index) = index {
|
||||||
let len = self.data.length();
|
let len = self.data.length();
|
||||||
let (left, right) = self.data.split_once(index);
|
let (left, right) = self.data.split_once::<INCL>(index);
|
||||||
|
|
||||||
let (left_tail, right_tail) = if index < mid {
|
let (left_tail, right_tail) = if index < mid {
|
||||||
// If we scanned backwards to find the separator, everything in
|
// If we scanned backwards to find the separator, everything in
|
||||||
|
|||||||
186
third_party/rust/rayon/src/str.rs
vendored
186
third_party/rust/rayon/src/str.rs
vendored
@@ -6,8 +6,8 @@
|
|||||||
//! Note: [`ParallelString::par_split()`] and [`par_split_terminator()`]
|
//! Note: [`ParallelString::par_split()`] and [`par_split_terminator()`]
|
||||||
//! reference a `Pattern` trait which is not visible outside this crate.
|
//! reference a `Pattern` trait which is not visible outside this crate.
|
||||||
//! This trait is intentionally kept private, for use only by Rayon itself.
|
//! This trait is intentionally kept private, for use only by Rayon itself.
|
||||||
//! It is implemented for `char`, `&[char]`, and any function or closure
|
//! It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`,
|
||||||
//! `F: Fn(char) -> bool + Sync + Send`.
|
//! and any function or closure `F: Fn(char) -> bool + Sync + Send`.
|
||||||
//!
|
//!
|
||||||
//! [`ParallelString::par_split()`]: trait.ParallelString.html#method.par_split
|
//! [`ParallelString::par_split()`]: trait.ParallelString.html#method.par_split
|
||||||
//! [`par_split_terminator()`]: trait.ParallelString.html#method.par_split_terminator
|
//! [`par_split_terminator()`]: trait.ParallelString.html#method.par_split_terminator
|
||||||
@@ -140,8 +140,8 @@ pub trait ParallelString {
|
|||||||
/// given character or predicate, similar to `str::split`.
|
/// given character or predicate, similar to `str::split`.
|
||||||
///
|
///
|
||||||
/// Note: the `Pattern` trait is private, for use only by Rayon itself.
|
/// Note: the `Pattern` trait is private, for use only by Rayon itself.
|
||||||
/// It is implemented for `char`, `&[char]`, and any function or closure
|
/// It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`,
|
||||||
/// `F: Fn(char) -> bool + Sync + Send`.
|
/// and any function or closure `F: Fn(char) -> bool + Sync + Send`.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@@ -157,14 +157,35 @@ pub trait ParallelString {
|
|||||||
Split::new(self.as_parallel_string(), separator)
|
Split::new(self.as_parallel_string(), separator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a parallel iterator over substrings separated by a
|
||||||
|
/// given character or predicate, keeping the matched part as a terminator
|
||||||
|
/// of the substring similar to `str::split_inclusive`.
|
||||||
|
///
|
||||||
|
/// Note: the `Pattern` trait is private, for use only by Rayon itself.
|
||||||
|
/// It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`,
|
||||||
|
/// and any function or closure `F: Fn(char) -> bool + Sync + Send`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
/// let lines: Vec<_> = "Mary had a little lamb\nlittle lamb\nlittle lamb."
|
||||||
|
/// .par_split_inclusive('\n')
|
||||||
|
/// .collect();
|
||||||
|
/// assert_eq!(lines, ["Mary had a little lamb\n", "little lamb\n", "little lamb."]);
|
||||||
|
/// ```
|
||||||
|
fn par_split_inclusive<P: Pattern>(&self, separator: P) -> SplitInclusive<'_, P> {
|
||||||
|
SplitInclusive::new(self.as_parallel_string(), separator)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a parallel iterator over substrings terminated by a
|
/// Returns a parallel iterator over substrings terminated by a
|
||||||
/// given character or predicate, similar to `str::split_terminator`.
|
/// given character or predicate, similar to `str::split_terminator`.
|
||||||
/// It's equivalent to `par_split`, except it doesn't produce an empty
|
/// It's equivalent to `par_split`, except it doesn't produce an empty
|
||||||
/// substring after a trailing terminator.
|
/// substring after a trailing terminator.
|
||||||
///
|
///
|
||||||
/// Note: the `Pattern` trait is private, for use only by Rayon itself.
|
/// Note: the `Pattern` trait is private, for use only by Rayon itself.
|
||||||
/// It is implemented for `char`, `&[char]`, and any function or closure
|
/// It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`,
|
||||||
/// `F: Fn(char) -> bool + Sync + Send`.
|
/// and any function or closure `F: Fn(char) -> bool + Sync + Send`.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@@ -203,6 +224,8 @@ pub trait ParallelString {
|
|||||||
///
|
///
|
||||||
/// As with `str::split_whitespace`, 'whitespace' is defined according to
|
/// As with `str::split_whitespace`, 'whitespace' is defined according to
|
||||||
/// the terms of the Unicode Derived Core Property `White_Space`.
|
/// the terms of the Unicode Derived Core Property `White_Space`.
|
||||||
|
/// If you only want to split on ASCII whitespace instead, use
|
||||||
|
/// [`par_split_ascii_whitespace`][`ParallelString::par_split_ascii_whitespace`].
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@@ -213,16 +236,71 @@ pub trait ParallelString {
|
|||||||
/// .max_by_key(|word| word.len());
|
/// .max_by_key(|word| word.len());
|
||||||
/// assert_eq!(Some("longest"), longest);
|
/// assert_eq!(Some("longest"), longest);
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// All kinds of whitespace are considered:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
/// let words: Vec<&str> = " Mary had\ta\u{2009}little \n\t lamb"
|
||||||
|
/// .par_split_whitespace()
|
||||||
|
/// .collect();
|
||||||
|
/// assert_eq!(words, ["Mary", "had", "a", "little", "lamb"]);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// If the string is empty or all whitespace, the iterator yields no string slices:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
/// assert_eq!("".par_split_whitespace().count(), 0);
|
||||||
|
/// assert_eq!(" ".par_split_whitespace().count(), 0);
|
||||||
|
/// ```
|
||||||
fn par_split_whitespace(&self) -> SplitWhitespace<'_> {
|
fn par_split_whitespace(&self) -> SplitWhitespace<'_> {
|
||||||
SplitWhitespace(self.as_parallel_string())
|
SplitWhitespace(self.as_parallel_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a parallel iterator over the sub-slices of a string that are
|
||||||
|
/// separated by any amount of ASCII whitespace.
|
||||||
|
///
|
||||||
|
/// To split by Unicode `White_Space` instead, use
|
||||||
|
/// [`par_split_whitespace`][`ParallelString::par_split_whitespace`].
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
/// let longest = "which is the longest word?"
|
||||||
|
/// .par_split_ascii_whitespace()
|
||||||
|
/// .max_by_key(|word| word.len());
|
||||||
|
/// assert_eq!(Some("longest"), longest);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// All kinds of ASCII whitespace are considered, but not Unicode `White_Space`:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
/// let words: Vec<&str> = " Mary had\ta\u{2009}little \n\t lamb"
|
||||||
|
/// .par_split_ascii_whitespace()
|
||||||
|
/// .collect();
|
||||||
|
/// assert_eq!(words, ["Mary", "had", "a\u{2009}little", "lamb"]);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// If the string is empty or all ASCII whitespace, the iterator yields no string slices:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rayon::prelude::*;
|
||||||
|
/// assert_eq!("".par_split_whitespace().count(), 0);
|
||||||
|
/// assert_eq!(" ".par_split_whitespace().count(), 0);
|
||||||
|
/// ```
|
||||||
|
fn par_split_ascii_whitespace(&self) -> SplitAsciiWhitespace<'_> {
|
||||||
|
SplitAsciiWhitespace(self.as_parallel_string())
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a parallel iterator over substrings that match a
|
/// Returns a parallel iterator over substrings that match a
|
||||||
/// given character or predicate, similar to `str::matches`.
|
/// given character or predicate, similar to `str::matches`.
|
||||||
///
|
///
|
||||||
/// Note: the `Pattern` trait is private, for use only by Rayon itself.
|
/// Note: the `Pattern` trait is private, for use only by Rayon itself.
|
||||||
/// It is implemented for `char`, `&[char]`, and any function or closure
|
/// It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`,
|
||||||
/// `F: Fn(char) -> bool + Sync + Send`.
|
/// and any function or closure `F: Fn(char) -> bool + Sync + Send`.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@@ -245,8 +323,8 @@ pub trait ParallelString {
|
|||||||
/// or predicate, with their positions, similar to `str::match_indices`.
|
/// or predicate, with their positions, similar to `str::match_indices`.
|
||||||
///
|
///
|
||||||
/// Note: the `Pattern` trait is private, for use only by Rayon itself.
|
/// Note: the `Pattern` trait is private, for use only by Rayon itself.
|
||||||
/// It is implemented for `char`, `&[char]`, and any function or closure
|
/// It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`,
|
||||||
/// `F: Fn(char) -> bool + Sync + Send`.
|
/// and any function or closure `F: Fn(char) -> bool + Sync + Send`.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@@ -291,6 +369,9 @@ mod private {
|
|||||||
fn rfind_in(&self, haystack: &str) -> Option<usize>;
|
fn rfind_in(&self, haystack: &str) -> Option<usize>;
|
||||||
fn is_suffix_of(&self, haystack: &str) -> bool;
|
fn is_suffix_of(&self, haystack: &str) -> bool;
|
||||||
fn fold_splits<'ch, F>(&self, haystack: &'ch str, folder: F, skip_last: bool) -> F
|
fn fold_splits<'ch, F>(&self, haystack: &'ch str, folder: F, skip_last: bool) -> F
|
||||||
|
where
|
||||||
|
F: Folder<&'ch str>;
|
||||||
|
fn fold_inclusive_splits<'ch, F>(&self, haystack: &'ch str, folder: F) -> F
|
||||||
where
|
where
|
||||||
F: Folder<&'ch str>;
|
F: Folder<&'ch str>;
|
||||||
fn fold_matches<'ch, F>(&self, haystack: &'ch str, folder: F) -> F
|
fn fold_matches<'ch, F>(&self, haystack: &'ch str, folder: F) -> F
|
||||||
@@ -338,6 +419,13 @@ macro_rules! impl_pattern {
|
|||||||
folder.consume_iter(split)
|
folder.consume_iter(split)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fold_inclusive_splits<'ch, F>(&$self, chars: &'ch str, folder: F) -> F
|
||||||
|
where
|
||||||
|
F: Folder<&'ch str>,
|
||||||
|
{
|
||||||
|
folder.consume_iter(chars.split_inclusive($pattern))
|
||||||
|
}
|
||||||
|
|
||||||
fn fold_matches<'ch, F>(&$self, chars: &'ch str, folder: F) -> F
|
fn fold_matches<'ch, F>(&$self, chars: &'ch str, folder: F) -> F
|
||||||
where
|
where
|
||||||
F: Folder<&'ch str>,
|
F: Folder<&'ch str>,
|
||||||
@@ -362,6 +450,17 @@ impl Pattern for &[char] {
|
|||||||
impl_pattern!(&self => *self);
|
impl_pattern!(&self => *self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO (MSRV 1.75): use `*self` for array patterns too.
|
||||||
|
// - Needs `DoubleEndedSearcher` so `split.next_back()` works.
|
||||||
|
|
||||||
|
impl<const N: usize> Pattern for [char; N] {
|
||||||
|
impl_pattern!(&self => self.as_slice());
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> Pattern for &[char; N] {
|
||||||
|
impl_pattern!(&self => self.as_slice());
|
||||||
|
}
|
||||||
|
|
||||||
impl<FN: Sync + Send + Fn(char) -> bool> Pattern for FN {
|
impl<FN: Sync + Send + Fn(char) -> bool> Pattern for FN {
|
||||||
impl_pattern!(&self => self);
|
impl_pattern!(&self => self);
|
||||||
}
|
}
|
||||||
@@ -600,20 +699,58 @@ impl<'ch, P: Pattern> Fissile<P> for &'ch str {
|
|||||||
separator.rfind_in(&self[..end])
|
separator.rfind_in(&self[..end])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn split_once(self, index: usize) -> (Self, Self) {
|
fn split_once<const INCL: bool>(self, index: usize) -> (Self, Self) {
|
||||||
|
if INCL {
|
||||||
|
// include the separator in the left side
|
||||||
|
let separator = self[index..].chars().next().unwrap();
|
||||||
|
self.split_at(index + separator.len_utf8())
|
||||||
|
} else {
|
||||||
let (left, right) = self.split_at(index);
|
let (left, right) = self.split_at(index);
|
||||||
let mut right_iter = right.chars();
|
let mut right_iter = right.chars();
|
||||||
right_iter.next(); // skip the separator
|
right_iter.next(); // skip the separator
|
||||||
(left, right_iter.as_str())
|
(left, right_iter.as_str())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn fold_splits<F>(self, separator: &P, folder: F, skip_last: bool) -> F
|
fn fold_splits<F, const INCL: bool>(self, separator: &P, folder: F, skip_last: bool) -> F
|
||||||
where
|
where
|
||||||
F: Folder<Self>,
|
F: Folder<Self>,
|
||||||
{
|
{
|
||||||
|
if INCL {
|
||||||
|
debug_assert!(!skip_last);
|
||||||
|
separator.fold_inclusive_splits(self, folder)
|
||||||
|
} else {
|
||||||
separator.fold_splits(self, folder, skip_last)
|
separator.fold_splits(self, folder, skip_last)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// /////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/// Parallel iterator over substrings separated by a pattern
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct SplitInclusive<'ch, P: Pattern> {
|
||||||
|
chars: &'ch str,
|
||||||
|
separator: P,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ch, P: Pattern> SplitInclusive<'ch, P> {
|
||||||
|
fn new(chars: &'ch str, separator: P) -> Self {
|
||||||
|
SplitInclusive { chars, separator }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ch, P: Pattern> ParallelIterator for SplitInclusive<'ch, P> {
|
||||||
|
type Item = &'ch str;
|
||||||
|
|
||||||
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<Self::Item>,
|
||||||
|
{
|
||||||
|
let producer = SplitInclusiveProducer::new_incl(self.chars, &self.separator);
|
||||||
|
bridge_unindexed(producer, consumer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// /////////////////////////////////////////////////////////////////////////
|
// /////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -733,6 +870,31 @@ impl<'ch> ParallelIterator for SplitWhitespace<'ch> {
|
|||||||
|
|
||||||
// /////////////////////////////////////////////////////////////////////////
|
// /////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/// Parallel iterator over substrings separated by ASCII whitespace
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct SplitAsciiWhitespace<'ch>(&'ch str);
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_ascii_whitespace(c: char) -> bool {
|
||||||
|
c.is_ascii_whitespace()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ch> ParallelIterator for SplitAsciiWhitespace<'ch> {
|
||||||
|
type Item = &'ch str;
|
||||||
|
|
||||||
|
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||||
|
where
|
||||||
|
C: UnindexedConsumer<Self::Item>,
|
||||||
|
{
|
||||||
|
self.0
|
||||||
|
.par_split(is_ascii_whitespace)
|
||||||
|
.filter(not_empty)
|
||||||
|
.drive_unindexed(consumer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// /////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// Parallel iterator over substrings that match a pattern
|
/// Parallel iterator over substrings that match a pattern
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Matches<'ch, P: Pattern> {
|
pub struct Matches<'ch, P: Pattern> {
|
||||||
|
|||||||
9
third_party/rust/rayon/src/vec.rs
vendored
9
third_party/rust/rayon/src/vec.rs
vendored
@@ -225,8 +225,9 @@ impl<'data, T: 'data + Send> Producer for DrainProducer<'data, T> {
|
|||||||
|
|
||||||
impl<'data, T: 'data + Send> Drop for DrainProducer<'data, T> {
|
impl<'data, T: 'data + Send> Drop for DrainProducer<'data, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// use `Drop for [T]`
|
// extract the slice so we can use `Drop for [T]`
|
||||||
unsafe { ptr::drop_in_place(self.slice) };
|
let slice_ptr: *mut [T] = mem::take::<&'data mut [T]>(&mut self.slice);
|
||||||
|
unsafe { ptr::drop_in_place::<[T]>(slice_ptr) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +277,7 @@ impl<'data, T: 'data> iter::FusedIterator for SliceDrain<'data, T> {}
|
|||||||
impl<'data, T: 'data> Drop for SliceDrain<'data, T> {
|
impl<'data, T: 'data> Drop for SliceDrain<'data, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// extract the iterator so we can use `Drop for [T]`
|
// extract the iterator so we can use `Drop for [T]`
|
||||||
let iter = mem::replace(&mut self.iter, [].iter_mut());
|
let slice_ptr: *mut [T] = mem::replace(&mut self.iter, [].iter_mut()).into_slice();
|
||||||
unsafe { ptr::drop_in_place(iter.into_slice()) };
|
unsafe { ptr::drop_in_place::<[T]>(slice_ptr) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
third_party/rust/rayon/tests/chars.rs
vendored
1
third_party/rust/rayon/tests/chars.rs
vendored
@@ -1,5 +1,4 @@
|
|||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use std::char;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn half_open_correctness() {
|
fn half_open_correctness() {
|
||||||
|
|||||||
26
third_party/rust/rayon/tests/clones.rs
vendored
26
third_party/rust/rayon/tests/clones.rs
vendored
@@ -10,6 +10,13 @@ where
|
|||||||
assert_eq!(a, b);
|
assert_eq!(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_count<I>(iter: I)
|
||||||
|
where
|
||||||
|
I: ParallelIterator + Clone,
|
||||||
|
{
|
||||||
|
assert_eq!(iter.clone().count(), iter.count());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn clone_binary_heap() {
|
fn clone_binary_heap() {
|
||||||
use std::collections::BinaryHeap;
|
use std::collections::BinaryHeap;
|
||||||
@@ -92,20 +99,24 @@ fn clone_str() {
|
|||||||
check(s.par_chars());
|
check(s.par_chars());
|
||||||
check(s.par_lines());
|
check(s.par_lines());
|
||||||
check(s.par_split('\n'));
|
check(s.par_split('\n'));
|
||||||
|
check(s.par_split_inclusive('\n'));
|
||||||
check(s.par_split_terminator('\n'));
|
check(s.par_split_terminator('\n'));
|
||||||
check(s.par_split_whitespace());
|
check(s.par_split_whitespace());
|
||||||
|
check(s.par_split_ascii_whitespace());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn clone_vec() {
|
fn clone_vec() {
|
||||||
let v: Vec<_> = (0..1000).collect();
|
let v: Vec<_> = (0..1000).collect();
|
||||||
check(v.par_iter());
|
check(v.par_iter());
|
||||||
|
check(v.par_chunk_by(i32::eq));
|
||||||
check(v.par_chunks(42));
|
check(v.par_chunks(42));
|
||||||
check(v.par_chunks_exact(42));
|
check(v.par_chunks_exact(42));
|
||||||
check(v.par_rchunks(42));
|
check(v.par_rchunks(42));
|
||||||
check(v.par_rchunks_exact(42));
|
check(v.par_rchunks_exact(42));
|
||||||
check(v.par_windows(42));
|
check(v.par_windows(42));
|
||||||
check(v.par_split(|x| x % 3 == 0));
|
check(v.par_split(|x| x % 3 == 0));
|
||||||
|
check(v.par_split_inclusive(|x| x % 3 == 0));
|
||||||
check(v.into_par_iter());
|
check(v.into_par_iter());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,6 +129,8 @@ fn clone_array() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn clone_adaptors() {
|
fn clone_adaptors() {
|
||||||
let v: Vec<_> = (0..1000).map(Some).collect();
|
let v: Vec<_> = (0..1000).map(Some).collect();
|
||||||
|
check(v.par_iter().by_exponential_blocks());
|
||||||
|
check(v.par_iter().by_uniform_blocks(100));
|
||||||
check(v.par_iter().chain(&v));
|
check(v.par_iter().chain(&v));
|
||||||
check(v.par_iter().cloned());
|
check(v.par_iter().cloned());
|
||||||
check(v.par_iter().copied());
|
check(v.par_iter().copied());
|
||||||
@@ -150,8 +163,10 @@ fn clone_adaptors() {
|
|||||||
check(v.par_iter().panic_fuse());
|
check(v.par_iter().panic_fuse());
|
||||||
check(v.par_iter().positions(|_| true));
|
check(v.par_iter().positions(|_| true));
|
||||||
check(v.par_iter().rev());
|
check(v.par_iter().rev());
|
||||||
check(v.par_iter().skip(1));
|
check(v.par_iter().skip(42));
|
||||||
check(v.par_iter().take(1));
|
check(v.par_iter().skip_any_while(|_| false));
|
||||||
|
check(v.par_iter().take(42));
|
||||||
|
check(v.par_iter().take_any_while(|_| true));
|
||||||
check(v.par_iter().cloned().while_some());
|
check(v.par_iter().cloned().while_some());
|
||||||
check(v.par_iter().with_max_len(1));
|
check(v.par_iter().with_max_len(1));
|
||||||
check(v.par_iter().with_min_len(1));
|
check(v.par_iter().with_min_len(1));
|
||||||
@@ -160,6 +175,13 @@ fn clone_adaptors() {
|
|||||||
check(v.par_iter().step_by(2));
|
check(v.par_iter().step_by(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn clone_counted_adaptors() {
|
||||||
|
let v: Vec<_> = (0..1000).collect();
|
||||||
|
check_count(v.par_iter().skip_any(42));
|
||||||
|
check_count(v.par_iter().take_any(42));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn clone_empty() {
|
fn clone_empty() {
|
||||||
check(rayon::iter::empty::<i32>());
|
check(rayon::iter::empty::<i32>());
|
||||||
|
|||||||
2
third_party/rust/rayon/tests/collect.rs
vendored
2
third_party/rust/rayon/tests/collect.rs
vendored
@@ -6,6 +6,7 @@ use std::sync::atomic::Ordering;
|
|||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(not(panic = "unwind"), ignore)]
|
||||||
fn collect_drop_on_unwind() {
|
fn collect_drop_on_unwind() {
|
||||||
struct Recorddrop<'a>(i64, &'a Mutex<Vec<i64>>);
|
struct Recorddrop<'a>(i64, &'a Mutex<Vec<i64>>);
|
||||||
|
|
||||||
@@ -61,6 +62,7 @@ fn collect_drop_on_unwind() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(not(panic = "unwind"), ignore)]
|
||||||
fn collect_drop_on_unwind_zst() {
|
fn collect_drop_on_unwind_zst() {
|
||||||
static INSERTS: AtomicUsize = AtomicUsize::new(0);
|
static INSERTS: AtomicUsize = AtomicUsize::new(0);
|
||||||
static DROPS: AtomicUsize = AtomicUsize::new(0);
|
static DROPS: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|||||||
1
third_party/rust/rayon/tests/cross-pool.rs
vendored
1
third_party/rust/rayon/tests/cross-pool.rs
vendored
@@ -2,6 +2,7 @@ use rayon::prelude::*;
|
|||||||
use rayon::ThreadPoolBuilder;
|
use rayon::ThreadPoolBuilder;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
|
||||||
fn cross_pool_busy() {
|
fn cross_pool_busy() {
|
||||||
let pool1 = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
|
let pool1 = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
|
||||||
let pool2 = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
|
let pool2 = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
|
||||||
|
|||||||
12
third_party/rust/rayon/tests/debug.rs
vendored
12
third_party/rust/rayon/tests/debug.rs
vendored
@@ -104,8 +104,10 @@ fn debug_str() {
|
|||||||
check(s.par_chars());
|
check(s.par_chars());
|
||||||
check(s.par_lines());
|
check(s.par_lines());
|
||||||
check(s.par_split('\n'));
|
check(s.par_split('\n'));
|
||||||
|
check(s.par_split_inclusive('\n'));
|
||||||
check(s.par_split_terminator('\n'));
|
check(s.par_split_terminator('\n'));
|
||||||
check(s.par_split_whitespace());
|
check(s.par_split_whitespace());
|
||||||
|
check(s.par_split_ascii_whitespace());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -119,6 +121,8 @@ fn debug_vec() {
|
|||||||
let mut v: Vec<_> = (0..10).collect();
|
let mut v: Vec<_> = (0..10).collect();
|
||||||
check(v.par_iter());
|
check(v.par_iter());
|
||||||
check(v.par_iter_mut());
|
check(v.par_iter_mut());
|
||||||
|
check(v.par_chunk_by(i32::eq));
|
||||||
|
check(v.par_chunk_by_mut(i32::eq));
|
||||||
check(v.par_chunks(42));
|
check(v.par_chunks(42));
|
||||||
check(v.par_chunks_exact(42));
|
check(v.par_chunks_exact(42));
|
||||||
check(v.par_chunks_mut(42));
|
check(v.par_chunks_mut(42));
|
||||||
@@ -129,7 +133,9 @@ fn debug_vec() {
|
|||||||
check(v.par_rchunks_exact_mut(42));
|
check(v.par_rchunks_exact_mut(42));
|
||||||
check(v.par_windows(42));
|
check(v.par_windows(42));
|
||||||
check(v.par_split(|x| x % 3 == 0));
|
check(v.par_split(|x| x % 3 == 0));
|
||||||
|
check(v.par_split_inclusive(|x| x % 3 == 0));
|
||||||
check(v.par_split_mut(|x| x % 3 == 0));
|
check(v.par_split_mut(|x| x % 3 == 0));
|
||||||
|
check(v.par_split_inclusive_mut(|x| x % 3 == 0));
|
||||||
check(v.par_drain(..));
|
check(v.par_drain(..));
|
||||||
check(v.into_par_iter());
|
check(v.into_par_iter());
|
||||||
}
|
}
|
||||||
@@ -143,6 +149,8 @@ fn debug_array() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn debug_adaptors() {
|
fn debug_adaptors() {
|
||||||
let v: Vec<_> = (0..10).collect();
|
let v: Vec<_> = (0..10).collect();
|
||||||
|
check(v.par_iter().by_exponential_blocks());
|
||||||
|
check(v.par_iter().by_uniform_blocks(5));
|
||||||
check(v.par_iter().chain(&v));
|
check(v.par_iter().chain(&v));
|
||||||
check(v.par_iter().cloned());
|
check(v.par_iter().cloned());
|
||||||
check(v.par_iter().copied());
|
check(v.par_iter().copied());
|
||||||
@@ -172,7 +180,11 @@ fn debug_adaptors() {
|
|||||||
check(v.par_iter().positions(|_| true));
|
check(v.par_iter().positions(|_| true));
|
||||||
check(v.par_iter().rev());
|
check(v.par_iter().rev());
|
||||||
check(v.par_iter().skip(1));
|
check(v.par_iter().skip(1));
|
||||||
|
check(v.par_iter().skip_any(1));
|
||||||
|
check(v.par_iter().skip_any_while(|_| false));
|
||||||
check(v.par_iter().take(1));
|
check(v.par_iter().take(1));
|
||||||
|
check(v.par_iter().take_any(1));
|
||||||
|
check(v.par_iter().take_any_while(|_| true));
|
||||||
check(v.par_iter().map(Some).while_some());
|
check(v.par_iter().map(Some).while_some());
|
||||||
check(v.par_iter().with_max_len(1));
|
check(v.par_iter().with_max_len(1));
|
||||||
check(v.par_iter().with_min_len(1));
|
check(v.par_iter().with_min_len(1));
|
||||||
|
|||||||
1
third_party/rust/rayon/tests/iter_panic.rs
vendored
1
third_party/rust/rayon/tests/iter_panic.rs
vendored
@@ -20,6 +20,7 @@ fn iter_panic() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(not(panic = "unwind"), ignore)]
|
||||||
fn iter_panic_fuse() {
|
fn iter_panic_fuse() {
|
||||||
// We only use a single thread in order to make the behavior
|
// We only use a single thread in order to make the behavior
|
||||||
// of 'panic_fuse' deterministic
|
// of 'panic_fuse' deterministic
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use rayon::prelude::*;
|
|||||||
use rayon::*;
|
use rayon::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
|
||||||
fn named_threads() {
|
fn named_threads() {
|
||||||
ThreadPoolBuilder::new()
|
ThreadPoolBuilder::new()
|
||||||
.thread_name(|i| format!("hello-name-test-{}", i))
|
.thread_name(|i| format!("hello-name-test-{}", i))
|
||||||
|
|||||||
32
third_party/rust/rayon/tests/octillion.rs
vendored
32
third_party/rust/rayon/tests/octillion.rs
vendored
@@ -68,7 +68,14 @@ fn two_threads<F: Send + FnOnce() -> R, R: Send>(f: F) -> R {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(not(target_pointer_width = "64"), ignore)]
|
#[cfg_attr(
|
||||||
|
any(
|
||||||
|
not(target_pointer_width = "64"),
|
||||||
|
target_os = "emscripten",
|
||||||
|
target_family = "wasm"
|
||||||
|
),
|
||||||
|
ignore
|
||||||
|
)]
|
||||||
fn find_last_octillion() {
|
fn find_last_octillion() {
|
||||||
// It would be nice if `find_last` could prioritize the later splits,
|
// It would be nice if `find_last` could prioritize the later splits,
|
||||||
// basically flipping the `join` args, without needing indexed `rev`.
|
// basically flipping the `join` args, without needing indexed `rev`.
|
||||||
@@ -78,32 +85,49 @@ fn find_last_octillion() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(not(target_pointer_width = "64"), ignore)]
|
#[cfg_attr(
|
||||||
|
any(
|
||||||
|
not(target_pointer_width = "64"),
|
||||||
|
target_os = "emscripten",
|
||||||
|
target_family = "wasm"
|
||||||
|
),
|
||||||
|
ignore
|
||||||
|
)]
|
||||||
fn find_last_octillion_inclusive() {
|
fn find_last_octillion_inclusive() {
|
||||||
let x = two_threads(|| octillion_inclusive().find_last(|_| true));
|
let x = two_threads(|| octillion_inclusive().find_last(|_| true));
|
||||||
assert_eq!(x, Some(OCTILLION));
|
assert_eq!(x, Some(OCTILLION));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(not(target_pointer_width = "64"), ignore)]
|
#[cfg_attr(
|
||||||
|
any(
|
||||||
|
not(target_pointer_width = "64"),
|
||||||
|
target_os = "emscripten",
|
||||||
|
target_family = "wasm"
|
||||||
|
),
|
||||||
|
ignore
|
||||||
|
)]
|
||||||
fn find_last_octillion_flat() {
|
fn find_last_octillion_flat() {
|
||||||
let x = two_threads(|| octillion_flat().find_last(|_| true));
|
let x = two_threads(|| octillion_flat().find_last(|_| true));
|
||||||
assert_eq!(x, Some(OCTILLION - 1));
|
assert_eq!(x, Some(OCTILLION - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
|
||||||
fn find_any_octillion() {
|
fn find_any_octillion() {
|
||||||
let x = two_threads(|| octillion().find_any(|x| *x > OCTILLION / 2));
|
let x = two_threads(|| octillion().find_any(|x| *x > OCTILLION / 2));
|
||||||
assert!(x.is_some());
|
assert!(x.is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
|
||||||
fn find_any_octillion_flat() {
|
fn find_any_octillion_flat() {
|
||||||
let x = two_threads(|| octillion_flat().find_any(|x| *x > OCTILLION / 2));
|
let x = two_threads(|| octillion_flat().find_any(|x| *x > OCTILLION / 2));
|
||||||
assert!(x.is_some());
|
assert!(x.is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
|
||||||
fn filter_find_any_octillion() {
|
fn filter_find_any_octillion() {
|
||||||
let x = two_threads(|| {
|
let x = two_threads(|| {
|
||||||
octillion()
|
octillion()
|
||||||
@@ -114,6 +138,7 @@ fn filter_find_any_octillion() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
|
||||||
fn filter_find_any_octillion_flat() {
|
fn filter_find_any_octillion_flat() {
|
||||||
let x = two_threads(|| {
|
let x = two_threads(|| {
|
||||||
octillion_flat()
|
octillion_flat()
|
||||||
@@ -124,6 +149,7 @@ fn filter_find_any_octillion_flat() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
|
||||||
fn fold_find_any_octillion_flat() {
|
fn fold_find_any_octillion_flat() {
|
||||||
let x = two_threads(|| octillion_flat().fold(|| (), |_, _| ()).find_any(|_| true));
|
let x = two_threads(|| octillion_flat().fold(|| (), |_, _| ()).find_any(|_| true));
|
||||||
assert!(x.is_some());
|
assert!(x.is_some());
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use std::iter::once_with;
|
|||||||
const N: usize = 100_000;
|
const N: usize = 100_000;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
|
||||||
fn par_bridge_recursion() {
|
fn par_bridge_recursion() {
|
||||||
let pool = rayon::ThreadPoolBuilder::new()
|
let pool = rayon::ThreadPoolBuilder::new()
|
||||||
.num_threads(10)
|
.num_threads(10)
|
||||||
|
|||||||
@@ -116,20 +116,17 @@ fn array() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty() {
|
fn empty() {
|
||||||
let v = vec![42];
|
check(&[], rayon::iter::empty::<i32>);
|
||||||
check(&v[..0], rayon::iter::empty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn once() {
|
fn once() {
|
||||||
let v = vec![42];
|
check(&[42], || rayon::iter::once(42));
|
||||||
check(&v, || rayon::iter::once(42));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn option() {
|
fn option() {
|
||||||
let v = vec![42];
|
check(&[42], || Some(42));
|
||||||
check(&v, || Some(42));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
23
third_party/rust/rayon/tests/sort-panic-safe.rs
vendored
23
third_party/rust/rayon/tests/sort-panic-safe.rs
vendored
@@ -2,17 +2,20 @@ use rand::distributions::Uniform;
|
|||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::cmp::{self, Ordering};
|
use std::cmp::Ordering;
|
||||||
use std::panic;
|
use std::panic;
|
||||||
use std::sync::atomic::AtomicUsize;
|
use std::sync::atomic::AtomicUsize;
|
||||||
use std::sync::atomic::Ordering::Relaxed;
|
use std::sync::atomic::Ordering::Relaxed;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
static VERSIONS: AtomicUsize = AtomicUsize::new(0);
|
// const is needed for array initializer
|
||||||
|
#[allow(clippy::declare_interior_mutable_const)]
|
||||||
|
const ZERO: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
const LEN: usize = 20_000;
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
static VERSIONS: AtomicUsize = ZERO;
|
||||||
static ref DROP_COUNTS: Vec<AtomicUsize> = (0..20_000).map(|_| AtomicUsize::new(0)).collect();
|
|
||||||
}
|
static DROP_COUNTS: [AtomicUsize; LEN] = [ZERO; LEN];
|
||||||
|
|
||||||
#[derive(Clone, Eq)]
|
#[derive(Clone, Eq)]
|
||||||
struct DropCounter {
|
struct DropCounter {
|
||||||
@@ -27,6 +30,7 @@ impl PartialEq for DropCounter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::non_canonical_partial_ord_impl)]
|
||||||
impl PartialOrd for DropCounter {
|
impl PartialOrd for DropCounter {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
self.version.set(self.version.get() + 1);
|
self.version.set(self.version.get() + 1);
|
||||||
@@ -65,7 +69,7 @@ macro_rules! test {
|
|||||||
let step = if len <= 100 {
|
let step = if len <= 100 {
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
cmp::max(1, panic_countdown / 10)
|
Ord::max(1, panic_countdown / 10)
|
||||||
};
|
};
|
||||||
|
|
||||||
// ... and then panic after each `step` comparisons.
|
// ... and then panic after each `step` comparisons.
|
||||||
@@ -114,9 +118,10 @@ macro_rules! test {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
|
thread_local!(static SILENCE_PANIC: Cell<bool> = const { Cell::new(false) });
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)]
|
||||||
fn sort_panic_safe() {
|
fn sort_panic_safe() {
|
||||||
let prev = panic::take_hook();
|
let prev = panic::take_hook();
|
||||||
panic::set_hook(Box::new(move |info| {
|
panic::set_hook(Box::new(move |info| {
|
||||||
@@ -144,8 +149,8 @@ fn sort_panic_safe() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
let a = rng.sample(&len_dist);
|
let a = rng.sample(len_dist);
|
||||||
let b = rng.sample(&len_dist);
|
let b = rng.sample(len_dist);
|
||||||
if a < b {
|
if a < b {
|
||||||
input[a..b].reverse();
|
input[a..b].reverse();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
85
third_party/rust/rayon/tests/str.rs
vendored
85
third_party/rust/rayon/tests/str.rs
vendored
@@ -56,39 +56,45 @@ pub fn execute_strings_split() {
|
|||||||
("foo\nbar\n\r\nbaz", '\n'),
|
("foo\nbar\n\r\nbaz", '\n'),
|
||||||
("A few words", ' '),
|
("A few words", ' '),
|
||||||
(" Mary had\ta\u{2009}little \n\t lamb", ' '),
|
(" Mary had\ta\u{2009}little \n\t lamb", ' '),
|
||||||
|
("Mary had a little lamb\nlittle lamb\nlittle lamb.", '\n'),
|
||||||
|
("Mary had a little lamb\nlittle lamb\nlittle lamb.\n", '\n'),
|
||||||
(include_str!("str.rs"), ' '),
|
(include_str!("str.rs"), ' '),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
macro_rules! check_separators {
|
||||||
|
($split:ident, $par_split:ident) => {
|
||||||
for &(string, separator) in &tests {
|
for &(string, separator) in &tests {
|
||||||
let serial: Vec<_> = string.split(separator).collect();
|
let serial: Vec<_> = string.$split(separator).collect();
|
||||||
let parallel: Vec<_> = string.par_split(separator).collect();
|
let parallel: Vec<_> = string.$par_split(separator).collect();
|
||||||
assert_eq!(serial, parallel);
|
assert_eq!(serial, parallel);
|
||||||
|
|
||||||
let pattern: &[char] = &['\u{0}', separator, '\u{1F980}'];
|
let array = ['\u{0}', separator, '\u{1F980}'];
|
||||||
let serial: Vec<_> = string.split(pattern).collect();
|
let array_ref = &array;
|
||||||
let parallel: Vec<_> = string.par_split(pattern).collect();
|
let slice: &[char] = array_ref;
|
||||||
|
|
||||||
|
let serial: Vec<_> = string.$split(slice).collect();
|
||||||
|
let parallel: Vec<_> = string.$par_split(slice).collect();
|
||||||
assert_eq!(serial, parallel);
|
assert_eq!(serial, parallel);
|
||||||
|
|
||||||
let serial_fn: Vec<_> = string.split(|c| c == separator).collect();
|
let serial: Vec<_> = string.$split(array).collect();
|
||||||
let parallel_fn: Vec<_> = string.par_split(|c| c == separator).collect();
|
let parallel: Vec<_> = string.$par_split(array).collect();
|
||||||
|
assert_eq!(serial, parallel);
|
||||||
|
|
||||||
|
let serial: Vec<_> = string.$split(array_ref).collect();
|
||||||
|
let parallel: Vec<_> = string.$par_split(array_ref).collect();
|
||||||
|
assert_eq!(serial, parallel);
|
||||||
|
|
||||||
|
let serial_fn: Vec<_> = string.$split(|c| c == separator).collect();
|
||||||
|
let parallel_fn: Vec<_> = string.$par_split(|c| c == separator).collect();
|
||||||
assert_eq!(serial_fn, parallel_fn);
|
assert_eq!(serial_fn, parallel_fn);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
for &(string, separator) in &tests {
|
|
||||||
let serial: Vec<_> = string.split_terminator(separator).collect();
|
|
||||||
let parallel: Vec<_> = string.par_split_terminator(separator).collect();
|
|
||||||
assert_eq!(serial, parallel);
|
|
||||||
|
|
||||||
let pattern: &[char] = &['\u{0}', separator, '\u{1F980}'];
|
|
||||||
let serial: Vec<_> = string.split_terminator(pattern).collect();
|
|
||||||
let parallel: Vec<_> = string.par_split_terminator(pattern).collect();
|
|
||||||
assert_eq!(serial, parallel);
|
|
||||||
|
|
||||||
let serial: Vec<_> = string.split_terminator(|c| c == separator).collect();
|
|
||||||
let parallel: Vec<_> = string.par_split_terminator(|c| c == separator).collect();
|
|
||||||
assert_eq!(serial, parallel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_separators!(split, par_split);
|
||||||
|
check_separators!(split_inclusive, par_split_inclusive);
|
||||||
|
check_separators!(split_terminator, par_split_terminator);
|
||||||
|
|
||||||
for &(string, _) in &tests {
|
for &(string, _) in &tests {
|
||||||
let serial: Vec<_> = string.lines().collect();
|
let serial: Vec<_> = string.lines().collect();
|
||||||
let parallel: Vec<_> = string.par_lines().collect();
|
let parallel: Vec<_> = string.par_lines().collect();
|
||||||
@@ -101,34 +107,13 @@ pub fn execute_strings_split() {
|
|||||||
assert_eq!(serial, parallel);
|
assert_eq!(serial, parallel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for &(string, _) in &tests {
|
||||||
|
let serial: Vec<_> = string.split_ascii_whitespace().collect();
|
||||||
|
let parallel: Vec<_> = string.par_split_ascii_whitespace().collect();
|
||||||
|
assert_eq!(serial, parallel);
|
||||||
|
}
|
||||||
|
|
||||||
// try matching separators too!
|
// try matching separators too!
|
||||||
for &(string, separator) in &tests {
|
check_separators!(matches, par_matches);
|
||||||
let serial: Vec<_> = string.matches(separator).collect();
|
check_separators!(match_indices, par_match_indices);
|
||||||
let parallel: Vec<_> = string.par_matches(separator).collect();
|
|
||||||
assert_eq!(serial, parallel);
|
|
||||||
|
|
||||||
let pattern: &[char] = &['\u{0}', separator, '\u{1F980}'];
|
|
||||||
let serial: Vec<_> = string.matches(pattern).collect();
|
|
||||||
let parallel: Vec<_> = string.par_matches(pattern).collect();
|
|
||||||
assert_eq!(serial, parallel);
|
|
||||||
|
|
||||||
let serial_fn: Vec<_> = string.matches(|c| c == separator).collect();
|
|
||||||
let parallel_fn: Vec<_> = string.par_matches(|c| c == separator).collect();
|
|
||||||
assert_eq!(serial_fn, parallel_fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
for &(string, separator) in &tests {
|
|
||||||
let serial: Vec<_> = string.match_indices(separator).collect();
|
|
||||||
let parallel: Vec<_> = string.par_match_indices(separator).collect();
|
|
||||||
assert_eq!(serial, parallel);
|
|
||||||
|
|
||||||
let pattern: &[char] = &['\u{0}', separator, '\u{1F980}'];
|
|
||||||
let serial: Vec<_> = string.match_indices(pattern).collect();
|
|
||||||
let parallel: Vec<_> = string.par_match_indices(pattern).collect();
|
|
||||||
assert_eq!(serial, parallel);
|
|
||||||
|
|
||||||
let serial_fn: Vec<_> = string.match_indices(|c| c == separator).collect();
|
|
||||||
let parallel_fn: Vec<_> = string.par_match_indices(|c| c == separator).collect();
|
|
||||||
assert_eq!(serial_fn, parallel_fn);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user