use std::collections::HashMap;
use log::trace;
use crate::arch::Arch;
use crate::encoding::dataflows::{Dest, IntoDestWithSize, Size};
use crate::state::Location;
use crate::utils::bitmap::GrowingBitmap;
#[derive(Clone, Debug, Default)]
pub struct SplitDests<A: Arch> {
outputs: HashMap<Location<A>, Vec<Size>>,
}
impl<A: Arch> SplitDests<A> {
pub fn new() -> Self {
Self::default()
}
pub fn split(&mut self, dest: Dest<A>) {
let location = Location::from(dest);
let size = dest.size();
let existing_sizes = self.outputs.remove(&location).unwrap_or_default();
trace!("Splitting {dest:?} with existing sizes {existing_sizes:?}");
let mut split_sizes = Vec::new();
let mut covered = GrowingBitmap::new_all_zeros(size.end_byte + 1);
for existing_size in existing_sizes {
covered.set_range(existing_size.start_byte..existing_size.end_byte + 1);
trace!("Checking {existing_size:?} vs {size:?}");
if let Some((before, overlapping, after)) = size.split_by_overlap(existing_size) {
trace!("Split into: {before:?} {overlapping:?} {after:?}");
split_sizes.push(overlapping);
for item in [before, after].into_iter().flatten() {
if existing_size.contains(&item) {
split_sizes.push(item);
}
}
} else {
split_sizes.push(existing_size);
}
}
trace!("Covered: {covered:?}");
let mut index = size.start_byte;
while index <= size.end_byte {
if !covered[index] {
let num = covered
.iter()
.skip(index)
.take(size.end_byte + 1 - index)
.take_while(|&b| !b)
.count();
let uncovered_size = Size::new(index, index + num - 1);
trace!("Adding uncovered {uncovered_size:?}");
split_sizes.push(uncovered_size);
index += num;
} else {
index += 1;
}
}
trace!("Result: {split_sizes:?}");
self.outputs.insert(location, split_sizes);
}
pub fn get(&self, loc: Dest<A>) -> impl Iterator<Item = Dest<A>> + '_ {
let loc_size = loc.size();
self.outputs
.get(&Location::from(loc))
.iter()
.flat_map(|v| v.iter())
.flat_map(move |size| {
if loc_size.contains(size) {
Some(loc.with_size(*size))
} else {
assert!(!loc_size.overlaps(size));
None
}
})
.collect::<Vec<_>>()
.into_iter()
}
pub fn iter(&self) -> impl Iterator<Item = Dest<A>> + '_ {
self.outputs
.iter()
.flat_map(|(loc, sizes)| sizes.iter().map(|&size| loc.into_dest_with_size(size)))
}
}