Skip to main content

versatile_dataloader/
cache.rs

1use std::{
2    borrow::Cow,
3    collections::{HashMap, hash_map::RandomState},
4    hash::{BuildHasher, Hash},
5    marker::PhantomData,
6    num::NonZeroUsize,
7};
8
9/// Factory for creating cache storage.
10pub trait CacheFactory: Send + Sync + 'static {
11    /// Create a cache storage.
12    ///
13    /// TODO: When GAT is stable, this memory allocation can be optimized away.
14    fn create<K, V>(&self) -> Box<dyn CacheStorage<Key = K, Value = V>>
15    where
16        K: Send + Sync + Clone + Eq + Hash + 'static,
17        V: Send + Sync + Clone + 'static;
18}
19
20/// Cache storage for [`crate::DataLoader`].
21pub trait CacheStorage: Send + Sync + 'static {
22    /// The key type of the record.
23    type Key: Send + Sync + Clone + Eq + Hash + 'static;
24
25    /// The value type of the record.
26    type Value: Send + Sync + Clone + 'static;
27
28    /// Returns a reference to the value of the key in the cache or None if it
29    /// is not present in the cache.
30    fn get(&mut self, key: &Self::Key) -> Option<&Self::Value>;
31
32    /// Puts a key-value pair into the cache. If the key already exists in the
33    /// cache, then it updates the key's value.
34    fn insert(&mut self, key: Cow<'_, Self::Key>, val: Cow<'_, Self::Value>);
35
36    /// Removes the value corresponding to the key from the cache.
37    fn remove(&mut self, key: &Self::Key);
38
39    /// Clears the cache, removing all key-value pairs.
40    fn clear(&mut self);
41
42    /// Returns an iterator over the key-value pairs in the cache.
43    fn iter(&self) -> Box<dyn Iterator<Item = (&'_ Self::Key, &'_ Self::Value)> + '_>;
44}
45
46/// No cache.
47pub struct NoCache;
48
49impl CacheFactory for NoCache {
50    fn create<K, V>(&self) -> Box<dyn CacheStorage<Key = K, Value = V>>
51    where
52        K: Send + Sync + Clone + Eq + Hash + 'static,
53        V: Send + Sync + Clone + 'static,
54    {
55        Box::new(NoCacheImpl {
56            _mark1: PhantomData,
57            _mark2: PhantomData,
58        })
59    }
60}
61
62struct NoCacheImpl<K, V> {
63    _mark1: PhantomData<K>,
64    _mark2: PhantomData<V>,
65}
66
67impl<K, V> CacheStorage for NoCacheImpl<K, V>
68where
69    K: Send + Sync + Clone + Eq + Hash + 'static,
70    V: Send + Sync + Clone + 'static,
71{
72    type Key = K;
73    type Value = V;
74
75    #[inline]
76    fn get(&mut self, _key: &K) -> Option<&V> {
77        None
78    }
79
80    #[inline]
81    fn insert(&mut self, _key: Cow<'_, Self::Key>, _val: Cow<'_, Self::Value>) {}
82
83    #[inline]
84    fn remove(&mut self, _key: &K) {}
85
86    #[inline]
87    fn clear(&mut self) {}
88
89    fn iter(&self) -> Box<dyn Iterator<Item = (&'_ Self::Key, &'_ Self::Value)> + '_> {
90        Box::new(std::iter::empty())
91    }
92}
93
94/// [`std::collections::HashMap`] cache.
95pub struct HashMapCache<S = RandomState> {
96    _mark: PhantomData<S>,
97}
98
99impl<S: Send + Sync + BuildHasher + Default + 'static> HashMapCache<S> {
100    /// Use specified `S: BuildHasher` to create a `HashMap` cache.
101    #[must_use]
102    pub fn new() -> Self {
103        Self { _mark: PhantomData }
104    }
105}
106
107impl Default for HashMapCache<RandomState> {
108    fn default() -> Self {
109        Self { _mark: PhantomData }
110    }
111}
112
113impl<S: Send + Sync + BuildHasher + Default + 'static> CacheFactory for HashMapCache<S> {
114    fn create<K, V>(&self) -> Box<dyn CacheStorage<Key = K, Value = V>>
115    where
116        K: Send + Sync + Clone + Eq + Hash + 'static,
117        V: Send + Sync + Clone + 'static,
118    {
119        Box::new(HashMapCacheImpl::<K, V, S>(HashMap::<K, V, S>::default()))
120    }
121}
122
123struct HashMapCacheImpl<K, V, S>(HashMap<K, V, S>);
124
125impl<K, V, S> CacheStorage for HashMapCacheImpl<K, V, S>
126where
127    K: Send + Sync + Clone + Eq + Hash + 'static,
128    V: Send + Sync + Clone + 'static,
129    S: Send + Sync + BuildHasher + 'static,
130{
131    type Key = K;
132    type Value = V;
133
134    #[inline]
135    fn get(&mut self, key: &Self::Key) -> Option<&Self::Value> {
136        self.0.get(key)
137    }
138
139    #[inline]
140    fn insert(&mut self, key: Cow<'_, Self::Key>, val: Cow<'_, Self::Value>) {
141        self.0.insert(key.into_owned(), val.into_owned());
142    }
143
144    #[inline]
145    fn remove(&mut self, key: &Self::Key) {
146        self.0.remove(key);
147    }
148
149    #[inline]
150    fn clear(&mut self) {
151        self.0.clear();
152    }
153
154    fn iter(&self) -> Box<dyn Iterator<Item = (&'_ Self::Key, &'_ Self::Value)> + '_> {
155        Box::new(self.0.iter())
156    }
157}
158
159/// LRU cache.
160pub struct LruCache {
161    cap: usize,
162}
163
164impl LruCache {
165    /// Creates a new LRU Cache that holds at most `cap` items.
166    #[must_use]
167    pub fn new(cap: usize) -> Self {
168        Self { cap }
169    }
170}
171
172impl CacheFactory for LruCache {
173    fn create<K, V>(&self) -> Box<dyn CacheStorage<Key = K, Value = V>>
174    where
175        K: Send + Sync + Clone + Eq + Hash + 'static,
176        V: Send + Sync + Clone + 'static,
177    {
178        Box::new(LruCacheImpl(lru::LruCache::new(
179            NonZeroUsize::new(self.cap).unwrap(),
180        )))
181    }
182}
183
184struct LruCacheImpl<K, V>(lru::LruCache<K, V>);
185
186impl<K, V> CacheStorage for LruCacheImpl<K, V>
187where
188    K: Send + Sync + Clone + Eq + Hash + 'static,
189    V: Send + Sync + Clone + 'static,
190{
191    type Key = K;
192    type Value = V;
193
194    #[inline]
195    fn get(&mut self, key: &Self::Key) -> Option<&Self::Value> {
196        self.0.get(key)
197    }
198
199    #[inline]
200    fn insert(&mut self, key: Cow<'_, Self::Key>, val: Cow<'_, Self::Value>) {
201        self.0.put(key.into_owned(), val.into_owned());
202    }
203
204    #[inline]
205    fn remove(&mut self, key: &Self::Key) {
206        self.0.pop(key);
207    }
208
209    #[inline]
210    fn clear(&mut self) {
211        self.0.clear();
212    }
213
214    fn iter(&self) -> Box<dyn Iterator<Item = (&'_ Self::Key, &'_ Self::Value)> + '_> {
215        Box::new(self.0.iter())
216    }
217}