use std::cmp;
use std::fmt;
use std::iter::Enumerate;
use std::usize;
use bstring::{bstr, Iter};
pub trait Pattern<'a>: Sized {
type Searcher: Searcher<'a>;
fn into_searcher(self, haystack: &'a bstr) -> Self::Searcher;
#[inline]
fn is_contained_in(self, haystack: &'a bstr) -> bool {
self.into_searcher(haystack).next_match().is_some()
}
#[inline]
fn is_prefix_of(self, haystack: &'a bstr) -> bool {
match self.into_searcher(haystack).next() {
SearchStep::Match(0, _) => true,
_ => false,
}
}
#[inline]
fn is_suffix_of(self, haystack: &'a bstr) -> bool
where Self::Searcher: ReverseSearcher<'a>
{
match self.into_searcher(haystack).next_back() {
SearchStep::Match(_, j) if haystack.len() == j => true,
_ => false,
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum SearchStep {
Match(usize, usize),
Reject(usize, usize),
Done
}
pub unsafe trait Searcher<'a> {
fn haystack(&self) -> &'a bstr;
fn next(&mut self) -> SearchStep;
#[inline]
fn next_match(&mut self) -> Option<(usize, usize)> {
loop {
match self.next() {
SearchStep::Match(a, b) => return Some((a, b)),
SearchStep::Done => return None,
_ => continue,
}
}
}
#[inline]
fn next_reject(&mut self) -> Option<(usize, usize)> {
loop {
match self.next() {
SearchStep::Reject(a, b) => return Some((a, b)),
SearchStep::Done => return None,
_ => continue,
}
}
}
}
pub unsafe trait ReverseSearcher<'a>: Searcher<'a> {
fn next_back(&mut self) -> SearchStep;
#[inline]
fn next_match_back(&mut self) -> Option<(usize, usize)>{
loop {
match self.next_back() {
SearchStep::Match(a, b) => return Some((a, b)),
SearchStep::Done => return None,
_ => continue,
}
}
}
#[inline]
fn next_reject_back(&mut self) -> Option<(usize, usize)>{
loop {
match self.next_back() {
SearchStep::Reject(a, b) => return Some((a, b)),
SearchStep::Done => return None,
_ => continue,
}
}
}
}
pub trait DoubleEndedSearcher<'a>: ReverseSearcher<'a> {}
#[doc(hidden)]
trait ByteEq {
fn matches(&mut self, c: u8) -> bool;
}
impl ByteEq for u8 {
#[inline]
fn matches(&mut self, c: u8) -> bool { *self == c }
}
impl<F> ByteEq for F where F: FnMut(u8) -> bool {
#[inline]
fn matches(&mut self, c: u8) -> bool { (*self)(c) }
}
impl<'a> ByteEq for &'a [u8] {
#[inline]
fn matches(&mut self, c: u8) -> bool {
self.iter().any(|&m| { let mut m = m; m.matches(c) })
}
}
impl<'a> ByteEq for &'a bstr {
#[inline]
fn matches(&mut self, c: u8) -> bool {
self.iter().any(|&m| { let mut m = m; m.matches(c) })
}
}
struct ByteEqPattern<B: ByteEq>(B);
#[derive(Clone, Debug)]
struct ByteEqSearcher<'a, B: ByteEq> {
byte_eq: B,
haystack: &'a bstr,
byte_indices: Enumerate<Iter<'a>>,
}
impl<'a, B: ByteEq> Pattern<'a> for ByteEqPattern<B> {
type Searcher = ByteEqSearcher<'a, B>;
#[inline]
fn into_searcher(self, haystack: &'a bstr) -> ByteEqSearcher<'a, B> {
ByteEqSearcher {
haystack: haystack,
byte_eq: self.0,
byte_indices: haystack.iter().enumerate(),
}
}
}
unsafe impl<'a, B: ByteEq> Searcher<'a> for ByteEqSearcher<'a, B> {
#[inline]
fn haystack(&self) -> &'a bstr {
self.haystack
}
#[inline]
fn next(&mut self) -> SearchStep {
let s = &mut self.byte_indices;
if let Some((i, &c)) = s.next() {
if self.byte_eq.matches(c) {
return SearchStep::Match(i, i + 1);
} else {
return SearchStep::Reject(i, i + 1);
}
}
SearchStep::Done
}
}
unsafe impl<'a, B: ByteEq> ReverseSearcher<'a> for ByteEqSearcher<'a, B> {
#[inline]
fn next_back(&mut self) -> SearchStep {
let s = &mut self.byte_indices;
if let Some((i, &c)) = s.next_back() {
if self.byte_eq.matches(c) {
return SearchStep::Match(i, i + 1);
} else {
return SearchStep::Reject(i, i + 1);
}
}
SearchStep::Done
}
}
impl<'a, B: ByteEq> DoubleEndedSearcher<'a> for ByteEqSearcher<'a, B> {}
macro_rules! pattern_methods {
($t:ty, $pmap:expr, $smap:expr) => {
type Searcher = $t;
#[inline]
fn into_searcher(self, haystack: &'a bstr) -> $t {
($smap)(($pmap)(self).into_searcher(haystack))
}
#[inline]
fn is_contained_in(self, haystack: &'a bstr) -> bool {
($pmap)(self).is_contained_in(haystack)
}
#[inline]
fn is_prefix_of(self, haystack: &'a bstr) -> bool {
($pmap)(self).is_prefix_of(haystack)
}
#[inline]
fn is_suffix_of(self, haystack: &'a bstr) -> bool
where $t: ReverseSearcher<'a>
{
($pmap)(self).is_suffix_of(haystack)
}
}
}
macro_rules! searcher_methods {
(forward) => {
#[inline]
fn haystack(&self) -> &'a bstr {
self.0.haystack()
}
#[inline]
fn next(&mut self) -> SearchStep {
self.0.next()
}
#[inline]
fn next_match(&mut self) -> Option<(usize, usize)> {
self.0.next_match()
}
#[inline]
fn next_reject(&mut self) -> Option<(usize, usize)> {
self.0.next_reject()
}
};
(reverse) => {
#[inline]
fn next_back(&mut self) -> SearchStep {
self.0.next_back()
}
#[inline]
fn next_match_back(&mut self) -> Option<(usize, usize)> {
self.0.next_match_back()
}
#[inline]
fn next_reject_back(&mut self) -> Option<(usize, usize)> {
self.0.next_reject_back()
}
}
}
#[derive(Clone, Debug)]
pub struct ByteSearcher<'a>(<ByteEqPattern<u8> as Pattern<'a>>::Searcher);
unsafe impl<'a> Searcher<'a> for ByteSearcher<'a> {
searcher_methods!(forward);
}
unsafe impl<'a> ReverseSearcher<'a> for ByteSearcher<'a> {
searcher_methods!(reverse);
}
impl<'a> DoubleEndedSearcher<'a> for ByteSearcher<'a> {}
impl<'a> Pattern<'a> for u8 {
type Searcher = ByteSearcher<'a>;
#[inline]
fn into_searcher(self, haystack: &'a bstr) -> Self::Searcher {
ByteSearcher(ByteEqPattern(self).into_searcher(haystack))
}
#[inline]
fn is_contained_in(self, haystack: &'a bstr) -> bool {
haystack.as_bytes().contains(&self)
}
#[inline]
fn is_prefix_of(self, haystack: &'a bstr) -> bool {
ByteEqPattern(self).is_prefix_of(haystack)
}
#[inline]
fn is_suffix_of(self, haystack: &'a bstr) -> bool
where Self::Searcher: ReverseSearcher<'a> {
ByteEqPattern(self).is_suffix_of(haystack)
}
}
#[derive(Clone, Debug)]
pub struct ByteSliceSearcher<'a, 'b>(<ByteEqPattern<&'b [u8]> as Pattern<'a>>::Searcher);
unsafe impl<'a, 'b> Searcher<'a> for ByteSliceSearcher<'a, 'b> {
searcher_methods!(forward);
}
unsafe impl<'a, 'b> ReverseSearcher<'a> for ByteSliceSearcher<'a, 'b> {
searcher_methods!(reverse);
}
impl<'a, 'b> DoubleEndedSearcher<'a> for ByteSliceSearcher<'a, 'b> {}
impl<'a, 'b> Pattern<'a> for &'b [u8] {
pattern_methods!(ByteSliceSearcher<'a, 'b>, ByteEqPattern, ByteSliceSearcher);
}
#[derive(Clone)]
pub struct BytePredicateSearcher<'a, F>(<ByteEqPattern<F> as Pattern<'a>>::Searcher)
where F: FnMut(u8) -> bool;
impl<'a, F> fmt::Debug for BytePredicateSearcher<'a, F>
where F: FnMut(u8) -> bool
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("BytePredicateSearcher")
.field("haystack", &self.0.haystack)
.field("byte_indices", &self.0.byte_indices)
.finish()
}
}
unsafe impl<'a, F> Searcher<'a> for BytePredicateSearcher<'a, F>
where F: FnMut(u8) -> bool
{
searcher_methods!(forward);
}
unsafe impl<'a, F> ReverseSearcher<'a> for BytePredicateSearcher<'a, F>
where F: FnMut(u8) -> bool
{
searcher_methods!(reverse);
}
impl<'a, F> DoubleEndedSearcher<'a> for BytePredicateSearcher<'a, F>
where F: FnMut(u8) -> bool {}
impl<'a, F> Pattern<'a> for F where F: FnMut(u8) -> bool {
pattern_methods!(BytePredicateSearcher<'a, F>, ByteEqPattern, BytePredicateSearcher);
}
impl<'a, 'b, 'c> Pattern<'a> for &'c &'b str {
pattern_methods!(StrSearcher<'a, 'b>,
|&s| <str as AsRef<bstr>>::as_ref(s), |s| s);
}
impl<'a, 'b> Pattern<'a> for &'b str {
pattern_methods!(StrSearcher<'a, 'b>,
|s| <str as AsRef<bstr>>::as_ref(s), |s| s);
}
impl<'a, 'b, 'c> Pattern<'a> for &'c &'b bstr {
pattern_methods!(StrSearcher<'a, 'b>, |&s| s, |s| s);
}
impl<'a, 'b> Pattern<'a> for &'b bstr {
type Searcher = StrSearcher<'a, 'b>;
#[inline]
fn into_searcher(self, haystack: &'a bstr) -> StrSearcher<'a, 'b> {
StrSearcher::new(haystack, self)
}
#[inline]
fn is_prefix_of(self, haystack: &'a bstr) -> bool {
self.len() <= haystack.len() &&
self == &haystack[..self.len()]
}
#[inline]
fn is_suffix_of(self, haystack: &'a bstr) -> bool {
self.len() <= haystack.len() &&
self == &haystack[haystack.len() - self.len()..]
}
}
#[derive(Clone, Debug)]
pub struct StrSearcher<'a, 'b> {
haystack: &'a bstr,
needle: &'b bstr,
searcher: StrSearcherImpl,
}
#[derive(Clone, Debug)]
enum StrSearcherImpl {
Empty(EmptyNeedle),
TwoWay(TwoWaySearcher),
}
#[derive(Clone, Debug)]
struct EmptyNeedle {
position: usize,
end: usize,
is_match_fw: bool,
is_match_bw: bool,
}
impl<'a, 'b> StrSearcher<'a, 'b> {
fn new(haystack: &'a bstr, needle: &'b bstr) -> StrSearcher<'a, 'b> {
if needle.is_empty() {
StrSearcher {
haystack: haystack,
needle: needle,
searcher: StrSearcherImpl::Empty(EmptyNeedle {
position: 0,
end: haystack.len(),
is_match_fw: true,
is_match_bw: true,
}),
}
} else {
StrSearcher {
haystack: haystack,
needle: needle,
searcher: StrSearcherImpl::TwoWay(
TwoWaySearcher::new(needle.as_bytes(), haystack.len())
),
}
}
}
}
unsafe impl<'a, 'b> Searcher<'a> for StrSearcher<'a, 'b> {
fn haystack(&self) -> &'a bstr { self.haystack }
#[inline]
fn next(&mut self) -> SearchStep {
match self.searcher {
StrSearcherImpl::Empty(ref mut searcher) => {
let is_match = searcher.is_match_fw;
searcher.is_match_fw = !searcher.is_match_fw;
let pos = searcher.position;
match self.haystack[pos..].iter().next() {
_ if is_match => SearchStep::Match(pos, pos),
None => SearchStep::Done,
Some(_) => {
searcher.position += 1;
SearchStep::Reject(pos, searcher.position)
}
}
}
StrSearcherImpl::TwoWay(ref mut searcher) => {
if searcher.position == self.haystack.len() {
return SearchStep::Done;
}
let is_long = searcher.memory == usize::MAX;
match searcher.next::<RejectAndMatch>(self.haystack.as_bytes(),
self.needle.as_bytes(),
is_long)
{
SearchStep::Reject(a, b) => {
searcher.position = cmp::max(b, searcher.position);
SearchStep::Reject(a, b)
}
otherwise => otherwise,
}
}
}
}
#[inline(always)]
fn next_match(&mut self) -> Option<(usize, usize)> {
match self.searcher {
StrSearcherImpl::Empty(..) => {
loop {
match self.next() {
SearchStep::Match(a, b) => return Some((a, b)),
SearchStep::Done => return None,
SearchStep::Reject(..) => { }
}
}
}
StrSearcherImpl::TwoWay(ref mut searcher) => {
let is_long = searcher.memory == usize::MAX;
if is_long {
searcher.next::<MatchOnly>(self.haystack.as_bytes(),
self.needle.as_bytes(),
true)
} else {
searcher.next::<MatchOnly>(self.haystack.as_bytes(),
self.needle.as_bytes(),
false)
}
}
}
}
}
unsafe impl<'a, 'b> ReverseSearcher<'a> for StrSearcher<'a, 'b> {
#[inline]
fn next_back(&mut self) -> SearchStep {
match self.searcher {
StrSearcherImpl::Empty(ref mut searcher) => {
let is_match = searcher.is_match_bw;
searcher.is_match_bw = !searcher.is_match_bw;
let end = searcher.end;
match self.haystack[..end].iter().next_back() {
_ if is_match => SearchStep::Match(end, end),
None => SearchStep::Done,
Some(_) => {
searcher.end -= 1;
SearchStep::Reject(searcher.end, end)
}
}
}
StrSearcherImpl::TwoWay(ref mut searcher) => {
if searcher.end == 0 {
return SearchStep::Done;
}
let is_long = searcher.memory == usize::MAX;
match searcher.next_back::<RejectAndMatch>(self.haystack.as_bytes(),
self.needle.as_bytes(),
is_long)
{
SearchStep::Reject(a, b) => {
searcher.end = cmp::min(a, searcher.end);
SearchStep::Reject(a, b)
}
otherwise => otherwise,
}
}
}
}
#[inline]
fn next_match_back(&mut self) -> Option<(usize, usize)> {
match self.searcher {
StrSearcherImpl::Empty(..) => {
loop {
match self.next_back() {
SearchStep::Match(a, b) => return Some((a, b)),
SearchStep::Done => return None,
SearchStep::Reject(..) => { }
}
}
}
StrSearcherImpl::TwoWay(ref mut searcher) => {
let is_long = searcher.memory == usize::MAX;
if is_long {
searcher.next_back::<MatchOnly>(self.haystack.as_bytes(),
self.needle.as_bytes(),
true)
} else {
searcher.next_back::<MatchOnly>(self.haystack.as_bytes(),
self.needle.as_bytes(),
false)
}
}
}
}
}
#[derive(Clone, Debug)]
struct TwoWaySearcher {
crit_pos: usize,
crit_pos_back: usize,
period: usize,
byteset: u64,
position: usize,
end: usize,
memory: usize,
memory_back: usize,
}
impl TwoWaySearcher {
fn new(needle: &[u8], end: usize) -> TwoWaySearcher {
let (crit_pos_false, period_false) = TwoWaySearcher::maximal_suffix(needle, false);
let (crit_pos_true, period_true) = TwoWaySearcher::maximal_suffix(needle, true);
let (crit_pos, period) =
if crit_pos_false > crit_pos_true {
(crit_pos_false, period_false)
} else {
(crit_pos_true, period_true)
};
if &needle[..crit_pos] == &needle[period.. period + crit_pos] {
let crit_pos_back = needle.len() - cmp::max(
TwoWaySearcher::reverse_maximal_suffix(needle, period, false),
TwoWaySearcher::reverse_maximal_suffix(needle, period, true));
TwoWaySearcher {
crit_pos: crit_pos,
crit_pos_back: crit_pos_back,
period: period,
byteset: Self::byteset_create(&needle[..period]),
position: 0,
end: end,
memory: 0,
memory_back: needle.len(),
}
} else {
TwoWaySearcher {
crit_pos: crit_pos,
crit_pos_back: crit_pos,
period: cmp::max(crit_pos, needle.len() - crit_pos) + 1,
byteset: Self::byteset_create(needle),
position: 0,
end: end,
memory: usize::MAX, memory_back: usize::MAX,
}
}
}
#[inline]
fn byteset_create(bytes: &[u8]) -> u64 {
bytes.iter().fold(0, |a, &b| (1 << (b & 0x3f)) | a)
}
#[inline(always)]
fn byteset_contains(&self, byte: u8) -> bool {
(self.byteset >> ((byte & 0x3f) as usize)) & 1 != 0
}
#[inline(always)]
fn next<S>(&mut self, haystack: &[u8], needle: &[u8], long_period: bool)
-> S::Output
where S: TwoWayStrategy
{
let old_pos = self.position;
let needle_last = needle.len() - 1;
'search: loop {
let tail_byte = match haystack.get(self.position + needle_last) {
Some(&b) => b,
None => {
self.position = haystack.len();
return S::rejecting(old_pos, self.position);
}
};
if S::use_early_reject() && old_pos != self.position {
return S::rejecting(old_pos, self.position);
}
if !self.byteset_contains(tail_byte) {
self.position += needle.len();
if !long_period {
self.memory = 0;
}
continue 'search;
}
let start = if long_period { self.crit_pos }
else { cmp::max(self.crit_pos, self.memory) };
for i in start..needle.len() {
if needle[i] != haystack[self.position + i] {
self.position += i - self.crit_pos + 1;
if !long_period {
self.memory = 0;
}
continue 'search;
}
}
let start = if long_period { 0 } else { self.memory };
for i in (start..self.crit_pos).rev() {
if needle[i] != haystack[self.position + i] {
self.position += self.period;
if !long_period {
self.memory = needle.len() - self.period;
}
continue 'search;
}
}
let match_pos = self.position;
self.position += needle.len();
if !long_period {
self.memory = 0; }
return S::matching(match_pos, match_pos + needle.len());
}
}
#[inline]
fn next_back<S>(&mut self, haystack: &[u8], needle: &[u8], long_period: bool)
-> S::Output
where S: TwoWayStrategy
{
let old_end = self.end;
'search: loop {
let front_byte = match haystack.get(self.end.wrapping_sub(needle.len())) {
Some(&b) => b,
None => {
self.end = 0;
return S::rejecting(0, old_end);
}
};
if S::use_early_reject() && old_end != self.end {
return S::rejecting(self.end, old_end);
}
if !self.byteset_contains(front_byte) {
self.end -= needle.len();
if !long_period {
self.memory_back = needle.len();
}
continue 'search;
}
let crit = if long_period { self.crit_pos_back }
else { cmp::min(self.crit_pos_back, self.memory_back) };
for i in (0..crit).rev() {
if needle[i] != haystack[self.end - needle.len() + i] {
self.end -= self.crit_pos_back - i;
if !long_period {
self.memory_back = needle.len();
}
continue 'search;
}
}
let needle_end = if long_period { needle.len() }
else { self.memory_back };
for i in self.crit_pos_back..needle_end {
if needle[i] != haystack[self.end - needle.len() + i] {
self.end -= self.period;
if !long_period {
self.memory_back = self.period;
}
continue 'search;
}
}
let match_pos = self.end - needle.len();
self.end -= needle.len();
if !long_period {
self.memory_back = needle.len();
}
return S::matching(match_pos, match_pos + needle.len());
}
}
#[inline]
fn maximal_suffix(arr: &[u8], order_greater: bool) -> (usize, usize) {
let mut left = 0; let mut right = 1; let mut offset = 0; let mut period = 1;
while let Some(&a) = arr.get(right + offset) {
let b = arr[left + offset];
if (a < b && !order_greater) || (a > b && order_greater) {
right += offset + 1;
offset = 0;
period = right - left;
} else if a == b {
if offset + 1 == period {
right += offset + 1;
offset = 0;
} else {
offset += 1;
}
} else {
left = right;
right += 1;
offset = 0;
period = 1;
}
}
(left, period)
}
fn reverse_maximal_suffix(arr: &[u8], known_period: usize,
order_greater: bool) -> usize
{
let mut left = 0; let mut right = 1; let mut offset = 0; let mut period = 1; let n = arr.len();
while right + offset < n {
let a = arr[n - (1 + right + offset)];
let b = arr[n - (1 + left + offset)];
if (a < b && !order_greater) || (a > b && order_greater) {
right += offset + 1;
offset = 0;
period = right - left;
} else if a == b {
if offset + 1 == period {
right += offset + 1;
offset = 0;
} else {
offset += 1;
}
} else {
left = right;
right += 1;
offset = 0;
period = 1;
}
if period == known_period {
break;
}
}
debug_assert!(period <= known_period);
left
}
}
trait TwoWayStrategy {
type Output;
fn use_early_reject() -> bool;
fn rejecting(a: usize, b: usize) -> Self::Output;
fn matching(a: usize, b: usize) -> Self::Output;
}
enum MatchOnly { }
impl TwoWayStrategy for MatchOnly {
type Output = Option<(usize, usize)>;
#[inline]
fn use_early_reject() -> bool { false }
#[inline]
fn rejecting(_a: usize, _b: usize) -> Self::Output { None }
#[inline]
fn matching(a: usize, b: usize) -> Self::Output { Some((a, b)) }
}
enum RejectAndMatch { }
impl TwoWayStrategy for RejectAndMatch {
type Output = SearchStep;
#[inline]
fn use_early_reject() -> bool { true }
#[inline]
fn rejecting(a: usize, b: usize) -> Self::Output { SearchStep::Reject(a, b) }
#[inline]
fn matching(a: usize, b: usize) -> Self::Output { SearchStep::Match(a, b) }
}