Skip to main content

dark_std/sync/
map_hash.rs

1use crate::lock::{SyncLock, SyncLockGuard};
2use serde::{Deserializer, Serialize, Serializer};
3use std::borrow::Borrow;
4use std::cell::UnsafeCell;
5use std::collections::{
6    hash_map::IntoIter as MapIntoIter, hash_map::Iter as MapIter, hash_map::IterMut as MapIterMut,
7    HashMap as Map,
8};
9use std::fmt::{Debug, Display, Formatter};
10use std::hash::Hash;
11use std::ops::{Deref, DerefMut};
12use std::sync::atomic::{AtomicBool, Ordering};
13use std::sync::Arc;
14
15use super::entry::{Entry, Retired};
16use super::snapshot::AtomicSnapshot;
17
18/// A concurrent HashMap with a Go `sync.Map`-style read/dirty architecture:
19///
20/// - `read`: an immutable snapshot, atomically published. `get` / `iter` /
21///   `Index` read it lock-free.
22/// - `dirty`: the canonical, mutable map, guarded by `lock`.
23///
24/// Every slot is an `Arc<Entry<V>>` shared between the snapshot and `dirty`.
25/// The entry holds an atomic pointer to the value, so updating an existing key
26/// swaps the pointer in place (O(1)) — no snapshot rebuild — and readers
27/// always see the latest value. New keys and removals are published lazily
28/// (tracked by the `amended` flag). Snapshots and retired values are kept
29/// alive until the map is dropped, so references returned by `get` stay valid.
30pub struct SyncHashMap<K: Eq + Hash, V> {
31    dirty: UnsafeCell<Map<K, Arc<Entry<V>>>>,
32    lock: SyncLock,
33    amended: AtomicBool,
34    read: AtomicSnapshot<Map<K, Arc<Entry<V>>>>,
35    retired: Retired<V>,
36}
37
38/// Safety: `dirty` is only ever accessed under `lock`; the `read` snapshot is
39/// immutable once published; values behind entries are immutable once
40/// published and swapped out atomically; retired values and retired snapshots
41/// are kept alive until the map is dropped, so references derived from `get`
42/// remain valid for the lifetime of `&self`.
43unsafe impl<K: Eq + Hash, V> Send for SyncHashMap<K, V> {}
44unsafe impl<K: Eq + Hash, V> Sync for SyncHashMap<K, V> {}
45
46impl<K, V> std::ops::Index<&K> for SyncHashMap<K, V>
47where
48    K: Eq + Hash + Clone,
49{
50    type Output = V;
51
52    fn index(&self, index: &K) -> &Self::Output {
53        self.get(index).expect("key not found")
54    }
55}
56
57impl<K, V> SyncHashMap<K, V>
58where
59    K: Eq + Hash,
60{
61    pub fn new_arc() -> Arc<Self> {
62        Arc::new(Self::new())
63    }
64
65    pub fn new() -> Self {
66        Self {
67            dirty: UnsafeCell::new(Map::new()),
68            lock: Default::default(),
69            amended: AtomicBool::new(false),
70            read: AtomicSnapshot::new(Map::new()),
71            retired: Retired::new(),
72        }
73    }
74
75    pub fn with_capacity(capacity: usize) -> Self {
76        Self {
77            dirty: UnsafeCell::new(Map::with_capacity(capacity)),
78            lock: Default::default(),
79            amended: AtomicBool::new(false),
80            read: AtomicSnapshot::new(Map::with_capacity(capacity)),
81            retired: Retired::new(),
82        }
83    }
84
85    pub fn with_map(map: Map<K, V>) -> Self {
86        let dirty = map
87            .into_iter()
88            .map(|(k, v)| (k, Arc::new(Entry::new(v))))
89            .collect();
90        Self {
91            read: AtomicSnapshot::new(Map::new()),
92            dirty: UnsafeCell::new(dirty),
93            lock: Default::default(),
94            amended: AtomicBool::new(true),
95            retired: Retired::new(),
96        }
97    }
98
99    /// Publish the current `dirty` map as a fresh immutable snapshot.
100    ///
101    /// The caller must hold `lock` (or have exclusive `&mut` access).
102    fn promote(&self)
103    where
104        K: Clone,
105    {
106        let dirty = unsafe { &*self.dirty.get() };
107        self.read.publish(dirty.clone());
108        // After publishing, `read` reflects `dirty`: nothing is pending.
109        self.amended.store(false, Ordering::Release);
110    }
111
112    pub fn insert(&self, k: K, v: V) -> Option<V>
113    where
114        K: Clone,
115        V: Clone,
116    {
117        let g = self.lock.lock();
118        let m = unsafe { &mut *self.dirty.get() };
119        if let Some(entry) = m.get(&k) {
120            // Update: swap the value in place (O(1)). The shared entry lets
121            // readers observe the new value without a snapshot rebuild.
122            let old = entry.swap(v);
123            let old_value = unsafe { (*old).clone() };
124            self.retired.push(old);
125            drop(g);
126            return Some(old_value);
127        }
128        // New key: leave it for lazy promotion and mark `amended`.
129        m.insert(k, Arc::new(Entry::new(v)));
130        self.amended.store(true, Ordering::Release);
131        drop(g);
132        None
133    }
134
135    pub fn insert_mut(&mut self, k: K, v: V) -> Option<V>
136    where
137        K: Clone,
138        V: Clone,
139    {
140        self.insert(k, v)
141    }
142
143    pub fn remove(&self, k: &K) -> Option<V>
144    where
145        K: Clone,
146        V: Clone,
147    {
148        let g = self.lock.lock();
149        let m = unsafe { &mut *self.dirty.get() };
150        if let Some(entry) = m.remove(k) {
151            // Clone the value out; the entry (and its value) stays alive in the
152            // retired snapshot published below.
153            let v = entry.load().clone();
154            // Refresh the snapshot so `get` no longer serves the removed key.
155            self.promote();
156            drop(g);
157            return Some(v);
158        }
159        drop(g);
160        None
161    }
162
163    pub fn remove_mut(&mut self, k: &K) -> Option<V>
164    where
165        K: Clone,
166        V: Clone,
167    {
168        self.remove(k)
169    }
170
171    pub fn len(&self) -> usize {
172        if !self.amended.load(Ordering::Acquire) {
173            return self.read.load().len();
174        }
175        let g = self.lock.lock();
176        let r = unsafe { (&*self.dirty.get()).len() };
177        drop(g);
178        r
179    }
180
181    pub fn is_empty(&self) -> bool {
182        if !self.amended.load(Ordering::Acquire) {
183            return self.read.load().is_empty();
184        }
185        let g = self.lock.lock();
186        let r = unsafe { (&*self.dirty.get()).is_empty() };
187        drop(g);
188        r
189    }
190
191    pub fn clear(&self)
192    where
193        K: Clone,
194    {
195        let g = self.lock.lock();
196        unsafe { (&mut *self.dirty.get()).clear() };
197        self.promote();
198        drop(g);
199    }
200
201    pub fn clear_mut(&mut self)
202    where
203        K: Clone,
204    {
205        self.clear()
206    }
207
208    pub fn shrink_to_fit(&self) {
209        let g = self.lock.lock();
210        unsafe { (&mut *self.dirty.get()).shrink_to_fit() };
211        drop(g);
212    }
213
214    pub fn shrink_to_fit_mut(&mut self) {
215        unsafe { (&mut *self.dirty.get()).shrink_to_fit() }
216    }
217
218    pub fn from(map: Map<K, V>) -> Self
219    where
220        K: Eq + Hash,
221    {
222        let s = Self::with_map(map);
223        s
224    }
225
226    /// Returns a reference to the value corresponding to the key.
227    ///
228    /// The key may be any borrowed form of the map's key type, but
229    /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
230    /// the key type.
231    ///
232    /// Reads are lock-free: the value is served from the immutable `read`
233    /// snapshot through a shared entry, so updates are visible immediately.
234    /// If the key was added to `dirty` since the last snapshot was published,
235    /// a fresh snapshot is published first.
236    ///
237    /// # Examples
238    ///
239    /// ```
240    /// use dark_std::sync::{SyncHashMap};
241    ///
242    /// let mut map = SyncHashMap::new();
243    /// map.insert_mut(1, "a");
244    /// assert_eq!(*map.get(&1).unwrap(), "a");
245    /// assert_eq!(map.get(&2).is_none(), true);
246    /// ```
247    #[inline]
248    pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
249    where
250        K: Borrow<Q> + Clone,
251        Q: Hash + Eq,
252    {
253        if let Some(entry) = self.read.load().get(k) {
254            return Some(entry.load());
255        }
256        // If nothing was written to `dirty` since the last snapshot was
257        // published, a snapshot miss is a real miss: no lock is needed.
258        if !self.amended.load(Ordering::Acquire) {
259            return None;
260        }
261        // Snapshot miss: the key may have been written to `dirty` without a
262        // snapshot refresh yet (lazy promotion). Publish a fresh snapshot and
263        // serve from it so the reference points into immutable, retained
264        // storage instead of the lock-guarded `dirty` map.
265        let g = self.lock.lock();
266        let found = unsafe { (&*self.dirty.get()).contains_key(k) };
267        if found {
268            self.promote();
269        }
270        drop(g);
271        if found {
272            self.read.load().get(k).map(|e| e.load())
273        } else {
274            None
275        }
276    }
277
278    /// Returns a mutable handle to the value for `k`, implemented with
279    /// copy-on-write: the value is cloned, the handle mutates the clone, and
280    /// the result is swapped back into the shared entry (O(1)) when the handle
281    /// is dropped. Concurrent readers may observe the pre-mutation value until
282    /// the handle is dropped.
283    #[inline]
284    pub fn get_mut(&self, k: &K) -> Option<HashMapRefMut<'_, K, V>>
285    where
286        K: Hash + Eq + Clone,
287        V: Clone,
288    {
289        let g = self.lock.lock();
290        let dirty = unsafe { &*self.dirty.get() };
291        let value = dirty.get(k)?.load().clone();
292        drop(g);
293        Some(HashMapRefMut {
294            k: k.clone(),
295            m: self,
296            value: Some(value),
297        })
298    }
299
300    #[inline]
301    pub fn contains_key(&self, x: &K) -> bool
302    where
303        K: PartialEq,
304    {
305        if self.read.load().contains_key(x) {
306            return true;
307        }
308        if !self.amended.load(Ordering::Acquire) {
309            return false;
310        }
311        let g = self.lock.lock();
312        let r = unsafe { (&*self.dirty.get()).contains_key(x) };
313        drop(g);
314        r
315    }
316
317    /// Iterate over the current contents. A fresh snapshot is published first,
318    /// so all entries written so far are visible.
319    pub fn iter(&self) -> Iter<'_, K, V>
320    where
321        K: Clone,
322    {
323        let g = self.lock.lock();
324        self.promote();
325        drop(g);
326        Iter {
327            inner: self.read.load().iter(),
328        }
329    }
330
331    pub fn iter_mut(&self) -> IterMut<'_, K, V>
332    where
333        K: Clone,
334        V: Clone,
335    {
336        let m = unsafe { &mut *self.dirty.get() };
337        IterMut {
338            m: self,
339            _g: self.lock.lock(),
340            inner: Some(m.iter_mut()),
341        }
342    }
343
344    pub fn into_iter(self) -> MapIntoIter<K, V> {
345        self.into_inner().into_iter()
346    }
347
348    pub fn into_inner(self) -> Map<K, V> {
349        // Move `dirty` out; the remaining fields (snapshots, retired values,
350        // lock) are dropped normally at the end of this function.
351        let dirty = self.dirty.into_inner();
352        dirty
353            .into_iter()
354            .map(|(k, entry)| (k, entry.take()))
355            .collect()
356    }
357}
358
359/// Iterator over `(&K, &V)`, served from the immutable snapshot.
360pub struct Iter<'a, K, V> {
361    inner: MapIter<'a, K, Arc<Entry<V>>>,
362}
363
364impl<'a, K, V> Iterator for Iter<'a, K, V> {
365    type Item = (&'a K, &'a V);
366
367    fn next(&mut self) -> Option<Self::Item> {
368        self.inner.next().map(|(k, e)| (k, e.load()))
369    }
370}
371
372impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> {
373    fn len(&self) -> usize {
374        self.inner.len()
375    }
376}
377
378/// Mutable iterator over `(&K, &mut V)`. Entries shared with snapshots are
379/// replaced with fresh unique ones; mutations are published when the iterator
380/// is dropped.
381pub struct IterMut<'a, K: Eq + Hash + Clone, V: Clone> {
382    m: &'a SyncHashMap<K, V>,
383    _g: SyncLockGuard<'a>,
384    inner: Option<MapIterMut<'a, K, Arc<Entry<V>>>>,
385}
386
387impl<'a, K: Eq + Hash + Clone, V: Clone> Drop for IterMut<'a, K, V> {
388    fn drop(&mut self) {
389        // Drop the `&mut` borrows into `dirty` first, then publish the
390        // mutations into a fresh snapshot. The lock (`_g`) is still held.
391        self.inner.take();
392        self.m.promote();
393    }
394}
395
396impl<'a, K: Eq + Hash + Clone, V: Clone> Iterator for IterMut<'a, K, V> {
397    type Item = (&'a K, &'a mut V);
398
399    fn next(&mut self) -> Option<Self::Item> {
400        let (k, entry) = self.inner.as_mut().unwrap().next()?;
401        // Make the entry uniquely owned so we can hand out `&mut V`.
402        if Arc::get_mut(entry).is_none() {
403            let current = entry.load().clone();
404            *entry = Arc::new(Entry::new(current));
405        }
406        Some((k, Arc::get_mut(entry).unwrap().get_mut()))
407    }
408}
409
410impl<'a, K: Eq + Hash + Clone, V: Clone> ExactSizeIterator for IterMut<'a, K, V> {
411    fn len(&self) -> usize {
412        self.inner.as_ref().unwrap().len()
413    }
414}
415
416pub struct HashMapRefMut<'a, K: Eq + Hash + Clone, V: Clone> {
417    k: K,
418    m: &'a SyncHashMap<K, V>,
419    value: Option<V>,
420}
421
422impl<'a, K: Eq + Hash + Clone, V: Clone> Drop for HashMapRefMut<'a, K, V> {
423    fn drop(&mut self) {
424        if let Some(v) = self.value.take() {
425            let g = self.m.lock.lock();
426            let dirty = unsafe { &mut *self.m.dirty.get() };
427            match dirty.get_mut(&self.k) {
428                Some(entry) => {
429                    let old = entry.swap(v);
430                    self.m.retired.push(old);
431                }
432                // The key was removed while the handle was held: keep the
433                // mutation by re-inserting it.
434                None => {
435                    dirty.insert(self.k.clone(), Arc::new(Entry::new(v)));
436                    self.m.amended.store(true, Ordering::Release);
437                }
438            }
439            drop(g);
440        }
441    }
442}
443
444impl<'a, K: Eq + Hash + Clone, V: Clone> Deref for HashMapRefMut<'_, K, V> {
445    type Target = V;
446
447    fn deref(&self) -> &Self::Target {
448        self.value.as_ref().unwrap()
449    }
450}
451
452impl<'a, K: Eq + Hash + Clone, V: Clone> DerefMut for HashMapRefMut<'_, K, V> {
453    fn deref_mut(&mut self) -> &mut Self::Target {
454        self.value.as_mut().unwrap()
455    }
456}
457
458impl<'a, K: Eq + Hash + Clone, V: Clone> Debug for HashMapRefMut<'_, K, V>
459where
460    V: Debug,
461{
462    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
463        self.value.as_ref().unwrap().fmt(f)
464    }
465}
466
467impl<'a, K: Eq + Hash + Clone, V: Clone> Display for HashMapRefMut<'_, K, V>
468where
469    V: Display,
470{
471    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
472        self.value.as_ref().unwrap().fmt(f)
473    }
474}
475
476impl<'a, K: Eq + Hash + Clone, V: Clone> PartialEq<Self> for HashMapRefMut<'_, K, V>
477where
478    V: Eq,
479{
480    fn eq(&self, other: &Self) -> bool {
481        self.value
482            .as_ref()
483            .unwrap()
484            .eq(&other.value.as_ref().unwrap())
485    }
486}
487
488impl<'a, K: Eq + Hash + Clone, V: Clone> Eq for HashMapRefMut<'_, K, V> where V: Eq {}
489
490impl<'a, K: Clone, V> IntoIterator for &'a SyncHashMap<K, V>
491where
492    K: Eq + Hash,
493{
494    type Item = (&'a K, &'a V);
495    type IntoIter = Iter<'a, K, V>;
496
497    fn into_iter(self) -> Self::IntoIter {
498        self.iter()
499    }
500}
501
502impl<K, V> IntoIterator for SyncHashMap<K, V>
503where
504    K: Eq + Hash,
505{
506    type Item = (K, V);
507    type IntoIter = MapIntoIter<K, V>;
508
509    fn into_iter(self) -> Self::IntoIter {
510        self.into_iter()
511    }
512}
513
514impl<K: Eq + Hash, V> From<Map<K, V>> for SyncHashMap<K, V> {
515    fn from(arg: Map<K, V>) -> Self {
516        Self::from(arg)
517    }
518}
519
520impl<K, V> serde::Serialize for SyncHashMap<K, V>
521where
522    K: Eq + Hash + Serialize,
523    V: Serialize,
524{
525    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
526    where
527        S: Serializer,
528    {
529        use serde::ser::SerializeMap;
530        let g = self.lock.lock();
531        let dirty = unsafe { &*self.dirty.get() };
532        let mut m = serializer.serialize_map(Some(dirty.len()))?;
533        for (k, e) in dirty.iter() {
534            m.serialize_entry(k, e.load())?;
535        }
536        drop(g);
537        m.end()
538    }
539}
540
541impl<'de, K, V> serde::Deserialize<'de> for SyncHashMap<K, V>
542where
543    K: Eq + Hash + serde::Deserialize<'de>,
544    V: serde::Deserialize<'de>,
545{
546    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
547    where
548        D: Deserializer<'de>,
549    {
550        let m = Map::deserialize(deserializer)?;
551        Ok(Self::from(m))
552    }
553}
554
555impl<K, V> Debug for SyncHashMap<K, V>
556where
557    K: Eq + Hash + Debug,
558    V: Debug,
559{
560    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
561        let g = self.lock.lock();
562        let r = unsafe { (&*self.dirty.get()).fmt(f) };
563        drop(g);
564        r
565    }
566}
567
568impl<K, V> Display for SyncHashMap<K, V>
569where
570    K: Eq + Hash + Display,
571    V: Display,
572{
573    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
574        use std::fmt::Pointer;
575        let g = self.lock.lock();
576        let r = unsafe { (&*self.dirty.get()).fmt(f) };
577        drop(g);
578        r
579    }
580}
581
582impl<K: Clone + Eq + Hash, V: Clone> Clone for SyncHashMap<K, V> {
583    fn clone(&self) -> Self {
584        let g = self.lock.lock();
585        let dirty = unsafe { &*self.dirty.get() };
586        let m = dirty
587            .iter()
588            .map(|(k, e)| (k.clone(), e.load().clone()))
589            .collect();
590        drop(g);
591        SyncHashMap::from(m)
592    }
593}
594
595impl<K: Eq + Hash, V> Default for SyncHashMap<K, V> {
596    fn default() -> Self {
597        SyncHashMap::new()
598    }
599}