Skip to main content

dark_std/sync/
vec.rs

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