pub(super) struct FrameBuffer<T> {
entries: Vec<Entry<T>>,
next_free: usize,
len: usize,
}
enum Entry<T> {
Vacant(usize),
Occupied { value: T, next: usize },
}
pub(super) struct Deque {
head: usize,
tail: usize,
}
const NONE: usize = usize::MAX;
impl<T> FrameBuffer<T> {
pub(super) const fn new() -> Self {
Self {
entries: Vec::new(),
next_free: NONE,
len: 0,
}
}
fn insert(&mut self, value: T) -> usize {
self.len += 1;
if self.next_free != NONE {
let idx = self.next_free;
match &self.entries[idx] {
Entry::Vacant(next) => self.next_free = *next,
Entry::Occupied { .. } => unreachable!("free-list slot is occupied"),
}
self.entries[idx] = Entry::Occupied { value, next: NONE };
idx
} else {
let idx = self.entries.len();
self.entries.push(Entry::Occupied { value, next: NONE });
idx
}
}
fn remove(&mut self, idx: usize) -> T {
self.len -= 1;
let entry = core::mem::replace(&mut self.entries[idx], Entry::Vacant(self.next_free));
self.next_free = idx;
match entry {
Entry::Occupied { value, .. } => value,
Entry::Vacant(_) => unreachable!("removed slot was already vacant"),
}
}
}
impl Deque {
pub(super) fn new() -> Self {
Self { head: NONE, tail: NONE }
}
pub(super) fn is_empty(&self) -> bool {
self.head == NONE
}
pub(super) fn push_back<T>(&mut self, buf: &mut FrameBuffer<T>, value: T) {
let key = buf.insert(value);
if self.tail != NONE {
match &mut buf.entries[self.tail] {
Entry::Occupied { next, .. } => *next = key,
Entry::Vacant(_) => unreachable!("deque tail points at vacant slot"),
}
self.tail = key;
} else {
self.head = key;
self.tail = key;
}
}
pub(super) fn pop_front<T>(&mut self, buf: &mut FrameBuffer<T>) -> Option<T> {
if self.head == NONE {
return None;
}
let idx = self.head;
let next = match &buf.entries[idx] {
Entry::Occupied { next, .. } => *next,
Entry::Vacant(_) => unreachable!("deque head points at vacant slot"),
};
if next == NONE {
self.tail = NONE;
}
self.head = next;
Some(buf.remove(idx))
}
pub(super) fn clear<T>(&mut self, buf: &mut FrameBuffer<T>) {
while self.pop_front(buf).is_some() {}
}
}