use dashmap::DashMap; use std::ops::Deref; use std::sync::Arc; use std::{collections::hash_map::RandomState, hash::Hash}; use std::{hash::BuildHasher, marker::PhantomData};
/// An insert-only map for caching the result of functions pubstruct CacheMap<K: Hash + Eq, V: ?Sized, S = RandomState> {
inner: DashMap<K, Arc<V>, S>,
}
/// A handle that can be converted to a &T or an Arc<T> pubstruct ArcRef<'a, T: ?Sized> { // this pointer never gets dereferenced, but it has to be T, so that Ref is the right size for wide pointers #[allow(dead_code)]
fake_ptr: *const T,
phantom: PhantomData<&'a T>,
}
impl<K: Hash + Eq, V, S: BuildHasher + Clone> CacheMap<K, V, S> { /// Fetch the value associated with the key, or run the provided function to insert one. /// /// # Example /// /// ``` /// use cachemap2::CacheMap; /// /// let m = CacheMap::new(); /// /// let fst = m.cache("key", || 5u32).as_ref(); /// let snd = m.cache("key", || 7u32).as_ref(); /// /// assert_eq!(*fst, *snd); /// assert_eq!(*fst, 5u32); /// ``` pubfn cache<F: FnOnce() -> V>(&self, key: K, f: F) -> ArcRef<'_, V> { self.cache_arc(key, || Arc::new(f()))
}
/// Fetch the value associated with the key, or insert a default value. pubfn cache_default(&self, key: K) -> ArcRef<'_, V> where
V: Default,
{ self.cache(key, || Default::default())
}
/// Return whether the map contains the given key. pubfn contains_key<Q: ?Sized>(&self, key: &Q) -> bool where
K: std::borrow::Borrow<Q>,
Q: Hash + Eq,
{ self.inner.contains_key(key)
}
}
impl<K: Hash + Eq, V: ?Sized, S: BuildHasher + Clone> CacheMap<K, V, S> { /// Creates a new CacheMap with the provided hasher pubfn with_hasher(hash_builder: S) -> Self { Self {
inner: DashMap::with_hasher(hash_builder),
}
}
/// Fetch the value associated with the key, or run the provided function to insert one. /// With this version, the function returns an Arc<V>, whch allows caching unsized types. /// /// # Example /// /// ``` /// use cachemap2::CacheMap; /// /// let m: CacheMap<_, [usize]> = CacheMap::new(); /// /// let a = m.cache_arc("a", || { /// let a = &[1,2,3][..]; /// a.into() /// }).as_ref(); /// /// let b = m.cache_arc("b", || { /// let b = &[9,9][..]; /// b.into() /// }).as_ref(); /// /// assert_eq!(a, &[1,2,3]); /// assert_eq!(b, &[9,9]); /// ``` pubfn cache_arc<F: FnOnce() -> Arc<V>>(&self, key: K, f: F) -> ArcRef<'_, V> { let val = self.inner.entry(key).or_insert_with(f); let arc: &Arc<V> = &*val; let arc_ref: &ArcRef<'_, V> = unsafe { std::mem::transmute(arc) };
*arc_ref
}
}
#[cfg(test)] mod tests { usesuper::*;
#[test] fn single_insert() { let m = CacheMap::new();
let a = m.cache("key", || 21u32).as_ref();
assert_eq!(21, *a);
}
#[test] fn contains_key() { let m = CacheMap::new();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.