Skip to content

Commit 9b938ba

Browse files
committed
Add ParallelString::par_match_indices, like str::match_indices
1 parent a7f5c77 commit 9b938ba

File tree

2 files changed

+93
-0
lines changed

2 files changed

+93
-0
lines changed

src/str.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,25 @@ pub trait ParallelString {
211211
fn par_matches<P: Pattern>(&self, pattern: P) -> Matches<P> {
212212
Matches { chars: self.as_parallel_string(), pattern }
213213
}
214+
215+
/// Returns a parallel iterator over substrings that match a given character
216+
/// or predicate, with their positions, similar to `str::match_indices`.
217+
///
218+
/// Note: the `Pattern` trait is private, for use only by Rayon itself.
219+
/// It is implemented for `char` and any `F: Fn(char) -> bool + Sync + Send`.
220+
///
221+
/// # Examples
222+
///
223+
/// ```
224+
/// use rayon::prelude::*;
225+
/// let digits: Vec<_> = "1, 2, buckle, 3, 4, door"
226+
/// .par_match_indices(char::is_numeric)
227+
/// .collect();
228+
/// assert_eq!(digits, vec![(0, "1"), (3, "2"), (14, "3"), (17, "4")]);
229+
/// ```
230+
fn par_match_indices<P: Pattern>(&self, pattern: P) -> MatchIndices<P> {
231+
MatchIndices { chars: self.as_parallel_string(), pattern }
232+
}
214233
}
215234

216235
impl ParallelString for str {
@@ -243,6 +262,8 @@ mod private {
243262
where F: Folder<&'ch str>;
244263
fn fold_matches<'ch, F>(&self, &'ch str, folder: F) -> F
245264
where F: Folder<&'ch str>;
265+
fn fold_match_indices<'ch, F>(&self, &'ch str, folder: F, base: usize) -> F
266+
where F: Folder<(usize, &'ch str)>;
246267
}
247268
}
248269
use self::private::Pattern;
@@ -280,6 +301,12 @@ impl Pattern for char {
280301
{
281302
folder.consume_iter(chars.matches(*self))
282303
}
304+
305+
fn fold_match_indices<'ch, F>(&self, chars: &'ch str, folder: F, base: usize) -> F
306+
where F: Folder<(usize, &'ch str)>
307+
{
308+
folder.consume_iter(chars.match_indices(*self).map(move |(i, s)| (base + i, s)))
309+
}
283310
}
284311

285312
impl<FN: Sync + Send + Fn(char) -> bool> Pattern for FN {
@@ -312,6 +339,12 @@ impl<FN: Sync + Send + Fn(char) -> bool> Pattern for FN {
312339
{
313340
folder.consume_iter(chars.matches(self))
314341
}
342+
343+
fn fold_match_indices<'ch, F>(&self, chars: &'ch str, folder: F, base: usize) -> F
344+
where F: Folder<(usize, &'ch str)>
345+
{
346+
folder.consume_iter(chars.match_indices(self).map(move |(i, s)| (base + i, s)))
347+
}
315348
}
316349

317350

@@ -686,3 +719,53 @@ impl<'ch, 'pat, P: Pattern> UnindexedProducer for MatchesProducer<'ch, 'pat, P>
686719
self.pattern.fold_matches(self.chars, folder)
687720
}
688721
}
722+
723+
724+
// /////////////////////////////////////////////////////////////////////////
725+
726+
/// Parallel iterator over substrings that match a pattern, with their positions
727+
#[derive(Debug, Clone)]
728+
pub struct MatchIndices<'ch, P: Pattern> {
729+
chars: &'ch str,
730+
pattern: P,
731+
}
732+
733+
struct MatchIndicesProducer<'ch, 'pat, P: Pattern + 'pat> {
734+
index: usize,
735+
chars: &'ch str,
736+
pattern: &'pat P,
737+
}
738+
739+
impl<'ch, P: Pattern> ParallelIterator for MatchIndices<'ch, P> {
740+
type Item = (usize, &'ch str);
741+
742+
fn drive_unindexed<C>(self, consumer: C) -> C::Result
743+
where C: UnindexedConsumer<Self::Item>
744+
{
745+
let producer = MatchIndicesProducer { index: 0, chars: self.chars, pattern: &self.pattern };
746+
bridge_unindexed(producer, consumer)
747+
}
748+
}
749+
750+
impl<'ch, 'pat, P: Pattern> UnindexedProducer for MatchIndicesProducer<'ch, 'pat, P> {
751+
type Item = (usize, &'ch str);
752+
753+
fn split(mut self) -> (Self, Option<Self>) {
754+
let index = find_char_midpoint(self.chars);
755+
if index > 0 {
756+
let (left, right) = self.chars.split_at(index);
757+
let right_index = self.index + index;
758+
let pattern = self.pattern;
759+
self.chars = left;
760+
(self, Some(MatchIndicesProducer { index: right_index, chars: right, pattern }))
761+
} else {
762+
(self, None)
763+
}
764+
}
765+
766+
fn fold_with<F>(self, folder: F) -> F
767+
where F: Folder<Self::Item>
768+
{
769+
self.pattern.fold_match_indices(self.chars, folder, self.index)
770+
}
771+
}

tests/str.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,14 @@ pub fn execute_strings_split() {
9898
let parallel_fn: Vec<_> = string.par_matches(|c| c == separator).collect();
9999
assert_eq!(serial_fn, parallel_fn);
100100
}
101+
102+
for &(string, separator) in &tests {
103+
let serial: Vec<_> = string.match_indices(separator).collect();
104+
let parallel: Vec<_> = string.par_match_indices(separator).collect();
105+
assert_eq!(serial, parallel);
106+
107+
let serial_fn: Vec<_> = string.match_indices(|c| c == separator).collect();
108+
let parallel_fn: Vec<_> = string.par_match_indices(|c| c == separator).collect();
109+
assert_eq!(serial_fn, parallel_fn);
110+
}
101111
}

0 commit comments

Comments
 (0)