Skip to content

Commit af9a2e3

Browse files
committed
Perform some cleanup on DisjointSet
1 parent 767d06b commit af9a2e3

File tree

2 files changed

+17
-47
lines changed

2 files changed

+17
-47
lines changed

rust/2018/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ clap = "2"
1515
z3 = "0.7"
1616
num = "0.3"
1717
derive_more = "0.99"
18-
parking_lot = { version = "0.11", features = ["nightly"] }
18+
parking_lot = { version = "0.12", features = ["nightly"] }

rust/2018/src/bin/25/disjoint_set.rs

Lines changed: 16 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub struct DisjointSet<T> {
3535
nodes: Vec<RwLock<Node>>,
3636
}
3737

38-
#[derive(Copy)]
38+
#[derive(Clone, Copy)]
3939
struct Node {
4040
rank: usize,
4141
parent_idx: usize,
@@ -44,20 +44,6 @@ struct Node {
4444
next: usize,
4545
}
4646

47-
// The derived Clone impl doesn't override clone_from,
48-
// so we'll do that here.
49-
impl Clone for Node {
50-
fn clone(&self) -> Self {
51-
*self
52-
}
53-
54-
fn clone_from(&mut self, source: &Self) {
55-
self.rank = source.rank;
56-
self.parent_idx = source.parent_idx;
57-
self.next = source.next;
58-
}
59-
}
60-
6147
impl<T> DisjointSet<T> {
6248
/// Creates an empty `DisjointSet`.
6349
pub fn new() -> Self {
@@ -273,27 +259,18 @@ impl<T> DisjointSet<T> {
273259
self.find_root_idx(elem_y_idx)?,
274260
);
275261

276-
// We don't have to do anything if this is the case. If we
277-
// didn't check this, we'd cause UB below by attempting
278-
// two mutable borrows of the same element.
279-
if x_root_idx == y_root_idx {
280-
return Some(false);
281-
}
282-
283-
let x_root: *mut _ = &mut self.nodes[x_root_idx];
284-
let y_root: *mut _ = &mut self.nodes[y_root_idx];
285-
286-
// We could just use RwLock::write here and avoid the need
287-
// for unsafe, but since we're in a &mut self context,
288-
// we can just ignore RwLock's overhead.
289-
let (mut x_root, mut y_root) =
290-
unsafe { ((&mut *x_root).get_mut(), (&mut *y_root).get_mut()) };
262+
let [x_root, y_root] = match self.nodes.get_disjoint_mut([x_root_idx, y_root_idx]) {
263+
Ok(r) => r,
264+
// An error here means that both indexes were the same so the elements
265+
// were already in the same subset, so we don't need to do anything.
266+
Err(_) => return Some(false),
267+
};
268+
let (x_root, y_root) = (x_root.get_mut(), y_root.get_mut());
291269

292270
if x_root.rank < y_root.rank {
293-
// Must use mem::swap here. If we shadowed,
294-
// it'd go out of scope when the if block ended.
271+
// Now we swap to ensure that x_root is always the one with the higher rank.
295272
mem::swap(&mut x_root_idx, &mut y_root_idx);
296-
mem::swap(&mut x_root, &mut y_root);
273+
mem::swap(x_root, y_root);
297274
}
298275

299276
// Now x_root.rank >= y_root.rank no matter what.
@@ -321,7 +298,7 @@ impl<T> DisjointSet<T> {
321298
/// operation was performed, Some(false) if it didn't need to be,
322299
/// or None if the element doesn't exist.
323300
pub fn make_singleton(&mut self, elem_idx: usize) -> Option<bool> {
324-
if self.is_singleton(elem_idx).contains(&true) {
301+
if self.is_singleton(elem_idx)? {
325302
return Some(false);
326303
}
327304

@@ -330,11 +307,11 @@ impl<T> DisjointSet<T> {
330307
let (&next_idx, &prev_idx) = set_idxs.get(1).zip(set_idxs.last()).unwrap();
331308

332309
if prev_idx != elem_idx {
333-
let mut prev = self.nodes[prev_idx].get_mut();
310+
let prev = self.nodes[prev_idx].get_mut();
334311
prev.next = next_idx;
335312
}
336313

337-
let mut node = self.nodes[elem_idx].get_mut();
314+
let node = self.nodes[elem_idx].get_mut();
338315

339316
self.roots.insert(elem_idx);
340317
node.parent_idx = elem_idx;
@@ -427,23 +404,16 @@ impl<T: Eq + Clone> Clone for DisjointSet<T> {
427404
self.elems.clone_from(&source.elems);
428405

429406
self.nodes.resize_with(source.num_elements(), || {
430-
// Temporary sentinel value. Node::clone_from should prevent
431-
// this from being an unncessary allocation since it'll be
432-
// only be mutated, not completely overwritten.
407+
// Temporary sentinel value.
433408
RwLock::new(Node {
434409
rank: 0,
435410
parent_idx: 0,
436411
next: 0,
437412
})
438413
});
439414

440-
for (source_node, dest_node) in source
441-
.nodes
442-
.iter()
443-
.map(|node_rwlock| node_rwlock.read())
444-
.zip(self.nodes.iter_mut())
445-
{
446-
dest_node.get_mut().clone_from(&source_node);
415+
for (source_node, dest_node) in source.nodes.iter().zip(self.nodes.iter_mut()) {
416+
dest_node.get_mut().clone_from(&source_node.read());
447417
}
448418
}
449419
}

0 commit comments

Comments
 (0)