Skip to content

Commit d3f6dbd

Browse files
Merge pull request #2 from bobtwinkles/optimize_relation_merge
Improve performance of Relation::merge
2 parents e20d246 + 092f902 commit d3f6dbd

File tree

1 file changed

+42
-17
lines changed

1 file changed

+42
-17
lines changed

src/lib.rs

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use std::rc::Rc;
1515
use std::cell::RefCell;
16+
use std::cmp::Ordering;
1617

1718
mod map;
1819
mod join;
@@ -34,27 +35,51 @@ impl<Tuple: Ord> Relation<Tuple> {
3435
let mut elements1 = self.elements;
3536
let mut elements2 = other.elements;
3637

37-
// Ensure elements1.cap() >= elements2.cap().
38-
if elements1.capacity() < elements2.capacity() {
39-
::std::mem::swap(&mut elements1, &mut elements2);
38+
// If one of the element lists is zero-length, we don't need to do any work
39+
if elements1.len() == 0 {
40+
return Relation { elements: elements2 };
41+
}
42+
if elements2.len() == 0 {
43+
return Relation { elements: elements1 };
44+
}
45+
46+
// Make sure that elements1 starts with the lower element
47+
// Will not panic since both collections must have at least 1 element at this point
48+
if elements1[0] > elements2[0] {
49+
std::mem::swap(&mut elements1, &mut elements2);
4050
}
4151

42-
// Merge results either in spare capacity or new vector.
43-
let mut elements =
44-
if elements1.len() + elements2.len() < elements1.capacity() {
52+
// Fast path for when all the new elements are after the exiting ones
53+
if elements1[elements1.len() - 1] < elements2[0] {
4554
elements1.extend(elements2.into_iter());
46-
elements1
55+
// println!("fast path");
56+
return Relation { elements: elements1 };
4757
}
48-
else {
49-
let mut vec = Vec::with_capacity(elements1.len() + elements2.len());
50-
vec.extend(elements1.into_iter());
51-
vec.extend(elements2.into_iter());
52-
vec
53-
};
54-
55-
// Sort, dedup, and return.
56-
elements.sort();
57-
elements.dedup();
58+
59+
let mut elements = Vec::with_capacity(elements1.len() + elements2.len());
60+
let mut elements1 = elements1.drain(..);
61+
let mut elements2 = elements2.drain(..).peekable();
62+
63+
elements.push(elements1.next().unwrap());
64+
if &elements[0] == elements2.peek().unwrap() {
65+
elements2.next();
66+
}
67+
68+
for elem in elements1 {
69+
while elements2.peek().map(|x| x.cmp(&elem)) == Some(Ordering::Less) {
70+
elements.push(elements2.next().unwrap());
71+
}
72+
if elements2.peek().map(|x| x.cmp(&elem)) == Some(Ordering::Equal) {
73+
elements2.next();
74+
}
75+
elements.push(elem);
76+
}
77+
78+
// Finish draining second list
79+
for elem in elements2 {
80+
elements.push(elem);
81+
}
82+
5883
Relation { elements }
5984
}
6085

0 commit comments

Comments
 (0)