about summary refs log tree commit diff
path: root/src/liballoc/string.rs
diff options
context:
space:
mode:
authorMurarth <murarth@gmail.com>2017-07-26 15:09:32 -0700
committerMurarth <murarth@gmail.com>2017-08-14 20:42:26 -0700
commit618ac89d256adca97518742db2ad2759c4f5fc72 (patch)
treeee0c3f861bf2c64d78d5205c54a7273b2bdc9b39 /src/liballoc/string.rs
parent599be0d18f4c6ddf36366d2a5a2ca6dc65886896 (diff)
downloadrust-618ac89d256adca97518742db2ad2759c4f5fc72.tar.gz
rust-618ac89d256adca97518742db2ad2759c4f5fc72.zip
Add method `String::retain`
Behaves like `Vec::retain`, accepting a predicate `FnMut(char) -> bool`
and reducing the string to only characters for which the predicate
returns `true`.
Diffstat (limited to 'src/liballoc/string.rs')
-rw-r--r--src/liballoc/string.rs51
1 files changed, 51 insertions, 0 deletions
diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs
index 622cc68964b..4acf42edb41 100644
--- a/src/liballoc/string.rs
+++ b/src/liballoc/string.rs
@@ -1031,6 +1031,57 @@ impl String {
         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