From 4c8ce48a15c88715955e56c9c35959d9dffad5ec Mon Sep 17 00:00:00 2001 From: VillSnow Date: Sun, 21 Jun 2020 13:52:26 +0900 Subject: [PATCH 1/9] Add partition_point --- src/libcore/slice/mod.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 21ba2b5abcfb6..fe472092b10ce 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2663,6 +2663,44 @@ impl [T] { { self.iter().is_sorted_by_key(f) } + + /// Returns index of partition point according to the given predicate, + /// such that all those that return true precede the index and + /// such that all those that return false succeed the index. + /// + /// 'self' must be partitioned. + /// + /// # Examples + /// + /// ``` + /// #![feature(partition_point)] + /// + /// let v = [1, 2, 3, 3, 5, 6, 7]; + /// let i = xs.partition_point(|&x| x < 5); + /// + /// assert_eq!(i, 4); + /// assert!(xs[..i].iter().all(|&x| x < 5)); + /// assert!(xs[i..].iter().all(|&x| !(x < 5))); + /// ``` + #[unstable(feature = "partition_point", reason = "new API", issue = "99999")] + pub fn partition_point

(&self, mut pred: P) -> usize + where + P: FnMut(&T) -> bool, + { + let mut left = 0; + let mut right = self.len(); + + while left != right { + let mid = left + (right - left) / 2; + let value = unsafe { self.get_unchecked(mid) }; + if pred(value) { + left = mid + 1; + } else { + right = mid; + } + } + return left; + } } #[lang = "slice_u8"] From c9b49157057a83a97801f9e726ed8051fb1d2231 Mon Sep 17 00:00:00 2001 From: VillSnow Date: Sun, 21 Jun 2020 18:54:55 +0900 Subject: [PATCH 2/9] fix: doc test --- src/libcore/slice/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index fe472092b10ce..13e5ef9ec6fca 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2676,11 +2676,11 @@ impl [T] { /// #![feature(partition_point)] /// /// let v = [1, 2, 3, 3, 5, 6, 7]; - /// let i = xs.partition_point(|&x| x < 5); + /// let i = v.partition_point(|&x| x < 5); /// /// assert_eq!(i, 4); - /// assert!(xs[..i].iter().all(|&x| x < 5)); - /// assert!(xs[i..].iter().all(|&x| !(x < 5))); + /// assert!(v[..i].iter().all(|&x| x < 5)); + /// assert!(v[i..].iter().all(|&x| !(x < 5))); /// ``` #[unstable(feature = "partition_point", reason = "new API", issue = "99999")] pub fn partition_point

