use std::ops::RangeInclusive;
use crate::image::Image;
pub struct Reach {
pub addresses: Vec<u64>,
pub slots: Vec<(u64, u64)>,
}
pub fn windows(targets: &[u64], back: u64) -> Vec<RangeInclusive<u64>> {
let mut windows: Vec<_> = targets.iter().map(|t| t.saturating_sub(back)..=*t).collect();
windows.sort_by_key(|w| *w.start());
windows
}
pub fn in_windows(windows: &[RangeInclusive<u64>], addr: u64) -> bool {
let end = windows.partition_point(|w| *w.start() <= addr);
windows[..end].iter().any(|w| w.contains(&addr))
}
pub fn reach(image: &Image, windows: impl IntoIterator<Item = RangeInclusive<u64>>) -> Reach {
let mut windows: Vec<_> = windows.into_iter().collect();
windows.sort_by_key(|w| *w.start());
let slots: Vec<(u64, u64)> =
image.pointers.iter().copied().filter(|(_, target)| in_windows(&windows, *target)).collect();
let mut addresses: Vec<u64> = windows.iter().flat_map(Clone::clone).collect();
addresses.extend(slots.iter().map(|(place, _)| *place));
addresses.sort_unstable();
addresses.dedup();
Reach { addresses, slots }
}
#[cfg(test)]
mod tests {
use super::{in_windows, windows};
#[test]
fn a_window_covers_the_length_byte_before_the_text() {
let windows = windows(&[0x43_9042, 0x10], 1);
assert!(in_windows(&windows, 0x43_9041));
assert!(in_windows(&windows, 0x43_9042));
assert!(!in_windows(&windows, 0x43_9040));
assert!(!in_windows(&windows, 0x43_9043));
assert!(in_windows(&windows, 0xf));
}
}