Skip to main content

dark_std/sync/
map_index.rs

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