(&self, mut pred: P) -> usize From 27b06f10dc01319c449d0f8c04218136431938c8 Mon Sep 17 00:00:00 2001 From: VillSnow Date: Mon, 22 Jun 2020 21:35:09 +0900 Subject: [PATCH 3/9] update: doc comment --- src/libcore/slice/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 13e5ef9ec6fca..a07690bc669f3 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2668,7 +2668,9 @@ impl [T] { /// such that all those that return true precede the index and /// such that all those that return false succeed the index. /// - /// 'self' must be partitioned. + /// The slice must be partitioned + /// so that all elements where the predicate returns true + /// precede the elements where the predicate returns false. /// /// # Examples /// From 8cc6998cd460f8534b3cf643a7620354bd007856 Mon Sep 17 00:00:00 2001 From: VillSnow Date: Mon, 22 Jun 2020 21:36:35 +0900 Subject: [PATCH 4/9] add: tests --- src/libcore/tests/lib.rs | 1 + src/libcore/tests/slice.rs | 40 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 37ebf4112808e..b5962505deeea 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -44,6 +44,7 @@ #![feature(const_forget)] #![feature(option_unwrap_none)] #![feature(peekable_next_if)] +#![feature(partition_point)] extern crate test; diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index cd46117f76322..fba73be92be09 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -81,6 +81,46 @@ fn test_binary_search_implementation_details() { assert_eq!(b.binary_search(&3), Ok(8)); } +#[test] +fn test_partition_point() { + let b: [i32; 0] = []; + assert_eq!(b.partition_point(|&x| x < 5), 0); + + let b = [4]; + assert_eq!(b.partition_point(|&x| x < 3), 0); + assert_eq!(b.partition_point(|&x| x < 4), 0); + assert_eq!(b.partition_point(|&x| x < 5), 1); + + let b = [1, 2, 4, 6, 8, 9]; + assert_eq!(b.partition_point(|&x| x < 5), 3); + assert_eq!(b.partition_point(|&x| x < 6), 3); + assert_eq!(b.partition_point(|&x| x < 7), 4); + assert_eq!(b.partition_point(|&x| x < 8), 4); + + let b = [1, 2, 4, 5, 6, 8]; + assert_eq!(b.partition_point(|&x| x < 9), 6); + + let b = [1, 2, 4, 6, 7, 8, 9]; + assert_eq!(b.partition_point(|&x| x < 6), 3); + assert_eq!(b.partition_point(|&x| x < 5), 3); + assert_eq!(b.partition_point(|&x| x < 8), 5); + + let b = [1, 2, 4, 5, 6, 8, 9]; + assert_eq!(b.partition_point(|&x| x < 7), 5); + assert_eq!(b.partition_point(|&x| x < 0), 0); + + let b = [1, 3, 3, 3, 7]; + assert_eq!(b.partition_point(|&x| x < 0), 0); + assert_eq!(b.partition_point(|&x| x < 1), 0); + assert_eq!(b.partition_point(|&x| x < 2), 1); + assert_eq!(b.partition_point(|&x| x < 3), 1); + assert_eq!(b.partition_point(|&x| x < 4), 4); + assert_eq!(b.partition_point(|&x| x < 5), 4); + assert_eq!(b.partition_point(|&x| x < 6), 4); + assert_eq!(b.partition_point(|&x| x < 7), 4); + assert_eq!(b.partition_point(|&x| x < 8), 5); +} + #[test] fn test_iterator_nth() { let v: &[_] = &[0, 1, 2, 3, 4]; From 52f976236f0dc1a797578ae41ba1193cbed50677 Mon Sep 17 00:00:00 2001 From: VillSnow Date: Sun, 28 Jun 2020 16:25:33 +0900 Subject: [PATCH 5/9] Add comment on use of unsafe --- src/libcore/slice/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index a07690bc669f3..3b51f973ffbf9 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2694,6 +2694,15 @@ impl [T] { while left != right { let mid = left + (right - left) / 2; + // SAFETY: + // When left < right, left <= mid < right. + // Therefore left always increases and right always decreases, + // and eigher of them is selected. + // In both cases left <= right is satisfied. + // Therefore if left < right in a step, + // left <= right is satisfied in the next step. + // Therefore as long as left != right, 0 <= left < right <= len is satisfied + // and if this case 0 <= mid < len is satisfied too. let value = unsafe { self.get_unchecked(mid) }; if pred(value) { left = mid + 1; From 93357876573943e6531c1deea3159f79428e017d Mon Sep 17 00:00:00 2001 From: VillSnow Date: Sun, 28 Jun 2020 16:26:47 +0900 Subject: [PATCH 6/9] Update src/libcore/slice/mod.rs Co-authored-by: Lukas Kalbertodt --- src/libcore/slice/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index a07690bc669f3..334efc0b91572 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2701,7 +2701,8 @@ impl [T] { right = mid; } } - return left; + + left } } From d720a19e2a0526794999997db399dd5d7521bd78 Mon Sep 17 00:00:00 2001 From: VillSnow Date: Sun, 28 Jun 2020 16:45:56 +0900 Subject: [PATCH 7/9] Update doc comment --- src/libcore/slice/mod.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index cd4967e10e44d..11561c392864f 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2664,13 +2664,17 @@ impl [T] { self.iter().is_sorted_by_key(f) } - /// Returns index of partition point according to the given predicate, - /// such that all those that return true precede the index and - /// such that all those that return false succeed the index. + /// Returns the index of the partition point according to the given predicate + // (the index of the first element of the second partition). /// - /// The slice must be partitioned - /// so that all elements where the predicate returns true - /// precede the elements where the predicate returns false. + /// The slice is assumed to be partitioned according to the given predicate. + /// This means that all elements for which the predicate returns true are at the start of the slice + /// and all elements for which the predicate returns false are at the end. + /// For example, [7, 15, 3, 5, 4, 12, 6] is a partitioned under the predicate x % 2 != 0 + /// (all odd numbers are at the start, all even at the end). + /// + /// If this slice is not partitioned, the returned result is unspecified and meaningless, + /// as this method performs a kind of binary search. /// /// # Examples /// From 60f2ba24031b52d3363e180dd7ad1c07608c6917 Mon Sep 17 00:00:00 2001 From: VillSnow Date: Sun, 28 Jun 2020 17:39:03 +0900 Subject: [PATCH 8/9] Update tracking issue number --- src/libcore/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 11561c392864f..07b45640a5225 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2688,7 +2688,7 @@ impl [T] { /// assert!(v[..i].iter().all(|&x| x < 5)); /// assert!(v[i..].iter().all(|&x| !(x < 5))); /// ``` - #[unstable(feature = "partition_point", reason = "new API", issue = "99999")] + #[unstable(feature = "partition_point", reason = "new API", issue = "73831")] pub fn partition_point

(&self, mut pred: P) -> usize where P: FnMut(&T) -> bool, From 6f8ad3b20858c6c63c2098e690fddf0f33a80d2b Mon Sep 17 00:00:00 2001 From: VillSnow Date: Sun, 28 Jun 2020 21:31:05 +0900 Subject: [PATCH 9/9] Update src/libcore/slice/mod.rs Co-authored-by: Amanieu d'Antras --- src/libcore/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 07b45640a5225..e7c8f5c88cd2f 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2665,7 +2665,7 @@ impl [T] { } /// Returns the index of the partition point according to the given predicate - // (the index of the first element of the second partition). + /// (the index of the first element of the second partition). /// /// The slice is assumed to be partitioned according to the given predicate. /// This means that all elements for which the predicate returns true are at the start of the slice