use crate::*;
pub(crate) const MAX_PINNED_PAGES: usize = 4;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub(crate) enum Spans {
Any,
Pages { pages: usize, unaligned: usize },
}
impl Spans {
pub(crate) fn shifted(self) -> Spans {
match self {
Spans::Pages { unaligned, .. } if unaligned <= MAX_PINNED_PAGES => Spans::Pages {
pages: unaligned,
unaligned,
},
_ => Spans::Any,
}
}
pub(crate) fn pages(self) -> usize {
match self {
Spans::Any => 0,
Spans::Pages { pages, .. } => pages,
}
}
}
fn pages_reached(positions: usize, alignment: usize, page_size: usize) -> usize {
(page_size - alignment + positions.max(1) - 1) / page_size + 1
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub(crate) struct PagedWindow {
pub(crate) sequences: Option<usize>,
pub(crate) positions: Option<usize>,
pub(crate) origin_alignment: usize,
}
impl PagedWindow {
pub(crate) fn spans(&self, page_size: usize) -> Spans {
match (self.sequences, self.positions) {
(Some(1), Some(positions)) => {
let alignment = gcd(self.origin_alignment, page_size);
match pages_reached(positions, alignment, page_size) {
pages if pages <= MAX_PINNED_PAGES => Spans::Pages {
pages,
unaligned: pages_reached(positions, 1, page_size),
},
_ => Spans::Any,
}
}
_ => Spans::Any,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub(crate) enum Pin {
Kept,
Resolved(Spans),
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub(crate) enum WindowCut {
Unmoved,
Level {
edges: Vec<Option<usize>>,
nested: bool,
},
Shifted,
}
#[cfg(test)]
mod tests {
use super::*;
fn window(sequences: usize, positions: usize, origin_alignment: usize) -> PagedWindow {
PagedWindow {
sequences: Some(sequences),
positions: Some(positions),
origin_alignment,
}
}
fn pages(pages: usize, unaligned: usize) -> Spans {
Spans::Pages { pages, unaligned }
}
#[test]
fn a_window_is_inside_one_page_only_where_its_alignment_proves_it() {
assert_eq!(window(1, 16, 0).spans(64), pages(1, 2));
assert_eq!(window(1, 16, 16).spans(64), pages(1, 2));
assert_eq!(window(1, 64, 128).spans(64), pages(1, 2));
assert_eq!(window(1, 16, 4).spans(64), pages(2, 2));
assert_eq!(window(1, 48, 48).spans(64), pages(2, 2));
assert_eq!(window(1, 80, 16).spans(64), pages(2, 3));
assert_eq!(window(2, 4, 0).spans(64), Spans::Any);
let unfixed = PagedWindow {
sequences: Some(1),
positions: None,
origin_alignment: 0,
};
assert_eq!(unfixed.spans(64), Spans::Any);
}
#[test]
fn a_window_wider_than_a_page_pins_the_pages_it_reaches() {
assert_eq!(window(1, 128, 0).spans(64), pages(2, 3));
assert_eq!(window(1, 64, 0).spans(16), pages(4, 5));
assert_eq!(window(1, 64, 16).spans(16), pages(4, 5));
assert_eq!(window(1, 64, 8).spans(16), Spans::Any);
assert_eq!(window(1, 128, 0).spans(16), Spans::Any);
}
#[test]
fn a_shifted_window_keeps_its_extent_not_its_page() {
assert_eq!(pages(1, 2).shifted(), pages(2, 2));
assert_eq!(pages(2, 2).shifted(), pages(2, 2));
assert_eq!(pages(4, 5).shifted(), Spans::Any);
assert_eq!(Spans::Any.shifted(), Spans::Any);
}
}