use std::collections::{BTreeMap, BTreeSet};
use crate::value::Value;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Address(usize);
impl Address {
#[must_use]
pub fn value(&self) -> usize {
self.0
}
}
impl From<usize> for Address {
fn from(value: usize) -> Self {
Self(value)
}
}
impl std::fmt::Display for Address {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "#{}", self.0)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Heap {
cells: BTreeMap<Address, Value>,
next: usize,
}
impl Heap {
#[must_use]
pub fn empty() -> Self {
Self {
cells: BTreeMap::new(),
next: 0,
}
}
#[must_use]
pub fn len(&self) -> usize {
self.cells.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.cells.is_empty()
}
#[must_use]
pub fn contains(&self, address: Address) -> bool {
self.cells.contains_key(&address)
}
pub fn addresses(&self) -> impl Iterator<Item = Address> + '_ {
self.cells.keys().copied()
}
#[must_use]
pub fn alloc(&self, value: Value) -> (Self, Address) {
let addr = Address(self.next);
let cells: BTreeMap<Address, Value> = self
.cells
.iter()
.map(|(k, v)| (*k, v.clone()))
.chain(std::iter::once((addr, value)))
.collect();
(
Self {
cells,
next: self.next + 1,
},
addr,
)
}
#[must_use]
pub fn load(&self, address: Address) -> Option<&Value> {
self.cells.get(&address)
}
#[must_use]
pub fn store(&self, address: Address, value: Value) -> Option<Self> {
self.cells.contains_key(&address).then(|| {
let cells: BTreeMap<Address, Value> = self
.cells
.iter()
.filter(|(k, _)| **k != address)
.map(|(k, v)| (*k, v.clone()))
.chain(std::iter::once((address, value)))
.collect();
Self {
cells,
next: self.next,
}
})
}
#[must_use]
pub fn retain(&self, live: &BTreeSet<Address>) -> Self {
let cells: BTreeMap<Address, Value> = self
.cells
.iter()
.filter(|(k, _)| live.contains(k))
.map(|(k, v)| (*k, v.clone()))
.collect();
Self {
cells,
next: self.next,
}
}
}
impl Default for Heap {
fn default() -> Self {
Self::empty()
}
}
impl std::fmt::Display for Heap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let entries = self
.cells
.iter()
.map(|(k, v)| format!("{k} = {v}"))
.collect::<Vec<_>>()
.join(", ");
write!(f, "[{entries}]")
}
}