]> git.lizzy.rs Git - rust.git/commitdiff
Add method `String::retain`
authorMurarth <murarth@gmail.com>
Wed, 26 Jul 2017 22:09:32 +0000 (15:09 -0700)
committerMurarth <murarth@gmail.com>
Tue, 15 Aug 2017 03:42:26 +0000 (20:42 -0700)
Behaves like `Vec::retain`, accepting a predicate `FnMut(char) -> bool`
and reducing the string to only characters for which the predicate
returns `true`.

src/doc/unstable-book/src/library-features/string-retain.md [new file with mode: 0644]
src/liballoc/string.rs
src/liballoc/tests/lib.rs
src/liballoc/tests/string.rs

diff --git a/src/doc/unstable-book/src/library-features/string-retain.md b/src/doc/unstable-book/src/library-features/string-retain.md
new file mode 100644 (file)
index 0000000..049444a
--- /dev/null
@@ -0,0 +1,23 @@
+# `string_retain`
+
+The tracking issue for this feature is: [#43874]
+
+[#43874]: https://github.com/rust-lang/rust/issues/43874
+
+------------------------
+
+Retains only the characters specified by the predicate.
+
+In other words, remove all characters `c` such that `f(c)` returns `false`.
+This method operates in place and preserves the order of the retained
+characters.
+
+```rust
+#![feature(string_retain)]
+
+let mut s = String::from("f_o_ob_ar");
+
+s.retain(|c| c != '_');
+
+assert_eq!(s, "foobar");
+```
index 622cc68964bf7061cc49d3832a69bbc63186c81c..4acf42edb412fca9aecb08cd7e9c17a3b8272b76 100644 (file)
@@ -1031,6 +1031,57 @@ pub fn remove(&mut self, idx: usize) -> char {
         ch
     }
 
+    /// Retains only the characters specified by the predicate.
+    ///
+    /// In other words, remove all characters `c` such that `f(c)` returns `false`.
+    /// This method operates in place and preserves the order of the retained
+    /// characters.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(string_retain)]
+    ///
+    /// let mut s = String::from("f_o_ob_ar");
+    ///
+    /// s.retain(|c| c != '_');
+    ///
+    /// assert_eq!(s, "foobar");
+    /// ```
+    #[inline]
+    #[unstable(feature = "string_retain", issue = "43874")]
+    pub fn retain<F>(&mut self, mut f: F)
+        where F: FnMut(char) -> bool
+    {
+        let len = self.len();
+        let mut del_bytes = 0;
+        let mut idx = 0;
+
+        while idx < len {
+            let ch = unsafe {
+                self.slice_unchecked(idx, len).chars().next().unwrap()
+            };
+            let ch_len = ch.len_utf8();
+
+            if !f(ch) {
+                del_bytes += ch_len;
+            } else if del_bytes > 0 {
+                unsafe {
+                    ptr::copy(self.vec.as_ptr().offset(idx as isize),
+                              self.vec.as_mut_ptr().offset((idx - del_bytes) as isize),
+                              ch_len);
+                }
+            }
+
+            // Point idx to the next char
+            idx += ch_len;
+        }
+
+        if del_bytes > 0 {
+            unsafe { self.vec.set_len(len - del_bytes); }
+        }
+    }
+
     /// Inserts a character into this `String` at a byte position.
     ///
     /// This is an `O(n)` operation as it requires copying every element in the
index c6d70ee7575f8a6754159504da48bd1075d0e4f6..d4f3a89ee99e252b8e64a0bbe9e7b33a32dab9a6 100644 (file)
@@ -26,6 +26,7 @@
 #![feature(splice)]
 #![feature(str_checked_slicing)]
 #![feature(str_escape)]
+#![feature(string_retain)]
 #![feature(test)]
 #![feature(unboxed_closures)]
 #![feature(unicode)]
index b1731b2a5dcaa486b8e189e97b88dbdf23b9e85f..f5c124c6b4458b3a666273daec3b88f3d5a8851f 100644 (file)
@@ -332,6 +332,26 @@ fn remove_bad() {
     "ศ".to_string().remove(1);
 }
 
+#[test]
+fn test_retain() {
+    let mut s = String::from("α_β_γ");
+
+    s.retain(|_| true);
+    assert_eq!(s, "α_β_γ");
+
+    s.retain(|c| c != '_');
+    assert_eq!(s, "αβγ");
+
+    s.retain(|c| c != 'β');
+    assert_eq!(s, "αγ");
+
+    s.retain(|c| c == 'α');
+    assert_eq!(s, "α");
+
+    s.retain(|_| false);
+    assert_eq!(s, "");
+}
+
 #[test]
 fn insert() {
     let mut s = "foobar".to_string();