use std::{fmt, u32};
use std::marker::PhantomData;
#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
struct Epoch(u32);
impl Epoch {
fn new() -> Self {
Epoch(1)
}
fn invalid() -> Self {
Epoch(0)
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(MallocSizeOf)]
pub struct FreeListHandle<M> {
index: u32,
epoch: Epoch,
_marker: PhantomData<M>,
}
impl<M> fmt::Debug for FreeListHandle<M> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("StrongHandle")
.field("index", &self.index)
.field("epoch", &self.epoch.0)
.finish()
}
}
impl<M> FreeListHandle<M> {
pub fn weak(&self) -> WeakFreeListHandle<M> {
WeakFreeListHandle {
index: self.index,
epoch: self.epoch,
_marker: PhantomData,
}
}
pub fn invalid() -> Self {
Self {
index: 0,
epoch: Epoch::invalid(),
_marker: PhantomData,
}
}
pub fn matches(&self, weak_handle: &WeakFreeListHandle<M>) -> bool {
self.index == weak_handle.index &&
self.epoch == weak_handle.epoch
}
}
impl<M> Clone for WeakFreeListHandle<M> {
fn clone(&self) -> Self {
WeakFreeListHandle {
index: self.index,
epoch: self.epoch,
_marker: PhantomData,
}
}
}
impl<M> PartialEq for WeakFreeListHandle<M> {
fn eq(&self, other: &Self) -> bool {
self.index == other.index && self.epoch == other.epoch
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(MallocSizeOf)]
pub struct WeakFreeListHandle<M> {
index: u32,
epoch: Epoch,
_marker: PhantomData<M>,
}
impl<M> fmt::Debug for WeakFreeListHandle<M> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("WeakHandle")
.field("index", &self.index)
.field("epoch", &self.epoch.0)
.finish()
}
}
impl<M> WeakFreeListHandle<M> {
pub fn invalid() -> Self {
Self {
index: 0,
epoch: Epoch::invalid(),
_marker: PhantomData,
}
}
}
#[derive(Debug, MallocSizeOf)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
struct Slot<T> {
next: Option<u32>,
epoch: Epoch,
value: Option<T>,
}
#[derive(Debug, MallocSizeOf)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct FreeList<T, M> {
slots: Vec<Slot<T>>,
free_list_head: Option<u32>,
active_count: usize,
_marker: PhantomData<M>,
}
impl<T, M> FreeList<T, M> {
pub fn new() -> Self {
let first_slot = Slot {
next: None,
epoch: Epoch::new(),
value: None,
};
FreeList {
slots: vec![first_slot],
free_list_head: Some(0),
active_count: 0,
_marker: PhantomData,
}
}
pub fn clear(&mut self) {
self.slots.truncate(1);
self.slots[0] = Slot {
next: None,
epoch: Epoch::new(),
value: None,
};
self.free_list_head = Some(0);
self.active_count = 0;
}
#[allow(dead_code)]
pub fn get(&self, id: &FreeListHandle<M>) -> &T {
self.slots[id.index as usize].value.as_ref().unwrap()
}
#[allow(dead_code)]
pub fn get_mut(&mut self, id: &FreeListHandle<M>) -> &mut T {
self.slots[id.index as usize].value.as_mut().unwrap()
}
pub fn get_opt(&self, id: &WeakFreeListHandle<M>) -> Option<&T> {
let slot = &self.slots[id.index as usize];
if slot.epoch == id.epoch {
slot.value.as_ref()
} else {
None
}
}
pub fn get_opt_mut(&mut self, id: &WeakFreeListHandle<M>) -> Option<&mut T> {
let slot = &mut self.slots[id.index as usize];
if slot.epoch == id.epoch {
slot.value.as_mut()
} else {
None
}
}
pub fn insert(&mut self, item: T) -> FreeListHandle<M> {
self.active_count += 1;
match self.free_list_head {
Some(free_index) => {
let slot = &mut self.slots[free_index as usize];
self.free_list_head = slot.next;
slot.next = None;
slot.value = Some(item);
FreeListHandle {
index: free_index,
epoch: slot.epoch,
_marker: PhantomData,
}
}
None => {
let index = self.slots.len() as u32;
let epoch = Epoch::new();
self.slots.push(Slot {
next: None,
epoch,
value: Some(item),
});
FreeListHandle {
index,
epoch,
_marker: PhantomData,
}
}
}
}
pub fn free(&mut self, id: FreeListHandle<M>) -> T {
self.active_count -= 1;
let slot = &mut self.slots[id.index as usize];
slot.next = self.free_list_head;
slot.epoch = Epoch(slot.epoch.0 + 1);
self.free_list_head = Some(id.index);
slot.value.take().unwrap()
}
#[allow(dead_code)]
pub fn len(&self) -> usize {
self.active_count
}
}