use crate::memory_management::ManagedMemoryHandle;
use crate::memory_management::memory_pool::MemoryPage;
use alloc::vec::Vec;
#[derive(Debug)]
pub struct OutdatedPages {
pages: Vec<MovablePage>,
}
#[derive(Debug)]
pub struct MovablePage {
pub live: Vec<LiveAllocation>,
}
#[derive(Debug)]
pub struct LiveAllocation {
pub handle: ManagedMemoryHandle,
pub size: u64,
}
impl OutdatedPages {
pub fn new<'a>(pages: impl IntoIterator<Item = &'a MemoryPage>) -> Self {
Self {
pages: pages
.into_iter()
.filter(|page| !page.is_guarded())
.filter_map(MovablePage::new)
.collect(),
}
}
pub fn plan(mut self) -> Vec<MovablePage> {
self.pages.sort_by_key(MovablePage::live_bytes);
self.pages
}
}
impl MovablePage {
fn new(page: &MemoryPage) -> Option<Self> {
if page.live().any(|slice| slice.handle.is_bound()) {
return None;
}
let live: Vec<_> = page
.live()
.map(|slice| LiveAllocation {
handle: slice.handle.clone(),
size: slice.storage.size(),
})
.collect();
(!live.is_empty()).then_some(Self { live })
}
pub fn live_bytes(&self) -> u64 {
self.live.iter().map(|allocation| allocation.size).sum()
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
#[test]
fn the_plan_empties_the_cheapest_pages_first() {
let plan = OutdatedPages {
pages: vec![movable(&[3, 2]), movable(&[1]), movable(&[4])],
}
.plan();
assert_eq!(sizes(&plan), [vec![1], vec![4], vec![3, 2]]);
}
fn movable(sizes: &[u64]) -> MovablePage {
MovablePage {
live: sizes
.iter()
.map(|&size| LiveAllocation {
handle: ManagedMemoryHandle::new(),
size,
})
.collect(),
}
}
fn sizes(plan: &[MovablePage]) -> Vec<Vec<u64>> {
plan.iter()
.map(|page| page.live.iter().map(|allocation| allocation.size).collect())
.collect()
}
}