Skip to content

Commit e237512

Browse files
committed
Implement range argument to match Vec
1 parent 7f01291 commit e237512

File tree

1 file changed

+75
-8
lines changed

1 file changed

+75
-8
lines changed

src/lib.rs

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ use core::ops::Bound;
160160
use core::ops::{Deref, DerefMut, RangeBounds};
161161
use core::ptr::NonNull;
162162
use core::slice::Iter;
163-
use core::{fmt, mem, ptr, slice};
163+
use core::{fmt, mem, ops, ptr, slice};
164164

165165
use impl_details::*;
166166

@@ -1591,20 +1591,85 @@ impl<T> ThinVec<T> {
15911591
/// assert_eq!(evens, thin_vec![2, 4, 6, 8, 14]);
15921592
/// assert_eq!(odds, thin_vec![1, 3, 5, 9, 11, 13, 15]);
15931593
/// ```
1594-
pub fn extract_if<F>(&mut self, filter: F) -> ExtractIf<'_, T, F>
1594+
pub fn extract_if<F, R: RangeBounds<usize>>(
1595+
&mut self,
1596+
filter: F,
1597+
range: R,
1598+
) -> ExtractIf<'_, T, F>
15951599
where
15961600
F: FnMut(&mut T) -> bool,
15971601
{
1602+
// Copy of https://github.com/rust-lang/rust/blob/ee361e8fca1c30e13e7a31cc82b64c045339d3a8/library/core/src/slice/index.rs#L37
1603+
fn slice_index_fail(start: usize, end: usize, len: usize) -> ! {
1604+
if start > len {
1605+
panic!(
1606+
"range start index {} out of range for slice of length {}",
1607+
start, len
1608+
)
1609+
}
1610+
1611+
if end > len {
1612+
panic!(
1613+
"range end index {} out of range for slice of length {}",
1614+
end, len
1615+
)
1616+
}
1617+
1618+
if start > end {
1619+
panic!("slice index starts at {} but ends at {}", start, end)
1620+
}
1621+
1622+
// Only reachable if the range was a `RangeInclusive` or a
1623+
// `RangeToInclusive`, with `end == len`.
1624+
panic!(
1625+
"range end index {} out of range for slice of length {}",
1626+
end, len
1627+
)
1628+
}
1629+
1630+
// Backport of https://github.com/rust-lang/rust/blob/ee361e8fca1c30e13e7a31cc82b64c045339d3a8/library/core/src/slice/index.rs#L855
1631+
pub fn slice_range<R>(range: R, bounds: ops::RangeTo<usize>) -> ops::Range<usize>
1632+
where
1633+
R: ops::RangeBounds<usize>,
1634+
{
1635+
let len = bounds.end;
1636+
1637+
let end = match range.end_bound() {
1638+
ops::Bound::Included(&end) if end >= len => slice_index_fail(0, end, len),
1639+
// Cannot overflow because `end < len` implies `end < usize::MAX`.
1640+
ops::Bound::Included(&end) => end + 1,
1641+
1642+
ops::Bound::Excluded(&end) if end > len => slice_index_fail(0, end, len),
1643+
ops::Bound::Excluded(&end) => end,
1644+
ops::Bound::Unbounded => len,
1645+
};
1646+
1647+
let start = match range.start_bound() {
1648+
ops::Bound::Excluded(&start) if start >= end => slice_index_fail(start, end, len),
1649+
// Cannot overflow because `start < end` implies `start < usize::MAX`.
1650+
ops::Bound::Excluded(&start) => start + 1,
1651+
1652+
ops::Bound::Included(&start) if start > end => slice_index_fail(start, end, len),
1653+
ops::Bound::Included(&start) => start,
1654+
1655+
ops::Bound::Unbounded => 0,
1656+
};
1657+
1658+
ops::Range { start, end }
1659+
}
1660+
15981661
let old_len = self.len();
1599-
// Guard against us getting leaked (leak amplification)
1662+
let ops::Range { start, end } = slice_range(range, ..old_len);
1663+
1664+
// Guard against the vec getting leaked (leak amplification)
16001665
unsafe {
16011666
self.set_len(0);
16021667
}
1603-
16041668
ExtractIf {
16051669
vec: self,
1606-
idx: 0,
1670+
idx: start,
16071671
del: 0,
1672+
end,
16081673
old_len,
16091674
pred: filter,
16101675
}
@@ -2851,6 +2916,8 @@ pub struct ExtractIf<'a, T, F> {
28512916
vec: &'a mut ThinVec<T>,
28522917
/// The index of the item that will be inspected by the next call to `next`.
28532918
idx: usize,
2919+
/// Elements at and beyond this point will be retained. Must be equal or smaller than `old_len`.
2920+
end: usize,
28542921
/// The number of items that have been drained (removed) thus far.
28552922
del: usize,
28562923
/// The original length of `vec` prior to draining.
@@ -2865,9 +2932,9 @@ where
28652932
{
28662933
type Item = T;
28672934

2868-
fn next(&mut self) -> Option<Self::Item> {
2935+
fn next(&mut self) -> Option<T> {
28692936
unsafe {
2870-
while self.idx < self.old_len {
2937+
while self.idx < self.end {
28712938
let i = self.idx;
28722939
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
28732940
let drained = (self.pred)(&mut v[i]);
@@ -2890,7 +2957,7 @@ where
28902957
}
28912958

28922959
fn size_hint(&self) -> (usize, Option<usize>) {
2893-
(0, Some(self.old_len - self.idx))
2960+
(0, Some(self.end - self.idx))
28942961
}
28952962
}
28962963

0 commit comments

Comments
 (0)