Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 1825810

Browse files
committed
Vec::dedup optimization
1 parent f1c47c7 commit 1825810

File tree

1 file changed

+44
-6
lines changed

1 file changed

+44
-6
lines changed

library/alloc/src/vec/mod.rs

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,15 +1514,53 @@ impl<T, A: Allocator> Vec<T, A> {
15141514
/// assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
15151515
/// ```
15161516
#[stable(feature = "dedup_by", since = "1.16.0")]
1517-
pub fn dedup_by<F>(&mut self, same_bucket: F)
1517+
pub fn dedup_by<F>(&mut self, mut same_bucket: F)
15181518
where
15191519
F: FnMut(&mut T, &mut T) -> bool,
15201520
{
1521-
let len = {
1522-
let (dedup, _) = self.as_mut_slice().partition_dedup_by(same_bucket);
1523-
dedup.len()
1524-
};
1525-
self.truncate(len);
1521+
let len = self.len();
1522+
if len <= 1 {
1523+
return;
1524+
}
1525+
1526+
let ptr = self.as_mut_ptr();
1527+
/* Offset of the element we want to check if it is duplicate */
1528+
let mut read: usize = 1;
1529+
/* Offset of the place where we want to place the non-duplicate
1530+
* when we find it. */
1531+
let mut write: usize = 1;
1532+
1533+
/* Drop items while going through Vec, it should be more efficient than
1534+
* doing slice partition_dedup + truncate */
1535+
1536+
/* INVARIANT: len > read >= write > write-1 >= 0
1537+
* SAFETY: Because of the invariant, read_ptr, prev_ptr and write_ptr
1538+
* are always in-bounds and read_ptr never aliases prev_ptr */
1539+
unsafe {
1540+
while read < len {
1541+
let read_ptr = ptr.add(read);
1542+
let prev_ptr = ptr.add(write.wrapping_sub(1));
1543+
1544+
if same_bucket(&mut *read_ptr, &mut *prev_ptr) {
1545+
/* We have found duplicate, drop it in-place */
1546+
ptr::drop_in_place(read_ptr);
1547+
} else {
1548+
let write_ptr = ptr.add(write);
1549+
1550+
/* Looks like doing just `copy` can be faster than
1551+
* conditional `copy_nonoverlapping` */
1552+
ptr::copy(read_ptr, write_ptr, 1);
1553+
1554+
/* We have filled that place, so go further */
1555+
write += 1;
1556+
}
1557+
1558+
read += 1;
1559+
}
1560+
1561+
/* `write` items are inside vec, rest is already dropped */
1562+
self.set_len(write);
1563+
}
15261564
}
15271565

15281566
/// Appends an element to the back of a collection.

0 commit comments

Comments
 (0)