use rayon::prelude::*;
pub const BLOCK: usize = 8192;
pub fn for_each_block<T, F>(slice: &[T], min_len: usize, f: F)
where
T: Sync,
F: Fn(usize, &[T]) + Send + Sync,
{
if slice.len() < min_len {
for (index, block) in slice.chunks(BLOCK).enumerate() {
f(index * BLOCK, block);
}
return;
}
slice
.par_chunks(BLOCK)
.enumerate()
.for_each(|(index, block)| f(index * BLOCK, block));
}
pub fn map_blocks_into<T, U, F>(src: &[T], dst: &mut [U], min_len: usize, f: F)
where
T: Sync,
U: Send,
F: Fn(&[T], &mut [U]) + Send + Sync,
{
let len = src.len().min(dst.len());
let (src, dst) = (&src[..len], &mut dst[..len]);
if len < min_len {
for (source, target) in src.chunks(BLOCK).zip(dst.chunks_mut(BLOCK)) {
f(source, target);
}
return;
}
src.par_chunks(BLOCK)
.zip(dst.par_chunks_mut(BLOCK))
.for_each(|(source, target)| f(source, target));
}
pub fn map_zip_blocks_into<T, U, V, F>(a: &[T], b: &[U], dst: &mut [V], min_len: usize, f: F)
where
T: Sync,
U: Sync,
V: Send,
F: Fn(&[T], &[U], &mut [V]) + Send + Sync,
{
let len = a.len().min(b.len()).min(dst.len());
let (a, b, dst) = (&a[..len], &b[..len], &mut dst[..len]);
if len < min_len {
for ((source, other), target) in a
.chunks(BLOCK)
.zip(b.chunks(BLOCK))
.zip(dst.chunks_mut(BLOCK))
{
f(source, other, target);
}
return;
}
a.par_chunks(BLOCK)
.zip(b.par_chunks(BLOCK))
.zip(dst.par_chunks_mut(BLOCK))
.for_each(|((source, other), target)| f(source, other, target));
}
pub fn reduce_blocks<T, A, Fold, Combine>(
slice: &[T],
min_len: usize,
identity: A,
fold: Fold,
combine: Combine,
) -> A
where
T: Sync,
A: Send + Clone,
Fold: Fn(&[T]) -> A + Send + Sync,
Combine: Fn(A, A) -> A,
{
if slice.len() < min_len {
return slice.chunks(BLOCK).map(&fold).fold(identity, &combine);
}
let partials: Vec<A> = slice.par_chunks(BLOCK).map(&fold).collect();
partials.into_iter().fold(identity, &combine)
}
pub fn all_blocks<T, F>(slice: &[T], min_len: usize, f: F) -> bool
where
T: Sync,
F: Fn(&[T]) -> bool + Send + Sync,
{
if slice.len() < min_len {
return slice.chunks(BLOCK).all(&f);
}
slice.par_chunks(BLOCK).all(&f)
}
#[cfg(test)]
#[path = "parallel_tests.rs"]
mod tests;