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