Skip to content

Commit 8ca25b8

Browse files
committedJan 31, 2023
Fix vec_deque::Drain FIXME
1 parent e37ff7e commit 8ca25b8

File tree

2 files changed

+19
-31
lines changed

2 files changed

+19
-31
lines changed
 

‎library/alloc/src/collections/vec_deque/drain.rs

+9-23
Original file line numberDiff line numberDiff line change
@@ -57,31 +57,17 @@ impl<'a, T, A: Allocator> Drain<'a, T, A> {
5757
unsafe fn as_slices(&self) -> (*mut [T], *mut [T]) {
5858
unsafe {
5959
let deque = self.deque.as_ref();
60-
// FIXME: This is doing almost exactly the same thing as the else branch in `VecDeque::slice_ranges`.
61-
// Unfortunately, we can't just call `slice_ranges` here, as the deque's `len` is currently
62-
// just `drain_start`, so the range check would (almost) always panic. Between temporarily
63-
// adjusting the deques `len` to call `slice_ranges`, and just copy pasting the `slice_ranges`
64-
// implementation, this seemed like the less hacky solution, though it might be good to
65-
// find a better one in the future.
66-
67-
// because `self.remaining != 0`, we know that `self.idx < deque.original_len`, so it's a valid
68-
// logical index.
69-
let wrapped_start = deque.to_physical_idx(self.idx);
70-
71-
let head_len = deque.capacity() - wrapped_start;
72-
73-
let (a_range, b_range) = if head_len >= self.remaining {
74-
(wrapped_start..wrapped_start + self.remaining, 0..0)
75-
} else {
76-
let tail_len = self.remaining - head_len;
77-
(wrapped_start..deque.capacity(), 0..tail_len)
78-
};
79-
80-
// SAFETY: the range `self.idx..self.idx+self.remaining` lies strictly inside
81-
// the range `0..deque.original_len`. because of this, and because of the fact
82-
// that we acquire `a_range` and `b_range` exactly like `slice_ranges` would,
60+
61+
let start = self.idx;
62+
// We know that `self.idx + self.remaining <= deque.len <= usize::MAX`, so this won't overflow.
63+
let end = start + self.remaining;
64+
65+
// SAFETY: the range `start..end` lies strictly inside
66+
// the range `0..deque.original_len`. Because of this, and because
67+
// we haven't touched the elements inside this range yet,
8368
// it's guaranteed that `a_range` and `b_range` represent valid ranges into
8469
// the deques buffer.
70+
let (a_range, b_range) = deque.slice_ranges(start..end, end);
8571
(deque.buffer_range(a_range), deque.buffer_range(b_range))
8672
}
8773
}

‎library/alloc/src/collections/vec_deque/mod.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -1147,7 +1147,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
11471147
#[inline]
11481148
#[stable(feature = "deque_extras_15", since = "1.5.0")]
11491149
pub fn as_slices(&self) -> (&[T], &[T]) {
1150-
let (a_range, b_range) = self.slice_ranges(..);
1150+
let (a_range, b_range) = self.slice_ranges(.., self.len);
11511151
// SAFETY: `slice_ranges` always returns valid ranges into
11521152
// the physical buffer.
11531153
unsafe { (&*self.buffer_range(a_range), &*self.buffer_range(b_range)) }
@@ -1181,7 +1181,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
11811181
#[inline]
11821182
#[stable(feature = "deque_extras_15", since = "1.5.0")]
11831183
pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
1184-
let (a_range, b_range) = self.slice_ranges(..);
1184+
let (a_range, b_range) = self.slice_ranges(.., self.len);
11851185
// SAFETY: `slice_ranges` always returns valid ranges into
11861186
// the physical buffer.
11871187
unsafe { (&mut *self.buffer_range(a_range), &mut *self.buffer_range(b_range)) }
@@ -1223,19 +1223,21 @@ impl<T, A: Allocator> VecDeque<T, A> {
12231223

12241224
/// Given a range into the logical buffer of the deque, this function
12251225
/// return two ranges into the physical buffer that correspond to
1226-
/// the given range.
1227-
fn slice_ranges<R>(&self, range: R) -> (Range<usize>, Range<usize>)
1226+
/// the given range. The `len` parameter should usually just be `self.len`;
1227+
/// the reason it's passed explicitly is that if the deque is wrapped in
1228+
/// a `Drain`, then `self.len` is not actually the length of the deque.
1229+
fn slice_ranges<R>(&self, range: R, len: usize) -> (Range<usize>, Range<usize>)
12281230
where
12291231
R: RangeBounds<usize>,
12301232
{
1231-
let Range { start, end } = slice::range(range, ..self.len);
1233+
let Range { start, end } = slice::range(range, ..len);
12321234
let len = end - start;
12331235

12341236
if len == 0 {
12351237
(0..0, 0..0)
12361238
} else {
12371239
// `slice::range` guarantees that `start <= end <= self.len`.
1238-
// because `len != 0`, we know that `start < end`, so `start < self.len`
1240+
// because `len != 0`, we know that `start < end`, so `start < len`
12391241
// and the indexing is valid.
12401242
let wrapped_start = self.to_physical_idx(start);
12411243

@@ -1281,7 +1283,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
12811283
where
12821284
R: RangeBounds<usize>,
12831285
{
1284-
let (a_range, b_range) = self.slice_ranges(range);
1286+
let (a_range, b_range) = self.slice_ranges(range, self.len);
12851287
// SAFETY: The ranges returned by `slice_ranges`
12861288
// are valid ranges into the physical buffer, so
12871289
// it's ok to pass them to `buffer_range` and
@@ -1321,7 +1323,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
13211323
where
13221324
R: RangeBounds<usize>,
13231325
{
1324-
let (a_range, b_range) = self.slice_ranges(range);
1326+
let (a_range, b_range) = self.slice_ranges(range, self.len);
13251327
// SAFETY: The ranges returned by `slice_ranges`
13261328
// are valid ranges into the physical buffer, so
13271329
// it's ok to pass them to `buffer_range` and

0 commit comments

Comments
 (0)
Please sign in to comment.