use std::iter::repeat;
mod iter;
mod memchr;
#[cfg(target_endian = "little")]
#[test]
fn byte_order() {
eprintln!("LITTLE ENDIAN");
}
#[cfg(target_endian = "big")]
#[test]
fn byte_order() {
eprintln!("BIG ENDIAN");
}
fn memchr_tests() -> Vec<MemchrTest> {
let mut tests = Vec::new();
for statict in MEMCHR_TESTS {
assert!(!statict.corpus.contains("%"), "% is not allowed in corpora");
assert!(!statict.corpus.contains("#"), "# is not allowed in corpora");
assert!(!statict.needles.contains(&b'%'), "% is an invalid needle");
assert!(!statict.needles.contains(&b'#'), "# is an invalid needle");
let t = MemchrTest {
corpus: statict.corpus.to_string(),
needles: statict.needles.to_vec(),
positions: statict.positions.to_vec(),
};
tests.push(t.clone());
tests.extend(t.expand());
}
tests
}
const MEMCHR_TESTS: &[MemchrTestStatic] = &[
MemchrTestStatic {
corpus: "a",
needles: &[b'a'],
positions: &[0],
},
MemchrTestStatic {
corpus: "aa",
needles: &[b'a'],
positions: &[0, 1],
},
MemchrTestStatic {
corpus: "aaa",
needles: &[b'a'],
positions: &[0, 1, 2],
},
MemchrTestStatic {
corpus: "",
needles: &[b'a'],
positions: &[],
},
MemchrTestStatic {
corpus: "z",
needles: &[b'a'],
positions: &[],
},
MemchrTestStatic {
corpus: "zz",
needles: &[b'a'],
positions: &[],
},
MemchrTestStatic {
corpus: "zza",
needles: &[b'a'],
positions: &[2],
},
MemchrTestStatic {
corpus: "zaza",
needles: &[b'a'],
positions: &[1, 3],
},
MemchrTestStatic {
corpus: "zzza",
needles: &[b'a'],
positions: &[3],
},
MemchrTestStatic {
corpus: "\x00a",
needles: &[b'a'],
positions: &[1],
},
MemchrTestStatic {
corpus: "\x00",
needles: &[b'\x00'],
positions: &[0],
},
MemchrTestStatic {
corpus: "\x00\x00",
needles: &[b'\x00'],
positions: &[0, 1],
},
MemchrTestStatic {
corpus: "\x00a\x00",
needles: &[b'\x00'],
positions: &[0, 2],
},
MemchrTestStatic {
corpus: "zzzzzzzzzzzzzzzza",
needles: &[b'a'],
positions: &[16],
},
MemchrTestStatic {
corpus: "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzza",
needles: &[b'a'],
positions: &[32],
},
MemchrTestStatic {
corpus: "az",
needles: &[b'a', b'z'],
positions: &[0, 1],
},
MemchrTestStatic {
corpus: "az",
needles: &[b'a', b'z'],
positions: &[0, 1],
},
MemchrTestStatic {
corpus: "az",
needles: &[b'x', b'y'],
positions: &[],
},
MemchrTestStatic {
corpus: "az",
needles: &[b'a', b'y'],
positions: &[0],
},
MemchrTestStatic {
corpus: "az",
needles: &[b'x', b'z'],
positions: &[1],
},
MemchrTestStatic {
corpus: "yyyyaz",
needles: &[b'a', b'z'],
positions: &[4, 5],
},
MemchrTestStatic {
corpus: "yyyyaz",
needles: &[b'z', b'a'],
positions: &[4, 5],
},
MemchrTestStatic {
corpus: "xyz",
needles: &[b'x', b'y', b'z'],
positions: &[0, 1, 2],
},
MemchrTestStatic {
corpus: "zxy",
needles: &[b'x', b'y', b'z'],
positions: &[0, 1, 2],
},
MemchrTestStatic {
corpus: "zxy",
needles: &[b'x', b'a', b'z'],
positions: &[0, 1],
},
MemchrTestStatic {
corpus: "zxy",
needles: &[b't', b'a', b'z'],
positions: &[0],
},
MemchrTestStatic {
corpus: "yxz",
needles: &[b't', b'a', b'z'],
positions: &[2],
},
];
#[derive(Clone, Debug)]
struct MemchrTest {
corpus: String,
needles: Vec<u8>,
positions: Vec<usize>,
}
#[derive(Clone, Debug)]
struct MemchrTestStatic {
corpus: &'static str,
needles: &'static [u8],
positions: &'static [usize],
}
impl MemchrTest {
fn one<F: Fn(u8, &[u8]) -> Option<usize>>(
&self,
reverse: bool,
f: F,
) {
let needles = match self.needles(1) {
None => return,
Some(needles) => needles,
};
for align in 0..130 {
let corpus = self.corpus(align);
assert_eq!(
self.positions(align, reverse).get(0).cloned(),
f(needles[0], corpus.as_bytes()),
"search for {:?} failed in: {:?} (len: {}, alignment: {})",
needles[0] as char,
corpus,
corpus.len(),
align
);
}
}
fn two<F: Fn(u8, u8, &[u8]) -> Option<usize>>(
&self,
reverse: bool,
f: F,
) {
let needles = match self.needles(2) {
None => return,
Some(needles) => needles,
};
for align in 0..130 {
let corpus = self.corpus(align);
assert_eq!(
self.positions(align, reverse).get(0).cloned(),
f(needles[0], needles[1], corpus.as_bytes()),
"search for {:?}|{:?} failed in: {:?} \
(len: {}, alignment: {})",
needles[0] as char,
needles[1] as char,
corpus,
corpus.len(),
align
);
}
}
fn three<F: Fn(u8, u8, u8, &[u8]) -> Option<usize>>(
&self,
reverse: bool,
f: F,
) {
let needles = match self.needles(3) {
None => return,
Some(needles) => needles,
};
for align in 0..130 {
let corpus = self.corpus(align);
assert_eq!(
self.positions(align, reverse).get(0).cloned(),
f(needles[0], needles[1], needles[2], corpus.as_bytes()),
"search for {:?}|{:?}|{:?} failed in: {:?} \
(len: {}, alignment: {})",
needles[0] as char,
needles[1] as char,
needles[2] as char,
corpus,
corpus.len(),
align
);
}
}
fn iter_one<'a, I, F>(&'a self, reverse: bool, f: F)
where F: FnOnce(u8, &'a [u8]) -> I,
I: Iterator<Item=usize>
{
if let Some(ns) = self.needles(1) {
self.iter(reverse, f(ns[0], self.corpus.as_bytes()));
}
}
fn iter_two<'a, I, F>(&'a self, reverse: bool, f: F)
where F: FnOnce(u8, u8, &'a [u8]) -> I,
I: Iterator<Item=usize>
{
if let Some(ns) = self.needles(2) {
self.iter(reverse, f(ns[0], ns[1], self.corpus.as_bytes()));
}
}
fn iter_three<'a, I, F>(&'a self, reverse: bool, f: F)
where F: FnOnce(u8, u8, u8, &'a [u8]) -> I,
I: Iterator<Item=usize>
{
if let Some(ns) = self.needles(3) {
self.iter(reverse, f(ns[0], ns[1], ns[2], self.corpus.as_bytes()));
}
}
fn iter<I: Iterator<Item=usize>>(&self, reverse: bool, it: I) {
assert_eq!(
self.positions(0, reverse),
it.collect::<Vec<usize>>(),
r"search for {:?} failed in: {:?}",
self.needles.iter().map(|&b| b as char).collect::<Vec<char>>(),
self.corpus
);
}
fn expand(&self) -> Vec<MemchrTest> {
let mut more = Vec::new();
for i in 1..515 {
let mut t = self.clone();
let mut new_corpus: String = repeat('%').take(i).collect();
new_corpus.push_str(&t.corpus);
t.corpus = new_corpus;
t.positions = t.positions.into_iter().map(|p| p + i).collect();
more.push(t);
}
for i in 1..515 {
let mut t = self.clone();
let mut padding: String = repeat('%').take(i).collect();
t.corpus.push_str(&padding);
more.push(t);
}
more
}
fn corpus(&self, align: usize) -> &str {
self.corpus.get(align..).unwrap_or("")
}
fn needles(&self, count: usize) -> Option<Vec<u8>> {
if self.needles.len() > count {
return None;
}
let mut needles = self.needles.to_vec();
for _ in needles.len()..count {
needles.push(b'#');
}
Some(needles)
}
fn positions(&self, align: usize, reverse: bool) -> Vec<usize> {
let positions =
if reverse {
let mut positions = self.positions.to_vec();
positions.reverse();
positions
} else {
self.positions.to_vec()
};
positions
.into_iter()
.filter(|&p| p >= align)
.map(|p| p - align)
.collect()
}
}