Skip to content
Merged
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
56 changes: 7 additions & 49 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub use iterators::{
mod macros;
#[cfg(feature = "malloc_size_of")]
mod mallocsizeof;
mod newrange;
mod rawsmallvec;
mod references;
#[cfg(feature = "serde")]
Expand Down Expand Up @@ -81,7 +82,8 @@ use {
copy_nonoverlapping,
drop_in_place
}
}
},
newrange::NewRange
};
#[cfg(feature = "internals")]
pub use {
Expand All @@ -94,50 +96,6 @@ use {
taggedlen::TaggedLen
};

#[inline]
/// A local copy of [`core::slice::range`]. The latter function is unstable
/// and thus cannot be used yet.
fn slice_range<R>(range: R, bounds: core::ops::RangeTo<usize>) -> core::ops::Range<usize>
where R: core::ops::RangeBounds<usize> {
#[cold]
#[inline(never)]
#[track_caller]
fn assert_failed(start: usize, end: usize, length: usize) -> ! {
if start > end {
panic!("slice index starts at {start} but ends at {end}");
} else {
panic!("range end index {end} out of range for slice of length {length}");
}
}

let length = bounds.end;

let start = match range.start_bound() {
core::ops::Bound::Included(&start) => start,
core::ops::Bound::Excluded(start) => start
.checked_add(1)
.unwrap_or_else(|| panic!("attempted to index slice from after maximum usize")),
core::ops::Bound::Unbounded => 0
};

let end = match range.end_bound() {
core::ops::Bound::Included(end) => end
.checked_add(1)
.unwrap_or_else(|| panic!("attempted to index slice up to maximum usize")),
core::ops::Bound::Excluded(&end) => end,
core::ops::Bound::Unbounded => length
};

if start > end || end > length {
assert_failed(start, end, length);
}

core::ops::Range {
start,
end
}
}

#[repr(C)]
pub struct SmallVec<T, const N: usize, A: Allocator = Global> {
length: TaggedLen<T>,
Expand Down Expand Up @@ -484,7 +442,7 @@ impl<T, const N: usize, A: Allocator> SmallVec<T, N, A> {
let core::ops::Range {
start,
end
} = slice_range(range, ..length);
} = core::ops::Range::new(range, length);

unsafe {
// SAFETY: `start <= length`
Expand Down Expand Up @@ -598,7 +556,7 @@ impl<T, const N: usize, A: Allocator> SmallVec<T, N, A> {
let core::ops::Range {
start,
end
} = slice_range(range, ..old_len);
} = core::ops::Range::new(range, old_len);

// Guard against us getting leaked (leak amplification)
unsafe {
Expand Down Expand Up @@ -1353,7 +1311,7 @@ impl<T, const N: usize, A: Allocator> SmallVec<T, N, A> {
R: core::ops::RangeBounds<usize>,
T: Copy
{
let src = slice_range(src, ..self.len());
let src = core::ops::Range::new(src, self.len());
let core::ops::Range {
start,
end
Expand Down Expand Up @@ -1439,7 +1397,7 @@ impl<T: Clone, const N: usize, A: Allocator> SmallVec<T, N, A> {

pub fn extend_from_within<R>(&mut self, src: R)
where R: core::ops::RangeBounds<usize> {
let src = slice_range(src, ..self.len());
let src = core::ops::Range::new(src, self.len());
self.reserve(src.len());

// SAFETY: The call to `reserve` ensures that the capacity is large
Expand Down
50 changes: 50 additions & 0 deletions src/newrange.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use core::ops::{
Bound,
Range,
RangeBounds
};

pub trait NewRange {
fn new(rangebounds: impl RangeBounds<usize>, length: usize) -> Self;
}

impl NewRange for Range<usize> {
#[inline]
fn new(rangebounds: impl RangeBounds<usize>, length: usize) -> Self {
#[cold]
#[inline(never)]
#[track_caller]
fn assert_failed(start: usize, end: usize, len: usize) -> ! {
if start > end {
panic!("slice index starts at {start} but ends at {end}");
} else {
panic!("range end index {end} out of range for slice of length {len}");
}
}

let start = match rangebounds.start_bound() {
Bound::Included(&start) => start,
Bound::Excluded(start) => start
.checked_add(1)
.unwrap_or_else(|| panic!("attempted to index slice from after maximum usize")),
Bound::Unbounded => 0
};

let end = match rangebounds.end_bound() {
Bound::Included(end) => end
.checked_add(1)
.unwrap_or_else(|| panic!("attempted to index slice up to maximum usize")),
Bound::Excluded(&end) => end,
Bound::Unbounded => length
};

if start > end || end > length {
assert_failed(start, end, length);
}

Range {
start,
end
}
}
}
Loading