use std::{mem::ManuallyDrop, sync::atomic::Ordering};
use rayon::prelude::*;
use crate::prelude::*;
pub struct Afforest<NI: Idx>(Box<[Atomic<NI>]>);
unsafe impl<NI: Idx> Send for Afforest<NI> {}
unsafe impl<NI: Idx> Sync for Afforest<NI> {}
impl<NI: Idx> UnionFind<NI> for Afforest<NI> {
fn union(&self, u: NI, v: NI) {
let mut p1 = self.find(u);
let mut p2 = self.find(v);
while p1 != p2 {
let high = NI::max(p1, p2);
let low = p1 + p2 - high;
let p_high = self.find(high);
if p_high == low
|| (p_high == high && self.update_parent(self.find(high), high, low).is_ok())
{
break;
}
p1 = self.parent(self.parent(high));
p2 = self.parent(low);
}
}
fn find(&self, u: NI) -> NI {
self.parent(u)
}
fn len(&self) -> usize {
self.0.len()
}
fn compress(&self) {
(0..self.len()).into_par_iter().map(NI::new).for_each(|n| {
while self.parent(n) != self.parent(self.parent(n)) {
self.0[n.index()].store(self.parent(self.parent(n)), Ordering::SeqCst)
}
});
}
}
impl<NI: Idx> Afforest<NI> {
pub fn new(size: usize) -> Self {
let mut v = Vec::with_capacity(size);
(0..size)
.into_par_iter()
.map(|i| Atomic::new(NI::new(i)))
.collect_into_vec(&mut v);
Self(v.into_boxed_slice())
}
fn parent(&self, i: NI) -> NI {
self.0[i.index()].load(Ordering::SeqCst)
}
fn update_parent(&self, id: NI, current: NI, new: NI) -> Result<NI, NI> {
self.0[id.index()].compare_exchange_weak(current, new, Ordering::SeqCst, Ordering::Relaxed)
}
}
impl<NI: Idx> Components<NI> for Afforest<NI> {
fn component(&self, node: NI) -> NI {
self.find(node)
}
fn to_vec(self) -> Vec<NI> {
let mut components = ManuallyDrop::new(self.0.into_vec());
let (ptr, len, cap) = (
components.as_mut_ptr(),
components.len(),
components.capacity(),
);
unsafe {
let ptr = ptr as *mut Vec<NI>;
let ptr = ptr as *mut _;
Vec::from_raw_parts(ptr, len, cap)
}
}
}
#[cfg(test)]
mod test {
use crate::prelude::*;
#[test]
fn test_union() {
let af = Afforest::new(10);
af.union(9, 7);
af.union(7, 4);
af.union(4, 2);
af.union(2, 0);
af.compress();
assert_eq!(af.find(9), 0);
}
}