From d70b98ebbb24424813de13bb459e6b47d07df545 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 6 Nov 2015 16:28:14 +0000 Subject: [PATCH 1/2] RFC to add retain_mut to Vec and VecDeque --- text/0000-vec-retain_mut.md | 66 +++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 text/0000-vec-retain_mut.md diff --git a/text/0000-vec-retain_mut.md b/text/0000-vec-retain_mut.md new file mode 100644 index 00000000000..55e3e1a8385 --- /dev/null +++ b/text/0000-vec-retain_mut.md @@ -0,0 +1,66 @@ +- Feature Name: retain_mut +- Start Date: 2015-11-6 +- RFC PR: (leave this empty) +- Rust Issue: (leave this empty) + +# Summary +[summary]: #summary + +Add a `retain_mut` method to `Vec` and `VecDeque` which allows elements to be +mutated before deciding whether to retain them. + +# Motivation +[motivation]: #motivation + +A common pattern with vectors is to look at each element, modify it and +remove it from the vector if a certain condition is met. The `retain` method +allows elements to be removed from a vector in-place but does not allow existing +elements to be modified. + +The lack of a `retain_mut` method means that users have to do 2 passes, one with +`iter_mut` and one with `retain`. The resulting code is harder to read and +slower. Another, more efficient, way of doing this would be to work with vector +indices directly and swap elements into place while mutating them, similar to +what `retain` already does. + +# Detailed design +[design]: #detailed-design + +The only difference between `retain_mut` and `retain` is that `retain_mut` takes +a `FnMut(&mut T)` parameter instead of a `FnMut(&T)`. This allows elements to +be mutated before deciding whether to retain them. + +The new `retain_mut` method will be added to both `Vec` and `VecDeque`. + +Here is an example which will decrement each element of a vector and filter out +elements that have reached a value of zero. + + let mut vec = vec![7, 1, 3, 10]; + vec.retain_mut(|x| { + *x -= 1; + *x != 0 + }); + assert_eq!(vec, [6, 2, 9]); + +# Drawbacks +[drawbacks]: #drawbacks + +The `retain` method really should have had a `FnMut(&mut T)` parameter from the +start, but it is too late to change that. Adding `retain_mut` will result in +two methods that have almost identical implementations. + +# Alternatives +[alternatives]: #alternatives + +Changing the existing `retain` method to take a `FnMut(&mut T)` was considered +in rust-lang/rust#25477 but this is likely to break a lot of existing code which +passes a closure defined using `|&x| {...}`. + +Another alternative is to not do anything. Users can implement their own version +of `retain_mut` or they can restructure their code into an `iter_mut` pass on +the vector followed by a `retain` pass. + +# Unresolved questions +[unresolved]: #unresolved-questions + +None From 74210ee78d16551545af515c7120550bbcef584e Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 27 May 2016 09:53:11 +0100 Subject: [PATCH 2/2] Rename retain_mut to filter_in_place, add filter_in_place_unordered and deprecate retain --- text/0000-vec-retain_mut.md | 62 ++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/text/0000-vec-retain_mut.md b/text/0000-vec-retain_mut.md index 55e3e1a8385..562dbd48db9 100644 --- a/text/0000-vec-retain_mut.md +++ b/text/0000-vec-retain_mut.md @@ -1,4 +1,4 @@ -- Feature Name: retain_mut +- Feature Name: filter_in_place - Start Date: 2015-11-6 - RFC PR: (leave this empty) - Rust Issue: (leave this empty) @@ -6,8 +6,12 @@ # Summary [summary]: #summary -Add a `retain_mut` method to `Vec` and `VecDeque` which allows elements to be -mutated before deciding whether to retain them. +Add `filter_in_place` and `filter_in_place_unordered` methods to `Vec` and +`VecDeque` which allow iterating through all elements mutably while deciding +whether to remove an element from the container. + +The existing `retain` method will be deprecated since its functionality is +superseded by the two new methods. # Motivation [motivation]: #motivation @@ -23,31 +27,53 @@ slower. Another, more efficient, way of doing this would be to work with vector indices directly and swap elements into place while mutating them, similar to what `retain` already does. +`Vec` and `VecDequeue` also lack a way of filtering elements without preserving +the order of elements in the vector, which can be implemented more efficiently +by simply swaping with the last element when removing from the vector. + # Detailed design [design]: #detailed-design -The only difference between `retain_mut` and `retain` is that `retain_mut` takes -a `FnMut(&mut T)` parameter instead of a `FnMut(&T)`. This allows elements to -be mutated before deciding whether to retain them. +Two new methods are added to `Vec` and `VecDequeue`: + +```rust +pub fn filter_in_place(&mut self, f: F) + where F: FnMut(&mut T) -> bool; + +pub fn filter_in_place_unordered(&mut self, f: F) + where F: FnMut(&mut T) -> bool; +``` + +The `filter_in_place` method is similar to `retain` in that it calls the given +closure for each element in the vector in their original order, and removes the +element from the vector if the closure returns `false`. Unlike `retain` however, +the closure is given a `&mut T` instead of a `&T`, which allows it to modify +elements before deciding whether to remove them from the vector. + +The `filter_in_place_unordered` method is similar to `filter_in_place` but does +not preserve the order of elements in the vector. The closure is only guaranteed +to be called once for all elements in the original vector, but not necessarily +in the original order. -The new `retain_mut` method will be added to both `Vec` and `VecDeque`. +The new `retain` method will be deprecated from both `Vec` and `VecDeque` since +it only provides a subset of the functionality of `filter_in_place`. Here is an example which will decrement each element of a vector and filter out elements that have reached a value of zero. - let mut vec = vec![7, 1, 3, 10]; - vec.retain_mut(|x| { - *x -= 1; - *x != 0 - }); - assert_eq!(vec, [6, 2, 9]); +```rust +let mut vec = vec![7, 1, 3, 10]; +vec.filter_in_place(|x| { + *x -= 1; + *x != 0 +}); +assert_eq!(vec, [6, 2, 9]); +``` # Drawbacks [drawbacks]: #drawbacks -The `retain` method really should have had a `FnMut(&mut T)` parameter from the -start, but it is too late to change that. Adding `retain_mut` will result in -two methods that have almost identical implementations. +This deprecates `retain`, which is a stable API. # Alternatives [alternatives]: #alternatives @@ -57,8 +83,8 @@ in rust-lang/rust#25477 but this is likely to break a lot of existing code which passes a closure defined using `|&x| {...}`. Another alternative is to not do anything. Users can implement their own version -of `retain_mut` or they can restructure their code into an `iter_mut` pass on -the vector followed by a `retain` pass. +of `filter_in_place` or they can restructure their code into an `iter_mut` pass +on the vector followed by a `retain` pass. # Unresolved questions [unresolved]: #unresolved-questions