use std::collections::BTreeMap;
#[derive(Default, Clone, Copy)]
pub struct AccessSet(u8);
impl AccessSet {
pub const READ: Self = Self(1 << 0);
pub const WRITTEN: Self = Self(1 << 1);
pub const MODIFIED: Self = Self(1 << 2);
pub fn accessed(&self) -> bool {
self.0 != 0
}
pub fn read(&self) -> bool {
self.0 & Self::READ.0 != 0
}
pub fn written(&self) -> bool {
self.0 & Self::WRITTEN.0 != 0
}
pub fn modified(&self) -> bool {
self.0 & Self::MODIFIED.0 != 0
}
}
impl std::ops::BitOr for AccessSet {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl std::ops::BitOrAssign for AccessSet {
fn bitor_assign(&mut self, rhs: Self) {
*self = *self | rhs;
}
}
impl std::fmt::Debug for AccessSet {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AccessFlags")
.field("accessed", &self.accessed())
.field("read", &self.read())
.field("written", &self.written())
.field("modified", &self.modified())
.finish()
}
}
#[derive(Debug)]
pub struct AccessObserver {
mem: BTreeMap<u16, AccessSet>
}
impl AccessObserver {
pub fn new() -> Self {
Self {
mem: Default::default()
}
}
pub fn clear(&mut self) {
std::mem::take(self);
}
pub fn get_mem_accesses(&self, addr: u16) -> AccessSet {
self.mem.get(&addr).copied().unwrap_or_default()
}
pub fn update_mem_accesses(&mut self, addr: u16, set: AccessSet) {
*self.mem.entry(addr).or_default() |= set;
}
pub fn take_mem_accesses(&mut self) -> impl Iterator<Item=(u16, AccessSet)> {
std::mem::take(&mut self.mem).into_iter()
}
}
impl Default for AccessObserver {
fn default() -> Self {
Self::new()
}
}