use crossbeam_deque::{Steal, Stealer, Worker};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::{Mutex, TryLockError};
use std::thread::yield_now;
use crate::current_num_threads;
use crate::iter::plumbing::{bridge_unindexed, Folder, UnindexedConsumer, UnindexedProducer};
use crate::iter::ParallelIterator;
pub trait ParallelBridge: Sized {
fn par_bridge(self) -> IterBridge<Self>;
}
impl<T: Iterator + Send> ParallelBridge for T
where
T::Item: Send,
{
fn par_bridge(self) -> IterBridge<Self> {
IterBridge { iter: self }
}
}
#[derive(Debug, Clone)]
pub struct IterBridge<Iter> {
iter: Iter,
}
impl<Iter: Iterator + Send> ParallelIterator for IterBridge<Iter>
where
Iter::Item: Send,
{
type Item = Iter::Item;
fn drive_unindexed<C>(self, consumer: C) -> C::Result
where
C: UnindexedConsumer<Self::Item>,
{
let split_count = AtomicUsize::new(current_num_threads());
let worker = Worker::new_fifo();
let stealer = worker.stealer();
let done = AtomicBool::new(false);
let iter = Mutex::new((self.iter, worker));
bridge_unindexed(
IterParallelProducer {
split_count: &split_count,
done: &done,
iter: &iter,
items: stealer,
},
consumer,
)
}
}
struct IterParallelProducer<'a, Iter: Iterator> {
split_count: &'a AtomicUsize,
done: &'a AtomicBool,
iter: &'a Mutex<(Iter, Worker<Iter::Item>)>,
items: Stealer<Iter::Item>,
}
impl<'a, Iter: Iterator + 'a> Clone for IterParallelProducer<'a, Iter> {
fn clone(&self) -> Self {
IterParallelProducer {
split_count: self.split_count,
done: self.done,
iter: self.iter,
items: self.items.clone(),
}
}
}
impl<'a, Iter: Iterator + Send + 'a> UnindexedProducer for IterParallelProducer<'a, Iter>
where
Iter::Item: Send,
{
type Item = Iter::Item;
fn split(self) -> (Self, Option<Self>) {
let mut count = self.split_count.load(Ordering::SeqCst);
loop {
let done = self.done.load(Ordering::SeqCst);
match count.checked_sub(1) {
Some(new_count) if !done => {
let last_count =
self.split_count
.compare_and_swap(count, new_count, Ordering::SeqCst);
if last_count == count {
return (self.clone(), Some(self));
} else {
count = last_count;
}
}
_ => {
return (self, None);
}
}
}
}
fn fold_with<F>(self, mut folder: F) -> F
where
F: Folder<Self::Item>,
{
loop {
match self.items.steal() {
Steal::Success(it) => {
folder = folder.consume(it);
if folder.full() {
return folder;
}
}
Steal::Empty => {
if self.done.load(Ordering::SeqCst) {
return folder;
} else {
match self.iter.try_lock() {
Ok(mut guard) => {
let count = current_num_threads();
let count = (count * count) * 2;
let (ref mut iter, ref worker) = *guard;
for _ in 0..count {
if let Some(it) = iter.next() {
worker.push(it);
} else {
self.done.store(true, Ordering::SeqCst);
break;
}
}
}
Err(TryLockError::WouldBlock) => {
yield_now(); }
Err(TryLockError::Poisoned(_)) => {
return folder;
}
}
}
}
Steal::Retry => (),
}
}
}
}