1use fuchsia_rcu::{RcuDroppable, RcuReadScope};
6use fuchsia_rcu_collections::rcu_raw_hash_map::{InsertionResult, RcuRawHashMap};
7use starnix_sync::{DynamicLockDepMutex, LockDepGuard, LockLevel, RcuHashMapLock};
8use std::borrow::Borrow;
9use std::hash::{BuildHasher, Hash};
10use std::marker::PhantomData;
11use std::ops::Deref;
12
13#[derive(RcuDroppable)]
16pub struct DynamicRcuHashMap<K, V, S = rapidhash::RapidBuildHasher>
17where
18 K: Eq + Hash + Clone + RcuDroppable + Sync,
19 V: Clone + RcuDroppable + Sync,
20 S: BuildHasher + Send + Sync + 'static,
21{
22 map: RcuRawHashMap<K, V, S>,
23 mutex: DynamicLockDepMutex<()>,
24}
25
26impl<K, V> Default for DynamicRcuHashMap<K, V, rapidhash::RapidBuildHasher>
27where
28 K: Eq + Hash + Clone + RcuDroppable + Sync,
29 V: Clone + RcuDroppable + Sync,
30{
31 fn default() -> Self {
32 Self::new::<RcuHashMapLock>()
33 }
34}
35
36impl<K, V> DynamicRcuHashMap<K, V, rapidhash::RapidBuildHasher>
37where
38 K: Eq + Hash + Clone + RcuDroppable + Sync,
39 V: Clone + RcuDroppable + Sync,
40{
41 pub fn new<L: LockLevel>() -> Self {
43 Self { map: Default::default(), mutex: DynamicLockDepMutex::new::<L>(()) }
44 }
45}
46
47impl<K, V, S> DynamicRcuHashMap<K, V, S>
48where
49 K: Eq + Hash + Clone + RcuDroppable + Sync,
50 V: Clone + RcuDroppable + Sync,
51 S: BuildHasher + Send + Sync + 'static,
52{
53 pub fn with_capacity_and_hasher<L: LockLevel>(capacity: usize, hash_builder: S) -> Self {
55 Self {
56 map: RcuRawHashMap::with_capacity_and_hasher(capacity, hash_builder),
57 mutex: DynamicLockDepMutex::new::<L>(()),
58 }
59 }
60
61 pub fn with_hasher<L: LockLevel>(hash_builder: S) -> Self {
63 Self {
64 map: RcuRawHashMap::with_hasher(hash_builder),
65 mutex: DynamicLockDepMutex::new::<L>(()),
66 }
67 }
68
69 pub fn get<'a, Q>(&self, scope: &'a RcuReadScope, key: &Q) -> Option<&'a V>
73 where
74 K: Borrow<Q>,
75 Q: ?Sized + Hash + Eq,
76 {
77 self.map.get(scope, key)
78 }
79
80 pub fn lock(&self) -> RcuHashMapGuard<'_, K, V, S> {
82 RcuHashMapGuard { map: &self.map, _guard: self.mutex.lock() }
83 }
84
85 pub fn insert(&self, key: K, value: V) -> Option<V> {
87 self.lock().insert(key, value)
88 }
89
90 pub fn remove<Q>(&self, key: &Q) -> Option<V>
92 where
93 K: Borrow<Q>,
94 Q: ?Sized + Hash + Eq,
95 {
96 self.lock().remove(key)
97 }
98
99 pub fn iter<'a>(&'a self, scope: &'a RcuReadScope) -> impl Iterator<Item = (&'a K, &'a V)> {
101 let mut cursor = self.map.cursor(scope);
102 std::iter::from_fn(move || {
103 let current = cursor.current();
104 if current.is_some() {
105 cursor.advance();
106 }
107 current
108 })
109 }
110
111 pub fn keys<'a>(&'a self, scope: &'a RcuReadScope) -> impl Iterator<Item = &'a K> {
113 self.iter(scope).map(|(k, _)| k)
114 }
115
116 pub fn values<'a>(&'a self, scope: &'a RcuReadScope) -> impl Iterator<Item = &'a V> {
118 self.iter(scope).map(|(_, v)| v)
119 }
120
121 pub fn len(&self) -> usize {
123 self.map.len()
124 }
125
126 pub fn is_empty(&self) -> bool {
128 self.map.is_empty()
129 }
130
131 pub fn clear(&self) {
133 self.lock().clear();
134 }
135}
136
137impl<K, V, S> starnix_sync::MutexLike for DynamicRcuHashMap<K, V, S>
138where
139 K: Eq + Hash + Clone + RcuDroppable + Sync,
140 V: Clone + RcuDroppable + Sync,
141 S: BuildHasher + Send + Sync + 'static,
142{
143 type Guard<'a>
144 = RcuHashMapGuard<'a, K, V, S>
145 where
146 Self: 'a;
147 type Context = <DynamicLockDepMutex<()> as starnix_sync::MutexLike>::Context;
148
149 #[inline(always)]
150 fn context() -> Self::Context {
151 <DynamicLockDepMutex<()> as starnix_sync::MutexLike>::context()
152 }
153
154 #[inline(always)]
155 fn lock(&self, context: &mut Self::Context) -> Self::Guard<'_> {
156 RcuHashMapGuard {
157 map: &self.map,
158 _guard: <DynamicLockDepMutex<()> as starnix_sync::MutexLike>::lock(
159 &self.mutex,
160 context,
161 ),
162 }
163 }
164}
165
166impl<K, V, S> fuchsia_sync::ResetDependencies for DynamicRcuHashMap<K, V, S>
167where
168 K: Eq + Hash + Clone + RcuDroppable + Sync,
169 V: Clone + RcuDroppable + Sync,
170 S: BuildHasher + Send + Sync + 'static,
171{
172 #[inline(always)]
173 unsafe fn reset_dependencies(&self) {
174 unsafe {
176 self.mutex.reset_dependencies();
177 }
178 }
179}
180
181impl<K, V, S> std::fmt::Debug for DynamicRcuHashMap<K, V, S>
183where
184 K: Eq + Hash + std::fmt::Debug + Clone + RcuDroppable + Sync,
185 V: std::fmt::Debug + Clone + RcuDroppable + Sync,
186 S: BuildHasher + Send + Sync + 'static,
187{
188 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189 f.debug_struct("DynamicRcuHashMap").field("map", &self.map).finish()
190 }
191}
192
193#[derive(RcuDroppable)]
200pub struct RcuHashMap<K, V, L = RcuHashMapLock, S = rapidhash::RapidBuildHasher>
201where
202 K: Eq + Hash + Clone + RcuDroppable + Sync,
203 V: Clone + RcuDroppable + Sync,
204 L: LockLevel,
205 S: BuildHasher + Send + Sync + 'static,
206{
207 inner: DynamicRcuHashMap<K, V, S>,
208 _level: PhantomData<L>,
209}
210
211impl<K, V> Default for RcuHashMap<K, V, RcuHashMapLock, rapidhash::RapidBuildHasher>
212where
213 K: Eq + Hash + Clone + RcuDroppable + Sync,
214 V: Clone + RcuDroppable + Sync,
215{
216 fn default() -> Self {
217 Self::new()
218 }
219}
220
221impl<K, V, L> RcuHashMap<K, V, L, rapidhash::RapidBuildHasher>
222where
223 K: Eq + Hash + Clone + RcuDroppable + Sync,
224 V: Clone + RcuDroppable + Sync,
225 L: LockLevel,
226{
227 pub fn new() -> Self {
229 Self { inner: DynamicRcuHashMap::new::<L>(), _level: PhantomData }
230 }
231}
232
233impl<K, V, S> RcuHashMap<K, V, RcuHashMapLock, S>
234where
235 K: Eq + Hash + Clone + RcuDroppable + Sync,
236 V: Clone + RcuDroppable + Sync,
237 S: BuildHasher + Send + Sync + 'static,
238{
239 pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self {
241 Self {
242 inner: DynamicRcuHashMap::with_capacity_and_hasher::<RcuHashMapLock>(
243 capacity,
244 hash_builder,
245 ),
246 _level: PhantomData,
247 }
248 }
249
250 pub fn with_hasher(hash_builder: S) -> Self {
252 Self {
253 inner: DynamicRcuHashMap::with_hasher::<RcuHashMapLock>(hash_builder),
254 _level: PhantomData,
255 }
256 }
257}
258
259impl<K, V, L, S> Deref for RcuHashMap<K, V, L, S>
260where
261 K: Eq + Hash + Clone + RcuDroppable + Sync,
262 V: Clone + RcuDroppable + Sync,
263 L: LockLevel,
264 S: BuildHasher + Send + Sync + 'static,
265{
266 type Target = DynamicRcuHashMap<K, V, S>;
267
268 fn deref(&self) -> &Self::Target {
269 &self.inner
270 }
271}
272
273impl<K, V, L, S> starnix_sync::MutexLike for RcuHashMap<K, V, L, S>
274where
275 K: Eq + Hash + Clone + RcuDroppable + Sync,
276 V: Clone + RcuDroppable + Sync,
277 L: LockLevel,
278 S: BuildHasher + Send + Sync + 'static,
279{
280 type Guard<'a>
281 = RcuHashMapGuard<'a, K, V, S>
282 where
283 Self: 'a;
284 type Context = <DynamicRcuHashMap<K, V, S> as starnix_sync::MutexLike>::Context;
285
286 #[inline(always)]
287 fn context() -> Self::Context {
288 <DynamicRcuHashMap<K, V, S> as starnix_sync::MutexLike>::context()
289 }
290
291 #[inline(always)]
292 fn lock(&self, context: &mut Self::Context) -> Self::Guard<'_> {
293 <DynamicRcuHashMap<K, V, S> as starnix_sync::MutexLike>::lock(&self.inner, context)
294 }
295}
296
297impl<K, V, L, S> fuchsia_sync::ResetDependencies for RcuHashMap<K, V, L, S>
298where
299 K: Eq + Hash + Clone + RcuDroppable + Sync,
300 V: Clone + RcuDroppable + Sync,
301 L: LockLevel,
302 S: BuildHasher + Send + Sync + 'static,
303{
304 #[inline(always)]
305 unsafe fn reset_dependencies(&self) {
306 unsafe {
308 self.inner.reset_dependencies();
309 }
310 }
311}
312
313impl<K, V, L, S> std::fmt::Debug for RcuHashMap<K, V, L, S>
315where
316 K: Eq + Hash + std::fmt::Debug + Clone + RcuDroppable + Sync,
317 V: std::fmt::Debug + Clone + RcuDroppable + Sync,
318 L: LockLevel,
319 S: BuildHasher + Send + Sync + 'static,
320{
321 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
322 f.debug_struct("RcuHashMap").field("map", &self.inner.map).finish()
323 }
324}
325
326pub struct RcuHashMapGuard<'a, K, V, S = rapidhash::RapidBuildHasher>
328where
329 K: Eq + Hash + Clone + RcuDroppable + Sync,
330 V: Clone + RcuDroppable + Sync,
331 S: BuildHasher + Send + Sync + 'static,
332{
333 map: &'a RcuRawHashMap<K, V, S>,
334 _guard: LockDepGuard<'a, ()>,
335}
336
337impl<'a, K, V, S> RcuHashMapGuard<'a, K, V, S>
338where
339 K: Eq + Hash + Clone + RcuDroppable + Sync,
340 V: Clone + RcuDroppable + Sync,
341 S: BuildHasher + Send + Sync + 'static,
342{
343 pub fn get<Q>(&self, key: &Q) -> Option<V>
345 where
346 K: Borrow<Q>,
347 Q: ?Sized + Hash + Eq,
348 {
349 let scope = RcuReadScope::new();
350 self.map.get(&scope, key).cloned()
351 }
352
353 pub fn insert(&mut self, key: K, value: V) -> Option<V> {
355 let scope = RcuReadScope::new();
356 match unsafe { self.map.insert(&scope, key, value) } {
358 InsertionResult::Inserted(_) => None,
359 InsertionResult::Updated(old_value) => Some(old_value),
360 }
361 }
362
363 pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
365 where
366 K: Borrow<Q>,
367 Q: ?Sized + Hash + Eq,
368 {
369 unsafe { self.map.remove(key) }
371 }
372
373 pub fn clear(&mut self) {
375 unsafe {
377 self.map.clear();
378 }
379 }
380
381 pub fn len(&self) -> usize {
383 self.map.len()
384 }
385
386 pub fn is_empty(&self) -> bool {
388 self.map.is_empty()
389 }
390
391 pub fn iter<'b>(&'b self, scope: &'b RcuReadScope) -> impl Iterator<Item = (&'b K, &'b V)> {
393 self.map.iter(scope)
394 }
395
396 pub fn drain<'b>(&'b mut self) -> impl Iterator<Item = (K, V)> + 'b {
398 let scope = RcuReadScope::new();
399 #[allow(clippy::needless_collect)]
401 let keys: Vec<_> = self.map.keys(&scope).map(Clone::clone).collect();
402 keys.into_iter().filter_map(move |k| self.remove(&k).map(|v| (k, v)))
403 }
404
405 pub fn contains_key<Q>(&self, key: &Q) -> bool
407 where
408 K: Borrow<Q>,
409 Q: ?Sized + Hash + Eq,
410 {
411 self.get(key).is_some()
412 }
413
414 pub fn entry<'b>(&'b mut self, key: K) -> Entry<'b, 'a, K, V, S> {
416 if self.get(&key).is_some() {
417 Entry::Occupied(OccupiedEntry { guard: self, key })
418 } else {
419 Entry::Vacant(VacantEntry { guard: self, key })
420 }
421 }
422}
423
424pub enum Entry<'b, 'a, K, V, S = rapidhash::RapidBuildHasher>
426where
427 K: Eq + Hash + Clone + RcuDroppable + Sync,
428 V: Clone + RcuDroppable + Sync,
429 S: BuildHasher + Send + Sync + 'static,
430{
431 Occupied(OccupiedEntry<'b, 'a, K, V, S>),
433 Vacant(VacantEntry<'b, 'a, K, V, S>),
435}
436
437impl<'b, 'a, K, V, S> Entry<'b, 'a, K, V, S>
438where
439 K: Eq + Hash + Clone + RcuDroppable + Sync,
440 V: Clone + RcuDroppable + Sync,
441 S: BuildHasher + Send + Sync + 'static,
442{
443 pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> OccupiedEntry<'b, 'a, K, V, S> {
446 match self {
447 Entry::Occupied(entry) => entry,
448 Entry::Vacant(entry) => entry.insert_entry(default()),
449 }
450 }
451}
452
453pub struct OccupiedEntry<'b, 'a, K, V, S = rapidhash::RapidBuildHasher>
455where
456 K: Eq + Hash + Clone + RcuDroppable + Sync,
457 V: Clone + RcuDroppable + Sync,
458 S: BuildHasher + Send + Sync + 'static,
459{
460 guard: &'b mut RcuHashMapGuard<'a, K, V, S>,
461 key: K,
462}
463
464impl<K, V, S> OccupiedEntry<'_, '_, K, V, S>
465where
466 K: Eq + Hash + Clone + RcuDroppable + Sync,
467 V: Clone + RcuDroppable + Sync,
468 S: BuildHasher + Send + Sync + 'static,
469{
470 pub fn get(&self) -> V {
472 self.guard.get(&self.key).unwrap()
473 }
474
475 pub fn insert(&mut self, value: V) -> V {
477 self.guard.insert(self.key.clone(), value).unwrap()
478 }
479
480 pub fn remove(self) -> V {
482 self.guard.remove(&self.key).unwrap()
483 }
484}
485
486pub struct VacantEntry<'b, 'a, K, V, S = rapidhash::RapidBuildHasher>
488where
489 K: Eq + Hash + Clone + RcuDroppable + Sync,
490 V: Clone + RcuDroppable + Sync,
491 S: BuildHasher + Send + Sync + 'static,
492{
493 guard: &'b mut RcuHashMapGuard<'a, K, V, S>,
494 key: K,
495}
496
497impl<'b, 'a, K, V, S> VacantEntry<'b, 'a, K, V, S>
498where
499 K: Eq + Hash + Clone + RcuDroppable + Sync,
500 V: Clone + RcuDroppable + Sync,
501 S: BuildHasher + Send + Sync + 'static,
502{
503 pub fn insert(self, value: V) {
505 self.guard.insert(self.key, value);
506 }
507
508 pub fn insert_entry(self, value: V) -> OccupiedEntry<'b, 'a, K, V, S> {
510 self.guard.insert(self.key.clone(), value);
511 OccupiedEntry { guard: self.guard, key: self.key }
512 }
513}
514
515#[cfg(test)]
516mod tests {
517 use super::*;
518 use fuchsia_rcu::rcu_run_callbacks;
519
520 #[test]
521 fn test_rcu_hash_map_custom_hasher() {
522 use std::collections::hash_map::DefaultHasher;
523 use std::hash::BuildHasherDefault;
524 let hasher = BuildHasherDefault::<DefaultHasher>::default();
525 let map = RcuHashMap::with_capacity_and_hasher(10, hasher);
526 let mut guard = map.lock();
527 guard.insert(1, 10);
528 assert_eq!(guard.get(&1), Some(10));
529 }
530
531 #[test]
532 fn test_rcu_hash_map_insert_and_get() {
533 let map = RcuHashMap::<i32, i32>::default();
534 let mut guard = map.lock();
535 let scope = RcuReadScope::new();
536
537 guard.insert(1, 10);
538 guard.insert(2, 20);
539
540 assert_eq!(guard.get(&1), Some(10));
541 assert_eq!(guard.get(&2), Some(20));
542 assert_eq!(guard.get(&3), None);
543
544 drop(guard);
546 assert_eq!(map.get(&scope, &1), Some(&10));
547 assert_eq!(map.get(&scope, &2), Some(&20));
548
549 drop(scope);
550 rcu_run_callbacks();
551 }
552
553 #[test]
554 fn test_rcu_hash_map_update() {
555 let map = RcuHashMap::<i32, i32>::default();
556 let mut guard = map.lock();
557 let scope = RcuReadScope::new();
558
559 guard.insert(1, 10);
560 assert_eq!(guard.get(&1), Some(10));
561
562 guard.insert(1, 20);
563 assert_eq!(guard.get(&1), Some(20));
564
565 drop(guard);
566 assert_eq!(map.get(&scope, &1), Some(&20));
567
568 drop(scope);
569 rcu_run_callbacks();
570 }
571
572 #[test]
573 fn test_rcu_hash_map_remove() {
574 let map = RcuHashMap::<i32, i32>::default();
575 let mut guard = map.lock();
576 let scope = RcuReadScope::new();
577
578 guard.insert(1, 10);
579 assert_eq!(guard.get(&1), Some(10));
580
581 guard.remove(&1);
582 assert_eq!(guard.get(&1), None);
583
584 drop(guard);
585 assert_eq!(map.get(&scope, &1), None);
586
587 drop(scope);
588 rcu_run_callbacks();
589 }
590
591 #[test]
592 fn test_rcu_hash_map_entry_api() {
593 let map = RcuHashMap::<i32, i32>::default();
594 let mut guard = map.lock();
595
596 match guard.entry(1) {
598 Entry::Vacant(e) => e.insert(10),
599 Entry::Occupied(_) => panic!("Should be vacant"),
600 }
601 assert_eq!(guard.get(&1), Some(10));
602
603 match guard.entry(1) {
605 Entry::Occupied(mut e) => {
606 assert_eq!(e.get(), 10);
607 e.insert(20);
608 }
609 Entry::Vacant(_) => panic!("Should be occupied"),
610 }
611 assert_eq!(guard.get(&1), Some(20));
612
613 drop(guard);
614 rcu_run_callbacks();
615 }
616
617 #[test]
618 fn test_rcu_hash_map_iter() {
619 let map = RcuHashMap::<i32, i32>::default();
620 let scope = RcuReadScope::new();
621 map.insert(1, 10);
622 map.insert(2, 20);
623 map.insert(3, 30);
624
625 let mut items: Vec<_> = map.iter(&scope).collect();
626 items.sort_by_key(|(k, _)| **k);
627 assert_eq!(items, vec![(&1, &10), (&2, &20), (&3, &30)]);
628 }
629
630 #[test]
631 fn test_rcu_hash_map_keys() {
632 let map = RcuHashMap::<i32, i32>::default();
633 let scope = RcuReadScope::new();
634 map.insert(1, 10);
635 map.insert(2, 20);
636 map.insert(3, 30);
637
638 let mut keys: Vec<_> = map.keys(&scope).collect();
639 keys.sort();
640 assert_eq!(keys, vec![&1, &2, &3]);
641 }
642
643 #[test]
644 fn test_rcu_hash_map_len() {
645 let map = RcuHashMap::<i32, i32>::default();
646 map.insert(1, 10);
647 map.insert(2, 20);
648 map.insert(3, 30);
649
650 assert_eq!(map.len(), 3);
651 }
652
653 #[test]
654 fn test_rcu_hash_map_or_insert_with() {
655 let map = RcuHashMap::<i32, i32>::default();
656 let mut guard = map.lock();
657
658 guard.entry(1).or_insert_with(|| 10);
660 assert!(guard.contains_key(&1));
661 assert_eq!(guard.get(&1), Some(10));
662
663 guard.entry(1).or_insert_with(|| 20);
665 assert_eq!(guard.get(&1), Some(10));
666
667 match guard.entry(1) {
669 Entry::Occupied(e) => {
670 assert_eq!(e.remove(), 10);
671 }
672 Entry::Vacant(_) => panic!("Should be occupied"),
673 }
674 assert!(!guard.contains_key(&1));
675 }
676
677 #[test]
678 fn test_rcu_hash_map_drain() {
679 let map = RcuHashMap::<i32, i32>::default();
680 let mut guard = map.lock();
681
682 guard.insert(1, 10);
683 guard.insert(2, 20);
684 guard.insert(3, 30);
685
686 let mut items: Vec<_> = guard.drain().collect();
687 items.sort_by_key(|(k, _)| *k);
688 assert_eq!(items, vec![(1, 10), (2, 20), (3, 30)]);
689
690 assert!(!guard.contains_key(&1));
691 assert!(!guard.contains_key(&2));
692 assert!(!guard.contains_key(&3));
693 }
694
695 #[test]
696 fn test_rcu_hash_map_capacity_zero() {
697 use std::collections::hash_map::RandomState;
698 let map = RcuHashMap::<i32, i32, RcuHashMapLock, RandomState>::with_capacity_and_hasher(
699 0,
700 RandomState::new(),
701 );
702 let mut guard = map.lock();
703
704 assert_eq!(guard.get(&1), None);
705
706 guard.insert(1, 10);
707 assert_eq!(guard.get(&1), Some(10));
708
709 guard.remove(&1);
710 assert_eq!(guard.get(&1), None);
711 }
712}