pattern_3/strings/
func.rs

1use needle::*;
2use haystack::Span;
3use std::ops::Range;
4
5#[derive(Copy, Clone, Debug)]
6pub struct MultiCharEq<'p>(&'p [char]);
7
8impl<'p> FnOnce<(char,)> for MultiCharEq<'p> {
9    type Output = bool;
10    #[inline]
11    extern "rust-call" fn call_once(self, args: (char,)) -> bool {
12        self.call(args)
13    }
14}
15
16impl<'p> FnMut<(char,)> for MultiCharEq<'p> {
17    #[inline]
18    extern "rust-call" fn call_mut(&mut self, args: (char,)) -> bool {
19        self.call(args)
20    }
21}
22
23impl<'p> Fn<(char,)> for MultiCharEq<'p> {
24    #[inline]
25    extern "rust-call" fn call(&self, (c,): (char,)) -> bool {
26        self.0.iter().any(|ch| *ch == c)
27    }
28}
29
30pub struct MultiCharSearcher<F> {
31    predicate: F,
32}
33
34unsafe impl<F: FnMut(char) -> bool> Searcher<str> for MultiCharSearcher<F> {
35    #[inline]
36    fn search(&mut self, span: Span<&str>) -> Option<Range<usize>> {
37        let (hay, range) = span.into_parts();
38        let st = range.start;
39        let h = &hay[range];
40        let mut chars = h.chars();
41        let c = chars.find(|c| (self.predicate)(*c))?;
42        let end = chars.as_str().as_ptr();
43        let end = unsafe { end.offset_from(h.as_ptr()) as usize } + st;
44        Some((end - c.len_utf8())..end)
45    }
46}
47
48unsafe impl<F: FnMut(char) -> bool> Consumer<str> for MultiCharSearcher<F> {
49    #[inline]
50    fn consume(&mut self, hay: Span<&str>) -> Option<usize> {
51        let (hay, range) = hay.into_parts();
52        let start = range.start;
53        if start == range.end {
54            return None;
55        }
56        let c = unsafe { hay.get_unchecked(start..) }.chars().next().unwrap();
57        if (self.predicate)(c) {
58            Some(start + c.len_utf8())
59        } else {
60            None
61        }
62    }
63
64    #[inline]
65    fn trim_start(&mut self, hay: &str) -> usize {
66        let mut chars = hay.chars();
67        let unconsume_amount = chars
68            .find_map(|c| if !(self.predicate)(c) { Some(c.len_utf8()) } else { None })
69            .unwrap_or(0);
70        let consumed = unsafe { chars.as_str().as_ptr().offset_from(hay.as_ptr()) as usize };
71        consumed.wrapping_sub(unconsume_amount)
72    }
73}
74
75unsafe impl<F: FnMut(char) -> bool> ReverseSearcher<str> for MultiCharSearcher<F> {
76    #[inline]
77    fn rsearch(&mut self, span: Span<&str>) -> Option<Range<usize>> {
78        let (hay, range) = span.into_parts();
79        let st = range.start;
80        let h = &hay[range];
81        let mut chars = h.chars();
82        let c = chars.rfind(|c| (self.predicate)(*c))?;
83        let start = chars.as_str().len() + st;
84        Some(start..(start + c.len_utf8()))
85    }
86}
87
88unsafe impl<F: FnMut(char) -> bool> ReverseConsumer<str> for MultiCharSearcher<F> {
89    #[inline]
90    fn rconsume(&mut self, hay: Span<&str>) -> Option<usize> {
91        let (hay, range) = hay.into_parts();
92        let end = range.end;
93        if range.start == end {
94            return None;
95        }
96        let c = unsafe { hay.get_unchecked(..end) }.chars().next_back().unwrap();
97        if (self.predicate)(c) {
98            Some(end - c.len_utf8())
99        } else {
100            None
101        }
102    }
103
104    #[inline]
105    fn trim_end(&mut self, hay: &str) -> usize {
106        // `find.map_or` is faster in trim_end in the microbenchmark, while
107        // `find.unwrap_or` is faster in trim_start. Don't ask me why.
108        let mut chars = hay.chars();
109        let unconsume_amount = chars
110            .by_ref()
111            .rev() // btw, `rev().find()` is faster than `rfind()`
112            .find(|c| !(self.predicate)(*c))
113            .map_or(0, |c| c.len_utf8());
114        chars.as_str().len() + unconsume_amount
115    }
116}
117
118unsafe impl<F: FnMut(char) -> bool> DoubleEndedSearcher<str> for MultiCharSearcher<F> {}
119unsafe impl<F: FnMut(char) -> bool> DoubleEndedConsumer<str> for MultiCharSearcher<F> {}
120
121macro_rules! impl_needle {
122    ($ty:ty) => {
123        impl<'h, F: FnMut(char) -> bool> Needle<$ty> for F {
124            type Searcher = MultiCharSearcher<F>;
125            type Consumer = MultiCharSearcher<F>;
126
127            #[inline]
128            fn into_searcher(self) -> Self::Searcher {
129                MultiCharSearcher { predicate: self }
130            }
131
132            #[inline]
133            fn into_consumer(self) -> Self::Consumer {
134                MultiCharSearcher { predicate: self }
135            }
136        }
137
138        impl<'h, 'p> Needle<$ty> for &'p [char] {
139            type Searcher = MultiCharSearcher<MultiCharEq<'p>>;
140            type Consumer = MultiCharSearcher<MultiCharEq<'p>>;
141
142            #[inline]
143            fn into_searcher(self) -> Self::Searcher {
144                MultiCharSearcher { predicate: MultiCharEq(self) }
145            }
146
147            #[inline]
148            fn into_consumer(self) -> Self::Consumer {
149                MultiCharSearcher { predicate: MultiCharEq(self) }
150            }
151        }
152    }
153}
154
155impl_needle!(&'h str);
156impl_needle!(&'h mut str);