diff options
| author | Pietro Albini <pietro@pietroalbini.org> | 2018-09-25 22:34:38 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-09-25 22:34:38 +0200 |
| commit | b940e1d961b274eb036e3155c6152705ac0d2227 (patch) | |
| tree | ed095f9d1178b1903dce354094cfd3174edaa553 /src/liballoc | |
| parent | 707c9795ac00bdc487f79f048618b4119f70ba0d (diff) | |
| parent | d560292a87a89587e0345e13b9714c90495ea50f (diff) | |
| download | rust-b940e1d961b274eb036e3155c6152705ac0d2227.tar.gz rust-b940e1d961b274eb036e3155c6152705ac0d2227.zip | |
Rollup merge of #54058 - Kerollmops:slice-dedup, r=shepmaster
Introduce the partition_dedup/by/by_key methods for slices
This PR propose to add three methods to the slice type, the `partition_dedup`, `partition_dedup_by` and `partition_dedup_by_key`. The two other methods are based on `slice::partition_dedup_by`.
These methods take a mutable slice, deduplicates it and moves all duplicates to the end of it, returning two mutable slices, the first containing the deduplicated elements and the second all the duplicates unordered.
```rust
let mut slice = [1, 2, 2, 3, 3, 2];
let (dedup, duplicates) = slice.partition_dedup();
assert_eq!(dedup, [1, 2, 3, 2]);
assert_eq!(duplicates, [3, 2]);
```
The benefits of adding these methods is that it is now possible to:
- deduplicate a slice without having to allocate and possibly clone elements on the heap, really useful for embedded stuff that can't allocate for example.
- not loose duplicate elements, because, when using `Vec::dedup`, duplicates elements are dropped. These methods add more flexibillity to the user.
Note that this is near a copy/paste of the `Vec::dedup_by` function, once this method is stable the goal is to replace the algorithm in `Vec` by the following.
```rust
pub fn Vec::dedup_by<F>(&mut self, same_bucket: F)
where F: FnMut(&mut T, &mut T) -> bool
{
let (dedup, _) = self.as_mut_slice().partition_dedup_by(same_bucket);
let len = dedup.len();
self.truncate(len);
}
```
Diffstat (limited to 'src/liballoc')
| -rw-r--r-- | src/liballoc/lib.rs | 1 | ||||
| -rw-r--r-- | src/liballoc/vec.rs | 100 |
2 files changed, 12 insertions, 89 deletions
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 089480c06d2..6ce24b65990 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -119,6 +119,7 @@ #![feature(exact_chunks)] #![feature(rustc_const_unstable)] #![feature(const_vec_new)] +#![feature(slice_partition_dedup)] #![feature(maybe_uninit)] // Allow testing this library diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 7fc4453fec5..e845438c0a8 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -947,10 +947,9 @@ impl<T> Vec<T> { /// Removes all but the first of consecutive elements in the vector satisfying a given equality /// relation. /// - /// The `same_bucket` function is passed references to two elements from the vector, and - /// returns `true` if the elements compare equal, or `false` if they do not. The elements are - /// passed in opposite order from their order in the vector, so if `same_bucket(a, b)` returns - /// `true`, `a` is removed. + /// The `same_bucket` function is passed references to two elements from the vector and + /// must determine if the elements compare equal. The elements are passed in opposite order + /// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is removed. /// /// If the vector is sorted, this removes all duplicates. /// @@ -964,90 +963,12 @@ impl<T> Vec<T> { /// assert_eq!(vec, ["foo", "bar", "baz", "bar"]); /// ``` #[stable(feature = "dedup_by", since = "1.16.0")] - pub fn dedup_by<F>(&mut self, mut same_bucket: F) where F: FnMut(&mut T, &mut T) -> bool { - unsafe { - // Although we have a mutable reference to `self`, we cannot make - // *arbitrary* changes. The `same_bucket` calls could panic, so we - // must ensure that the vector is in a valid state at all time. - // - // The way that we handle this is by using swaps; we iterate - // over all the elements, swapping as we go so that at the end - // the elements we wish to keep are in the front, and those we - // wish to reject are at the back. We can then truncate the - // vector. This operation is still O(n). - // - // Example: We start in this state, where `r` represents "next - // read" and `w` represents "next_write`. - // - // r - // +---+---+---+---+---+---+ - // | 0 | 1 | 1 | 2 | 3 | 3 | - // +---+---+---+---+---+---+ - // w - // - // Comparing self[r] against self[w-1], this is not a duplicate, so - // we swap self[r] and self[w] (no effect as r==w) and then increment both - // r and w, leaving us with: - // - // r - // +---+---+---+---+---+---+ - // | 0 | 1 | 1 | 2 | 3 | 3 | - // +---+---+---+---+---+---+ - // w - // - // Comparing self[r] against self[w-1], this value is a duplicate, - // so we increment `r` but leave everything else unchanged: - // - // r - // +---+---+---+---+---+---+ - // | 0 | 1 | 1 | 2 | 3 | 3 | - // +---+---+---+---+---+---+ - // w - // - // Comparing self[r] against self[w-1], this is not a duplicate, - // so swap self[r] and self[w] and advance r and w: - // - // r - // +---+---+---+---+---+---+ - // | 0 | 1 | 2 | 1 | 3 | 3 | - // +---+---+---+---+---+---+ - // w - // - // Not a duplicate, repeat: - // - // r - // +---+---+---+---+---+---+ - // | 0 | 1 | 2 | 3 | 1 | 3 | - // +---+---+---+---+---+---+ - // w - // - // Duplicate, advance r. End of vec. Truncate to w. - - let ln = self.len(); - if ln <= 1 { - return; - } - - // Avoid bounds checks by using raw pointers. - let p = self.as_mut_ptr(); - let mut r: usize = 1; - let mut w: usize = 1; - - while r < ln { - let p_r = p.add(r); - let p_wm1 = p.add(w - 1); - if !same_bucket(&mut *p_r, &mut *p_wm1) { - if r != w { - let p_w = p_wm1.offset(1); - mem::swap(&mut *p_r, &mut *p_w); - } - w += 1; - } - r += 1; - } - - self.truncate(w); - } + pub fn dedup_by<F>(&mut self, same_bucket: F) where F: FnMut(&mut T, &mut T) -> bool { + let len = { + let (dedup, _) = self.as_mut_slice().partition_dedup_by(same_bucket); + dedup.len() + }; + self.truncate(len); } /// Appends an element to the back of a collection. @@ -1533,7 +1454,8 @@ impl<'a> Drop for SetLenOnDrop<'a> { } impl<T: PartialEq> Vec<T> { - /// Removes consecutive repeated elements in the vector. + /// Removes consecutive repeated elements in the vector according to the + /// [`PartialEq`] trait implementation. /// /// If the vector is sorted, this removes all duplicates. /// |
