Skip to content

Commit 60f1449

Browse files
committed
Add Iterator::partition_mut() and is_partitioned()
`partition_mut()` swaps `&mut T` items in-place to satisfy the predicate, so all `true` items precede all `false` items. This requires a `DoubleEndedIterator` so we can search from front and back for items that need swapping. `is_partitioned()` checks whether the predicate is already satisfied.
1 parent b8ec4c4 commit 60f1449

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

src/libcore/iter/traits/iterator.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,6 +1472,11 @@ pub trait Iterator {
14721472
/// `partition()` returns a pair, all of the elements for which it returned
14731473
/// `true`, and all of the elements for which it returned `false`.
14741474
///
1475+
/// See also [`is_partitioned()`] and [`partition_mut()`].
1476+
///
1477+
/// [`is_partitioned()`]: #method.is_partitioned
1478+
/// [`partition_mut()`]: #method.partition_mut
1479+
///
14751480
/// # Examples
14761481
///
14771482
/// Basic usage:
@@ -1506,6 +1511,72 @@ pub trait Iterator {
15061511
(left, right)
15071512
}
15081513

1514+
/// Reorder the elements of this iterator *in-place* according to the given predicate,
1515+
/// such that all those that return `true` precede all those that return `false`.
1516+
///
1517+
/// The relative order of partitioned items is not maintained.
1518+
///
1519+
/// See also [`is_partitioned()`] and [`partition()`].
1520+
///
1521+
/// [`is_partitioned()`]: #method.is_partitioned
1522+
/// [`partition()`]: #method.partition
1523+
///
1524+
/// # Examples
1525+
///
1526+
/// ```
1527+
/// #![feature(iter_partition_mut)]
1528+
///
1529+
/// let mut a = [1, 2, 3, 4, 5, 6, 7];
1530+
///
1531+
/// // partition in-place between evens and odds
1532+
/// a.iter_mut().partition_mut(|&n| n % 2 == 0);
1533+
///
1534+
/// assert!(a[..3].iter().all(|&n| n % 2 == 0)); // evens
1535+
/// assert!(a[3..].iter().all(|&n| n % 2 == 1)); // odds
1536+
/// ```
1537+
#[unstable(feature = "iter_partition_mut", reason = "new API", issue = "0")]
1538+
fn partition_mut<'a, T: 'a, P>(mut self, mut predicate: P)
1539+
where
1540+
Self: Sized + DoubleEndedIterator<Item = &'a mut T>,
1541+
P: FnMut(&T) -> bool,
1542+
{
1543+
// Repeatedly find the first `false` and swap it with the last `true`.
1544+
while let Some(head) = self.find(|x| !predicate(x)) {
1545+
if let Some(tail) = self.rfind(|x| predicate(x)) {
1546+
crate::mem::swap(head, tail);
1547+
} else {
1548+
break;
1549+
}
1550+
}
1551+
}
1552+
1553+
/// Checks if the elements of this iterator are partitioned according to the given predicate,
1554+
/// such that all those that return `true` precede all those that return `false`.
1555+
///
1556+
/// See also [`partition()`] and [`partition_mut()`].
1557+
///
1558+
/// [`partition()`]: #method.partition
1559+
/// [`partition_mut()`]: #method.partition_mut
1560+
///
1561+
/// # Examples
1562+
///
1563+
/// ```
1564+
/// #![feature(iter_is_partitioned)]
1565+
///
1566+
/// assert!("Iterator".chars().is_partitioned(char::is_uppercase));
1567+
/// assert!(!"IntoIterator".chars().is_partitioned(char::is_uppercase));
1568+
/// ```
1569+
#[unstable(feature = "iter_is_partitioned", reason = "new API", issue = "0")]
1570+
fn is_partitioned<P>(mut self, mut predicate: P) -> bool
1571+
where
1572+
Self: Sized,
1573+
P: FnMut(Self::Item) -> bool,
1574+
{
1575+
// Either all items test `true`, or the first clause stops at `false`
1576+
// and we check that there are no more `true` items after that.
1577+
self.all(&mut predicate) || !self.any(predicate)
1578+
}
1579+
15091580
/// An iterator method that applies a function as long as it returns
15101581
/// successfully, producing a single, final value.
15111582
///

0 commit comments

Comments
 (0)