Skip to content

Commit

Permalink
add Vec::clear for reusing previously allocated space
Browse files Browse the repository at this point in the history
  • Loading branch information
l4l authored Nov 7, 2024
1 parent 7b52f00 commit a640e09
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,23 @@ impl<T> Vec<T> {
}
}

/// Creates a new `Vec<T>` reusing allocated space from the `self`.
///
/// # Examples
/// ```
/// let vec = boxcar::Vec::new();
/// vec.push(1);
/// vec.push(2);
///
/// let mut vec = vec;
/// vec.clear();
/// assert_eq!(vec.count(), 0);
/// vec.push(3); // will not allocate
/// ```
pub fn clear(&mut self) {
self.raw.clear();
}

/// Reserves capacity for at least `additional` more elements to be inserted
/// in the given `Vec<T>`. The collection may reserve more space to avoid
/// frequent reallocations.
Expand Down
20 changes: 20 additions & 0 deletions src/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,26 @@ impl<T> Vec<T> {
}
}

pub fn clear(&mut self) {
self.count.store(0, Ordering::Relaxed);
self.inflight.store(0, Ordering::Relaxed);

for (i, b) in self.buckets.iter_mut().enumerate() {
let e = b.entries.load(Ordering::Relaxed);
if e.is_null() {
continue;
}

let len = Location::bucket_capacity(i);
for i in 0..len {
let e = unsafe { &mut *e.add(i) };
if e.active.swap(false, Ordering::Relaxed) {
unsafe { ptr::drop_in_place((*e.slot.get()).as_mut_ptr()) }
}
}
}
}

/// Returns the number of elements in the vector.
pub fn count(&self) -> usize {
self.count.load(Ordering::Acquire)
Expand Down
36 changes: 36 additions & 0 deletions tests/vec.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::sync::atomic::{AtomicUsize, Ordering};
use std::{sync::Barrier, thread};

#[test]
Expand All @@ -21,6 +22,41 @@ fn simple() {
}
}

#[test]
fn clear() {
struct T<'a>(&'a AtomicUsize);
impl Drop for T<'_> {
fn drop(&mut self) {
self.0.fetch_add(1, Ordering::Relaxed);
}
}

let drops = AtomicUsize::new(0);

let mut vec = boxcar::Vec::new();
vec.push(T(&drops));
vec.push(T(&drops));

let first_ptr: *const _ = vec.iter().next().unwrap().1 as _;

vec.clear();
assert_eq!(vec.count(), 0);
assert_eq!(vec.iter().count(), 0);
assert_eq!(drops.swap(0, Ordering::Relaxed), 2);

vec.clear();
assert_eq!(vec.count(), 0);
assert_eq!(vec.iter().count(), 0);
assert_eq!(drops.load(Ordering::Relaxed), 0);

vec.push(T(&drops));
let ptr: *const _ = vec.iter().next().unwrap().1 as _;
assert_eq!(ptr, first_ptr);

drop(vec);
assert_eq!(drops.load(Ordering::Relaxed), 1);
}

#[test]
fn stress() {
let vec = boxcar::Vec::new();
Expand Down

0 comments on commit a640e09

Please sign in to comment.