use egglog_numeric_id as numeric_id;
use numeric_id::NumericId;
use std::cmp;
pub mod concurrent;
#[cfg(test)]
mod tests;
#[derive(Clone)]
pub struct UnionFind<Value> {
parents: Vec<Value>,
}
impl<V> Default for UnionFind<V> {
fn default() -> Self {
Self {
parents: Vec::new(),
}
}
}
impl<Value: NumericId> UnionFind<Value> {
pub fn reset(&mut self) {
for (i, v) in self.parents.iter_mut().enumerate() {
*v = Value::from_usize(i);
}
}
pub fn reserve(&mut self, v: Value) {
if v.index() >= self.parents.len() {
for i in self.parents.len()..=v.index() {
self.parents.push(Value::from_usize(i));
}
}
}
pub fn union(&mut self, a: Value, b: Value) -> (Value /* parent */, Value /* child */) {
self.reserve(a);
self.reserve(b);
let a = self.find(a);
let b = self.find(b);
if a != b {
let parent = cmp::min(a, b);
let child = cmp::max(a, b);
self.parents[child.index()] = parent;
(parent, child)
} else {
(a, a)
}
}
pub fn find(&mut self, id: Value) -> Value {
self.reserve(id);
let mut cur = id;
loop {
let parent = self.parents[cur.index()];
if cur == parent {
break;
}
let grand = self.parents[parent.index()];
self.parents[cur.index()] = grand;
cur = grand;
}
cur
}
pub fn find_naive(&self, id: Value) -> Value {
if self.parents.len() <= id.index() {
return id;
}
let mut cur = id;
loop {
let parent = self.parents[cur.index()];
if cur == parent {
break;
}
cur = parent;
}
cur
}
}