Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 82be83c

Browse files
committedAug 15, 2017
Auto merge of rust-lang#43500 - murarth:string-retain, r=alexcrichton
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`.
2 parents 1b08e0f + 618ac89 commit 82be83c

File tree

4 files changed

+95
-0
lines changed

4 files changed

+95
-0
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# `string_retain`
2+
3+
The tracking issue for this feature is: [#43874]
4+
5+
[#43874]: https://github.com/rust-lang/rust/issues/43874
6+
7+
------------------------
8+
9+
Retains only the characters specified by the predicate.
10+
11+
In other words, remove all characters `c` such that `f(c)` returns `false`.
12+
This method operates in place and preserves the order of the retained
13+
characters.
14+
15+
```rust
16+
#![feature(string_retain)]
17+
18+
let mut s = String::from("f_o_ob_ar");
19+
20+
s.retain(|c| c != '_');
21+
22+
assert_eq!(s, "foobar");
23+
```

‎src/liballoc/string.rs

+51
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,57 @@ impl String {
10611061
ch
10621062
}
10631063

1064+
/// Retains only the characters specified by the predicate.
1065+
///
1066+
/// In other words, remove all characters `c` such that `f(c)` returns `false`.
1067+
/// This method operates in place and preserves the order of the retained
1068+
/// characters.
1069+
///
1070+
/// # Examples
1071+
///
1072+
/// ```
1073+
/// #![feature(string_retain)]
1074+
///
1075+
/// let mut s = String::from("f_o_ob_ar");
1076+
///
1077+
/// s.retain(|c| c != '_');
1078+
///
1079+
/// assert_eq!(s, "foobar");
1080+
/// ```
1081+
#[inline]
1082+
#[unstable(feature = "string_retain", issue = "43874")]
1083+
pub fn retain<F>(&mut self, mut f: F)
1084+
where F: FnMut(char) -> bool
1085+
{
1086+
let len = self.len();
1087+
let mut del_bytes = 0;
1088+
let mut idx = 0;
1089+
1090+
while idx < len {
1091+
let ch = unsafe {
1092+
self.slice_unchecked(idx, len).chars().next().unwrap()
1093+
};
1094+
let ch_len = ch.len_utf8();
1095+
1096+
if !f(ch) {
1097+
del_bytes += ch_len;
1098+
} else if del_bytes > 0 {
1099+
unsafe {
1100+
ptr::copy(self.vec.as_ptr().offset(idx as isize),
1101+
self.vec.as_mut_ptr().offset((idx - del_bytes) as isize),
1102+
ch_len);
1103+
}
1104+
}
1105+
1106+
// Point idx to the next char
1107+
idx += ch_len;
1108+
}
1109+
1110+
if del_bytes > 0 {
1111+
unsafe { self.vec.set_len(len - del_bytes); }
1112+
}
1113+
}
1114+
10641115
/// Inserts a character into this `String` at a byte position.
10651116
///
10661117
/// This is an `O(n)` operation as it requires copying every element in the

‎src/liballoc/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#![feature(slice_rotate)]
2626
#![feature(splice)]
2727
#![feature(str_escape)]
28+
#![feature(string_retain)]
2829
#![feature(test)]
2930
#![feature(unboxed_closures)]
3031
#![feature(unicode)]

‎src/liballoc/tests/string.rs

+20
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,26 @@ fn remove_bad() {
332332
"ศ".to_string().remove(1);
333333
}
334334

335+
#[test]
336+
fn test_retain() {
337+
let mut s = String::from("α_β_γ");
338+
339+
s.retain(|_| true);
340+
assert_eq!(s, "α_β_γ");
341+
342+
s.retain(|c| c != '_');
343+
assert_eq!(s, "αβγ");
344+
345+
s.retain(|c| c != 'β');
346+
assert_eq!(s, "αγ");
347+
348+
s.retain(|c| c == 'α');
349+
assert_eq!(s, "α");
350+
351+
s.retain(|_| false);
352+
assert_eq!(s, "");
353+
}
354+
335355
#[test]
336356
fn insert() {
337357
let mut s = "foobar".to_string();

0 commit comments

Comments
 (0)
Please sign in to comment.