//! Parallel iterator types for [strings][std::str] //! //! You will rarely need to interact with this module directly unless you need //! to name one of the iterator types. //! //! Note: [`ParallelString::par_split()`] and [`par_split_terminator()`] //! reference a `Pattern` trait which is not visible outside this crate. //! This trait is intentionally kept private, for use only by Rayon itself. //! It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`, //! and any function or closure `F: Fn(char) -> bool + Sync + Send`. //! //! [`ParallelString::par_split()`]: trait.ParallelString.html#method.par_split //! [`par_split_terminator()`]: trait.ParallelString.html#method.par_split_terminator //! //! [std::str]: https://doc.rust-lang.org/stable/std/str/
/// Test if a byte is the start of a UTF-8 character. /// (extracted from `str::is_char_boundary`) #[inline] fn is_char_boundary(b: u8) -> bool { // This is bit magic equivalent to: b < 128 || b >= 192
(b as i8) >= -0x40
}
/// Find the index of a character boundary near the midpoint. #[inline] fn find_char_midpoint(chars: &str) -> usize { let mid = chars.len() / 2;
// We want to split near the midpoint, but we need to find an actual // character boundary. So we look at the raw bytes, first scanning // forward from the midpoint for a boundary, then trying backward. let (left, right) = chars.as_bytes().split_at(mid); match right.iter().copied().position(is_char_boundary) {
Some(i) => mid + i,
None => left
.iter()
.copied()
.rposition(is_char_boundary)
.unwrap_or(0),
}
}
/// Try to split a string near the midpoint. #[inline] fn split(chars: &str) -> Option<(&str, &str)> { let index = find_char_midpoint(chars); if index > 0 {
Some(chars.split_at(index))
} else {
None
}
}
/// Parallel extensions for strings. pubtrait ParallelString { /// Returns a plain string slice, which is used to implement the rest of /// the parallel methods. fn as_parallel_string(&self) -> &str;
/// Returns a parallel iterator over the characters of a string. /// /// # Examples /// /// ``` /// use rayon::prelude::*; /// let max = "hello".par_chars().max_by_key(|c| *c as i32); /// assert_eq!(Some('o'), max); /// ``` fn par_chars(&self) -> Chars<'_> {
Chars {
chars: self.as_parallel_string(),
}
}
/// Returns a parallel iterator over the characters of a string, with their positions. /// /// # Examples /// /// ``` /// use rayon::prelude::*; /// let min = "hello".par_char_indices().min_by_key(|&(_i, c)| c as i32); /// assert_eq!(Some((1, 'e')), min); /// ``` fn par_char_indices(&self) -> CharIndices<'_> {
CharIndices {
chars: self.as_parallel_string(),
}
}
/// Returns a parallel iterator over the bytes of a string. /// /// Note that multi-byte sequences (for code points greater than `U+007F`) /// are produced as separate items, but will not be split across threads. /// If you would prefer an indexed iterator without that guarantee, consider /// `string.as_bytes().par_iter().copied()` instead. /// /// # Examples /// /// ``` /// use rayon::prelude::*; /// let max = "hello".par_bytes().max(); /// assert_eq!(Some(b'o'), max); /// ``` fn par_bytes(&self) -> Bytes<'_> {
Bytes {
chars: self.as_parallel_string(),
}
}
/// Returns a parallel iterator over a string encoded as UTF-16. /// /// Note that surrogate pairs (for code points greater than `U+FFFF`) are /// produced as separate items, but will not be split across threads. /// /// # Examples /// /// ``` /// use rayon::prelude::*; /// /// let max = "hello".par_encode_utf16().max(); /// assert_eq!(Some(b'o' as u16), max); /// /// let text = "Zażółć gęślą jaźń"; /// let utf8_len = text.len(); /// let utf16_len = text.par_encode_utf16().count(); /// assert!(utf16_len <= utf8_len); /// ``` fn par_encode_utf16(&self) -> EncodeUtf16<'_> {
EncodeUtf16 {
chars: self.as_parallel_string(),
}
}
/// Returns a parallel iterator over substrings separated by a /// given character or predicate, similar to `str::split`. /// /// Note: the `Pattern` trait is private, for use only by Rayon itself. /// It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`, /// and any function or closure `F: Fn(char) -> bool + Sync + Send`. /// /// # Examples /// /// ``` /// use rayon::prelude::*; /// let total = "1, 2, buckle, 3, 4, door" /// .par_split(',') /// .filter_map(|s| s.trim().parse::<i32>().ok()) /// .sum(); /// assert_eq!(10, total); /// ``` fn par_split<P: Pattern>(&self, separator: P) -> Split<'_, P> {
Split::new(self.as_parallel_string(), separator)
}
/// Returns a parallel iterator over substrings separated by a /// given character or predicate, keeping the matched part as a terminator /// of the substring similar to `str::split_inclusive`. /// /// Note: the `Pattern` trait is private, for use only by Rayon itself. /// It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`, /// and any function or closure `F: Fn(char) -> bool + Sync + Send`. /// /// # Examples /// /// ``` /// use rayon::prelude::*; /// let lines: Vec<_> = "Mary had a little lamb\nlittle lamb\nlittle lamb." /// .par_split_inclusive('\n') /// .collect(); /// assert_eq!(lines, ["Mary had a little lamb\n", "little lamb\n", "little lamb."]); /// ``` fn par_split_inclusive<P: Pattern>(&self, separator: P) -> SplitInclusive<'_, P> {
SplitInclusive::new(self.as_parallel_string(), separator)
}
/// Returns a parallel iterator over substrings terminated by a /// given character or predicate, similar to `str::split_terminator`. /// It's equivalent to `par_split`, except it doesn't produce an empty /// substring after a trailing terminator. /// /// Note: the `Pattern` trait is private, for use only by Rayon itself. /// It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`, /// and any function or closure `F: Fn(char) -> bool + Sync + Send`. /// /// # Examples /// /// ``` /// use rayon::prelude::*; /// let parts: Vec<_> = "((1 + 3) * 2)" /// .par_split_terminator(|c| c == '(' || c == ')') /// .collect(); /// assert_eq!(vec!["", "", "1 + 3", " * 2"], parts); /// ``` fn par_split_terminator<P: Pattern>(&self, terminator: P) -> SplitTerminator<'_, P> {
SplitTerminator::new(self.as_parallel_string(), terminator)
}
/// Returns a parallel iterator over the lines of a string, ending with an /// optional carriage return and with a newline (`\r\n` or just `\n`). /// The final line ending is optional, and line endings are not included in /// the output strings. /// /// # Examples /// /// ``` /// use rayon::prelude::*; /// let lengths: Vec<_> = "hello world\nfizbuzz" /// .par_lines() /// .map(|l| l.len()) /// .collect(); /// assert_eq!(vec![11, 7], lengths); /// ``` fn par_lines(&self) -> Lines<'_> {
Lines(self.as_parallel_string())
}
/// Returns a parallel iterator over the sub-slices of a string that are /// separated by any amount of whitespace. /// /// As with `str::split_whitespace`, 'whitespace' is defined according to /// the terms of the Unicode Derived Core Property `White_Space`. /// If you only want to split on ASCII whitespace instead, use /// [`par_split_ascii_whitespace`][`ParallelString::par_split_ascii_whitespace`]. /// /// # Examples /// /// ``` /// use rayon::prelude::*; /// let longest = "which is the longest word?" /// .par_split_whitespace() /// .max_by_key(|word| word.len()); /// assert_eq!(Some("longest"), longest); /// ``` /// /// All kinds of whitespace are considered: /// /// ``` /// use rayon::prelude::*; /// let words: Vec<&str> = " Mary had\ta\u{2009}little \n\t lamb" /// .par_split_whitespace() /// .collect(); /// assert_eq!(words, ["Mary", "had", "a", "little", "lamb"]); /// ``` /// /// If the string is empty or all whitespace, the iterator yields no string slices: /// /// ``` /// use rayon::prelude::*; /// assert_eq!("".par_split_whitespace().count(), 0); /// assert_eq!(" ".par_split_whitespace().count(), 0); /// ``` fn par_split_whitespace(&self) -> SplitWhitespace<'_> {
SplitWhitespace(self.as_parallel_string())
}
/// Returns a parallel iterator over the sub-slices of a string that are /// separated by any amount of ASCII whitespace. /// /// To split by Unicode `White_Space` instead, use /// [`par_split_whitespace`][`ParallelString::par_split_whitespace`]. /// /// # Examples /// /// ``` /// use rayon::prelude::*; /// let longest = "which is the longest word?" /// .par_split_ascii_whitespace() /// .max_by_key(|word| word.len()); /// assert_eq!(Some("longest"), longest); /// ``` /// /// All kinds of ASCII whitespace are considered, but not Unicode `White_Space`: /// /// ``` /// use rayon::prelude::*; /// let words: Vec<&str> = " Mary had\ta\u{2009}little \n\t lamb" /// .par_split_ascii_whitespace() /// .collect(); /// assert_eq!(words, ["Mary", "had", "a\u{2009}little", "lamb"]); /// ``` /// /// If the string is empty or all ASCII whitespace, the iterator yields no string slices: /// /// ``` /// use rayon::prelude::*; /// assert_eq!("".par_split_whitespace().count(), 0); /// assert_eq!(" ".par_split_whitespace().count(), 0); /// ``` fn par_split_ascii_whitespace(&self) -> SplitAsciiWhitespace<'_> {
SplitAsciiWhitespace(self.as_parallel_string())
}
/// Returns a parallel iterator over substrings that match a /// given character or predicate, similar to `str::matches`. /// /// Note: the `Pattern` trait is private, for use only by Rayon itself. /// It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`, /// and any function or closure `F: Fn(char) -> bool + Sync + Send`. /// /// # Examples /// /// ``` /// use rayon::prelude::*; /// let total = "1, 2, buckle, 3, 4, door" /// .par_matches(char::is_numeric) /// .map(|s| s.parse::<i32>().expect("digit")) /// .sum(); /// assert_eq!(10, total); /// ``` fn par_matches<P: Pattern>(&self, pattern: P) -> Matches<'_, P> {
Matches {
chars: self.as_parallel_string(),
pattern,
}
}
/// Returns a parallel iterator over substrings that match a given character /// or predicate, with their positions, similar to `str::match_indices`. /// /// Note: the `Pattern` trait is private, for use only by Rayon itself. /// It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`, /// and any function or closure `F: Fn(char) -> bool + Sync + Send`. /// /// # Examples /// /// ``` /// use rayon::prelude::*; /// let digits: Vec<_> = "1, 2, buckle, 3, 4, door" /// .par_match_indices(char::is_numeric) /// .collect(); /// assert_eq!(digits, vec![(0, "1"), (3, "2"), (14, "3"), (17, "4")]); /// ``` fn par_match_indices<P: Pattern>(&self, pattern: P) -> MatchIndices<'_, P> {
MatchIndices {
chars: self.as_parallel_string(),
pattern,
}
}
}
/// We hide the `Pattern` trait in a private module, as its API is not meant /// for general consumption. If we could have privacy on trait items, then it /// would be nicer to have its basic existence and implementors public while /// keeping all of the methods private. mod private { usecrate::iter::plumbing::Folder;
/// Pattern-matching trait for `ParallelString`, somewhat like a mix of /// `std::str::pattern::{Pattern, Searcher}`. /// /// Implementing this trait is not permitted outside of `rayon`. pubtrait Pattern: Sized + Sync + Send {
private_decl! {} fn find_in(&self, haystack: &str) -> Option<usize>; fn rfind_in(&self, haystack: &str) -> Option<usize>; fn is_suffix_of(&self, haystack: &str) -> bool; fn fold_splits<'ch, F>(&self, haystack: &'ch str, folder: F, skip_last: bool) -> F where
F: Folder<&'ch str>; fn fold_inclusive_splits<'ch, F>(&self, haystack: &'ch str, folder: F) -> F where
F: Folder<&'ch str>; fn fold_matches<'ch, F>(&self, haystack: &'ch str, folder: F) -> F where
F: Folder<&'ch str>; fn fold_match_indices<'ch, F>(&self, haystack: &'ch str, folder: F, base: usize) -> F where
F: Folder<(usize, &'ch str)>;
}
} useself::private::Pattern;
fn fold_with<F>(self, folder: F) -> F where
F: Folder<Self::Item>,
{ let base = self.index;
folder.consume_iter(self.chars.char_indices().map(offset(base)))
}
}
fn split_once<const INCL: bool>(self, index: usize) -> (Self, Self) { if INCL { // include the separator in the left side let separator = self[index..].chars().next().unwrap(); self.split_at(index + separator.len_utf8())
} else { let (left, right) = self.split_at(index); letmut right_iter = right.chars();
right_iter.next(); // skip the separator
(left, right_iter.as_str())
}
}
/// Parallel iterator over substrings that match a pattern, with their positions #[derive(Debug, Clone)] pubstruct MatchIndices<'ch, P: Pattern> {
chars: &'ch str,
pattern: P,
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.