@@ -1514,15 +1514,53 @@ impl<T, A: Allocator> Vec<T, A> {
1514
1514
/// assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
1515
1515
/// ```
1516
1516
#[ 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 )
1518
1518
where
1519
1519
F : FnMut ( & mut T , & mut T ) -> bool ,
1520
1520
{
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
+ }
1526
1564
}
1527
1565
1528
1566
/// Appends an element to the back of a collection.
0 commit comments