Skip to main content

append_only_vec/
lib.rs

1//! AppendOnlyVec
2//!
3//! This is a pretty simple type, which is a vector that you can push into, but
4//! cannot modify the elements of.  The data structure never moves an element
5//! once allocated, so you can push to the vec even while holding references to
6//! elements that have already been pushed.
7//!
8//! ### Scaling
9//!
10//! 1. Accessing an element is O(1), but slightly more expensive than for a
11//!    standard `Vec`.
12//!
13//! 2. Pushing a new element amortizes to O(1), but may require allocation of a
14//!    new chunk.
15//!
16//! ### Example
17//!
18//! ```
19//! use append_only_vec::AppendOnlyVec;
20//! static V: AppendOnlyVec<String> = AppendOnlyVec::<String>::new();
21//! let mut threads = Vec::new();
22//! for thread_num in 0..10 {
23//!     threads.push(std::thread::spawn(move || {
24//!          for n in 0..100 {
25//!               let s = format!("thread {} says {}", thread_num, n);
26//!               let which = V.push(s.clone());
27//!               assert_eq!(&V[which], &s);
28//!          }
29//!     }));
30//! }
31//! for t in threads {
32//!    t.join();
33//! }
34//! assert_eq!(V.len(), 1000);
35//! ```
36//!
37//! ### `no_std`
38//!
39//! This crate needs only `core` and `alloc`.  The `std` feature, which is on by
40//! default, lets a thread that has waited a long time for another to finish a
41//! push yield to the operating system instead of continuing to spin; without
42//! it (`default-features = false`) the crate is `no_std` and always spins.
43//! If you turn off default features on a platform that does have `std`, turn
44//! `std` back on to keep that behavior.
45//!
46//! Without `std`, a push that finds another push unfinished spins until it
47//! completes.  So never push from an interrupt handler, or from a task that
48//! can preempt another task's push without letting it run, to a vec that the
49//! interrupted code also pushes to: the handler would spin forever.
50//!
51//! On targets without atomic compare-and-swap (such as `thumbv6m-none-eabi`),
52//! the `portable-atomic` feature uses the `portable-atomic` crate's atomics
53//! instead of `core`'s.  As that crate explains, such targets also need one of
54//! its features that says how to provide them (for instance `critical-section`).
55
56#![cfg_attr(not(any(feature = "std", test)), no_std)]
57
58extern crate alloc;
59
60use alloc::vec::Vec;
61use core::cell::UnsafeCell;
62use core::ops::{Index, IndexMut};
63#[cfg(not(feature = "portable-atomic"))]
64use core::sync::atomic::AtomicUsize;
65use core::sync::atomic::Ordering;
66#[cfg(feature = "portable-atomic")]
67use portable_atomic::AtomicUsize;
68pub struct AppendOnlyVec<T> {
69    count: AtomicUsize,
70    reserved: AtomicUsize,
71    data: [UnsafeCell<*mut T>; BITS_USED - 1 - 3],
72}
73
74unsafe impl<T: Send> Send for AppendOnlyVec<T> {}
75unsafe impl<T: Sync + Send> Sync for AppendOnlyVec<T> {}
76
77const BITS: usize = core::mem::size_of::<usize>() * 8;
78
79#[cfg(target_arch = "x86_64")]
80const BITS_USED: usize = 48;
81#[cfg(all(not(target_arch = "x86_64"), target_pointer_width = "64"))]
82const BITS_USED: usize = 64;
83#[cfg(target_pointer_width = "32")]
84const BITS_USED: usize = 32;
85#[cfg(target_pointer_width = "16")]
86const BITS_USED: usize = 16;
87
88// This takes an index into a vec, and determines which data array will hold it
89// (the first return value), and what the index will be into that data array
90// (second return value)
91//
92// The ith data array holds 1<<i values.
93const fn indices(i: usize) -> (u32, usize) {
94    let i = i + 8;
95    let bin = BITS as u32 - 1 - i.leading_zeros();
96    let bin = bin - 3;
97    let offset = i - bin_size(bin);
98    (bin, offset)
99}
100const fn bin_size(array: u32) -> usize {
101    (1 << 3) << array
102}
103
104#[cfg(feature = "std")]
105fn spin_wait(failures: &mut usize) {
106    // Saturate, since a long enough wait would overflow a 32-bit counter.
107    *failures = failures.saturating_add(1);
108    if *failures <= 3 {
109        // If there haven't been many failures yet, then we optimistically
110        // spinloop.
111        for _ in 0..(1 << *failures) {
112            core::hint::spin_loop();
113        }
114    } else {
115        // If there have been many failures, then continuing to spinloop will
116        // probably just waste CPU, and whoever we are waiting for has been
117        // preempted then spinning could actively delay completion of the task.
118        // So instead, we cooperatively yield to the OS scheduler.
119        std::thread::yield_now();
120    }
121}
122
123/// Without `std` there is no scheduler to yield to, so we always spin, backing
124/// off up to 8 spins per call.
125#[cfg(not(feature = "std"))]
126fn spin_wait(failures: &mut usize) {
127    *failures = (*failures + 1).min(3);
128    for _ in 0..(1 << *failures) {
129        core::hint::spin_loop();
130    }
131}
132
133#[test]
134fn test_indices() {
135    for i in 0..32 {
136        println!("{:3}: {} {}", i, indices(i).0, indices(i).1);
137    }
138    let mut array = 0;
139    let mut offset = 0;
140    let mut index = 0;
141    while index < 1000 {
142        index += 1;
143        offset += 1;
144        if offset >= bin_size(array) {
145            offset = 0;
146            array += 1;
147        }
148        assert_eq!(indices(index), (array, offset));
149    }
150}
151
152impl<T> Default for AppendOnlyVec<T> {
153    fn default() -> Self {
154        Self::new()
155    }
156}
157
158impl<T> AppendOnlyVec<T> {
159    /// Return an `Iterator` over the elements of the vec.
160    pub fn iter(&self) -> impl DoubleEndedIterator<Item = &T> + ExactSizeIterator {
161        // FIXME this could be written to be a little more efficient probably,
162        // if we made it read each pointer only once.  On the other hand, that
163        // could make a reversed iterator less efficient?
164        (0..self.len()).map(|i| unsafe { self.get_unchecked(i) })
165    }
166    /// Find the length of the array.
167    #[inline]
168    pub fn len(&self) -> usize {
169        self.count.load(Ordering::Acquire)
170    }
171
172    fn layout(&self, array: u32) -> alloc::alloc::Layout {
173        alloc::alloc::Layout::array::<T>(bin_size(array)).unwrap()
174    }
175    /// Internal-only function requests a slot and puts data into it.
176    ///
177    /// However this does not update the size of the vec, which *must* be done
178    /// in order for either the value to be readable *or* for future pushes to
179    /// actually terminate.
180    fn pre_push(&self, val: T) -> usize {
181        let idx = self.reserved.fetch_add(1, Ordering::Relaxed);
182        let (array, offset) = indices(idx);
183        let ptr = if self.len() < 1 + idx - offset {
184            // We are working on a new array, which may not have been allocated...
185            if offset == 0 {
186                // It is our job to allocate the array!  The size of the array
187                // is determined in the self.layout method, which needs to be
188                // consistent with the indices function.
189                let layout = self.layout(array);
190                let ptr = if layout.size() == 0 {
191                    // Zero-sized types need no memory, and allocating a
192                    // zero-sized layout is undefined behavior.
193                    core::ptr::NonNull::<T>::dangling().as_ptr()
194                } else {
195                    let ptr = unsafe { alloc::alloc::alloc(layout) } as *mut T;
196                    if ptr.is_null() {
197                        alloc::alloc::handle_alloc_error(layout);
198                    }
199                    ptr
200                };
201                unsafe {
202                    *self.data[array as usize].get() = ptr;
203                }
204                ptr
205            } else {
206                // We need to wait for the array to be allocated.
207                let mut failures = 0;
208                while self.len() < 1 + idx - offset {
209                    spin_wait(&mut failures);
210                }
211                // The Ordering::Acquire semantics of self.len() ensures that
212                // this pointer read will get the non-null pointer allocated
213                // above.
214                unsafe { *self.data[array as usize].get() }
215            }
216        } else {
217            // The Ordering::Acquire semantics of self.len() ensures that
218            // this pointer read will get the non-null pointer allocated
219            // above.
220            unsafe { *self.data[array as usize].get() }
221        };
222
223        // The contents of this offset are guaranteed to be unused (so far)
224        // because we got the idx from our fetch_add above, and ptr is
225        // guaranteed to be valid because of the loop we used above, which used
226        // self.len() which has Ordering::Acquire semantics.
227        unsafe { (ptr.add(offset)).write(val) };
228        idx
229    }
230    /// Append an element to the array
231    ///
232    /// This is notable in that it doesn't require a `&mut self`, because it
233    /// does appropriate atomic synchronization.
234    ///
235    /// The return value is the index tha was pushed to.
236    pub fn push(&self, val: T) -> usize {
237        let idx = self.pre_push(val);
238
239        // Now we need to increase the size of the vec, so it can get read.  We
240        // use Release upon success, to ensure that the value which we wrote is
241        // visible to any thread that has confirmed that the count is big enough
242        // to read that element.  In case of failure, we can be relaxed, since
243        // we don't do anything with the result other than try again.
244        let mut failures = 0;
245        while self
246            .count
247            .compare_exchange(idx, idx + 1, Ordering::Release, Ordering::Relaxed)
248            .is_err()
249        {
250            // This means that someone else *started* pushing before we started,
251            // but hasn't yet finished.  We have to wait for them to finish
252            // pushing before we can update the count.
253            spin_wait(&mut failures);
254        }
255        idx
256    }
257    /// Extend the vec with the contents of an iterator.
258    ///
259    /// Note: this is currently no more efficient than calling `push` for each
260    /// element of the iterator.
261    pub fn extend(&self, iter: impl IntoIterator<Item = T>) {
262        for val in iter {
263            self.push(val);
264        }
265    }
266    /// Append an element to the array with exclusive access
267    ///
268    /// This is slightly more efficient than [`AppendOnlyVec::push`] since it
269    /// doesn't need to worry about concurrent access.
270    ///
271    /// The return value is the new size of the array.
272    pub fn push_mut(&mut self, val: T) -> usize {
273        let idx = self.pre_push(val);
274        // We do not need synchronization here because no one else has access to
275        // this data, and if it is passed to another thread that will involve
276        // the appropriate memory barrier.
277        self.count.store(idx + 1, Ordering::Relaxed);
278        idx
279    }
280    const EMPTY: UnsafeCell<*mut T> = UnsafeCell::new(core::ptr::null_mut());
281    /// Allocate a new empty array
282    pub const fn new() -> Self {
283        AppendOnlyVec {
284            count: AtomicUsize::new(0),
285            reserved: AtomicUsize::new(0),
286            data: [Self::EMPTY; BITS_USED - 1 - 3],
287        }
288    }
289
290    /// Index the vec without checking the bounds.
291    ///
292    /// To use this correctly, you *must* first ensure that the `idx <
293    /// self.len()`.  This not only prevents overwriting the bounds, but also
294    /// creates the memory barriers to ensure that the data is visible to the
295    /// current thread.  In single-threaded code, however, it is not needed to
296    /// call `self.len()` explicitly (if e.g. you have counted the number of
297    /// elements pushed).
298    unsafe fn get_unchecked(&self, idx: usize) -> &T {
299        let (array, offset) = indices(idx);
300        // We use a Relaxed load of the pointer, because the length check (which
301        // was supposed to be performed) should ensure that the data we want is
302        // already visible, since self.len() used Ordering::Acquire on
303        // `self.count` which synchronizes with the Ordering::Release write in
304        // `self.push`.
305        let ptr = *self.data[array as usize].get();
306        &*ptr.add(offset)
307    }
308
309    /// Convert into a standard `Vec`
310    pub fn into_vec(self) -> Vec<T> {
311        let mut vec = Vec::with_capacity(self.len());
312
313        for idx in 0..self.len() {
314            let (array, offset) = indices(idx);
315            // We use a Relaxed load of the pointer, because the loop above (which
316            // ends before `self.len()`) should ensure that the data we want is
317            // already visible, since it Acquired `self.count` which synchronizes
318            // with the write in `self.push`.
319            let ptr = unsafe { *self.data[array as usize].get() };
320
321            // Copy the element value. The copy remaining in the array must not
322            // be used again (i.e. make sure we do not drop it)
323            let value = unsafe { ptr.add(offset).read() };
324
325            vec.push(value);
326        }
327
328        // Prevent dropping the copied-out values by marking the count as 0 before
329        // our own drop is run
330        self.count.store(0, Ordering::Relaxed);
331
332        vec
333    }
334}
335impl<T> core::fmt::Debug for AppendOnlyVec<T>
336where
337    T: core::fmt::Debug,
338{
339    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
340        f.debug_list().entries(self.iter()).finish()
341    }
342}
343
344impl<T> Index<usize> for AppendOnlyVec<T> {
345    type Output = T;
346
347    fn index(&self, idx: usize) -> &Self::Output {
348        assert!(idx < self.len()); // this includes the required ordering memory barrier
349        let (array, offset) = indices(idx);
350        // The ptr value below is safe, because the length check above will
351        // ensure that the data we want is already visible, since it used
352        // Ordering::Acquire on `self.count` which synchronizes with the
353        // Ordering::Release write in `self.push`.
354        let ptr = unsafe { *self.data[array as usize].get() };
355        unsafe { &*ptr.add(offset) }
356    }
357}
358
359impl<T> IndexMut<usize> for AppendOnlyVec<T> {
360    fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
361        assert!(idx < self.len()); // this includes the required ordering memory barrier
362        let (array, offset) = indices(idx);
363        // The ptr value below is safe, because the length check above will
364        // ensure that the data we want is already visible, since it used
365        // Ordering::Acquire on `self.count` which synchronizes with the
366        // Ordering::Release write in `self.push`.
367        let ptr = unsafe { *self.data[array as usize].get() };
368
369        // `&mut` is safe because there can be no access to data owned by
370        // `self` except via `self`, and we have `&mut` on `self`
371        unsafe { &mut *ptr.add(offset) }
372    }
373}
374
375impl<T> Drop for AppendOnlyVec<T> {
376    fn drop(&mut self) {
377        // First we'll drop all the `T` in a slightly sloppy way.  FIXME this
378        // could be optimized to avoid reloading the `ptr`.
379        for idx in 0..self.len() {
380            let (array, offset) = indices(idx);
381            // We use a Relaxed load of the pointer, because the loop above (which
382            // ends before `self.len()`) should ensure that the data we want is
383            // already visible, since it Acquired `self.count` which synchronizes
384            // with the write in `self.push`.
385            let ptr = unsafe { *self.data[array as usize].get() };
386            unsafe {
387                core::ptr::drop_in_place(ptr.add(offset));
388            }
389        }
390        // Now we will free all the arrays.
391        for array in 0..self.data.len() as u32 {
392            // This load is relaxed because no other thread can have a reference
393            // to Self because we have a &mut self.
394            let ptr = unsafe { *self.data[array as usize].get() };
395            if !ptr.is_null() {
396                let layout = self.layout(array);
397                // Zero-sized types were never allocated (see `pre_push`).
398                if layout.size() != 0 {
399                    unsafe { alloc::alloc::dealloc(ptr as *mut u8, layout) };
400                }
401            } else {
402                break;
403            }
404        }
405    }
406}
407
408impl<T> Clone for AppendOnlyVec<T>
409where
410    T: Clone,
411{
412    fn clone(&self) -> Self {
413        // FIXME this could be optimized to avoid reloading pointers.
414        self.iter().cloned().collect()
415    }
416}
417
418/// An `Iterator` for the values contained in the `AppendOnlyVec`
419#[derive(Debug)]
420pub struct IntoIter<T>(alloc::vec::IntoIter<T>);
421
422impl<T> Iterator for IntoIter<T> {
423    type Item = T;
424
425    fn next(&mut self) -> Option<Self::Item> {
426        self.0.next()
427    }
428
429    fn size_hint(&self) -> (usize, Option<usize>) {
430        self.0.size_hint()
431    }
432}
433
434impl<T> DoubleEndedIterator for IntoIter<T> {
435    fn next_back(&mut self) -> Option<Self::Item> {
436        self.0.next_back()
437    }
438}
439
440impl<T> ExactSizeIterator for IntoIter<T> {
441    fn len(&self) -> usize {
442        self.0.len()
443    }
444}
445
446impl<T> IntoIterator for AppendOnlyVec<T> {
447    type Item = T;
448
449    type IntoIter = IntoIter<T>;
450
451    fn into_iter(self) -> Self::IntoIter {
452        IntoIter(self.into_vec().into_iter())
453    }
454}
455
456impl<T> FromIterator<T> for AppendOnlyVec<T> {
457    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
458        let out = Self::new();
459        for x in iter {
460            let idx = out.pre_push(x);
461            // We can be relaxed here because no one else has access to
462            // this data, and if it is passed to another thread that will involve
463            // the appropriate memory barrier.
464            out.count.store(idx + 1, Ordering::Relaxed);
465        }
466        out
467    }
468}
469
470impl<T> From<Vec<T>> for AppendOnlyVec<T> {
471    fn from(value: Vec<T>) -> Self {
472        value.into_iter().collect()
473    }
474}
475
476#[test]
477fn test_pushing_and_indexing() {
478    let v = AppendOnlyVec::<usize>::new();
479
480    for n in 0..50 {
481        v.push(n);
482        assert_eq!(v.len(), n + 1);
483        for i in 0..(n + 1) {
484            assert_eq!(v[i], i);
485        }
486    }
487
488    let vec: Vec<usize> = v.iter().copied().collect();
489    let ve2: Vec<usize> = (0..50).collect();
490    assert_eq!(vec, ve2);
491}
492
493#[test]
494fn test_parallel_pushing() {
495    use std::sync::Arc;
496    let v = Arc::new(AppendOnlyVec::<u64>::new());
497    let mut threads = Vec::new();
498    const N: u64 = 100;
499    for thread_num in 0..N {
500        let v = v.clone();
501        threads.push(std::thread::spawn(move || {
502            let which1 = v.push(thread_num);
503            let which2 = v.push(thread_num);
504            assert_eq!(v[which1 as usize], thread_num);
505            assert_eq!(v[which2 as usize], thread_num);
506        }));
507    }
508    for t in threads {
509        t.join().ok();
510    }
511    for thread_num in 0..N {
512        assert_eq!(2, v.iter().copied().filter(|&x| x == thread_num).count());
513    }
514}
515
516#[test]
517fn test_into_vec() {
518    struct SafeToDrop(bool);
519
520    impl Drop for SafeToDrop {
521        fn drop(&mut self) {
522            assert!(self.0);
523        }
524    }
525
526    let v = AppendOnlyVec::new();
527
528    for _ in 0..50 {
529        v.push(SafeToDrop(false));
530    }
531
532    let mut v = v.into_vec();
533
534    for i in v.iter_mut() {
535        i.0 = true;
536    }
537}
538
539#[test]
540fn test_push_then_index_mut() {
541    let mut v = AppendOnlyVec::<usize>::new();
542    for i in 0..1024 {
543        v.push(i);
544    }
545    for i in 0..1024 {
546        v[i] += i;
547    }
548    for i in 0..1024 {
549        assert_eq!(v[i], 2 * i);
550    }
551}
552
553#[test]
554fn test_from_vec() {
555    for v in [vec![5_i32, 4, 3, 2, 1], Vec::new(), vec![1]] {
556        let aov: AppendOnlyVec<i32> = v.clone().into();
557        assert_eq!(v, aov.into_vec());
558    }
559}
560
561#[test]
562fn test_clone() {
563    let v = AppendOnlyVec::<String>::new();
564    for i in 0..1024 {
565        v.push(format!("{}", i));
566    }
567    let v2 = v.clone();
568
569    assert_eq!(v.len(), v2.len());
570    for i in 0..1024 {
571        assert_eq!(v[i], v2[i]);
572    }
573}
574
575#[test]
576fn test_push_mut() {
577    let mut v = AppendOnlyVec::new();
578    for i in 0..1024 {
579        v.push_mut(format!("{}", i));
580    }
581    assert_eq!(v.len(), 1024);
582}
583
584#[test]
585fn test_zero_sized() {
586    let v = AppendOnlyVec::<()>::new();
587    for _ in 0..1024 {
588        v.push(());
589    }
590    assert_eq!(v.len(), 1024);
591    assert_eq!(v.iter().count(), 1024);
592    assert_eq!(v.into_vec().len(), 1024);
593}