@@ -1402,6 +1402,178 @@ impl<T> [T] {
1402
1402
sort:: quicksort ( self , |a, b| f ( a) . lt ( & f ( b) ) ) ;
1403
1403
}
1404
1404
1405
+ /// Moves all consecutive repeated elements to the end of the slice according to the
1406
+ /// [`PartialEq`] trait implementation.
1407
+ ///
1408
+ /// Returns two slices. The first contains no consecutive repeated elements.
1409
+ /// The second contains all the duplicates in no specified order.
1410
+ ///
1411
+ /// If the slice is sorted, the first returned slice contains no duplicates.
1412
+ ///
1413
+ /// # Examples
1414
+ ///
1415
+ /// ```
1416
+ /// #![feature(slice_partition_dedup)]
1417
+ ///
1418
+ /// let mut slice = [1, 2, 2, 3, 3, 2, 1, 1];
1419
+ ///
1420
+ /// let (dedup, duplicates) = slice.partition_dedup();
1421
+ ///
1422
+ /// assert_eq!(dedup, [1, 2, 3, 2, 1]);
1423
+ /// assert_eq!(duplicates, [2, 3, 1]);
1424
+ /// ```
1425
+ #[ unstable( feature = "slice_partition_dedup" , issue = "54279" ) ]
1426
+ #[ inline]
1427
+ pub fn partition_dedup ( & mut self ) -> ( & mut [ T ] , & mut [ T ] )
1428
+ where T : PartialEq
1429
+ {
1430
+ self . partition_dedup_by ( |a, b| a == b)
1431
+ }
1432
+
1433
+ /// Moves all but the first of consecutive elements to the end of the slice satisfying
1434
+ /// a given equality relation.
1435
+ ///
1436
+ /// Returns two slices. The first contains no consecutive repeated elements.
1437
+ /// The second contains all the duplicates in no specified order.
1438
+ ///
1439
+ /// The `same_bucket` function is passed references to two elements from the slice and
1440
+ /// must determine if the elements compare equal. The elements are passed in opposite order
1441
+ /// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is moved
1442
+ /// at the end of the slice.
1443
+ ///
1444
+ /// If the slice is sorted, the first returned slice contains no duplicates.
1445
+ ///
1446
+ /// # Examples
1447
+ ///
1448
+ /// ```
1449
+ /// #![feature(slice_partition_dedup)]
1450
+ ///
1451
+ /// let mut slice = ["foo", "Foo", "BAZ", "Bar", "bar", "baz", "BAZ"];
1452
+ ///
1453
+ /// let (dedup, duplicates) = slice.partition_dedup_by(|a, b| a.eq_ignore_ascii_case(b));
1454
+ ///
1455
+ /// assert_eq!(dedup, ["foo", "BAZ", "Bar", "baz"]);
1456
+ /// assert_eq!(duplicates, ["bar", "Foo", "BAZ"]);
1457
+ /// ```
1458
+ #[ unstable( feature = "slice_partition_dedup" , issue = "54279" ) ]
1459
+ #[ inline]
1460
+ pub fn partition_dedup_by < F > ( & mut self , mut same_bucket : F ) -> ( & mut [ T ] , & mut [ T ] )
1461
+ where F : FnMut ( & mut T , & mut T ) -> bool
1462
+ {
1463
+ // Although we have a mutable reference to `self`, we cannot make
1464
+ // *arbitrary* changes. The `same_bucket` calls could panic, so we
1465
+ // must ensure that the slice is in a valid state at all times.
1466
+ //
1467
+ // The way that we handle this is by using swaps; we iterate
1468
+ // over all the elements, swapping as we go so that at the end
1469
+ // the elements we wish to keep are in the front, and those we
1470
+ // wish to reject are at the back. We can then split the slice.
1471
+ // This operation is still O(n).
1472
+ //
1473
+ // Example: We start in this state, where `r` represents "next
1474
+ // read" and `w` represents "next_write`.
1475
+ //
1476
+ // r
1477
+ // +---+---+---+---+---+---+
1478
+ // | 0 | 1 | 1 | 2 | 3 | 3 |
1479
+ // +---+---+---+---+---+---+
1480
+ // w
1481
+ //
1482
+ // Comparing self[r] against self[w-1], this is not a duplicate, so
1483
+ // we swap self[r] and self[w] (no effect as r==w) and then increment both
1484
+ // r and w, leaving us with:
1485
+ //
1486
+ // r
1487
+ // +---+---+---+---+---+---+
1488
+ // | 0 | 1 | 1 | 2 | 3 | 3 |
1489
+ // +---+---+---+---+---+---+
1490
+ // w
1491
+ //
1492
+ // Comparing self[r] against self[w-1], this value is a duplicate,
1493
+ // so we increment `r` but leave everything else unchanged:
1494
+ //
1495
+ // r
1496
+ // +---+---+---+---+---+---+
1497
+ // | 0 | 1 | 1 | 2 | 3 | 3 |
1498
+ // +---+---+---+---+---+---+
1499
+ // w
1500
+ //
1501
+ // Comparing self[r] against self[w-1], this is not a duplicate,
1502
+ // so swap self[r] and self[w] and advance r and w:
1503
+ //
1504
+ // r
1505
+ // +---+---+---+---+---+---+
1506
+ // | 0 | 1 | 2 | 1 | 3 | 3 |
1507
+ // +---+---+---+---+---+---+
1508
+ // w
1509
+ //
1510
+ // Not a duplicate, repeat:
1511
+ //
1512
+ // r
1513
+ // +---+---+---+---+---+---+
1514
+ // | 0 | 1 | 2 | 3 | 1 | 3 |
1515
+ // +---+---+---+---+---+---+
1516
+ // w
1517
+ //
1518
+ // Duplicate, advance r. End of slice. Split at w.
1519
+
1520
+ let len = self . len ( ) ;
1521
+ if len <= 1 {
1522
+ return ( self , & mut [ ] )
1523
+ }
1524
+
1525
+ let ptr = self . as_mut_ptr ( ) ;
1526
+ let mut next_read: usize = 1 ;
1527
+ let mut next_write: usize = 1 ;
1528
+
1529
+ unsafe {
1530
+ // Avoid bounds checks by using raw pointers.
1531
+ while next_read < len {
1532
+ let ptr_read = ptr. add ( next_read) ;
1533
+ let prev_ptr_write = ptr. add ( next_write - 1 ) ;
1534
+ if !same_bucket ( & mut * ptr_read, & mut * prev_ptr_write) {
1535
+ if next_read != next_write {
1536
+ let ptr_write = prev_ptr_write. offset ( 1 ) ;
1537
+ mem:: swap ( & mut * ptr_read, & mut * ptr_write) ;
1538
+ }
1539
+ next_write += 1 ;
1540
+ }
1541
+ next_read += 1 ;
1542
+ }
1543
+ }
1544
+
1545
+ self . split_at_mut ( next_write)
1546
+ }
1547
+
1548
+ /// Moves all but the first of consecutive elements to the end of the slice that resolve
1549
+ /// to the same key.
1550
+ ///
1551
+ /// Returns two slices. The first contains no consecutive repeated elements.
1552
+ /// The second contains all the duplicates in no specified order.
1553
+ ///
1554
+ /// If the slice is sorted, the first returned slice contains no duplicates.
1555
+ ///
1556
+ /// # Examples
1557
+ ///
1558
+ /// ```
1559
+ /// #![feature(slice_partition_dedup)]
1560
+ ///
1561
+ /// let mut slice = [10, 20, 21, 30, 30, 20, 11, 13];
1562
+ ///
1563
+ /// let (dedup, duplicates) = slice.partition_dedup_by_key(|i| *i / 10);
1564
+ ///
1565
+ /// assert_eq!(dedup, [10, 20, 30, 20, 11]);
1566
+ /// assert_eq!(duplicates, [21, 30, 13]);
1567
+ /// ```
1568
+ #[ unstable( feature = "slice_partition_dedup" , issue = "54279" ) ]
1569
+ #[ inline]
1570
+ pub fn partition_dedup_by_key < K , F > ( & mut self , mut key : F ) -> ( & mut [ T ] , & mut [ T ] )
1571
+ where F : FnMut ( & mut T ) -> K ,
1572
+ K : PartialEq ,
1573
+ {
1574
+ self . partition_dedup_by ( |a, b| key ( a) == key ( b) )
1575
+ }
1576
+
1405
1577
/// Rotates the slice in-place such that the first `mid` elements of the
1406
1578
/// slice move to the end while the last `self.len() - mid` elements move to
1407
1579
/// the front. After calling `rotate_left`, the element previously at index
0 commit comments