1use fuchsia_rcu::{RcuDroppable, RcuReadScope};
6use fuchsia_rcu_collections::rcu_raw_hash_map::{InsertionResult, RcuRawHashMap};
7use starnix_sync::Mutex;
8use std::borrow::Borrow;
9use std::hash::{BuildHasher, Hash};
10
11#[derive(RcuDroppable)]
20pub struct RcuHashMap<K, V, S = rapidhash::RapidBuildHasher>
21where
22 K: Eq + Hash + Clone + RcuDroppable + Sync,
23 V: Clone + RcuDroppable + Sync,
24 S: BuildHasher + Send + Sync + 'static,
25{
26 map: RcuRawHashMap<K, V, S>,
27 mutex: Mutex<()>,
28}
29
30impl<K, V> Default for RcuHashMap<K, V, rapidhash::RapidBuildHasher>
31where
32 K: Eq + Hash + Clone + RcuDroppable + Sync,
33 V: Clone + RcuDroppable + Sync,
34{
35 fn default() -> Self {
36 Self { map: Default::default(), mutex: Mutex::new(()) }
37 }
38}
39
40impl<K, V, S> RcuHashMap<K, V, S>
41where
42 K: Eq + Hash + Clone + RcuDroppable + Sync,
43 V: Clone + RcuDroppable + Sync,
44 S: BuildHasher + Send + Sync + 'static,
45{
46 pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self {
48 Self {
49 map: RcuRawHashMap::with_capacity_and_hasher(capacity, hash_builder),
50 mutex: Mutex::new(()),
51 }
52 }
53
54 pub fn with_hasher(hash_builder: S) -> Self {
56 Self { map: RcuRawHashMap::with_hasher(hash_builder), mutex: Mutex::new(()) }
57 }
58
59 pub fn get<'a, Q>(&self, scope: &'a RcuReadScope, key: &Q) -> Option<&'a V>
63 where
64 K: Borrow<Q>,
65 Q: ?Sized + Hash + Eq,
66 {
67 self.map.get(scope, key)
68 }
69
70 pub fn lock(&self) -> RcuHashMapGuard<'_, K, V, S> {
72 RcuHashMapGuard { map: &self.map, _guard: self.mutex.lock() }
73 }
74
75 pub fn insert(&self, key: K, value: V) -> Option<V> {
77 self.lock().insert(key, value)
78 }
79
80 pub fn remove<Q>(&self, key: &Q) -> Option<V>
82 where
83 K: Borrow<Q>,
84 Q: ?Sized + Hash + Eq,
85 {
86 self.lock().remove(key)
87 }
88
89 pub fn iter<'a>(&'a self, scope: &'a RcuReadScope) -> impl Iterator<Item = (&'a K, &'a V)> {
91 let mut cursor = self.map.cursor(scope);
92 std::iter::from_fn(move || {
93 let current = cursor.current();
94 if current.is_some() {
95 cursor.advance();
96 }
97 current
98 })
99 }
100
101 pub fn keys<'a>(&'a self, scope: &'a RcuReadScope) -> impl Iterator<Item = &'a K> {
103 self.iter(scope).map(|(k, _)| k)
104 }
105
106 pub fn len(&self) -> usize {
108 self.map.len()
109 }
110}
111
112impl<K, V, S> std::fmt::Debug for RcuHashMap<K, V, S>
114where
115 K: Eq + Hash + std::fmt::Debug + Clone + RcuDroppable + Sync,
116 V: std::fmt::Debug + Clone + RcuDroppable + Sync,
117 S: BuildHasher + Send + Sync + 'static,
118{
119 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120 f.debug_struct("RcuHashMap").field("map", &self.map).finish()
121 }
122}
123
124pub struct RcuHashMapGuard<'a, K, V, S = rapidhash::RapidBuildHasher>
126where
127 K: Eq + Hash + Clone + RcuDroppable + Sync,
128 V: Clone + RcuDroppable + Sync,
129 S: BuildHasher + Send + Sync + 'static,
130{
131 map: &'a RcuRawHashMap<K, V, S>,
132 _guard: starnix_sync::MutexGuard<'a, ()>,
133}
134
135impl<'a, K, V, S> RcuHashMapGuard<'a, K, V, S>
136where
137 K: Eq + Hash + Clone + RcuDroppable + Sync,
138 V: Clone + RcuDroppable + Sync,
139 S: BuildHasher + Send + Sync + 'static,
140{
141 pub fn get<Q>(&self, key: &Q) -> Option<V>
143 where
144 K: Borrow<Q>,
145 Q: ?Sized + Hash + Eq,
146 {
147 let scope = RcuReadScope::new();
148 self.map.get(&scope, key).cloned()
149 }
150
151 pub fn insert(&mut self, key: K, value: V) -> Option<V> {
153 let scope = RcuReadScope::new();
154 match unsafe { self.map.insert(&scope, key, value) } {
156 InsertionResult::Inserted(_) => None,
157 InsertionResult::Updated(old_value) => Some(old_value),
158 }
159 }
160
161 pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
163 where
164 K: Borrow<Q>,
165 Q: ?Sized + Hash + Eq,
166 {
167 unsafe { self.map.remove(key) }
169 }
170
171 pub fn drain<'b>(&'b mut self) -> impl Iterator<Item = (K, V)> + 'b {
173 let scope = RcuReadScope::new();
174 #[allow(clippy::needless_collect)]
176 let keys: Vec<_> = self.map.keys(&scope).map(Clone::clone).collect();
177 keys.into_iter().filter_map(move |k| self.remove(&k).map(|v| (k, v)))
178 }
179
180 pub fn contains_key<Q>(&self, key: &Q) -> bool
182 where
183 K: Borrow<Q>,
184 Q: ?Sized + Hash + Eq,
185 {
186 self.get(key).is_some()
187 }
188
189 pub fn entry<'b>(&'b mut self, key: K) -> Entry<'b, 'a, K, V, S> {
191 if self.get(&key).is_some() {
192 Entry::Occupied(OccupiedEntry { guard: self, key })
193 } else {
194 Entry::Vacant(VacantEntry { guard: self, key })
195 }
196 }
197}
198
199pub enum Entry<'b, 'a, K, V, S = rapidhash::RapidBuildHasher>
201where
202 K: Eq + Hash + Clone + RcuDroppable + Sync,
203 V: Clone + RcuDroppable + Sync,
204 S: BuildHasher + Send + Sync + 'static,
205{
206 Occupied(OccupiedEntry<'b, 'a, K, V, S>),
208 Vacant(VacantEntry<'b, 'a, K, V, S>),
210}
211
212impl<'b, 'a, K, V, S> Entry<'b, 'a, K, V, S>
213where
214 K: Eq + Hash + Clone + RcuDroppable + Sync,
215 V: Clone + RcuDroppable + Sync,
216 S: BuildHasher + Send + Sync + 'static,
217{
218 pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> OccupiedEntry<'b, 'a, K, V, S> {
221 match self {
222 Entry::Occupied(entry) => entry,
223 Entry::Vacant(entry) => entry.insert_entry(default()),
224 }
225 }
226}
227
228pub struct OccupiedEntry<'b, 'a, K, V, S = rapidhash::RapidBuildHasher>
230where
231 K: Eq + Hash + Clone + RcuDroppable + Sync,
232 V: Clone + RcuDroppable + Sync,
233 S: BuildHasher + Send + Sync + 'static,
234{
235 guard: &'b mut RcuHashMapGuard<'a, K, V, S>,
236 key: K,
237}
238
239impl<K, V, S> OccupiedEntry<'_, '_, K, V, S>
240where
241 K: Eq + Hash + Clone + RcuDroppable + Sync,
242 V: Clone + RcuDroppable + Sync,
243 S: BuildHasher + Send + Sync + 'static,
244{
245 pub fn get(&self) -> V {
247 self.guard.get(&self.key).unwrap()
248 }
249
250 pub fn insert(&mut self, value: V) -> V {
252 self.guard.insert(self.key.clone(), value).unwrap()
253 }
254
255 pub fn remove(self) -> V {
257 self.guard.remove(&self.key).unwrap()
258 }
259}
260
261pub struct VacantEntry<'b, 'a, K, V, S = rapidhash::RapidBuildHasher>
263where
264 K: Eq + Hash + Clone + RcuDroppable + Sync,
265 V: Clone + RcuDroppable + Sync,
266 S: BuildHasher + Send + Sync + 'static,
267{
268 guard: &'b mut RcuHashMapGuard<'a, K, V, S>,
269 key: K,
270}
271
272impl<'b, 'a, K, V, S> VacantEntry<'b, 'a, K, V, S>
273where
274 K: Eq + Hash + Clone + RcuDroppable + Sync,
275 V: Clone + RcuDroppable + Sync,
276 S: BuildHasher + Send + Sync + 'static,
277{
278 pub fn insert(self, value: V) {
280 self.guard.insert(self.key, value);
281 }
282
283 pub fn insert_entry(self, value: V) -> OccupiedEntry<'b, 'a, K, V, S> {
285 self.guard.insert(self.key.clone(), value);
286 OccupiedEntry { guard: self.guard, key: self.key }
287 }
288}
289
290#[cfg(test)]
291mod tests {
292 use super::*;
293 use fuchsia_rcu::rcu_run_callbacks;
294
295 #[test]
296 fn test_rcu_hash_map_custom_hasher() {
297 use std::collections::hash_map::DefaultHasher;
298 use std::hash::BuildHasherDefault;
299 let hasher = BuildHasherDefault::<DefaultHasher>::default();
300 let map = RcuHashMap::with_capacity_and_hasher(10, hasher);
301 let mut guard = map.lock();
302 guard.insert(1, 10);
303 assert_eq!(guard.get(&1), Some(10));
304 }
305
306 #[test]
307 fn test_rcu_hash_map_insert_and_get() {
308 let map = RcuHashMap::<i32, i32>::default();
309 let mut guard = map.lock();
310 let scope = RcuReadScope::new();
311
312 guard.insert(1, 10);
313 guard.insert(2, 20);
314
315 assert_eq!(guard.get(&1), Some(10));
316 assert_eq!(guard.get(&2), Some(20));
317 assert_eq!(guard.get(&3), None);
318
319 drop(guard);
321 assert_eq!(map.get(&scope, &1), Some(&10));
322 assert_eq!(map.get(&scope, &2), Some(&20));
323
324 drop(scope);
325 rcu_run_callbacks();
326 }
327
328 #[test]
329 fn test_rcu_hash_map_update() {
330 let map = RcuHashMap::<i32, i32>::default();
331 let mut guard = map.lock();
332 let scope = RcuReadScope::new();
333
334 guard.insert(1, 10);
335 assert_eq!(guard.get(&1), Some(10));
336
337 guard.insert(1, 20);
338 assert_eq!(guard.get(&1), Some(20));
339
340 drop(guard);
341 assert_eq!(map.get(&scope, &1), Some(&20));
342
343 drop(scope);
344 rcu_run_callbacks();
345 }
346
347 #[test]
348 fn test_rcu_hash_map_remove() {
349 let map = RcuHashMap::<i32, i32>::default();
350 let mut guard = map.lock();
351 let scope = RcuReadScope::new();
352
353 guard.insert(1, 10);
354 assert_eq!(guard.get(&1), Some(10));
355
356 guard.remove(&1);
357 assert_eq!(guard.get(&1), None);
358
359 drop(guard);
360 assert_eq!(map.get(&scope, &1), None);
361
362 drop(scope);
363 rcu_run_callbacks();
364 }
365
366 #[test]
367 fn test_rcu_hash_map_entry_api() {
368 let map = RcuHashMap::<i32, i32>::default();
369 let mut guard = map.lock();
370
371 match guard.entry(1) {
373 Entry::Vacant(e) => e.insert(10),
374 Entry::Occupied(_) => panic!("Should be vacant"),
375 }
376 assert_eq!(guard.get(&1), Some(10));
377
378 match guard.entry(1) {
380 Entry::Occupied(mut e) => {
381 assert_eq!(e.get(), 10);
382 e.insert(20);
383 }
384 Entry::Vacant(_) => panic!("Should be occupied"),
385 }
386 assert_eq!(guard.get(&1), Some(20));
387
388 drop(guard);
389 rcu_run_callbacks();
390 }
391
392 #[test]
393 fn test_rcu_hash_map_iter() {
394 let map = RcuHashMap::<i32, i32>::default();
395 let scope = RcuReadScope::new();
396 map.insert(1, 10);
397 map.insert(2, 20);
398 map.insert(3, 30);
399
400 let mut items: Vec<_> = map.iter(&scope).collect();
401 items.sort_by_key(|(k, _)| **k);
402 assert_eq!(items, vec![(&1, &10), (&2, &20), (&3, &30)]);
403 }
404
405 #[test]
406 fn test_rcu_hash_map_keys() {
407 let map = RcuHashMap::<i32, i32>::default();
408 let scope = RcuReadScope::new();
409 map.insert(1, 10);
410 map.insert(2, 20);
411 map.insert(3, 30);
412
413 let mut keys: Vec<_> = map.keys(&scope).collect();
414 keys.sort();
415 assert_eq!(keys, vec![&1, &2, &3]);
416 }
417
418 #[test]
419 fn test_rcu_hash_map_len() {
420 let map = RcuHashMap::<i32, i32>::default();
421 map.insert(1, 10);
422 map.insert(2, 20);
423 map.insert(3, 30);
424
425 assert_eq!(map.len(), 3);
426 }
427
428 #[test]
429 fn test_rcu_hash_map_or_insert_with() {
430 let map = RcuHashMap::<i32, i32>::default();
431 let mut guard = map.lock();
432
433 guard.entry(1).or_insert_with(|| 10);
435 assert!(guard.contains_key(&1));
436 assert_eq!(guard.get(&1), Some(10));
437
438 guard.entry(1).or_insert_with(|| 20);
440 assert_eq!(guard.get(&1), Some(10));
441
442 match guard.entry(1) {
444 Entry::Occupied(e) => {
445 assert_eq!(e.remove(), 10);
446 }
447 Entry::Vacant(_) => panic!("Should be occupied"),
448 }
449 assert!(!guard.contains_key(&1));
450 }
451
452 #[test]
453 fn test_rcu_hash_map_drain() {
454 let map = RcuHashMap::<i32, i32>::default();
455 let mut guard = map.lock();
456
457 guard.insert(1, 10);
458 guard.insert(2, 20);
459 guard.insert(3, 30);
460
461 let mut items: Vec<_> = guard.drain().collect();
462 items.sort_by_key(|(k, _)| *k);
463 assert_eq!(items, vec![(1, 10), (2, 20), (3, 30)]);
464
465 assert!(!guard.contains_key(&1));
466 assert!(!guard.contains_key(&2));
467 assert!(!guard.contains_key(&3));
468 }
469
470 #[test]
471 fn test_rcu_hash_map_capacity_zero() {
472 use std::collections::hash_map::RandomState;
473 let map =
474 RcuHashMap::<i32, i32, RandomState>::with_capacity_and_hasher(0, RandomState::new());
475 let mut guard = map.lock();
476
477 assert_eq!(guard.get(&1), None);
478
479 guard.insert(1, 10);
480 assert_eq!(guard.get(&1), Some(10));
481
482 guard.remove(&1);
483 assert_eq!(guard.get(&1), None);
484 }
485}