pub trait KeyEquivalence<K> {
fn equivalent(&self, left: &K, right: &K) -> bool;
}
impl<K, F> KeyEquivalence<K> for F
where
F: Fn(&K, &K) -> bool,
{
fn equivalent(&self, left: &K, right: &K) -> bool {
self(left, right)
}
}
#[derive(Clone, Debug)]
struct OrderedEntry<K, V> {
key: K,
value: Option<V>,
}
#[derive(Debug)]
struct OrderedState<K, V> {
entries: Vec<OrderedEntry<K, V>>,
live_len: usize,
active_iterators: Cell<usize>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CompactionResult {
Compacted(usize),
NotNeeded,
ActiveIterator,
BudgetExceeded {
required: usize,
},
}
#[derive(Debug)]
pub struct OrderedTable<K, V, E> {
state: Rc<RefCell<OrderedState<K, V>>>,
equivalence: E,
}
impl<K, V, E> OrderedTable<K, V, E>
where
E: KeyEquivalence<K>,
{
pub fn new(equivalence: E) -> Self {
Self {
state: Rc::new(RefCell::new(OrderedState {
entries: Vec::new(),
live_len: 0,
active_iterators: Cell::new(0),
})),
equivalence,
}
}
pub fn len(&self) -> usize {
self.state.borrow().live_len
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get(&self, key: &K) -> Option<V>
where
V: Clone,
{
let state = self.state.borrow();
state
.entries
.iter()
.find(|entry| entry.value.is_some() && self.equivalence.equivalent(&entry.key, key))
.and_then(|entry| entry.value.clone())
}
pub fn insert(&self, key: K, value: V) -> Option<V> {
let mut state = self.state.borrow_mut();
if let Some(entry) = state
.entries
.iter_mut()
.find(|entry| entry.value.is_some() && self.equivalence.equivalent(&entry.key, &key))
{
return entry.value.replace(value);
}
state.entries.push(OrderedEntry {
key,
value: Some(value),
});
state.live_len += 1;
None
}
pub fn remove(&self, key: &K) -> Option<V> {
let mut state = self.state.borrow_mut();
let removed = state
.entries
.iter_mut()
.find(|entry| entry.value.is_some() && self.equivalence.equivalent(&entry.key, key))?
.value
.take();
state.live_len -= 1;
removed
}
pub fn iter(&self) -> OrderedTableIter<K, V> {
let state = self.state.borrow();
state
.active_iterators
.set(state.active_iterators.get().saturating_add(1));
drop(state);
OrderedTableIter {
state: Rc::clone(&self.state),
next_slot: 0,
}
}
pub fn compact(&self, max_work: usize) -> CompactionResult {
let mut state = self.state.borrow_mut();
if state.active_iterators.get() != 0 {
return CompactionResult::ActiveIterator;
}
let required = state.entries.len();
if required == state.live_len {
return CompactionResult::NotNeeded;
}
if required > max_work {
return CompactionResult::BudgetExceeded { required };
}
let removed = required - state.live_len;
state.entries.retain(|entry| entry.value.is_some());
CompactionResult::Compacted(removed)
}
#[cfg(test)]
fn slot_len(&self) -> usize {
self.state.borrow().entries.len()
}
}
pub struct OrderedTableIter<K, V> {
state: Rc<RefCell<OrderedState<K, V>>>,
next_slot: usize,
}
impl<K, V> Clone for OrderedTableIter<K, V> {
fn clone(&self) -> Self {
let state = self.state.borrow();
state
.active_iterators
.set(state.active_iterators.get().saturating_add(1));
drop(state);
Self {
state: Rc::clone(&self.state),
next_slot: self.next_slot,
}
}
}
impl<K, V> Iterator for OrderedTableIter<K, V>
where
K: Clone,
V: Clone,
{
type Item = (K, V);
fn next(&mut self) -> Option<Self::Item> {
let state = self.state.borrow();
while self.next_slot < state.entries.len() {
let slot = self.next_slot;
self.next_slot += 1;
let entry = &state.entries[slot];
if let Some(value) = &entry.value {
return Some((entry.key.clone(), value.clone()));
}
}
None
}
}
impl<K, V> Drop for OrderedTableIter<K, V> {
fn drop(&mut self) {
let state = self.state.borrow();
state
.active_iterators
.set(state.active_iterators.get().saturating_sub(1));
}
}