use std::{ops::Deref, sync::Arc};
use arc_swap::ArcSwap;
use smallvec::SmallVec;
#[derive(Debug)]
pub struct FrimMap<K, V>
where
K: Clone + PartialEq,
V: Clone,
{
inner: ArcSwap<SmallVec<[(K, V); 8]>>,
}
impl<K, V> Default for FrimMap<K, V>
where
K: Clone + PartialEq,
V: Clone,
{
fn default() -> Self {
Self {
inner: ArcSwap::new(Arc::new(SmallVec::<[(K, V); 8]>::new())),
}
}
}
pub struct IterGuard<K, V>
where
K: Clone + PartialEq,
V: Clone,
{
#[allow(clippy::type_complexity)]
guard: arc_swap::Guard<Arc<SmallVec<[(K, V); 8]>>>,
}
impl<K, V> IterGuard<K, V>
where
K: Clone + PartialEq,
V: Clone,
{
pub fn iter(&self) -> Iter<'_, K, V> {
Iter {
iter: self.guard.iter(),
}
}
}
pub struct Iter<'a, K, V> {
iter: std::slice::Iter<'a, (K, V)>,
}
impl<'a, K, V> Iterator for Iter<'a, K, V> {
type Item = &'a (K, V);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
}
pub enum Entry<'a, K, V>
where
K: Clone + PartialEq,
V: Clone,
{
Occupied(V),
Vacant(&'a FrimMap<K, V>, K),
}
impl<'a, K, V> Entry<'a, K, V>
where
K: Clone + PartialEq,
V: Clone,
{
pub fn or_insert_with<F>(self, default: F) -> V
where
F: FnOnce() -> V,
{
match self {
Entry::Occupied(v) => v,
Entry::Vacant(map, key) => {
let v = default();
map.insert(key, v.clone());
v
}
}
}
}
impl<K, V> FrimMap<K, V>
where
K: Clone + PartialEq,
V: Clone,
{
pub fn len(&self) -> usize {
self.inner.load().len()
}
#[allow(dead_code)]
pub fn is_empty(&self) -> bool {
self.inner.load().is_empty()
}
pub fn guard(&self) -> IterGuard<K, V> {
IterGuard {
guard: self.inner.load(),
}
}
pub fn contains_key(&self, key: &K) -> bool {
self.get(key).is_some()
}
pub fn get(&self, key: &K) -> Option<V> {
self.inner
.load()
.iter()
.find(|(k, _v)| k == key)
.map(|(_k, v)| v.clone())
}
pub fn entry(&self, key: K) -> Entry<K, V> {
match self.get(&key) {
Some(v) => Entry::Occupied(v),
None => Entry::Vacant(self, key),
}
}
pub fn insert(&self, key: K, value: V) {
self.inner.rcu(|inner| {
inner
.iter()
.filter(|(k, _v)| k != &key)
.chain(&[(key.clone(), value.clone())])
.cloned()
.collect::<SmallVec<_>>()
});
}
pub fn retain<F>(&self, mut f: F)
where
F: FnMut(&K, &V) -> bool,
{
self.inner.rcu(|inner| {
inner
.iter()
.filter(|(k, v)| f(k, v))
.cloned()
.collect::<SmallVec<_>>()
});
}
pub fn replace(&self, new: Self) {
self.inner.store(new.inner.into_inner())
}
pub fn remove(&self, key: &K) -> Option<V> {
let mut found = None;
self.inner.rcu(|inner| {
let mut new = inner.deref().clone();
if let Some(pos) = inner.iter().position(|(k, _v)| k == key) {
let (_, v) = new.remove(pos);
found = Some(v);
}
new
});
found
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn frim_map_tests() {
let map = FrimMap::<u8, u8>::default();
assert_eq!(map.len(), 0);
assert_eq!(map.guard().iter().next(), None);
map.insert(1, 1);
assert_eq!(map.len(), 1);
map.insert(1, 2);
assert_eq!(map.len(), 1);
map.insert(3, 4);
assert_eq!(map.len(), 2);
map.insert(5, 6);
assert_eq!(map.len(), 3);
let guard = map.guard();
let mut iter = guard.iter();
assert_eq!(iter.next(), Some(&(1, 2)));
assert_eq!(iter.next(), Some(&(3, 4)));
assert_eq!(iter.next(), Some(&(5, 6)));
assert_eq!(iter.next(), None);
assert_eq!(map.remove(&1), Some(2));
assert_eq!(map.len(), 2);
assert_eq!(map.remove(&1), None);
assert_eq!(map.len(), 2);
map.retain(|&k, &v| k == 3 && v == 4);
assert_eq!(map.len(), 1);
let map2 = FrimMap::<u8, u8>::default();
map2.insert(1, 1);
map2.insert(2, 2);
map.replace(map2);
assert_eq!(map.len(), 2);
let guard = map.guard();
let mut iter = guard.iter();
assert_eq!(iter.next(), Some(&(1, 1)));
assert_eq!(iter.next(), Some(&(2, 2)));
assert_eq!(iter.next(), None);
}
}