use broccoli::{
aabb::Aabb,
aabb::ManySwap,
Tree,
{
build::Sorter,
build::{DefaultSorter, NodeBuildResult, TreeBuildVisitor},
node::Node,
},
};
use broccoli::num_level;
pub trait RayonBuildPar<'a, T: Aabb> {
fn par_new(bots: &'a mut [T]) -> Self;
}
impl<'a, T: Aabb + ManySwap> RayonBuildPar<'a, T> for Tree<'a, T>
where
T: Send,
T::Num: Send,
{
fn par_new(bots: &'a mut [T]) -> Self {
let num_level = num_level::default(bots.len());
assert!(num_level >= 1);
let num_nodes = num_level::num_nodes(num_level);
let mut buffer = Vec::with_capacity(num_nodes);
recurse_par(
SEQ_FALLBACK_DEFAULT,
&mut DefaultSorter,
&mut buffer,
TreeBuildVisitor::new(num_level, bots),
);
assert_eq!(buffer.len(), num_nodes);
Tree::from_nodes(buffer)
}
}
pub const SEQ_FALLBACK_DEFAULT: usize = 16;
pub fn recurse_par<'a, T: Aabb + ManySwap, S: Sorter<T> + Clone>(
num_seq_fallback: usize,
sorter: &mut S,
buffer: &mut Vec<Node<'a, T, T::Num>>,
vistr: TreeBuildVisitor<'a, T>,
) where
S: Send,
T: Send,
T::Num: Send,
{
let NodeBuildResult { node, rest } = vistr.build_and_next();
if let Some([left, right]) = rest {
if node.get_min_elem() <= num_seq_fallback {
buffer.push(node.finish(sorter));
left.recurse_seq(sorter, buffer);
right.recurse_seq(sorter, buffer);
} else {
let mut s2 = sorter.clone();
let (_, mut buffer2) = rayon::join(
|| {
buffer.push(node.finish(sorter));
recurse_par(num_seq_fallback, sorter, buffer, left);
},
|| {
let num_nodes = num_level::num_nodes(right.get_height() + 1);
let mut buffer2 = Vec::with_capacity(num_nodes);
recurse_par(num_seq_fallback, &mut s2, &mut buffer2, right);
assert_eq!(num_nodes, buffer2.len());
buffer2
},
);
buffer.append(&mut buffer2);
}
} else {
buffer.push(node.finish(sorter));
}
}