use std::cell::RefCell;
use std::cmp::Ordering;
use std::fmt::{self, Debug};
use std::hash::{Hash, Hasher};
use std::rc::Rc;
use std::mem;
pub struct UnionFindNode<Data = ()>(Rc<RefCell<NodeImpl<Data>>>);
enum NodeImpl<Data> {
Root {
data: Data,
rank: u8,
},
Link(UnionFindNode<Data>),
Dummy,
}
use self::NodeImpl::*;
impl<Data> UnionFindNode<Data> {
fn id(&self) -> usize {
&*self.0 as *const _ as usize
}
}
impl<Data> Debug for UnionFindNode<Data> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "UnionFindNode({:p})", self.0)
}
}
impl<Data> PartialEq for UnionFindNode<Data> {
fn eq(&self, other: &UnionFindNode<Data>) -> bool {
self.id() == other.id()
}
}
impl<Data> Eq for UnionFindNode<Data> { }
impl<Data> PartialOrd for UnionFindNode<Data> {
fn partial_cmp(&self, other: &UnionFindNode<Data>) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<Data> Ord for UnionFindNode<Data> {
fn cmp(&self, other: &UnionFindNode<Data>) -> Ordering {
self.id().cmp(&other.id())
}
}
impl<Data> Hash for UnionFindNode<Data> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id().hash(state)
}
}
impl<Data> Clone for UnionFindNode<Data> {
fn clone(&self) -> Self {
UnionFindNode(self.0.clone())
}
}
impl<Data: Default> Default for UnionFindNode<Data> {
fn default() -> Self {
UnionFindNode::new(Default::default())
}
}
impl<Data> UnionFindNode<Data> {
pub fn new(data: Data) -> Self {
UnionFindNode(Rc::new(RefCell::new(Root {
data: data,
rank: 0,
})))
}
pub fn union_with<R, F>(&mut self, other: &mut Self, f: F) -> Option<R>
where F: FnOnce(Data, Data) -> (Data, R) {
let (a, rank_a) = self.find_with_rank();
let (b, rank_b) = other.find_with_rank();
if a == b {
None
} else if rank_a > rank_b {
Some(b.set_parent_with(a, |b_data, a_data| f(a_data, b_data)))
} else if rank_b > rank_a {
Some(a.set_parent_with(b, f))
} else {
b.increment_rank();
Some(a.set_parent_with(b, f))
}
}
pub fn union(&mut self, other: &mut Self) -> Option<Data> {
let (a, rank_a) = self.find_with_rank();
let (b, rank_b) = other.find_with_rank();
if a == b {
return None
} else if rank_a > rank_b {
Some(b.set_parent(a))
} else if rank_b > rank_a {
Some(a.set_parent(b))
} else {
b.increment_rank();
Some(a.set_parent(b))
}
}
pub fn find(&self) -> Self {
match *self.0.borrow_mut() {
Root { .. } => self.clone(),
Link(ref mut parent) => {
let root = parent.find();
*parent = root.clone();
root
}
Dummy => panic!("find: got dummy"),
}
}
fn find_with_rank(&self) -> (Self, u8) {
match *self.0.borrow_mut() {
Root { rank, .. } => (self.clone(), rank),
Link(ref mut parent) => {
let (root, rank) = parent.find_with_rank();
*parent = root.clone();
(root, rank)
}
Dummy => panic!("find: got dummy"),
}
}
pub fn equiv(&self, other: &Self) -> bool {
self.find() == other.find()
}
pub fn replace_data(&self, new: Data) -> Data {
use std::mem::replace;
self.with_data(|data| replace(data, new))
}
pub fn clone_data(&self) -> Data
where Data: Clone {
self.with_data(|data| data.clone())
}
pub fn with_data<R, F>(&self, f: F) -> R
where F: FnOnce(&mut Data) -> R {
self.find().root_with_data(f)
}
fn root_with_data<R, F>(&self, f: F) -> R
where F: FnOnce(&mut Data) -> R {
match &mut *self.0.borrow_mut() {
&mut Root { ref mut data, .. } => f(data),
_ => panic!("with_data: non-root")
}
}
fn increment_rank(&self) {
match *self.0.borrow_mut() {
Root { ref mut rank, .. } => {
*rank += 1;
}
_ => panic!("increment_rank: non-root")
}
}
fn set_parent(&self, new_parent: Self) -> Data {
match mem::replace(&mut *self.0.borrow_mut(), Link(new_parent)) {
Root { data, .. } => data,
_ => panic!("set_parent: non-root"),
}
}
fn set_parent_with<R, F>(&self, parent: Self, f: F) -> R
where F: FnOnce(Data, Data) -> (Data, R) {
let mut guard_self = self.0.borrow_mut();
let mut guard_parent = parent.0.borrow_mut();
let contents_self = mem::replace(&mut *guard_self,
Link(parent.clone()));
let contents_parent = mem::replace(&mut *guard_parent, Dummy);
match (contents_self, contents_parent) {
(Root { data: data_self, .. },
Root { data: data_parent, rank }) => {
let (new_data, result) = f(data_self, data_parent);
mem::replace(&mut *guard_parent, Root {
data: new_data,
rank: rank,
});
result
}
_ => panic!("set_parent_with: non-root"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn union() {
let mut uf0 = UnionFindNode::new(());
let mut uf1 = UnionFindNode::new(());
assert!(!uf0.equiv(&uf1));
uf0.union(&mut uf1);
assert!(uf0.equiv(&uf1));
}
#[test]
fn unions() {
let mut uf0 = UnionFindNode::new(());
let mut uf1 = UnionFindNode::new(());
let mut uf2 = UnionFindNode::new(());
let mut uf3 = UnionFindNode::new(());
let mut uf4 = UnionFindNode::new(());
let mut uf5 = UnionFindNode::new(());
let mut uf6 = UnionFindNode::new(());
let mut uf7 = UnionFindNode::new(());
uf0.union(&mut uf1);
uf1.union(&mut uf2);
uf4.union(&mut uf3);
uf3.union(&mut uf2);
assert!(uf0.equiv(&uf1));
assert!(uf0.equiv(&uf2));
assert!(uf0.equiv(&uf3));
assert!(uf0.equiv(&uf4));
assert!(!uf0.equiv(&uf5));
uf3.union(&mut uf5);
assert!(uf0.equiv(&uf5));
uf7.union(&mut uf6);
assert!(uf6.equiv(&uf7));
assert!(!uf5.equiv(&uf7));
uf0.union(&mut uf7);
assert!(uf5.equiv(&uf7));
}
}