retain_mut-0.1.7/.cargo_vcs_info.json0000644000000001360000000000100132100ustar { "git": { "sha1": "19ce064285bb077a5ee62e1db84ab9cf56e6576b" }, "path_in_vcs": "" }retain_mut-0.1.7/.gitignore000064400000000000000000000000360072674642500140170ustar 00000000000000/target **/*.rs.bk Cargo.lock retain_mut-0.1.7/Cargo.toml0000644000000015260000000000100112120ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] name = "retain_mut" version = "0.1.7" authors = ["Xidorn Quan "] description = "Provide retain_mut method that has the same functionality as retain but gives mutable borrow to the predicate." readme = "README.md" keywords = ["retain", "no_std"] categories = ["rust-patterns"] license = "MIT" repository = "https://github.com/upsuper/retain_mut" [dependencies] retain_mut-0.1.7/Cargo.toml.orig000064400000000000000000000006040072674642500147170ustar 00000000000000[package] name = "retain_mut" version = "0.1.7" authors = ["Xidorn Quan "] description = "Provide retain_mut method that has the same functionality as retain but gives mutable borrow to the predicate." license = "MIT" repository = "https://github.com/upsuper/retain_mut" categories = ["rust-patterns"] keywords = ["retain", "no_std"] readme = "README.md" [dependencies] retain_mut-0.1.7/LICENSE000064400000000000000000000017770072674642500130510ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. retain_mut-0.1.7/README.md000064400000000000000000000023360072674642500133130ustar 00000000000000# RetainMut This crate provides trait `RetainMut` which provides `retain_mut` method for `Vec` and `VecDeque`. `retain_mut` is basically the same as `retain` except that it gives mutable reference of items to the predicate function. Since there is no reason `retain` couldn't have been designed this way, this crate basically just copies the code from std with minor changes to hand out mutable reference. The code these impls are based on can be found in code comments of this crate. This was probably a historical mistake in Rust library, that `retain` should do this at the very beginning. See [rust-lang/rust#25477](https://github.com/rust-lang/rust/issues/25477). From Rust 1.58, an unstable `retain_mut` method has been added to the std, see [rust-lang/rust#90829](https://github.com/rust-lang/rust/issues/90829). Once it gets stabilized, you can simply remove this crate. ## Examples ### `Vec` ```rust let mut vec = vec![1, 2, 3, 4]; vec.retain_mut(|x| { *x *= 3; *x % 2 == 0 }); assert_eq!(vec, [6, 12]); ``` ### `VecDeque` ```rust let mut deque = VecDeque::from(vec![1, 2, 3, 4]); deque.retain_mut(|x| { *x *= 3; *x % 2 == 0 }); assert_eq!(deque, [6, 12]); ``` retain_mut-0.1.7/src/lib.rs000064400000000000000000000161230072674642500137360ustar 00000000000000//! This crate provides trait `RetainMut` which //! provides `retain_mut` method for `Vec` and `VecDeque`. //! //! `retain_mut` is basically the same as `retain` except that //! it gives mutable reference of items to the predicate function. //! //! Since there is no reason `retain` couldn't have been designed this way, //! this crate basically just copies the code from std with minor changes //! to hand out mutable reference. //! The code these impls are based on can be found in code comments of this crate. //! //! This was probably a historical mistake in Rust library, //! that `retain` should do this at the very beginning. //! See [rust-lang/rust#25477](https://github.com/rust-lang/rust/issues/25477). //! //! From Rust 1.58, an unstable `retain_mut` method has been added to the std, see //! [rust-lang/rust#90829](https://github.com/rust-lang/rust/issues/90829). //! Once it gets stabilized, you can simply remove this crate. //! //! ## Examples //! //! ### `Vec` //! //! ``` //! # use retain_mut::RetainMut; //! let mut vec = vec![1, 2, 3, 4]; //! vec.retain_mut(|x| { *x *= 3; *x % 2 == 0 }); //! assert_eq!(vec, [6, 12]); //! ``` //! //! ### `VecDeque` //! //! ``` //! # use retain_mut::RetainMut; //! # use std::collections::VecDeque; //! let mut deque = VecDeque::from(vec![1, 2, 3, 4]); //! deque.retain_mut(|x| { *x *= 3; *x % 2 == 0 }); //! assert_eq!(deque, [6, 12]); //! ``` #![no_std] extern crate alloc; use alloc::collections::vec_deque::VecDeque; use alloc::vec::Vec; use core::ptr; /// Trait that provides `retain_mut` method. pub trait RetainMut { /// Retains only the elements specified by the predicate, passing a mutable reference to it. /// /// In other words, remove all elements `e` such that `f(&mut e)` returns `false`. /// This method operates in place, visiting each element exactly once in the /// original order, and preserves the order of the retained elements. fn retain_mut(&mut self, f: F) where F: FnMut(&mut T) -> bool; } impl RetainMut for Vec { // The implementation is based on // https://github.com/rust-lang/rust/blob/03c8ffaacb040a8753ef8e1accea701bc9f5be85/library/alloc/src/vec/mod.rs#L1478-L1569 fn retain_mut(&mut self, mut f: F) where F: FnMut(&mut T) -> bool, { let original_len = self.len(); // Avoid double drop if the drop guard is not executed, // since we may make some holes during the process. unsafe { self.set_len(0) }; // Vec: [Kept, Kept, Hole, Hole, Hole, Hole, Unchecked, Unchecked] // |<- processed len ->| ^- next to check // |<- deleted cnt ->| // |<- original_len ->| // Kept: Elements which predicate returns true on. // Hole: Moved or dropped element slot. // Unchecked: Unchecked valid elements. // // This drop guard will be invoked when predicate or `drop` of element panicked. // It shifts unchecked elements to cover holes and `set_len` to the correct length. // In cases when predicate and `drop` never panick, it will be optimized out. struct BackshiftOnDrop<'a, T> { v: &'a mut Vec, processed_len: usize, deleted_cnt: usize, original_len: usize, } impl Drop for BackshiftOnDrop<'_, T> { fn drop(&mut self) { if self.deleted_cnt > 0 { // SAFETY: Trailing unchecked items must be valid since we never touch them. unsafe { ptr::copy( self.v.as_ptr().add(self.processed_len), self.v .as_mut_ptr() .add(self.processed_len - self.deleted_cnt), self.original_len - self.processed_len, ); } } // SAFETY: After filling holes, all items are in contiguous memory. unsafe { self.v.set_len(self.original_len - self.deleted_cnt); } } } let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len, }; fn process_loop( original_len: usize, f: &mut F, g: &mut BackshiftOnDrop<'_, T>, ) where F: FnMut(&mut T) -> bool, { while g.processed_len != original_len { // SAFETY: Unchecked element must be valid. let cur = unsafe { &mut *g.v.as_mut_ptr().add(g.processed_len) }; if !f(cur) { // Advance early to avoid double drop if `drop_in_place` panicked. g.processed_len += 1; g.deleted_cnt += 1; // SAFETY: We never touch this element again after dropped. unsafe { ptr::drop_in_place(cur) }; // We already advanced the counter. if DELETED { continue; } else { break; } } if DELETED { // SAFETY: `deleted_cnt` > 0, so the hole slot must not overlap with current element. // We use copy for move, and never touch this element again. unsafe { let hole_slot = g.v.as_mut_ptr().add(g.processed_len - g.deleted_cnt); ptr::copy_nonoverlapping(cur, hole_slot, 1); } } g.processed_len += 1; } } // Stage 1: Nothing was deleted. process_loop::(original_len, &mut f, &mut g); // Stage 2: Some elements were deleted. process_loop::(original_len, &mut f, &mut g); // All item are processed. This can be optimized to `set_len` by LLVM. drop(g); } } impl RetainMut for VecDeque { // The implementation is based on // https://github.com/rust-lang/rust/blob/3e21768a0a3fc84befd1cbe825ae6849e9941b73/library/alloc/src/collections/vec_deque/mod.rs#L2148-L2180 fn retain_mut(&mut self, mut f: F) where F: FnMut(&mut T) -> bool, { let len = self.len(); let mut idx = 0; let mut cur = 0; // Stage 1: All values are retained. while cur < len { if !f(&mut self[cur]) { cur += 1; break; } cur += 1; idx += 1; } // Stage 2: Swap retained value into current idx. while cur < len { if !f(&mut self[cur]) { cur += 1; continue; } self.swap(idx, cur); cur += 1; idx += 1; } // Stage 3: Trancate all values after idx. if cur != idx { self.truncate(idx); } } }