use super::policy::{ExecutionPolicy, Parallel};
use melinoe::cell::MelinoeCell;
use melinoe::region::WriterShard;
use moirai_executor::{SyncTask, global, initialize};
pub fn par_partition_for_each<'brand, T, F>(
cells: &mut [MelinoeCell<'brand, T>],
chunk_size: usize,
f: F,
) where
T: Send,
F: Fn(usize, WriterShard<'_, 'brand, T>) + Send + Sync,
{
par_partition_for_each_with_policy::<Parallel, T, F>(cells, chunk_size, f);
}
pub fn par_partition_for_each_with_policy<'brand, P, T, F>(
cells: &mut [MelinoeCell<'brand, T>],
chunk_size: usize,
f: F,
) where
P: ExecutionPolicy,
T: Send,
F: Fn(usize, WriterShard<'_, 'brand, T>) + Send + Sync,
{
let n = cells.len();
if n == 0 || chunk_size == 0 {
return;
}
let num_chunks = n.div_ceil(chunk_size);
if !P::parallelize(n) {
for (c, chunk) in cells.chunks_mut(chunk_size).enumerate() {
f(c * chunk_size, WriterShard::new(chunk));
}
return;
}
initialize();
let partitions = WriterShard::new(cells).par_chunks(chunk_size);
let f = &f;
global()
.for_each_indexed::<SyncTask, _>(num_chunks, move |c| {
let shard = unsafe { partitions.get_unchecked_chunk(c) };
f(c * chunk_size, shard);
})
.expect("moirai global executor: par_partition_for_each");
}
pub fn par_partition_map<'brand, T, R, F>(
cells: &mut [MelinoeCell<'brand, T>],
chunk_size: usize,
f: F,
) -> Vec<R>
where
T: Send,
R: Send,
F: Fn(usize, WriterShard<'_, 'brand, T>) -> R + Send + Sync,
{
par_partition_map_with_policy::<Parallel, T, R, F>(cells, chunk_size, f)
}
pub fn par_partition_map_with_policy<'brand, P, T, R, F>(
cells: &mut [MelinoeCell<'brand, T>],
chunk_size: usize,
f: F,
) -> Vec<R>
where
P: ExecutionPolicy,
T: Send,
R: Send,
F: Fn(usize, WriterShard<'_, 'brand, T>) -> R + Send + Sync,
{
let n = cells.len();
if n == 0 || chunk_size == 0 {
return Vec::new();
}
let num_chunks = n.div_ceil(chunk_size);
if !P::parallelize(n) {
let mut results = Vec::with_capacity(num_chunks);
for (c, chunk) in cells.chunks_mut(chunk_size).enumerate() {
results.push(f(c * chunk_size, WriterShard::new(chunk)));
}
return results;
}
initialize();
let mut out: Vec<core::mem::MaybeUninit<R>> = Vec::with_capacity(num_chunks);
unsafe {
out.set_len(num_chunks);
}
let cells_partitions = WriterShard::new(cells).par_chunks(chunk_size);
let out_partitions =
WriterShard::new(MelinoeCell::from_mut_slice(out.as_mut_slice())).par_chunks(1);
let f = &f;
global()
.for_each_indexed::<SyncTask, _>(num_chunks, move |c| {
let shard = unsafe { cells_partitions.get_unchecked_chunk(c) };
let mut out_shard = unsafe { out_partitions.get_unchecked_chunk(c) };
let result = f(c * chunk_size, shard);
if let Some(slot) = out_shard.get_mut(0) {
slot.write(result);
}
})
.expect("moirai global executor: par_partition_map");
let mut out = core::mem::ManuallyDrop::new(out);
unsafe { Vec::from_raw_parts(out.as_mut_ptr().cast::<R>(), num_chunks, out.capacity()) }
}