1#![cfg_attr(not(test), no_std)]
2#![cfg_attr(feature = "pattern", feature(pattern))]
3
4#[cfg(test)]
7extern crate core;
8
9use core::cmp;
10use core::usize;
11
12extern crate memchr;
13
14mod tw;
15pub mod bmh;
16#[cfg(feature = "test-set")]
17pub mod set;
18
19#[cfg(feature = "pattern")]
20use core::str::pattern::{
21 Pattern,
22 Searcher,
23 ReverseSearcher,
24 SearchStep,
25};
26
27mod private { pub trait Sealed {} }
28
29impl<A> private::Sealed for [A] {}
30impl private::Sealed for str {}
31
32pub trait SubsliceExt: private::Sealed {
34 fn find(&self, other: &Self) -> Option<usize>;
39
40 fn rfind(&self, other: &Self) -> Option<usize>;
45}
46
47impl<A: Ord> SubsliceExt for [A] {
48 #[inline]
49 fn find(&self, other: &Self) -> Option<usize> {
50 if other.is_empty() { Some(0) }
51 else if other.len() == 1 { self.iter().position(|a| *a == other[0]) }
52 else {
53 let mut searcher = TwoWaySearcher::new(other, self.len());
54 let is_long = searcher.memory == usize::MAX;
55 if is_long {
58 searcher.next::<_, MatchOnly>(self, other, true).map(|t| t.0)
59 } else {
60 searcher.next::<_, MatchOnly>(self, other, false).map(|t| t.0)
61 }
62 }
63 }
64
65 #[inline]
66 fn rfind(&self, other: &Self) -> Option<usize> {
67 if other.is_empty() { Some(self.len()) }
68 else if other.len() == 1 { self.iter().rposition(|a| *a == other[0]) }
69 else {
70 let mut searcher = TwoWaySearcher::new(other, self.len());
71 let is_long = searcher.memory == usize::MAX;
72 if is_long {
75 searcher.next_back::<_, MatchOnly>(self, other, true).map(|t| t.0)
76 } else {
77 searcher.next_back::<_, MatchOnly>(self, other, false).map(|t| t.0)
78 }
79 }
80 }
81}
82
83impl SubsliceExt for str {
84 #[inline]
85 fn find(&self, other: &Self) -> Option<usize> { self.as_bytes().find(other.as_bytes()) }
86
87 #[inline]
88 fn rfind(&self, other: &Self) -> Option<usize> { self.as_bytes().rfind(other.as_bytes()) }
89}
90
91#[doc(hidden)]
93pub struct Str<'a>(pub &'a str);
94
95#[cfg(feature = "pattern")]
96impl<'a, 'b> Pattern<'a> for Str<'b> {
101 type Searcher = StrSearcher<'a, 'b>;
102
103 #[inline]
104 fn into_searcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> {
105 StrSearcher::new(haystack, self.0)
106 }
107
108 #[inline]
110 fn is_prefix_of(self, haystack: &'a str) -> bool {
111 let self_ = self.0;
112 haystack.is_char_boundary(self_.len()) &&
113 self_ == &haystack[..self_.len()]
114 }
115
116 #[inline]
118 fn is_suffix_of(self, haystack: &'a str) -> bool {
119 let self_ = self.0;
120 self_.len() <= haystack.len() &&
121 haystack.is_char_boundary(haystack.len() - self_.len()) &&
122 self_ == &haystack[haystack.len() - self_.len()..]
123 }
124
125}
126
127#[derive(Clone, Debug)]
128#[doc(hidden)]
129pub struct StrSearcher<'a, 'b> {
131 haystack: &'a str,
132 needle: &'b str,
133
134 searcher: StrSearcherImpl,
135}
136
137#[derive(Clone, Debug)]
138enum StrSearcherImpl {
139 Empty(EmptyNeedle),
140 TwoWay(TwoWaySearcher),
141}
142
143#[derive(Clone, Debug)]
144struct EmptyNeedle {
145 position: usize,
146 end: usize,
147 is_match_fw: bool,
148 is_match_bw: bool,
149}
150
151impl<'a, 'b> StrSearcher<'a, 'b> {
152 pub fn new(haystack: &'a str, needle: &'b str) -> StrSearcher<'a, 'b> {
153 if needle.is_empty() {
154 StrSearcher {
155 haystack, needle,
156 searcher: StrSearcherImpl::Empty(EmptyNeedle {
157 position: 0,
158 end: haystack.len(),
159 is_match_fw: true,
160 is_match_bw: true,
161 }),
162 }
163 } else {
164 StrSearcher {
165 haystack, needle,
166 searcher: StrSearcherImpl::TwoWay(
167 TwoWaySearcher::new(needle.as_bytes(), haystack.len())
168 ),
169 }
170 }
171 }
172}
173
174#[cfg(feature = "pattern")]
175unsafe impl<'a, 'b> Searcher<'a> for StrSearcher<'a, 'b> {
176 fn haystack(&self) -> &'a str { self.haystack }
177
178 #[inline]
179 fn next(&mut self) -> SearchStep {
180 match self.searcher {
181 StrSearcherImpl::Empty(ref mut searcher) => {
182 let is_match = searcher.is_match_fw;
184 searcher.is_match_fw = !searcher.is_match_fw;
185 let pos = searcher.position;
186 match self.haystack[pos..].chars().next() {
187 _ if is_match => SearchStep::Match(pos, pos),
188 None => SearchStep::Done,
189 Some(ch) => {
190 searcher.position += ch.len_utf8();
191 SearchStep::Reject(pos, searcher.position)
192 }
193 }
194 }
195 StrSearcherImpl::TwoWay(ref mut searcher) => {
196 if searcher.position == self.haystack.len() {
202 return SearchStep::Done;
203 }
204 let is_long = searcher.memory == usize::MAX;
205 match searcher.next::<_, RejectAndMatch>(self.haystack.as_bytes(),
206 self.needle.as_bytes(),
207 is_long)
208 {
209 SearchStep::Reject(a, mut b) => {
210 while !self.haystack.is_char_boundary(b) {
212 b += 1;
213 }
214 searcher.position = cmp::max(b, searcher.position);
215 SearchStep::Reject(a, b)
216 }
217 otherwise => otherwise,
218 }
219 }
220 }
221 }
222
223 #[inline(always)]
224 fn next_match(&mut self) -> Option<(usize, usize)> {
225 match self.searcher {
226 StrSearcherImpl::Empty(..) => {
227 loop {
228 match self.next() {
229 SearchStep::Match(a, b) => return Some((a, b)),
230 SearchStep::Done => return None,
231 SearchStep::Reject(..) => { }
232 }
233 }
234 }
235
236 StrSearcherImpl::TwoWay(ref mut searcher) => {
237 let is_long = searcher.memory == usize::MAX;
238 if is_long {
241 searcher.next::<_, MatchOnly>(self.haystack.as_bytes(),
242 self.needle.as_bytes(),
243 true)
244 } else {
245 searcher.next::<_, MatchOnly>(self.haystack.as_bytes(),
246 self.needle.as_bytes(),
247 false)
248 }
249 }
250 }
251 }
252}
253
254#[cfg(feature = "pattern")]
255unsafe impl<'a, 'b> ReverseSearcher<'a> for StrSearcher<'a, 'b> {
256 #[inline]
257 fn next_back(&mut self) -> SearchStep {
258 match self.searcher {
259 StrSearcherImpl::Empty(ref mut searcher) => {
260 let is_match = searcher.is_match_bw;
261 searcher.is_match_bw = !searcher.is_match_bw;
262 let end = searcher.end;
263 match self.haystack[..end].chars().next_back() {
264 _ if is_match => SearchStep::Match(end, end),
265 None => SearchStep::Done,
266 Some(ch) => {
267 searcher.end -= ch.len_utf8();
268 SearchStep::Reject(searcher.end, end)
269 }
270 }
271 }
272 StrSearcherImpl::TwoWay(ref mut searcher) => {
273 if searcher.end == 0 {
274 return SearchStep::Done;
275 }
276 let is_long = searcher.memory == usize::MAX;
277 match searcher.next_back::<_, RejectAndMatch>(self.haystack.as_bytes(),
278 self.needle.as_bytes(),
279 is_long)
280 {
281 SearchStep::Reject(mut a, b) => {
282 while !self.haystack.is_char_boundary(a) {
284 a -= 1;
285 }
286 searcher.end = cmp::min(a, searcher.end);
287 SearchStep::Reject(a, b)
288 }
289 otherwise => otherwise,
290 }
291 }
292 }
293 }
294
295 #[inline]
296 fn next_match_back(&mut self) -> Option<(usize, usize)> {
297 match self.searcher {
298 StrSearcherImpl::Empty(..) => {
299 loop {
300 match self.next_back() {
301 SearchStep::Match(a, b) => return Some((a, b)),
302 SearchStep::Done => return None,
303 SearchStep::Reject(..) => { }
304 }
305 }
306 }
307 StrSearcherImpl::TwoWay(ref mut searcher) => {
308 let is_long = searcher.memory == usize::MAX;
309 if is_long {
311 searcher.next_back::<_, MatchOnly>(self.haystack.as_bytes(),
312 self.needle.as_bytes(),
313 true)
314 } else {
315 searcher.next_back::<_, MatchOnly>(self.haystack.as_bytes(),
316 self.needle.as_bytes(),
317 false)
318 }
319 }
320 }
321 }
322}
323
324#[derive(Clone, Debug)]
326#[doc(hidden)]
327pub struct TwoWaySearcher {
328 crit_pos: usize,
331 crit_pos_back: usize,
333 period: usize,
334
335 position: usize,
337 end: usize,
338 memory: usize,
340 memory_back: usize,
342}
343
344impl TwoWaySearcher {
418 pub fn new<A: Ord>(needle: &[A], end: usize) -> TwoWaySearcher {
419 let (crit_pos, period) = TwoWaySearcher::crit_params(needle);
420
421 if needle[..crit_pos] == needle[period.. period + crit_pos] {
431 let crit_pos_back = needle.len() - cmp::max(
441 TwoWaySearcher::reverse_maximal_suffix(needle, period, false),
442 TwoWaySearcher::reverse_maximal_suffix(needle, period, true));
443
444 TwoWaySearcher {
445 crit_pos, crit_pos_back, period,
446
447 position: 0,
448 end,
449 memory: 0,
450 memory_back: needle.len(),
451 }
452 } else {
453 TwoWaySearcher {
461 crit_pos, crit_pos_back: crit_pos,
462 period: cmp::max(crit_pos, needle.len() - crit_pos) + 1,
463
464 position: 0,
465 end,
466 memory: usize::MAX, memory_back: usize::MAX,
468 }
469 }
470 }
471
472 #[inline(always)]
477 fn crit_params<A: Ord>(needle: &[A]) -> (usize, usize) {
478 let (crit_pos_false, period_false) = TwoWaySearcher::maximal_suffix(needle, false);
479 let (crit_pos_true, period_true) = TwoWaySearcher::maximal_suffix(needle, true);
480
481 if crit_pos_false > crit_pos_true {
482 (crit_pos_false, period_false)
483 } else {
484 (crit_pos_true, period_true)
485 }
486 }
487 #[inline(always)]
493 fn next<A: Eq, S>(&mut self, haystack: &[A], needle: &[A], long_period: bool)
494 -> S::Output
495 where S: TwoWayStrategy
496 {
497 let old_pos = self.position;
499 let needle_last = needle.len() - 1;
500 'search: loop {
501 match haystack.get(self.position + needle_last) {
505 Some(_) => (),
506 None => {
507 self.position = haystack.len();
508 return S::rejecting(old_pos, self.position);
509 }
510 };
511
512 if S::use_early_reject() && old_pos != self.position {
513 return S::rejecting(old_pos, self.position);
514 }
515
516 let start = if long_period { self.crit_pos }
518 else { cmp::max(self.crit_pos, self.memory) };
519 for i in start..needle.len() {
520 if needle[i] != haystack[self.position + i] {
521 self.position += i - self.crit_pos + 1;
522 if !long_period {
523 self.memory = 0;
524 }
525 continue 'search;
526 }
527 }
528
529 let start = if long_period { 0 } else { self.memory };
531 for i in (start..self.crit_pos).rev() {
532 if needle[i] != haystack[self.position + i] {
533 self.position += self.period;
534 if !long_period {
535 self.memory = needle.len() - self.period;
536 }
537 continue 'search;
538 }
539 }
540
541 let match_pos = self.position;
543
544 self.position += needle.len();
546 if !long_period {
547 self.memory = 0; }
549
550 return S::matching(match_pos, match_pos + needle.len());
551 }
552 }
553
554 #[inline]
567 fn next_back<A: Eq, S>(&mut self, haystack: &[A], needle: &[A], long_period: bool)
568 -> S::Output
569 where S: TwoWayStrategy
570 {
571 let old_end = self.end;
574 'search: loop {
575 match haystack.get(self.end.wrapping_sub(needle.len())) {
580 Some(_) => (),
581 None => {
582 self.end = 0;
583 return S::rejecting(0, old_end);
584 }
585 };
586
587 if S::use_early_reject() && old_end != self.end {
588 return S::rejecting(self.end, old_end);
589 }
590
591 let crit = if long_period { self.crit_pos_back }
593 else { cmp::min(self.crit_pos_back, self.memory_back) };
594 for i in (0..crit).rev() {
595 if needle[i] != haystack[self.end - needle.len() + i] {
596 self.end -= self.crit_pos_back - i;
597 if !long_period {
598 self.memory_back = needle.len();
599 }
600 continue 'search;
601 }
602 }
603
604 let needle_end = if long_period { needle.len() }
606 else { self.memory_back };
607 for i in self.crit_pos_back..needle_end {
608 if needle[i] != haystack[self.end - needle.len() + i] {
609 self.end -= self.period;
610 if !long_period {
611 self.memory_back = self.period;
612 }
613 continue 'search;
614 }
615 }
616
617 let match_pos = self.end - needle.len();
619 self.end -= needle.len();
621 if !long_period {
622 self.memory_back = needle.len();
623 }
624
625 return S::matching(match_pos, match_pos + needle.len());
626 }
627 }
628
629 #[inline]
642 pub fn maximal_suffix<A: Ord>(arr: &[A], order_greater: bool) -> (usize, usize) {
643 let mut left = 0; let mut right = 1; let mut offset = 0; let mut period = 1; while let Some(a) = arr.get(right + offset) {
650 let b = &arr[left + offset];
652 if (*a < *b && !order_greater) || (*a > *b && order_greater) {
653 right += offset + 1;
655 offset = 0;
656 period = right - left;
657 } else if *a == *b {
658 if offset + 1 == period {
660 right += offset + 1;
661 offset = 0;
662 } else {
663 offset += 1;
664 }
665 } else {
666 left = right;
668 right += 1;
669 offset = 0;
670 period = 1;
671 }
672 }
673 (left, period)
674 }
675
676 pub fn reverse_maximal_suffix<A: Ord>(arr: &[A], known_period: usize,
689 order_greater: bool) -> usize
690 {
691 let mut left = 0; let mut right = 1; let mut offset = 0; let mut period = 1; let n = arr.len();
697
698 while right + offset < n {
699 let a = &arr[n - (1 + right + offset)];
700 let b = &arr[n - (1 + left + offset)];
701 if (*a < *b && !order_greater) || (*a > *b && order_greater) {
702 right += offset + 1;
704 offset = 0;
705 period = right - left;
706 } else if *a == *b {
707 if offset + 1 == period {
709 right += offset + 1;
710 offset = 0;
711 } else {
712 offset += 1;
713 }
714 } else {
715 left = right;
717 right += 1;
718 offset = 0;
719 period = 1;
720 }
721 if period == known_period {
722 break;
723 }
724 }
725 debug_assert!(period <= known_period);
726 left
727 }
728}
729
730trait TwoWayStrategy {
733 type Output;
734 fn use_early_reject() -> bool;
735 fn rejecting(usize, usize) -> Self::Output;
736 fn matching(usize, usize) -> Self::Output;
737}
738
739enum MatchOnly { }
741
742impl TwoWayStrategy for MatchOnly {
743 type Output = Option<(usize, usize)>;
744
745 #[inline]
746 fn use_early_reject() -> bool { false }
747 #[inline]
748 fn rejecting(_a: usize, _b: usize) -> Self::Output { None }
749 #[inline]
750 fn matching(a: usize, b: usize) -> Self::Output { Some((a, b)) }
751}
752
753#[cfg(feature = "pattern")]
754enum RejectAndMatch { }
756
757#[cfg(feature = "pattern")]
758impl TwoWayStrategy for RejectAndMatch {
759 type Output = SearchStep;
760
761 #[inline]
762 fn use_early_reject() -> bool { true }
763 #[inline]
764 fn rejecting(a: usize, b: usize) -> Self::Output { SearchStep::Reject(a, b) }
765 #[inline]
766 fn matching(a: usize, b: usize) -> Self::Output { SearchStep::Match(a, b) }
767}
768
769
770#[cfg(feature = "pattern")]
771#[cfg(test)]
772impl<'a, 'b> StrSearcher<'a, 'b> {
773 fn twoway(&self) -> &TwoWaySearcher {
774 match self.searcher {
775 StrSearcherImpl::TwoWay(ref inner) => inner,
776 _ => panic!("Not a TwoWaySearcher"),
777 }
778 }
779}
780
781#[cfg(feature = "pattern")]
782#[test]
783fn test_basic() {
784 let t = StrSearcher::new("", "aab");
785 println!("{:?}", t);
786 let t = StrSearcher::new("", "abaaaba");
787 println!("{:?}", t);
788 let mut t = StrSearcher::new("GCATCGCAGAGAGTATACAGTACG", "GCAGAGAG");
789 println!("{:?}", t);
790
791 loop {
792 match t.next() {
793 SearchStep::Done => break,
794 m => println!("{:?}", m),
795 }
796 }
797
798 let mut t = StrSearcher::new("GCATCGCAGAGAGTATACAGTACG", "GCAGAGAG");
799 println!("{:?}", t);
800
801 loop {
802 match t.next_back() {
803 SearchStep::Done => break,
804 m => println!("{:?}", m),
805 }
806 }
807
808 let mut t = StrSearcher::new("banana", "nana");
809 println!("{:?}", t);
810
811 loop {
812 match t.next() {
813 SearchStep::Done => break,
814 m => println!("{:?}", m),
815 }
816 }
817}
818
819#[cfg(feature = "pattern")]
820#[cfg(test)]
821fn contains(hay: &str, n: &str) -> bool {
822 let mut tws = StrSearcher::new(hay, n);
823 loop {
824 match tws.next() {
825 SearchStep::Done => return false,
826 SearchStep::Match(..) => return true,
827 _ => { }
828 }
829 }
830}
831
832#[cfg(feature = "pattern")]
833#[cfg(test)]
834fn contains_rev(hay: &str, n: &str) -> bool {
835 let mut tws = StrSearcher::new(hay, n);
836 loop {
837 match tws.next_back() {
838 SearchStep::Done => return false,
839 SearchStep::Match(..) => return true,
840 rej => { println!("{:?}", rej); }
841 }
842 }
843}
844
845
846#[cfg(feature = "pattern")]
847#[test]
848fn test_contains() {
849 let h = "";
850 let n = "";
851 assert!(contains(h, n));
852 assert!(contains_rev(h, n));
853
854 let h = "BDC\0\0\0";
855 let n = "BDC\u{0}";
856 assert!(contains(h, n));
857 assert!(contains_rev(h, n));
858
859
860 let h = "ADA\0";
861 let n = "ADA";
862 assert!(contains(h, n));
863 assert!(contains_rev(h, n));
864
865 let h = "\u{0}\u{0}\u{0}\u{0}";
866 let n = "\u{0}";
867 assert!(contains(h, n));
868 assert!(contains_rev(h, n));
869}
870
871#[cfg(feature = "pattern")]
872#[test]
873fn test_rev_2() {
874 let h = "BDC\0\0\0";
875 let n = "BDC\u{0}";
876 let mut t = StrSearcher::new(h, n);
877 println!("{:?}", t);
878 println!("{:?}", h.contains(&n));
879
880 loop {
881 match t.next_back() {
882 SearchStep::Done => break,
883 m => println!("{:?}", m),
884 }
885 }
886
887 let h = "aabaabx";
888 let n = "aabaab";
889 let mut t = StrSearcher::new(h, n);
890 println!("{:?}", t);
891 assert_eq!(t.twoway().crit_pos, 2);
892 assert_eq!(t.twoway().crit_pos_back, 5);
893
894 loop {
895 match t.next_back() {
896 SearchStep::Done => break,
897 m => println!("{:?}", m),
898 }
899 }
900
901 let h = "abababac";
902 let n = "ababab";
903 let mut t = StrSearcher::new(h, n);
904 println!("{:?}", t);
905 assert_eq!(t.twoway().crit_pos, 1);
906 assert_eq!(t.twoway().crit_pos_back, 5);
907
908 loop {
909 match t.next_back() {
910 SearchStep::Done => break,
911 m => println!("{:?}", m),
912 }
913 }
914
915 let h = "abababac";
916 let n = "abab";
917 let mut t = StrSearcher::new(h, n);
918 println!("{:?}", t);
919
920 loop {
921 match t.next_back() {
922 SearchStep::Done => break,
923 m => println!("{:?}", m),
924 }
925 }
926
927 let h = "baabbbaabc";
928 let n = "baabb";
929 let t = StrSearcher::new(h, n);
930 println!("{:?}", t);
931 assert_eq!(t.twoway().crit_pos, 3);
932 assert_eq!(t.twoway().crit_pos_back, 3);
933
934 let h = "aabaaaabaabxx";
935 let n = "aabaaaabaa";
936 let mut t = StrSearcher::new(h, n);
937 println!("{:?}", t);
938
939 loop {
940 match t.next_back() {
941 SearchStep::Done => break,
942 m => println!("{:?}", m),
943 }
944 }
945
946 let h = "babbabax";
947 let n = "babbab";
948 let mut t = StrSearcher::new(h, n);
949 println!("{:?}", t);
950 assert_eq!(t.twoway().crit_pos, 2);
951 assert_eq!(t.twoway().crit_pos_back, 4);
952
953 loop {
954 match t.next_back() {
955 SearchStep::Done => break,
956 m => println!("{:?}", m),
957 }
958 }
959
960 let h = "xacbaabcax";
961 let n = "abca";
962 let mut t = StrSearcher::new(h, n);
963 assert_eq!(t.next_match_back(), Some((5, 9)));
964
965 let h = "xacbaacbxxcba";
966 let m = "acba";
967 let mut s = StrSearcher::new(h, m);
968 assert_eq!(s.next_match_back(), Some((1, 5)));
969 assert_eq!(s.twoway().crit_pos, 1);
970 assert_eq!(s.twoway().crit_pos_back, 2);
971}
972
973#[cfg(feature = "pattern")]
974#[test]
975fn test_rev_unicode() {
976 let h = "ααααααβ";
977 let n = "αβ";
978 let mut t = StrSearcher::new(h, n);
979 println!("{:?}", t);
980
981 loop {
982 match t.next() {
983 SearchStep::Done => break,
984 m => println!("{:?}", m),
985 }
986 }
987
988 let mut t = StrSearcher::new(h, n);
989 loop {
990 match t.next_back() {
991 SearchStep::Done => break,
992 m => println!("{:?}", m),
993 }
994 }
995}
996
997#[test]
998fn maximal_suffix() {
999 assert_eq!((2, 1), TwoWaySearcher::maximal_suffix(b"aab", false));
1000 assert_eq!((0, 3), TwoWaySearcher::maximal_suffix(b"aab", true));
1001
1002 assert_eq!((0, 3), TwoWaySearcher::maximal_suffix(b"aabaa", true));
1003 assert_eq!((2, 3), TwoWaySearcher::maximal_suffix(b"aabaa", false));
1004
1005 assert_eq!((0, 7), TwoWaySearcher::maximal_suffix(b"gcagagag", false));
1006 assert_eq!((2, 2), TwoWaySearcher::maximal_suffix(b"gcagagag", true));
1007
1008 assert_eq!((2, 2), TwoWaySearcher::maximal_suffix(b"banana", false));
1010 assert_eq!((1, 2), TwoWaySearcher::maximal_suffix(b"banana", true));
1011 assert_eq!((0, 6), TwoWaySearcher::maximal_suffix(b"zanana", false));
1012 assert_eq!((1, 2), TwoWaySearcher::maximal_suffix(b"zanana", true));
1013}
1014
1015#[test]
1016fn maximal_suffix_verbose() {
1017 fn maximal_suffix(arr: &[u8], order_greater: bool) -> (usize, usize) {
1018 let mut left: usize = 0; let mut right = 1; let mut offset = 0; let mut period = 1; macro_rules! asstr {
1024 ($e:expr) => (::std::str::from_utf8($e).unwrap())
1025 }
1026
1027 while let Some(&a) = arr.get(right + offset) {
1028 debug_assert!(left <= right);
1030 let b = unsafe { *arr.get_unchecked(left + offset) };
1031 println!("str={}, l={}, r={}, offset={}, p={}", asstr!(arr), left, right, offset, period);
1032 if (a < b && !order_greater) || (a > b && order_greater) {
1033 right += offset + 1;
1035 offset = 0;
1036 period = right - left;
1037 } else if a == b {
1038 if offset + 1 == period {
1040 right += offset + 1;
1041 offset = 0;
1042 } else {
1043 offset += 1;
1044 }
1045 } else {
1046 left = right;
1048 right += 1;
1049 offset = 0;
1050 period = 1;
1051 }
1052 }
1053 println!("str={}, l={}, r={}, offset={}, p={} ==END==", asstr!(arr), left, right, offset, period);
1054 (left, period)
1055 }
1056
1057 fn reverse_maximal_suffix(arr: &[u8], known_period: usize, order_greater: bool) -> usize {
1058 let n = arr.len();
1059 let mut left: usize = 0; let mut right = 1; let mut offset = 0; let mut period = 1; macro_rules! asstr {
1065 ($e:expr) => (::std::str::from_utf8($e).unwrap())
1066 }
1067
1068 while right + offset < n {
1069 debug_assert!(left <= right);
1071 let a = unsafe { *arr.get_unchecked(n - (1 + right + offset)) };
1072 let b = unsafe { *arr.get_unchecked(n - (1 + left + offset)) };
1073 println!("str={}, l={}, r={}, offset={}, p={}", asstr!(arr), left, right, offset, period);
1074 if (a < b && !order_greater) || (a > b && order_greater) {
1075 right += offset + 1;
1077 offset = 0;
1078 period = right - left;
1079 if period == known_period {
1080 break;
1081 }
1082 } else if a == b {
1083 if offset + 1 == period {
1085 right += offset + 1;
1086 offset = 0;
1087 } else {
1088 offset += 1;
1089 }
1090 } else {
1091 left = right;
1093 right += 1;
1094 offset = 0;
1095 period = 1;
1096 }
1097 }
1098 println!("str={}, l={}, r={}, offset={}, p={} ==END==", asstr!(arr), left, right, offset, period);
1099 debug_assert!(period == known_period);
1100 left
1101 }
1102
1103 assert_eq!((2, 2), maximal_suffix(b"banana", false));
1104 assert_eq!((1, 2), maximal_suffix(b"banana", true));
1105 assert_eq!((0, 7), maximal_suffix(b"gcagagag", false));
1106 assert_eq!((2, 2), maximal_suffix(b"gcagagag", true));
1107 assert_eq!((2, 1), maximal_suffix(b"bac", false));
1108 assert_eq!((1, 2), maximal_suffix(b"bac", true));
1109 assert_eq!((0, 9), maximal_suffix(b"baaaaaaaa", false));
1110 assert_eq!((1, 1), maximal_suffix(b"baaaaaaaa", true));
1111
1112 assert_eq!((2, 3), maximal_suffix(b"babbabbab", false));
1113 assert_eq!((1, 3), maximal_suffix(b"babbabbab", true));
1114
1115 assert_eq!(2, reverse_maximal_suffix(b"babbabbab", 3, false));
1116 assert_eq!(1, reverse_maximal_suffix(b"babbabbab", 3, true));
1117
1118 assert_eq!((0, 2), maximal_suffix(b"bababa", false));
1119 assert_eq!((1, 2), maximal_suffix(b"bababa", true));
1120
1121 assert_eq!(1, reverse_maximal_suffix(b"bababa", 2, false));
1122 assert_eq!(0, reverse_maximal_suffix(b"bababa", 2, true));
1123
1124 assert_eq!((2, 2), maximal_suffix(b"abca", false));
1126 assert_eq!((0, 3), maximal_suffix(b"abca", true));
1127
1128 assert_eq!((3, 2), maximal_suffix(b"abcda", false));
1129 assert_eq!((0, 4), maximal_suffix(b"abcda", true));
1130
1131 assert_eq!((1, 3), maximal_suffix(b"acba", false));
1133 assert_eq!((0, 3), maximal_suffix(b"acba", true));
1134 }
1137
1138#[cfg(feature = "pattern")]
1139#[test]
1140fn test_find_rfind() {
1141 fn find(hay: &str, pat: &str) -> Option<usize> {
1142 let mut t = pat.into_searcher(hay);
1143 t.next_match().map(|(x, _)| x)
1144 }
1145
1146 fn rfind(hay: &str, pat: &str) -> Option<usize> {
1147 let mut t = pat.into_searcher(hay);
1148 t.next_match_back().map(|(x, _)| x)
1149 }
1150
1151 let string = "Việt Namacbaabcaabaaba";
1153 for (i, ci) in string.char_indices() {
1154 let ip = i + ci.len_utf8();
1155 for j in string[ip..].char_indices()
1156 .map(|(i, _)| i)
1157 .chain(Some(string.len() - ip))
1158 {
1159 let pat = &string[i..ip + j];
1160 assert!(match find(string, pat) {
1161 None => false,
1162 Some(x) => x <= i,
1163 });
1164 assert!(match rfind(string, pat) {
1165 None => false,
1166 Some(x) => x >= i,
1167 });
1168 }
1169 }
1170}