From 2e2e8ee2f0ce051280348e118040ed54eb895058 Mon Sep 17 00:00:00 2001 From: Michael Darakananda Date: Sun, 5 Jan 2014 05:13:07 -0800 Subject: [PATCH 1/2] Added rotate, partition, and friends --- src/libstd/vec.rs | 165 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 450cf1a4ef25c..d3230d5c6b3fb 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -1017,6 +1017,17 @@ pub trait ImmutableVector<'a, T> { * Fails if slice is empty. */ fn pop_ref(&mut self) -> &'a T; + + /** + * Returns true if all the elements in vector + * for which pred returns true precede those for which it returns false. + * + * # Example + * ```rust + * let even = |x: &int| *x % 2 == 0; + * assert!([2, 4, 6, 1, 3, 5].is_partitioned(|x| even(x))); + */ + fn is_partitioned(self, f: |&T| -> bool) -> bool; } impl<'a,T> ImmutableVector<'a, T> for &'a [T] { @@ -1200,6 +1211,18 @@ impl<'a,T> ImmutableVector<'a, T> for &'a [T] { &*raw::pop_ptr(s) } } + + fn is_partitioned(self, f: |&T| -> bool) -> bool { + let mut i = 0; + let len = self.len(); + while i < len && f(&self[i]) { + i += 1; + } + while i < len && !f(&self[i]) { + i += 1; + } + i == len + } } /// Extension methods for vectors contain `Eq` elements. @@ -2302,6 +2325,45 @@ pub trait MutableVector<'a, T> { /// ignores move semantics. `self` and `src` must not /// overlap. Fails if `self` is shorter than `src`. unsafe fn copy_memory(self, src: &[T]); + + /// Rotates elements of the vector around pivot `mid` in place. + /// This method behaves similarly to STL rotate. + /// + /// # Example + /// + /// ```rust + /// let mut v = [1, 2, 3, 4, 5, 6]; + /// let i = v.rotate(2); + /// assert_eq!(v, [3, 4, 5, 6, 1, 2]); + /// assert_eq!(i, 4); + /// ``` + fn rotate(self, mid: uint) -> uint; + + /// Partitions the vector so that all elements satisfying `pred` + /// precede those that do not. The partitioning is unstable. + /// + /// # Example + /// + /// ```rust + /// let mut v = [1, 2, 3, 4, 5, 6]; + /// let is_even = |x: &int| *x % 2 == 0; + /// assert_eq!(v.partition(|x| is_even(x)), 3); + /// assert!(v.is_partitioned(is_even)) + /// ``` + fn partition(self, pred: |&T| -> bool) -> uint; + + /// Partitions the vector so that all elements satisfying `pred` + /// precede those that do not. The partitioning in stable. + /// + /// # Example + /// + /// ```rust + /// let mut v = [1, 2, 3, 4, 5, 6]; + /// let is_even = |x: &int| *x % 2 == 0; + /// assert_eq!(v.partition(|x| is_even(x)), 3); + /// assert_eq!(v, [2, 4, 6, 1, 3, 5]); + /// ``` + fn partition_stable(self, f: |&T| -> bool) -> uint; } impl<'a,T> MutableVector<'a, T> for &'a mut [T] { @@ -2443,6 +2505,64 @@ impl<'a,T> MutableVector<'a, T> for &'a mut [T] { assert!(self.len() >= len_src); ptr::copy_nonoverlapping_memory(self.as_mut_ptr(), src.as_ptr(), len_src) } + + fn rotate(self, mid: uint) -> uint { + let end = self.len(); + if mid == 0 { + return end; + } + if mid == end { + return 0; + } + if mid > end { + fail!("index out of bounds: len is {} but rotating around {}", end, mid); + } + let (mut a, mut b) = (0, mid); + + let mut piv = mid; + while a != b { + self.swap(a, b); + a += 1; + b += 1; + + if b == end { + b = piv; + } else if a == piv { + piv = b; + } + } + end - mid + } + + fn partition(self, f: |&T| -> bool) -> uint { + let (mut a, mut b) = (0, self.len()); + while a != b { + if f(&self[a]) { + a += 1; + } else { + b -= 1; + self.swap(a, b); + } + } + a + } + + fn partition_stable(self, f: |&T| -> bool) -> uint { + let len = self.len(); + if len == 0 { + return 0; + } + if len == 1 { + if f(&self[0]) { + return 1; + } + return 0; + } + let mid = len / 2; + let a = self.mut_slice_to(mid).partition_stable(|x| f(x)); + let b = self.mut_slice_from(mid).partition_stable(f) + mid; + self.mut_slice(a, b).rotate(mid-a) + a + } } /// Trait for &[T] where T is Cloneable @@ -4447,6 +4567,51 @@ mod tests { let mut x: &mut [int] = []; x.mut_pop_ref(); } + + #[test] + fn test_rotate() { + let mut v = [1, 2, 3, 4, 5, 6]; + assert_eq!(v.rotate(0), 6); + assert_eq!(v.rotate(6), 0); + assert_eq!(v.rotate(3), 3); + assert_eq!(v, [4, 5, 6, 1, 2, 3]); + let mut v = [1, 2, 3, 4, 5, 6]; + assert_eq!(v.rotate(2), 4); + assert_eq!(v, [3, 4, 5, 6, 1, 2]); + let mut v = [1, 2, 3, 4, 5, 6]; + assert_eq!(v.rotate(4), 2); + assert_eq!(v, [5, 6, 1, 2, 3, 4]); + } + + #[test] + #[should_fail] + fn test_rotate_fail() { + let mut v = [1, 2, 3, 4, 5, 6]; + v.rotate(10); + } + + #[test] + fn test_is_partitioned() { + let even = |x: &int| *x % 2 == 0; + assert!([2, 4, 6, 1, 3, 5].is_partitioned(|x| even(x))); + assert!(![1, 2, 4, 6, 3, 5].is_partitioned(|x| even(x))); + } + + #[test] + fn test_partion() { + let mut v = [1, 2, 3, 4, 5, 6]; + let is_even = |x: &int| *x % 2 == 0; + assert_eq!(v.partition(|x| is_even(x)), 3); + assert!(v.is_partitioned(is_even)) + } + + #[test] + fn test_partion_stable() { + let mut v = [1, 2, 3, 4, 5, 6]; + let is_even = |x: &int| *x % 2 == 0; + assert_eq!(v.partition_stable(|x| is_even(x)), 3); + assert_eq!(v, [2, 4, 6, 1, 3, 5]); + } } #[cfg(test)] From d36a0d81d2cf5127c7898d164854e88c1157ba6d Mon Sep 17 00:00:00 2001 From: Michael Darakananda Date: Sun, 5 Jan 2014 07:36:52 -0800 Subject: [PATCH 2/2] Fixed comments @huonw --- src/libstd/vec.rs | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 35e74d4f2f3cd..fb73dcde67c53 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -1018,15 +1018,14 @@ pub trait ImmutableVector<'a, T> { */ fn pop_ref(&mut self) -> &'a T; - /** - * Returns true if all the elements in vector - * for which pred returns true precede those for which it returns false. - * - * # Example - * ```rust - * let even = |x: &int| *x % 2 == 0; - * assert!([2, 4, 6, 1, 3, 5].is_partitioned(|x| even(x))); - */ + /// Returns true if all the elements in vector for which pred returns + /// true precede those for which it returns false. + /// + /// # Example + /// ```rust + /// let even = |x: &int| *x % 2 == 0; + /// assert!([2, 4, 6, 1, 3, 5].is_partitioned(|x| even(x))); + /// ``` fn is_partitioned(self, f: |&T| -> bool) -> bool; } @@ -2326,8 +2325,9 @@ pub trait MutableVector<'a, T> { /// overlap. Fails if `self` is shorter than `src`. unsafe fn copy_memory(self, src: &[T]); - /// Rotates elements of the vector around pivot `mid` in place. - /// This method behaves similarly to STL rotate. + /// Rotates the vector n places to the right by placing the first n elements at the end of the vector, + /// and moving the rest left to fill the gap. Operates in place. Returns the index to which + /// the first element of the vector was moved. /// /// # Example /// @@ -2341,6 +2341,10 @@ pub trait MutableVector<'a, T> { /// Partitions the vector so that all elements satisfying `pred` /// precede those that do not. The partitioning is unstable. + /// Returns the index of the first element not satisfying `pred`. + /// + /// Complexity O(N), where N is the length of the vector. + /// For stable version, see `partition_stable`. /// /// # Example /// @@ -2353,7 +2357,11 @@ pub trait MutableVector<'a, T> { fn partition(self, pred: |&T| -> bool) -> uint; /// Partitions the vector so that all elements satisfying `pred` - /// precede those that do not. The partitioning in stable. + /// precede those that do not. The partitioning is stable. + /// Returns the index of the first element not satisfying `pred`. + /// + /// Complexity O(N * log(N)), where N is the length of the vector. + /// If the stability is not required, consider using linear-time `partition` instead. /// /// # Example ///