pub fn estimate_frequency(pattern: &[u8], body: &[u8]) -> usize {
assert!(body.len() >= pattern.len());
const PRIME: isize = 2654435761;
const ALPHABET_SIZE: isize = 256;
let mut pattern_hash: isize = 0;
let mut window_hash: isize = 0;
let mut h: isize = 1;
h = (h * ALPHABET_SIZE) % PRIME;
for i in 0..pattern.len() {
pattern_hash = (ALPHABET_SIZE * pattern_hash + pattern[i] as isize) % PRIME;
window_hash = (ALPHABET_SIZE * window_hash + body[i] as isize) % PRIME;
}
let mut num_occurances = 0;
for i in 0..=body.len() - pattern.len() {
if pattern_hash == window_hash {
num_occurances += 1;
}
if i < body.len() - pattern.len() {
window_hash = (ALPHABET_SIZE * (window_hash - body[i] as isize * h)
+ body[i + pattern.len()] as isize)
% PRIME;
}
}
num_occurances
}
#[cfg(test)]
mod tests {
use super::estimate_frequency;
#[test]
fn dead_beef() {
assert_eq!(
estimate_frequency(&[0xde, 0xad], &[0xde, 0xad, 0xbe, 0xef, 0xde, 0xad]),
2
);
}
#[test]
fn smallest_body() {
assert_eq!(estimate_frequency(&[0x00, 0xff], &[0x00, 0xff]), 1);
}
#[test]
fn no_match() {
assert_eq!(
estimate_frequency(&[0xff, 0xff], &[0xde, 0xad, 0xbe, 0xef, 0xde, 0xad]),
0
);
}
}