2014-12-30 21:54:17 +01:00
|
|
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
#![allow(missing_docs)]
|
|
|
|
|
|
|
|
use prelude::*;
|
|
|
|
use super::CharEq;
|
|
|
|
|
|
|
|
// Pattern
|
|
|
|
|
|
|
|
pub trait Pattern<'a>: Sized {
|
2015-01-27 14:09:18 +01:00
|
|
|
type Searcher: Searcher<'a>;
|
2015-02-17 22:57:14 +01:00
|
|
|
fn into_searcher(self, haystack: &'a str) -> Self::Searcher;
|
2014-12-30 21:54:17 +01:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn is_contained_in(self, haystack: &'a str) -> bool {
|
2015-02-17 22:57:14 +01:00
|
|
|
self.into_searcher(haystack).next_match().is_some()
|
2015-01-27 14:09:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn match_starts_at(self, haystack: &'a str, idx: usize) -> bool {
|
2015-02-17 22:57:14 +01:00
|
|
|
let mut matcher = self.into_searcher(haystack);
|
2015-01-27 14:09:18 +01:00
|
|
|
loop {
|
|
|
|
match matcher.next() {
|
|
|
|
SearchStep::Match(i, _) if i == idx => return true,
|
|
|
|
SearchStep::Match(i, _)
|
|
|
|
| SearchStep::Reject(i, _) if i >= idx => break,
|
|
|
|
SearchStep::Done => break,
|
|
|
|
_ => continue,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn match_ends_at(self, haystack: &'a str, idx: usize) -> bool
|
|
|
|
where Self::Searcher: ReverseSearcher<'a> {
|
2015-02-17 22:57:14 +01:00
|
|
|
let mut matcher = self.into_searcher(haystack);
|
2015-01-27 14:09:18 +01:00
|
|
|
loop {
|
|
|
|
match matcher.next_back() {
|
|
|
|
SearchStep::Match(_, j) if idx == j => return true,
|
|
|
|
SearchStep::Match(_, j)
|
|
|
|
| SearchStep::Reject(_, j) if idx >= j => break,
|
|
|
|
SearchStep::Done => break,
|
|
|
|
_ => continue,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
2014-12-30 21:54:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-27 14:09:18 +01:00
|
|
|
// Searcher
|
|
|
|
|
2015-02-17 23:47:08 +01:00
|
|
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
2015-01-27 14:09:18 +01:00
|
|
|
pub enum SearchStep {
|
|
|
|
Match(usize, usize),
|
|
|
|
Reject(usize, usize),
|
|
|
|
Done
|
|
|
|
}
|
2014-12-30 21:54:17 +01:00
|
|
|
|
2015-01-27 14:09:18 +01:00
|
|
|
pub unsafe trait Searcher<'a> {
|
2014-12-30 21:54:17 +01:00
|
|
|
fn haystack(&self) -> &'a str;
|
2015-01-27 14:09:18 +01:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-12-30 21:54:17 +01:00
|
|
|
}
|
|
|
|
|
2015-01-27 14:09:18 +01:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-12-30 21:54:17 +01:00
|
|
|
}
|
|
|
|
|
2015-01-27 14:09:18 +01:00
|
|
|
pub trait DoubleEndedSearcher<'a>: ReverseSearcher<'a> {}
|
2014-12-30 21:54:17 +01:00
|
|
|
|
2015-02-17 22:57:14 +01:00
|
|
|
// Impl for a CharEq wrapper
|
2014-12-30 21:54:17 +01:00
|
|
|
|
2015-02-17 22:57:14 +01:00
|
|
|
struct CharEqPattern<C: CharEq>(C);
|
|
|
|
|
|
|
|
pub struct CharEqSearcher<'a, C: CharEq> {
|
2015-01-27 14:09:18 +01:00
|
|
|
char_eq: C,
|
|
|
|
haystack: &'a str,
|
|
|
|
char_indices: super::CharIndices<'a>,
|
|
|
|
#[allow(dead_code)]
|
|
|
|
ascii_only: bool,
|
|
|
|
}
|
2014-12-30 21:54:17 +01:00
|
|
|
|
2015-02-17 22:57:14 +01:00
|
|
|
impl<'a, C: CharEq> Pattern<'a> for CharEqPattern<C> {
|
2015-01-27 14:09:18 +01:00
|
|
|
type Searcher = CharEqSearcher<'a, C>;
|
2014-12-30 21:54:17 +01:00
|
|
|
|
|
|
|
#[inline]
|
2015-02-17 22:57:14 +01:00
|
|
|
fn into_searcher(self, haystack: &'a str) -> CharEqSearcher<'a, C> {
|
2015-01-27 14:09:18 +01:00
|
|
|
CharEqSearcher {
|
2015-02-17 22:57:14 +01:00
|
|
|
ascii_only: self.0.only_ascii(),
|
2015-01-27 14:09:18 +01:00
|
|
|
haystack: haystack,
|
2015-02-17 22:57:14 +01:00
|
|
|
char_eq: self.0,
|
2015-01-27 14:09:18 +01:00
|
|
|
char_indices: haystack.char_indices(),
|
|
|
|
}
|
2014-12-30 21:54:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-27 14:09:18 +01:00
|
|
|
unsafe impl<'a, C: CharEq> Searcher<'a> for CharEqSearcher<'a, C> {
|
2014-12-30 21:54:17 +01:00
|
|
|
#[inline]
|
|
|
|
fn haystack(&self) -> &'a str {
|
2015-01-27 14:09:18 +01:00
|
|
|
self.haystack
|
2014-12-30 21:54:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2015-01-27 14:09:18 +01:00
|
|
|
fn next(&mut self) -> SearchStep {
|
|
|
|
let s = &mut self.char_indices;
|
|
|
|
// Compare lengths of the internal byte slice iterator
|
|
|
|
// to find length of current char
|
|
|
|
let (pre_len, _) = s.iter.iter.size_hint();
|
|
|
|
if let Some((i, c)) = s.next() {
|
|
|
|
let (len, _) = s.iter.iter.size_hint();
|
|
|
|
let char_len = pre_len - len;
|
|
|
|
if self.char_eq.matches(c) {
|
|
|
|
return SearchStep::Match(i, i + char_len);
|
|
|
|
} else {
|
|
|
|
return SearchStep::Reject(i, i + char_len);
|
2014-12-30 21:54:17 +01:00
|
|
|
}
|
|
|
|
}
|
2015-01-27 14:09:18 +01:00
|
|
|
SearchStep::Done
|
2014-12-30 21:54:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-27 14:09:18 +01:00
|
|
|
unsafe impl<'a, C: CharEq> ReverseSearcher<'a> for CharEqSearcher<'a, C> {
|
2014-12-30 21:54:17 +01:00
|
|
|
#[inline]
|
2015-01-27 14:09:18 +01:00
|
|
|
fn next_back(&mut self) -> SearchStep {
|
|
|
|
let s = &mut self.char_indices;
|
|
|
|
// Compare lengths of the internal byte slice iterator
|
|
|
|
// to find length of current char
|
|
|
|
let (pre_len, _) = s.iter.iter.size_hint();
|
|
|
|
if let Some((i, c)) = s.next_back() {
|
|
|
|
let (len, _) = s.iter.iter.size_hint();
|
|
|
|
let char_len = pre_len - len;
|
|
|
|
if self.char_eq.matches(c) {
|
|
|
|
return SearchStep::Match(i, i + char_len);
|
|
|
|
} else {
|
|
|
|
return SearchStep::Reject(i, i + char_len);
|
2014-12-30 21:54:17 +01:00
|
|
|
}
|
|
|
|
}
|
2015-01-27 14:09:18 +01:00
|
|
|
SearchStep::Done
|
2014-12-30 21:54:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-27 14:09:18 +01:00
|
|
|
impl<'a, C: CharEq> DoubleEndedSearcher<'a> for CharEqSearcher<'a, C> {}
|
2014-12-30 21:54:17 +01:00
|
|
|
|
|
|
|
// Impl for &str
|
|
|
|
|
2015-02-17 23:47:08 +01:00
|
|
|
// Todo: Optimize the naive implementation here
|
2015-01-27 14:09:18 +01:00
|
|
|
|
2015-01-14 20:45:51 +01:00
|
|
|
#[derive(Clone)]
|
2015-01-27 14:09:18 +01:00
|
|
|
pub struct StrSearcher<'a, 'b> {
|
|
|
|
haystack: &'a str,
|
|
|
|
needle: &'b str,
|
|
|
|
start: usize,
|
|
|
|
end: usize,
|
|
|
|
done: bool,
|
|
|
|
}
|
2014-12-30 21:54:17 +01:00
|
|
|
|
2015-01-14 20:45:51 +01:00
|
|
|
impl<'a, 'b> Pattern<'a> for &'b str {
|
2015-01-27 14:09:18 +01:00
|
|
|
type Searcher = StrSearcher<'a, 'b>;
|
2014-12-30 21:54:17 +01:00
|
|
|
|
|
|
|
#[inline]
|
2015-02-17 22:57:14 +01:00
|
|
|
fn into_searcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> {
|
2015-01-27 14:09:18 +01:00
|
|
|
StrSearcher {
|
2014-12-30 21:54:17 +01:00
|
|
|
haystack: haystack,
|
|
|
|
needle: self,
|
2015-01-27 14:09:18 +01:00
|
|
|
start: 0,
|
|
|
|
end: haystack.len(),
|
|
|
|
done: false,
|
|
|
|
}
|
2014-12-30 21:54:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-27 14:09:18 +01:00
|
|
|
unsafe impl<'a, 'b> Searcher<'a> for StrSearcher<'a, 'b> {
|
2014-12-30 21:54:17 +01:00
|
|
|
#[inline]
|
|
|
|
fn haystack(&self) -> &'a str {
|
2015-01-27 14:09:18 +01:00
|
|
|
self.haystack
|
2014-12-30 21:54:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2015-01-27 14:09:18 +01:00
|
|
|
fn next(&mut self) -> SearchStep {
|
|
|
|
str_search_step(self,
|
|
|
|
|m: &mut StrSearcher| {
|
|
|
|
// Forward step for empty needle
|
|
|
|
let current_start = m.start;
|
|
|
|
if !m.done {
|
|
|
|
m.start = m.haystack.char_range_at(current_start).next;
|
|
|
|
}
|
|
|
|
SearchStep::Match(current_start, current_start)
|
|
|
|
},
|
|
|
|
|m: &mut StrSearcher| {
|
|
|
|
// Forward step for nonempty needle
|
2015-02-17 23:47:08 +01:00
|
|
|
// Compare if bytes are equal
|
|
|
|
let possible_match = &m.haystack.as_bytes()[m.start .. m.start + m.needle.len()];
|
2015-01-27 14:09:18 +01:00
|
|
|
let current_start = m.start;
|
2015-02-17 23:47:08 +01:00
|
|
|
if possible_match == m.needle.as_bytes() {
|
2015-01-27 14:09:18 +01:00
|
|
|
m.start += m.needle.len();
|
|
|
|
SearchStep::Match(current_start, m.start)
|
|
|
|
} else {
|
2015-02-17 23:47:08 +01:00
|
|
|
// Skip a char
|
|
|
|
let haystack_suffix = &m.haystack[m.start..];
|
|
|
|
m.start += haystack_suffix.chars().next().unwrap().len_utf8();
|
2015-01-27 14:09:18 +01:00
|
|
|
SearchStep::Reject(current_start, m.start)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl<'a, 'b> ReverseSearcher<'a> for StrSearcher<'a, 'b> {
|
|
|
|
#[inline]
|
|
|
|
fn next_back(&mut self) -> SearchStep {
|
|
|
|
str_search_step(self,
|
|
|
|
|m: &mut StrSearcher| {
|
|
|
|
// Backward step for empty needle
|
|
|
|
let current_end = m.end;
|
|
|
|
if !m.done {
|
|
|
|
m.end = m.haystack.char_range_at_reverse(current_end).next;
|
|
|
|
}
|
|
|
|
SearchStep::Match(current_end, current_end)
|
|
|
|
},
|
|
|
|
|m: &mut StrSearcher| {
|
|
|
|
// Backward step for nonempty needle
|
2015-02-17 23:47:08 +01:00
|
|
|
// Compare if bytes are equal
|
|
|
|
let possible_match = &m.haystack.as_bytes()[m.end - m.needle.len() .. m.end];
|
2015-01-27 14:09:18 +01:00
|
|
|
let current_end = m.end;
|
2015-02-17 23:47:08 +01:00
|
|
|
if possible_match == m.needle.as_bytes() {
|
2015-01-27 14:09:18 +01:00
|
|
|
m.end -= m.needle.len();
|
|
|
|
SearchStep::Match(m.end, current_end)
|
|
|
|
} else {
|
2015-02-17 23:47:08 +01:00
|
|
|
// Skip a char
|
|
|
|
let haystack_prefix = &m.haystack[..m.end];
|
|
|
|
m.end -= haystack_prefix.chars().rev().next().unwrap().len_utf8();
|
2015-01-27 14:09:18 +01:00
|
|
|
SearchStep::Reject(m.end, current_end)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn str_search_step<F, G>(mut m: &mut StrSearcher, f: F, g: G) -> SearchStep
|
|
|
|
where F: FnOnce(&mut StrSearcher) -> SearchStep,
|
|
|
|
G: FnOnce(&mut StrSearcher) -> SearchStep
|
|
|
|
{
|
|
|
|
if m.done {
|
|
|
|
SearchStep::Done
|
|
|
|
} else if m.needle.len() == 0 && m.start <= m.end {
|
|
|
|
// Case for needle == ""
|
|
|
|
if m.start == m.end {
|
|
|
|
m.done = true;
|
|
|
|
}
|
|
|
|
f(&mut m)
|
|
|
|
} else if m.start + m.needle.len() <= m.end {
|
|
|
|
// Case for needle != ""
|
|
|
|
g(&mut m)
|
2015-02-17 23:47:08 +01:00
|
|
|
} else if m.start < m.end {
|
|
|
|
m.done = true;
|
|
|
|
SearchStep::Reject(m.start, m.end)
|
2015-01-27 14:09:18 +01:00
|
|
|
} else {
|
|
|
|
m.done = true;
|
|
|
|
SearchStep::Done
|
2014-12-30 21:54:17 +01:00
|
|
|
}
|
|
|
|
}
|
2015-02-17 22:57:14 +01:00
|
|
|
|
|
|
|
macro_rules! associated_items {
|
|
|
|
($t:ty, $s:ident, $e:expr) => {
|
|
|
|
// FIXME: #22463
|
|
|
|
//type Searcher = $t;
|
|
|
|
|
|
|
|
fn into_searcher(self, haystack: &'a str) -> $t {
|
|
|
|
let $s = self;
|
|
|
|
$e.into_searcher(haystack)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn is_contained_in(self, haystack: &'a str) -> bool {
|
|
|
|
let $s = self;
|
|
|
|
$e.is_contained_in(haystack)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn match_starts_at(self, haystack: &'a str, idx: usize) -> bool {
|
|
|
|
let $s = self;
|
|
|
|
$e.match_starts_at(haystack, idx)
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: #21750
|
|
|
|
/*#[inline]
|
|
|
|
fn match_ends_at(self, haystack: &'a str, idx: usize) -> bool
|
|
|
|
where $t: ReverseSearcher<'a> {
|
|
|
|
let $s = self;
|
|
|
|
$e.match_ends_at(haystack, idx)
|
|
|
|
}*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// CharEq delegation impls
|
|
|
|
|
|
|
|
impl<'a, 'b> Pattern<'a> for &'b [char] {
|
|
|
|
type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
|
|
|
|
associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
|
|
|
|
s, CharEqPattern(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Pattern<'a> for char {
|
|
|
|
type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
|
|
|
|
associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
|
|
|
|
s, CharEqPattern(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool {
|
|
|
|
type Searcher = <CharEqPattern<Self> as Pattern<'a>>::Searcher;
|
|
|
|
associated_items!(<CharEqPattern<Self> as Pattern<'a>>::Searcher,
|
|
|
|
s, CharEqPattern(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deref-forward impl
|
|
|
|
|
|
|
|
use ops::Deref;
|
|
|
|
|
2015-02-17 23:47:08 +01:00
|
|
|
impl<'a, 'b, P: 'b + ?Sized, T: Deref<Target = P> + ?Sized> Pattern<'a> for &'b T
|
|
|
|
where &'b P: Pattern<'a> {
|
2015-02-17 22:57:14 +01:00
|
|
|
type Searcher = <&'b P as Pattern<'a>>::Searcher;
|
|
|
|
associated_items!(<&'b P as Pattern<'a>>::Searcher,
|
|
|
|
s, (&**s));
|
|
|
|
}
|