Skip to content

Commit d9dc44a

Browse files
committed
Fill in forward searcher impl for char
1 parent 585ad9f commit d9dc44a

File tree

1 file changed

+65
-13
lines changed

1 file changed

+65
-13
lines changed

src/libcore/str/pattern.rs

+65-13
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
use cmp;
2121
use fmt;
22+
use slice::memchr;
2223
use usize;
2324

2425
// Pattern
@@ -241,25 +242,66 @@ pub trait DoubleEndedSearcher<'a>: ReverseSearcher<'a> {}
241242

242243
/// Associated type for `<char as Pattern<'a>>::Searcher`.
243244
#[derive(Clone, Debug)]
244-
pub struct CharSearcher<'a>(&'a str);
245+
pub struct CharSearcher<'a> {
246+
haystack: &'a str,
247+
// invariant: `finger` must be a valid utf8 byte index of `haystack`
248+
finger: usize,
249+
needle: char,
250+
// For ascii chars
251+
// invariant: must be an ASCII byte (no high bit)
252+
single_byte: Option<u8>,
253+
}
245254

246255
unsafe impl<'a> Searcher<'a> for CharSearcher<'a> {
247256
#[inline]
248257
fn haystack(&self) -> &'a str {
249-
unimplemented!();
258+
self.haystack
250259
}
251260
#[inline]
252261
fn next(&mut self) -> SearchStep {
253-
unimplemented!();
262+
let old_finger = self.finger;
263+
let slice = unsafe { self.haystack.get_unchecked(old_finger..) };
264+
let mut iter = slice.chars();
265+
let old_len = iter.iter.len();
266+
if let Some(ch) = iter.next() {
267+
// add byte offset of current character
268+
// without recalculating
269+
self.finger += iter.iter.len() - old_len;
270+
if ch == self.needle {
271+
SearchStep::Match(old_finger, self.finger)
272+
} else {
273+
SearchStep::Reject(old_finger, self.finger)
274+
}
275+
} else {
276+
SearchStep::Done
277+
}
254278
}
255279
#[inline]
256280
fn next_match(&mut self) -> Option<(usize, usize)> {
257-
unimplemented!();
258-
}
259-
#[inline]
260-
fn next_reject(&mut self) -> Option<(usize, usize)> {
261-
unimplemented!();
281+
if let Some(byte) = self.single_byte {
282+
let old_finger = self.finger;
283+
let slice = unsafe { self.haystack.get_unchecked(old_finger..) };
284+
let bytes = slice.as_bytes();
285+
if let Some(index) = memchr::memchr(byte, bytes) {
286+
// index is the index of a valid ASCII byte,
287+
// so we can add one to it
288+
self.finger += index + 1;
289+
Some((index, self.finger))
290+
} else {
291+
None
292+
}
293+
} else {
294+
loop {
295+
match self.next() {
296+
SearchStep::Match(a, b) => break Some((a, b)),
297+
SearchStep::Done => break None,
298+
_ => continue,
299+
}
300+
}
301+
}
262302
}
303+
304+
// let next_reject use the default implementation from the Searcher trait
263305
}
264306

265307
unsafe impl<'a> ReverseSearcher<'a> for CharSearcher<'a> {
@@ -271,10 +313,8 @@ unsafe impl<'a> ReverseSearcher<'a> for CharSearcher<'a> {
271313
fn next_match_back(&mut self) -> Option<(usize, usize)> {
272314
unimplemented!();
273315
}
274-
#[inline]
275-
fn next_reject_back(&mut self) -> Option<(usize, usize)> {
276-
unimplemented!();
277-
}
316+
317+
// let next_reject_back use the default implementation from the Searcher trait
278318
}
279319

280320
impl<'a> DoubleEndedSearcher<'a> for CharSearcher<'a> {}
@@ -285,7 +325,19 @@ impl<'a> Pattern<'a> for char {
285325

286326
#[inline]
287327
fn into_searcher(self, haystack: &'a str) -> Self::Searcher {
288-
CharSearcher(haystack)
328+
let single_byte = if self.len_utf8() == 1 {
329+
let mut storage = [0];
330+
self.encode_utf8(&mut storage);
331+
Some(storage[0])
332+
} else {
333+
None
334+
};
335+
CharSearcher {
336+
haystack,
337+
finger: 0,
338+
needle: self,
339+
single_byte,
340+
}
289341
}
290342

291343
#[inline]

0 commit comments

Comments
 (0)