Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![doc = include_str!("../README.md")]
#![deny(unsafe_op_in_unsafe_fn)]
#![allow(clippy::needless_doctest_main)]
#![allow(clippy::needless_doctest_main, clippy::ok_expect)]
#![no_std]

extern crate alloc;
Expand Down Expand Up @@ -168,11 +168,32 @@ impl<T> Vec<T> {
/// assert_eq!(vec, [0, 1, 2]);
/// ```
#[inline]
pub fn push_with<F>(&self, f: F) -> usize
pub fn push_with<F>(&self, create: F) -> usize
where
F: FnOnce(usize) -> T,
{
self.raw.push_with(f)
self.raw.push_with(create)
}

/// Appends `count` elements to the back of the vector, initializing each
/// element with the closure called with the index of the given element.
///
/// The indices passed to the closure are guaranteed to be in sequential order,
/// and the first index that was created is returned.
///
/// # Examples
///
/// ```
/// let vec = boxcar::vec![0, 1];
/// vec.push_many(3, |index| index);
/// assert_eq!(vec, [0, 1, 2, 3, 4]);
/// ```
#[inline]
pub fn push_many<F>(&self, count: usize, create: F) -> usize
where
F: FnMut(usize) -> T,
{
self.raw.push_many(count, create)
}

/// Returns the number of elements in the vector.
Expand Down
51 changes: 45 additions & 6 deletions src/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,29 +210,68 @@ impl<T> Vec<T> {
index
}

/// Appends an element to the back of the vector.
#[inline]
pub fn push(&self, value: T) -> usize {
// Safety: `next_index` is always in-bounds and unique.
unsafe { self.write(self.next_index(), value) }
}

/// Appends the element returned from the closure to the back of the vector
/// at the index represented by the `usize` passed to closure.
///
/// This allows for use of the would-be index to be utilized within the
/// element.
#[inline]
pub fn push_with<F>(&self, f: F) -> usize
pub fn push_with<F>(&self, create: F) -> usize
where
F: FnOnce(usize) -> T,
{
// Acquire a unique index to insert into.
let index = self.next_index();
let value = f(index);
let value = create(index);

// Safety: `next_index` is always in-bounds and unique.
unsafe { self.write(index, value) }
}

/// Appends an element to the back of the vector.
/// Appends `count` elements to the back of the vector, initializing each
/// element with the closure called with the index of the given element.
///
/// The indices passed to the closure are guaranteed to be in sequential order,
/// and the first index that was created is returned.
#[inline]
pub fn push(&self, value: T) -> usize {
// Safety: `next_index` is always in-bounds and unique.
unsafe { self.write(self.next_index(), value) }
pub fn push_many<F>(&self, count: usize, mut create: F) -> usize
where
F: FnMut(usize) -> T,
{
let index = self
.inflight
// Note that the `Relaxed` ordering here is sufficient, as we only care about
// the index being unique and do not use it for synchronization.
.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |index| {
// Ensure the next index does not overflow.
let next_index = index.checked_add(count)?;

// Ensure that the final index we are creating is in-bounds.
if (next_index - 1) > MAX_INDEX {
return None;
}

Some(next_index)
})
.ok()
.expect("capacity overflow");

for index in index..index + count {
let value = create(index);

// Safety: We uniquely claimed every every index from `index..index + count`
// and ensured that they are in-bounds.
unsafe { self.write(index, value) };
}

index
}

/// Write an element at the given index.
Expand Down