Skip to content

Commit ecc9554

Browse files
committed
add push_atomic()
1 parent c9d5388 commit ecc9554

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

src/lib.rs

+26
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,32 @@ impl<H, T> HeaderVec<H, T> {
408408
fn end_ptr_atomic_mut(&self) -> *mut T {
409409
unsafe { self.ptr.add(Self::offset()).add(self.len_atomic_acquire()) }
410410
}
411+
412+
/// Atomically adds an item to the end of the list without reallocation.
413+
///
414+
/// # Errors
415+
///
416+
/// If the vector is full, the item is returned.
417+
///
418+
/// # Safety
419+
///
420+
/// There must be only one thread calling this method at any time. Synchronization has to
421+
/// be provided by the user.
422+
pub unsafe fn push_atomic(&self, item: T) -> Result<(), T> {
423+
// relaxed is good enough here because this should be the only thread calling this method.
424+
let len = self.len_atomic_relaxed();
425+
if len < self.capacity() {
426+
unsafe {
427+
core::ptr::write(self.end_ptr_atomic_mut(), item);
428+
};
429+
let len_again = self.len_atomic_add_release(1);
430+
// in debug builds we check for races, the chance to catch these are still pretty minimal
431+
debug_assert_eq!(len_again, len, "len was updated by another thread");
432+
Ok(())
433+
} else {
434+
Err(item)
435+
}
436+
}
411437
}
412438

413439
impl<H, T> Drop for HeaderVec<H, T> {

tests/atomic_append.rs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![cfg(feature = "atomic_append")]
2+
extern crate std;
3+
4+
use header_vec::*;
5+
6+
#[test]
7+
fn test_atomic_append() {
8+
let mut hv = HeaderVec::with_capacity(10, ());
9+
10+
hv.push(1);
11+
unsafe { hv.push_atomic(2).unwrap() };
12+
hv.push(3);
13+
14+
assert_eq!(hv.len(), 3);
15+
assert_eq!(hv.as_slice(), [1, 2, 3]);
16+
}

0 commit comments

Comments
 (0)