Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
84 changes: 58 additions & 26 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ impl<T> Clone for TaggedLen<T> {
fn clone(&self) -> Self {
Self(self.0, PhantomData)
}

#[inline]
fn clone_from(&mut self, source: &Self) {
self.0 = source.0;
Expand Down Expand Up @@ -508,7 +508,10 @@ impl<T, const N: usize> Drain<'_, T, N> {
let range_start = vec.len();
let range_end = self.tail_start;
let range_slice = unsafe {
core::slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start)
core::slice::from_raw_parts_mut(
vec.as_mut_ptr().add(range_start),
range_end - range_start,
)
};

for place in range_slice {
Expand Down Expand Up @@ -708,7 +711,11 @@ impl<I: Iterator, const N: usize> Drop for Splice<'_, I, N> {
}

// Collect any remaining elements.
let mut collected = self.replace_with.by_ref().collect::<SmallVec<I::Item, N>>().into_iter();
let mut collected = self
.replace_with
.by_ref()
.collect::<SmallVec<I::Item, N>>()
.into_iter();
// Now we have an exact count.
if collected.len() > 0 {
self.drain.move_tail(collected.len());
Expand Down Expand Up @@ -744,7 +751,6 @@ unsafe impl<T, const N: usize> Send for IntoIter<T, N> where T: Send {}
unsafe impl<T, const N: usize> Sync for IntoIter<T, N> where T: Sync {}

impl<T, const N: usize> IntoIter<T, N> {

#[inline]
const fn as_ptr(&self) -> *const T {
let on_heap = self.end.on_heap();
Expand Down Expand Up @@ -773,10 +779,7 @@ impl<T, const N: usize> IntoIter<T, N> {
// So the pointer arithmetic is valid, and so is the construction of the slice
unsafe {
let ptr = self.as_ptr();
core::slice::from_raw_parts(
ptr.add(self.begin),
self.end.value() - self.begin,
)
core::slice::from_raw_parts(ptr.add(self.begin), self.end.value() - self.begin)
}
}

Expand All @@ -785,10 +788,7 @@ impl<T, const N: usize> IntoIter<T, N> {
// SAFETY: see above
unsafe {
let ptr = self.as_mut_ptr();
core::slice::from_raw_parts_mut(
ptr.add(self.begin),
self.end.value() - self.begin,
)
core::slice::from_raw_parts_mut(ptr.add(self.begin), self.end.value() - self.begin)
}
}
}
Expand Down Expand Up @@ -861,7 +861,9 @@ impl<T, const N: usize> SmallVec<T, N> {

#[inline]
pub const fn from_buf<const S: usize>(elements: [T; S]) -> Self {
const { assert!(S <= N); }
const {
assert!(S <= N);
}

// Although we create a new buffer, since S and N are known at compile time,
// even with `-C opt-level=1`, it gets optimized as best as it could be. (Checked with <godbolt.org>)
Expand Down Expand Up @@ -1218,21 +1220,34 @@ impl<T, const N: usize> SmallVec<T, N> {
R: core::ops::RangeBounds<usize>,
I: IntoIterator<Item = T>,
{
Splice { drain: self.drain(range), replace_with: replace_with.into_iter() }
Splice {
drain: self.drain(range),
replace_with: replace_with.into_iter(),
}
}

#[inline]
pub fn push(&mut self, value: T) {
_ = self.push_mut(value);
}

#[inline]
#[must_use]
pub fn push_mut(&mut self, value: T) -> &mut T {
let len = self.len();
if len == self.capacity() {
self.reserve(1);
}

// SAFETY: both the input and output are within the allocation
let ptr = unsafe { self.as_mut_ptr().add(len) };
// SAFETY: we allocated enough space in case it wasn't enough, so the address is valid for
// writes.
unsafe { ptr.write(value) };
unsafe { self.set_len(len + 1) }

let result = unsafe { ptr.as_mut() };
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just &mut *ptr? Or why would as_mut().unwrap_unchecked() be preferred?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is just my writing style; it makes it easier to search.
I simplified it anyway

unsafe { result.unwrap_unchecked() }
}

#[inline]
Expand All @@ -1253,7 +1268,11 @@ impl<T, const N: usize> SmallVec<T, N> {
#[inline]
pub fn pop_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option<T> {
let last = self.last_mut()?;
if predicate(last) { self.pop() } else { None }
if predicate(last) {
self.pop()
} else {
None
}
}

#[inline]
Expand Down Expand Up @@ -1418,7 +1437,10 @@ impl<T, const N: usize> SmallVec<T, N> {
self.set_inline();
alloc::alloc::dealloc(
ptr.cast().as_ptr(),
Layout::from_size_align_unchecked(capacity * size_of::<T>(), align_of::<T>()),
Layout::from_size_align_unchecked(
capacity * size_of::<T>(),
align_of::<T>(),
),
);
}
} else if target < self.capacity() {
Expand Down Expand Up @@ -1449,7 +1471,10 @@ impl<T, const N: usize> SmallVec<T, N> {
#[inline]
pub fn swap_remove(&mut self, index: usize) -> T {
let len = self.len();
assert!(index < len, "swap_remove index (is {index}) should be < len (is {len})");
assert!(
index < len,
"swap_remove index (is {index}) should be < len (is {len})"
);
// This can't overflow since `len > index >= 0`
let new_len = len - 1;
unsafe {
Expand Down Expand Up @@ -1481,7 +1506,10 @@ impl<T, const N: usize> SmallVec<T, N> {
#[inline]
pub fn remove(&mut self, index: usize) -> T {
let len = self.len();
assert!(index < len, "removal index (is {index}) should be < len (is {len})");
assert!(
index < len,
"removal index (is {index}) should be < len (is {len})"
);
let new_len = len - 1;
unsafe {
// SAFETY: new_len < len
Expand All @@ -1498,7 +1526,10 @@ impl<T, const N: usize> SmallVec<T, N> {
#[inline]
pub fn insert(&mut self, index: usize, value: T) {
let len = self.len();
assert!(index <= len, "insertion index (is {index}) should be <= len (is {len})");
assert!(
index <= len,
"insertion index (is {index}) should be <= len (is {len})"
);
self.reserve(1);
let ptr = self.as_mut_ptr();
unsafe {
Expand Down Expand Up @@ -1694,7 +1725,9 @@ impl<T, const N: usize> SmallVec<T, N> {

pub fn leak<'a>(self) -> &'a mut [T] {
if !self.spilled() {
panic!("SmallVec::leak() called on inline (stack) SmallVec, which cannot be safely leaked");
panic!(
"SmallVec::leak() called on inline (stack) SmallVec, which cannot be safely leaked"
);
}
let mut me = ManuallyDrop::new(self);
unsafe { core::slice::from_raw_parts_mut(me.as_mut_ptr(), me.len()) }
Expand Down Expand Up @@ -1827,12 +1860,11 @@ impl<T: Clone, const N: usize> SmallVec<T, N> {
#[inline]
pub fn extend_from_slice_copy(&mut self, other: &[T])
where
T: Copy
T: Copy,
{

let len = other.len();
let src = other.as_ptr();

let l = self.len();
self.reserve(len);

Expand All @@ -1848,7 +1880,7 @@ impl<T: Clone, const N: usize> SmallVec<T, N> {
pub fn extend_from_within_copy<R>(&mut self, src: R)
where
R: core::ops::RangeBounds<usize>,
T: Copy
T: Copy,
{
let src = slice_range(src, ..self.len());
let core::ops::Range { start, end } = src;
Expand All @@ -1867,7 +1899,7 @@ impl<T: Clone, const N: usize> SmallVec<T, N> {

pub fn insert_from_slice_copy(&mut self, index: usize, other: &[T])
where
T: Copy
T: Copy,
{
let l = self.len();
let len = other.len();
Expand All @@ -1891,7 +1923,7 @@ impl<T: Clone, const N: usize> SmallVec<T, N> {
/// for types with the [`Copy`] trait.
pub fn from_slice_copy(slice: &[T]) -> Self
where
T: Copy
T: Copy,
{
let src = slice.as_ptr();
let len = slice.len();
Expand Down
19 changes: 15 additions & 4 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ pub fn test_zero() {

// We heap allocate all these strings so that double frees will show up under valgrind.

#[test]
pub fn test_push_mut() {
let mut v = SmallVec::<_, 16>::new();

let first_elem = v.push_mut("hello".to_owned());
assert_eq!(&*first_elem, &"hello".to_owned());

*first_elem = "hi".to_owned();
assert_eq!(&*first_elem, &"hi".to_owned());

v.push("there".to_owned());
assert_eq!(&*v, &["hi".to_owned(), "there".to_owned(),][..]);
}

#[test]
pub fn test_inline() {
let mut v = SmallVec::<_, 16>::new();
Expand Down Expand Up @@ -587,10 +601,7 @@ fn test_from() {
#[test]
fn test_from_slice() {
assert_eq!(&SmallVec::<u32, 2>::from(&[1][..])[..], [1]);
assert_eq!(
&SmallVec::<u32, 2>::from(&[1, 2, 3][..])[..],
[1, 2, 3]
);
assert_eq!(&SmallVec::<u32, 2>::from(&[1, 2, 3][..])[..], [1, 2, 3]);
}

#[test]
Expand Down