Skip to content

Commit 5097217

Browse files
authored
Add retain_mut (#198)
* Add retain_mut This adds a `retain_mut` method to `ArrayVec` and `TinyVec` that's just `retain` but with mutable references. This method is present on `std::vec::Vec` as of a while ago so it's nice to have in `tinyvec` too. Fixes #195 * `TinyVec::retain_mut` requires rustc_1_61 feature It calls `std::vec::Vec::retain_mut` which is only available since Rust 1.61. People that still want to use a very old compiler (CI seems to use 1.47) still get to compile the crate, they just don't get `TinyVec::retain_mut`. Note that `ArrayVec::retain_mut` is implemented inside the crate so it's still available, just the `TinyVec` format is not. * Add some tests for ArrayVec::retain_mut
1 parent 612c87d commit 5097217

3 files changed

Lines changed: 124 additions & 0 deletions

File tree

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ rustc_1_55 = []
4141
# add try_reserve functions to types that heap allocate.
4242
rustc_1_57 = ["rustc_1_55"]
4343

44+
# features that require rustc 1.61
45+
# add retain_mut function to TinyVec
46+
rustc_1_61 = []
47+
4448
# allow use of nightly feature `slice_partition_dedup`,
4549
# will become useless once that is stabilized:
4650
# https://github.com/rust-lang/rust/issues/54279

src/arrayvec.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,63 @@ impl<A: Array> ArrayVec<A> {
816816
}
817817
}
818818

819+
/// Retains only the elements specified by the predicate, passing a mutable
820+
/// reference to it.
821+
///
822+
/// In other words, remove all elements e such that f(&mut e) returns false.
823+
/// This method operates in place, visiting each element exactly once in the
824+
/// original order, and preserves the order of the retained elements.
825+
///
826+
///
827+
/// ## Example
828+
///
829+
/// ```rust
830+
/// # use tinyvec::*;
831+
///
832+
/// let mut av = array_vec!([i32; 10] => 1, 1, 2, 3, 3, 4);
833+
/// av.retain_mut(|x| if *x % 2 == 0 { *x *= 2; true } else { false });
834+
/// assert_eq!(&av[..], [4, 8]);
835+
/// ```
836+
#[inline]
837+
pub fn retain_mut<F>(&mut self, mut acceptable: F)
838+
where
839+
F: FnMut(&mut A::Item) -> bool,
840+
{
841+
// Drop guard to contain exactly the remaining elements when the test
842+
// panics.
843+
struct JoinOnDrop<'vec, Item> {
844+
items: &'vec mut [Item],
845+
done_end: usize,
846+
// Start of tail relative to `done_end`.
847+
tail_start: usize,
848+
}
849+
850+
impl<Item> Drop for JoinOnDrop<'_, Item> {
851+
fn drop(&mut self) {
852+
self.items[self.done_end..].rotate_left(self.tail_start);
853+
}
854+
}
855+
856+
let mut rest = JoinOnDrop {
857+
items: &mut self.data.as_slice_mut()[..self.len as usize],
858+
done_end: 0,
859+
tail_start: 0,
860+
};
861+
862+
let len = self.len as usize;
863+
for idx in 0..len {
864+
// Loop start invariant: idx = rest.done_end + rest.tail_start
865+
if !acceptable(&mut rest.items[idx]) {
866+
let _ = core::mem::take(&mut rest.items[idx]);
867+
self.len -= 1;
868+
rest.tail_start += 1;
869+
} else {
870+
rest.items.swap(rest.done_end, idx);
871+
rest.done_end += 1;
872+
}
873+
}
874+
}
875+
819876
/// Forces the length of the vector to `new_len`.
820877
///
821878
/// ## Panics
@@ -1893,3 +1950,45 @@ where
18931950
Ok(new_arrayvec)
18941951
}
18951952
}
1953+
1954+
#[cfg(test)]
1955+
mod test {
1956+
use super::*;
1957+
1958+
#[test]
1959+
fn retain_mut_empty_vec() {
1960+
let mut av: ArrayVec<[i32; 4]> = ArrayVec::new();
1961+
av.retain_mut(|&mut x| x % 2 == 0);
1962+
assert_eq!(av.len(), 0);
1963+
}
1964+
1965+
#[test]
1966+
fn retain_mut_all_elements() {
1967+
let mut av: ArrayVec<[i32; 4]> = array_vec!([i32; 4] => 2, 4, 6, 8);
1968+
av.retain_mut(|&mut x| x % 2 == 0);
1969+
assert_eq!(av.len(), 4);
1970+
assert_eq!(av.as_slice(), &[2, 4, 6, 8]);
1971+
}
1972+
1973+
#[test]
1974+
fn retain_mut_some_elements() {
1975+
let mut av: ArrayVec<[i32; 4]> = array_vec!([i32; 4] => 1, 2, 3, 4);
1976+
av.retain_mut(|&mut x| x % 2 == 0);
1977+
assert_eq!(av.len(), 2);
1978+
assert_eq!(av.as_slice(), &[2, 4]);
1979+
}
1980+
1981+
#[test]
1982+
fn retain_mut_no_elements() {
1983+
let mut av: ArrayVec<[i32; 4]> = array_vec!([i32; 4] => 1, 3, 5, 7);
1984+
av.retain_mut(|&mut x| x % 2 == 0);
1985+
assert_eq!(av.len(), 0);
1986+
}
1987+
1988+
#[test]
1989+
fn retain_mut_zero_capacity() {
1990+
let mut av: ArrayVec<[i32; 0]> = ArrayVec::new();
1991+
av.retain_mut(|&mut x| x % 2 == 0);
1992+
assert_eq!(av.len(), 0);
1993+
}
1994+
}

src/tinyvec.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,27 @@ impl<A: Array> TinyVec<A> {
647647
}
648648
}
649649

650+
/// Walk the vec and keep only the elements that pass the predicate given,
651+
/// having the opportunity to modify the elements at the same time.
652+
///
653+
/// ## Example
654+
///
655+
/// ```rust
656+
/// use tinyvec::*;
657+
///
658+
/// let mut tv = tiny_vec!([i32; 10] => 1, 2, 3, 4);
659+
/// tv.retain_mut(|x| if *x % 2 == 0 { *x *= 2; true } else { false });
660+
/// assert_eq!(tv.as_slice(), &[4, 8][..]);
661+
/// ```
662+
#[inline]
663+
#[cfg(feature = "rustc_1_61")]
664+
pub fn retain_mut<F: FnMut(&mut A::Item) -> bool>(&mut self, acceptable: F) {
665+
match self {
666+
TinyVec::Inline(i) => i.retain_mut(acceptable),
667+
TinyVec::Heap(h) => h.retain_mut(acceptable),
668+
}
669+
}
670+
650671
/// Helper for getting the mut slice.
651672
#[inline(always)]
652673
#[must_use]

0 commit comments

Comments
 (0)