#[cfg(miri)] #[macro_export] macro_rules! define_memchr_quickcheck { ($($tt:tt)*) => {}; } #[cfg(not(miri))] #[macro_export] macro_rules! define_memchr_quickcheck { ($mod:ident) => { define_memchr_quickcheck!($mod, new); }; ($mod:ident, $cons:ident) => { use alloc::vec::Vec; use quickcheck::TestResult; use crate::tests::memchr::{ naive, prop::{double_ended_take, naive1_iter, naive2_iter, naive3_iter}, }; quickcheck::quickcheck! { fn qc_memchr_matches_naive(n1: u8, corpus: Vec) -> TestResult { let expected = naive::memchr(n1, &corpus); let got = match $mod::One::$cons(n1) { None => return TestResult::discard(), Some(f) => f.find(&corpus), }; TestResult::from_bool(expected == got) } fn qc_memrchr_matches_naive(n1: u8, corpus: Vec) -> TestResult { let expected = naive::memrchr(n1, &corpus); let got = match $mod::One::$cons(n1) { None => return TestResult::discard(), Some(f) => f.rfind(&corpus), }; TestResult::from_bool(expected == got) } fn qc_memchr2_matches_naive(n1: u8, n2: u8, corpus: Vec) -> TestResult { let expected = naive::memchr2(n1, n2, &corpus); let got = match $mod::Two::$cons(n1, n2) { None => return TestResult::discard(), Some(f) => f.find(&corpus), }; TestResult::from_bool(expected == got) } fn qc_memrchr2_matches_naive(n1: u8, n2: u8, corpus: Vec) -> TestResult { let expected = naive::memrchr2(n1, n2, &corpus); let got = match $mod::Two::$cons(n1, n2) { None => return TestResult::discard(), Some(f) => f.rfind(&corpus), }; TestResult::from_bool(expected == got) } fn qc_memchr3_matches_naive( n1: u8, n2: u8, n3: u8, corpus: Vec ) -> TestResult { let expected = naive::memchr3(n1, n2, n3, &corpus); let got = match $mod::Three::$cons(n1, n2, n3) { None => return TestResult::discard(), Some(f) => f.find(&corpus), }; TestResult::from_bool(expected == got) } fn qc_memrchr3_matches_naive( n1: u8, n2: u8, n3: u8, corpus: Vec ) -> TestResult { let expected = naive::memrchr3(n1, n2, n3, &corpus); let got = match $mod::Three::$cons(n1, n2, n3) { None => return TestResult::discard(), Some(f) => f.rfind(&corpus), }; TestResult::from_bool(expected == got) } fn qc_memchr_double_ended_iter( needle: u8, data: Vec, take_side: Vec ) -> TestResult { // make nonempty let mut take_side = take_side; if take_side.is_empty() { take_side.push(true) }; let finder = match $mod::One::$cons(needle) { None => return TestResult::discard(), Some(finder) => finder, }; let iter = finder.iter(&data); let got = double_ended_take( iter, take_side.iter().cycle().cloned(), ); let expected = naive1_iter(needle, &data); TestResult::from_bool(got.iter().cloned().eq(expected)) } fn qc_memchr2_double_ended_iter( needle1: u8, needle2: u8, data: Vec, take_side: Vec ) -> TestResult { // make nonempty let mut take_side = take_side; if take_side.is_empty() { take_side.push(true) }; let finder = match $mod::Two::$cons(needle1, needle2) { None => return TestResult::discard(), Some(finder) => finder, }; let iter = finder.iter(&data); let got = double_ended_take( iter, take_side.iter().cycle().cloned(), ); let expected = naive2_iter(needle1, needle2, &data); TestResult::from_bool(got.iter().cloned().eq(expected)) } fn qc_memchr3_double_ended_iter( needle1: u8, needle2: u8, needle3: u8, data: Vec, take_side: Vec ) -> TestResult { // make nonempty let mut take_side = take_side; if take_side.is_empty() { take_side.push(true) }; let finder = match $mod::Three::$cons(needle1, needle2, needle3) { None => return TestResult::discard(), Some(finder) => finder, }; let iter = finder.iter(&data); let got = double_ended_take( iter, take_side.iter().cycle().cloned(), ); let expected = naive3_iter(needle1, needle2, needle3, &data); TestResult::from_bool(got.iter().cloned().eq(expected)) } fn qc_memchr1_iter(data: Vec) -> TestResult { let needle = 0; let finder = match $mod::One::$cons(needle) { None => return TestResult::discard(), Some(finder) => finder, }; let got = finder.iter(&data); let expected = naive1_iter(needle, &data); TestResult::from_bool(got.eq(expected)) } fn qc_memchr1_rev_iter(data: Vec) -> TestResult { let needle = 0; let finder = match $mod::One::$cons(needle) { None => return TestResult::discard(), Some(finder) => finder, }; let got = finder.iter(&data).rev(); let expected = naive1_iter(needle, &data).rev(); TestResult::from_bool(got.eq(expected)) } fn qc_memchr2_iter(data: Vec) -> TestResult { let needle1 = 0; let needle2 = 1; let finder = match $mod::Two::$cons(needle1, needle2) { None => return TestResult::discard(), Some(finder) => finder, }; let got = finder.iter(&data); let expected = naive2_iter(needle1, needle2, &data); TestResult::from_bool(got.eq(expected)) } fn qc_memchr2_rev_iter(data: Vec) -> TestResult { let needle1 = 0; let needle2 = 1; let finder = match $mod::Two::$cons(needle1, needle2) { None => return TestResult::discard(), Some(finder) => finder, }; let got = finder.iter(&data).rev(); let expected = naive2_iter(needle1, needle2, &data).rev(); TestResult::from_bool(got.eq(expected)) } fn qc_memchr3_iter(data: Vec) -> TestResult { let needle1 = 0; let needle2 = 1; let needle3 = 2; let finder = match $mod::Three::$cons(needle1, needle2, needle3) { None => return TestResult::discard(), Some(finder) => finder, }; let got = finder.iter(&data); let expected = naive3_iter(needle1, needle2, needle3, &data); TestResult::from_bool(got.eq(expected)) } fn qc_memchr3_rev_iter(data: Vec) -> TestResult { let needle1 = 0; let needle2 = 1; let needle3 = 2; let finder = match $mod::Three::$cons(needle1, needle2, needle3) { None => return TestResult::discard(), Some(finder) => finder, }; let got = finder.iter(&data).rev(); let expected = naive3_iter(needle1, needle2, needle3, &data).rev(); TestResult::from_bool(got.eq(expected)) } fn qc_memchr1_iter_size_hint(data: Vec) -> TestResult { // test that the size hint is within reasonable bounds let needle = 0; let finder = match $mod::One::$cons(needle) { None => return TestResult::discard(), Some(finder) => finder, }; let mut iter = finder.iter(&data); let mut real_count = data .iter() .filter(|&&elt| elt == needle) .count(); while let Some(index) = iter.next() { real_count -= 1; let (lower, upper) = iter.size_hint(); assert!(lower <= real_count); assert!(upper.unwrap() >= real_count); assert!(upper.unwrap() <= data.len() - index); } TestResult::passed() } } }; } // take items from a DEI, taking front for each true and back for each false. // Return a vector with the concatenation of the fronts and the reverse of the // backs. #[cfg(not(miri))] pub(crate) fn double_ended_take( mut iter: I, take_side: J, ) -> alloc::vec::Vec where I: DoubleEndedIterator, J: Iterator, { let mut found_front = alloc::vec![]; let mut found_back = alloc::vec![]; for take_front in take_side { if take_front { if let Some(pos) = iter.next() { found_front.push(pos); } else { break; } } else { if let Some(pos) = iter.next_back() { found_back.push(pos); } else { break; } }; } let mut all_found = found_front; all_found.extend(found_back.into_iter().rev()); all_found } // return an iterator of the 0-based indices of haystack that match the needle #[cfg(not(miri))] pub(crate) fn naive1_iter<'a>( n1: u8, haystack: &'a [u8], ) -> impl DoubleEndedIterator + 'a { haystack.iter().enumerate().filter(move |&(_, &b)| b == n1).map(|t| t.0) } #[cfg(not(miri))] pub(crate) fn naive2_iter<'a>( n1: u8, n2: u8, haystack: &'a [u8], ) -> impl DoubleEndedIterator + 'a { haystack .iter() .enumerate() .filter(move |&(_, &b)| b == n1 || b == n2) .map(|t| t.0) } #[cfg(not(miri))] pub(crate) fn naive3_iter<'a>( n1: u8, n2: u8, n3: u8, haystack: &'a [u8], ) -> impl DoubleEndedIterator + 'a { haystack .iter() .enumerate() .filter(move |&(_, &b)| b == n1 || b == n2 || b == n3) .map(|t| t.0) }