about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorJosh Stone <jistone@redhat.com>2019-07-01 11:49:44 -0700
committerJosh Stone <jistone@redhat.com>2019-07-09 12:39:25 -0700
commit60f1449b61a2e118916105d5fc225c005757e42e (patch)
treeb62731f26cdab0f6ed1e71444c72663295fd9683 /src/libcore
parentb8ec4c4d11ede0fba333a0474ed473dbe82aacf1 (diff)
downloadrust-60f1449b61a2e118916105d5fc225c005757e42e.tar.gz
rust-60f1449b61a2e118916105d5fc225c005757e42e.zip
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.
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/iter/traits/iterator.rs71
1 files changed, 71 insertions, 0 deletions
diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs
index b9a98236f18..b5835f19d74 100644
--- a/src/libcore/iter/traits/iterator.rs
+++ b/src/libcore/iter/traits/iterator.rs
@@ -1472,6 +1472,11 @@ pub trait Iterator {
     /// `partition()` returns a pair, all of the elements for which it returned
     /// `true`, and all of the elements for which it returned `false`.
     ///
+    /// See also [`is_partitioned()`] and [`partition_mut()`].
+    ///
+    /// [`is_partitioned()`]: #method.is_partitioned
+    /// [`partition_mut()`]: #method.partition_mut
+    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -1506,6 +1511,72 @@ pub trait Iterator {
         (left, right)
     }
 
+    /// Reorder the elements of this iterator *in-place* according to the given predicate,
+    /// such that all those that return `true` precede all those that return `false`.
+    ///
+    /// The relative order of partitioned items is not maintained.
+    ///
+    /// See also [`is_partitioned()`] and [`partition()`].
+    ///
+    /// [`is_partitioned()`]: #method.is_partitioned
+    /// [`partition()`]: #method.partition
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(iter_partition_mut)]
+    ///
+    /// let mut a = [1, 2, 3, 4, 5, 6, 7];
+    ///
+    /// // partition in-place between evens and odds
+    /// a.iter_mut().partition_mut(|&n| n % 2 == 0);
+    ///
+    /// assert!(a[..3].iter().all(|&n| n % 2 == 0)); // evens
+    /// assert!(a[3..].iter().all(|&n| n % 2 == 1)); // odds
+    /// ```
+    #[unstable(feature = "iter_partition_mut", reason = "new API", issue = "0")]
+    fn partition_mut<'a, T: 'a, P>(mut self, mut predicate: P)
+    where
+        Self: Sized + DoubleEndedIterator<Item = &'a mut T>,
+        P: FnMut(&T) -> bool,
+    {
+        // Repeatedly find the first `false` and swap it with the last `true`.
+        while let Some(head) = self.find(|x| !predicate(x)) {
+            if let Some(tail) = self.rfind(|x| predicate(x)) {
+                crate::mem::swap(head, tail);
+            } else {
+                break;
+            }
+        }
+    }
+
+    /// Checks if the elements of this iterator are partitioned according to the given predicate,
+    /// such that all those that return `true` precede all those that return `false`.
+    ///
+    /// See also [`partition()`] and [`partition_mut()`].
+    ///
+    /// [`partition()`]: #method.partition
+    /// [`partition_mut()`]: #method.partition_mut
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(iter_is_partitioned)]
+    ///
+    /// assert!("Iterator".chars().is_partitioned(char::is_uppercase));
+    /// assert!(!"IntoIterator".chars().is_partitioned(char::is_uppercase));
+    /// ```
+    #[unstable(feature = "iter_is_partitioned", reason = "new API", issue = "0")]
+    fn is_partitioned<P>(mut self, mut predicate: P) -> bool
+    where
+        Self: Sized,
+        P: FnMut(Self::Item) -> bool,
+    {
+        // Either all items test `true`, or the first clause stops at `false`
+        // and we check that there are no more `true` items after that.
+        self.all(&mut predicate) || !self.any(predicate)
+    }
+
     /// An iterator method that applies a function as long as it returns
     /// successfully, producing a single, final value.
     ///