Skip to content

Commit af568e6

Browse files
committed
implement VecDeque extend_from_within and prepend_from_within, add tests
1 parent 21a13b8 commit af568e6

File tree

3 files changed

+470
-0
lines changed

3 files changed

+470
-0
lines changed

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

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,76 @@ impl<T, A: Allocator> VecDeque<T, A> {
227227
wrap_index(idx.wrapping_sub(subtrahend).wrapping_add(self.capacity()), self.capacity())
228228
}
229229

230+
/// Get source, destination and count (like the arguments to [`ptr::copy_nonoverlapping`])
231+
/// for copying `count` values from index `src` to index `dst`.
232+
/// One of the ranges can wrap around the physical buffer, for this reason 2 triples are returned.
233+
///
234+
/// Use of the word "ranges" specifically refers to `src..src + count` and `dst..dst + count`.
235+
///
236+
/// # Safety
237+
///
238+
/// - Ranges must not overlap: `src.abs_diff(dst) >= count`.
239+
/// - Ranges must be in bounds of the logical buffer: `src + count <= self.capacity()` and `dst + count <= self.capacity()`.
240+
/// - `head` must be in bounds: `head < self.capacity()`.
241+
#[cfg(not(no_global_oom_handling))]
242+
unsafe fn nonoverlapping_ranges(
243+
&mut self,
244+
src: usize,
245+
dst: usize,
246+
count: usize,
247+
head: usize,
248+
) -> [(*const T, *mut T, usize); 2] {
249+
// "`src` and `dst` must be at least as far apart as `count`"
250+
debug_assert!(
251+
src.abs_diff(dst) >= count,
252+
"`src` and `dst` must not overlap. src={src} dst={dst} count={count}",
253+
);
254+
debug_assert!(
255+
src.max(dst) + count <= self.capacity(),
256+
"ranges must be in bounds. src={src} dst={dst} count={count} cap={}",
257+
self.capacity(),
258+
);
259+
260+
let wrapped_src = self.wrap_add(head, src);
261+
let wrapped_dst = self.wrap_add(head, dst);
262+
263+
let room_after_src = self.capacity() - wrapped_src;
264+
let room_after_dst = self.capacity() - wrapped_dst;
265+
266+
let src_wraps = room_after_src < count;
267+
let dst_wraps = room_after_dst < count;
268+
269+
debug_assert!(
270+
!(src_wraps && dst_wraps),
271+
"BUG: at most one of src and dst can wrap. src={src} dst={dst} count={count} cap={}",
272+
self.capacity(),
273+
);
274+
275+
unsafe {
276+
let ptr = self.ptr();
277+
let src_ptr = ptr.add(wrapped_src);
278+
let dst_ptr = ptr.add(wrapped_dst);
279+
280+
if src_wraps {
281+
[
282+
(src_ptr, dst_ptr, room_after_src),
283+
(ptr, dst_ptr.add(room_after_src), count - room_after_src),
284+
]
285+
} else if dst_wraps {
286+
[
287+
(src_ptr, dst_ptr, room_after_dst),
288+
(src_ptr.add(room_after_dst), ptr, count - room_after_dst),
289+
]
290+
} else {
291+
[
292+
(src_ptr, dst_ptr, count),
293+
// null pointers are fine as long as the count is 0
294+
(ptr::null(), ptr::null_mut(), 0),
295+
]
296+
}
297+
}
298+
}
299+
230300
/// Copies a contiguous block of memory len long from src to dst
231301
#[inline]
232302
unsafe fn copy(&mut self, src: usize, dst: usize, len: usize) {
@@ -2971,6 +3041,208 @@ impl<T: Clone, A: Allocator> VecDeque<T, A> {
29713041
self.truncate(new_len);
29723042
}
29733043
}
3044+
3045+
/// Clones the elements at the range `src` and appends them to the end.
3046+
///
3047+
/// # Panics
3048+
///
3049+
/// Panics if the starting index is greater than the end index
3050+
/// or if either index is greater than the length of the vector.
3051+
///
3052+
/// # Examples
3053+
///
3054+
/// ```
3055+
/// #![feature(deque_extend_front)]
3056+
/// use std::collections::VecDeque;
3057+
///
3058+
/// let mut characters = VecDeque::from(['a', 'b', 'c', 'd', 'e']);
3059+
/// characters.extend_from_within(2..);
3060+
/// assert_eq!(characters, ['a', 'b', 'c', 'd', 'e', 'c', 'd', 'e']);
3061+
///
3062+
/// let mut numbers = VecDeque::from([0, 1, 2, 3, 4]);
3063+
/// numbers.extend_from_within(..2);
3064+
/// assert_eq!(numbers, [0, 1, 2, 3, 4, 0, 1]);
3065+
///
3066+
/// let mut strings = VecDeque::from([String::from("hello"), String::from("world"), String::from("!")]);
3067+
/// strings.extend_from_within(1..=2);
3068+
/// assert_eq!(strings, ["hello", "world", "!", "world", "!"]);
3069+
/// ```
3070+
#[cfg(not(no_global_oom_handling))]
3071+
#[unstable(feature = "deque_extend_front", issue = "146975")]
3072+
pub fn extend_from_within<R>(&mut self, src: R)
3073+
where
3074+
R: RangeBounds<usize>,
3075+
{
3076+
let range = slice::range(src, ..self.len());
3077+
self.reserve(range.len());
3078+
3079+
// SAFETY:
3080+
// - `slice::range` guarantees that the given range is valid for indexing self
3081+
// - at least `range.len()` additional space is available
3082+
unsafe {
3083+
self.spec_extend_from_within(range);
3084+
}
3085+
}
3086+
3087+
/// Clones the elements at the range `src` and prepends them to the front.
3088+
///
3089+
/// # Panics
3090+
///
3091+
/// Panics if the starting index is greater than the end index
3092+
/// or if either index is greater than the length of the vector.
3093+
///
3094+
/// # Examples
3095+
///
3096+
/// ```
3097+
/// #![feature(deque_extend_front)]
3098+
/// use std::collections::VecDeque;
3099+
///
3100+
/// let mut characters = VecDeque::from(['a', 'b', 'c', 'd', 'e']);
3101+
/// characters.prepend_from_within(2..);
3102+
/// assert_eq!(characters, ['c', 'd', 'e', 'a', 'b', 'c', 'd', 'e']);
3103+
///
3104+
/// let mut numbers = VecDeque::from([0, 1, 2, 3, 4]);
3105+
/// numbers.prepend_from_within(..2);
3106+
/// assert_eq!(numbers, [0, 1, 0, 1, 2, 3, 4]);
3107+
///
3108+
/// let mut strings = VecDeque::from([String::from("hello"), String::from("world"), String::from("!")]);
3109+
/// strings.prepend_from_within(1..=2);
3110+
/// assert_eq!(strings, ["world", "!", "hello", "world", "!"]);
3111+
/// ```
3112+
#[cfg(not(no_global_oom_handling))]
3113+
#[unstable(feature = "deque_extend_front", issue = "146975")]
3114+
pub fn prepend_from_within<R>(&mut self, src: R)
3115+
where
3116+
R: RangeBounds<usize>,
3117+
{
3118+
let range = slice::range(src, ..self.len());
3119+
self.reserve(range.len());
3120+
3121+
// SAFETY:
3122+
// - `slice::range` guarantees that the given range is valid for indexing self
3123+
// - at least `range.len()` additional space is available
3124+
unsafe {
3125+
self.spec_prepend_from_within(range);
3126+
}
3127+
}
3128+
}
3129+
3130+
/// Associated functions have the following preconditions:
3131+
///
3132+
/// - `src` needs to be a valid range: `src.start <= src.end <= self.len()`.
3133+
/// - The buffer must have enough spare capacity: `self.capacity() - self.len() >= src.len()`.
3134+
#[cfg(not(no_global_oom_handling))]
3135+
trait SpecExtendFromWithin {
3136+
unsafe fn spec_extend_from_within(&mut self, src: Range<usize>);
3137+
3138+
unsafe fn spec_prepend_from_within(&mut self, src: Range<usize>);
3139+
}
3140+
3141+
#[cfg(not(no_global_oom_handling))]
3142+
impl<T: Clone, A: Allocator> SpecExtendFromWithin for VecDeque<T, A> {
3143+
default unsafe fn spec_extend_from_within(&mut self, src: Range<usize>) {
3144+
let dst = self.len();
3145+
let count = src.end - src.start;
3146+
let src = src.start;
3147+
3148+
unsafe {
3149+
// SAFETY:
3150+
// - Ranges do not overlap: src entirely spans initialized values, dst entirely spans uninitialized values.
3151+
// - Ranges are in bounds: guaranteed by the caller.
3152+
let ranges = self.nonoverlapping_ranges(src, dst, count, self.head);
3153+
for (src, dst, count) in ranges {
3154+
for offset in 0..count {
3155+
dst.add(offset).write((*src.add(offset)).clone());
3156+
self.len += 1;
3157+
}
3158+
}
3159+
}
3160+
}
3161+
3162+
default unsafe fn spec_prepend_from_within(&mut self, src: Range<usize>) {
3163+
let dst = 0;
3164+
let count = src.end - src.start;
3165+
let src = src.start + count;
3166+
3167+
let new_head = self.wrap_sub(self.head, count);
3168+
let cap = self.capacity();
3169+
3170+
unsafe {
3171+
// SAFETY:
3172+
// - Ranges do not overlap: src entirely spans initialized values, dst entirely spans uninitialized values.
3173+
// - Ranges are in bounds: guaranteed by the caller.
3174+
let ranges = self.nonoverlapping_ranges(src, dst, count, new_head);
3175+
let (src, dst, count) = ranges[1];
3176+
for offset in (0..count).rev() {
3177+
dst.add(offset).write((*src.add(offset)).clone());
3178+
self.head -= 1;
3179+
self.len += 1;
3180+
}
3181+
3182+
let (src, dst, count) = ranges[0];
3183+
let mut iter = (0..count).rev();
3184+
if let Some(offset) = iter.next() {
3185+
dst.add(offset).write((*src.add(offset)).clone());
3186+
if self.head == 0 {
3187+
self.head = cap;
3188+
}
3189+
self.head -= 1;
3190+
self.len += 1;
3191+
3192+
for offset in iter {
3193+
dst.add(offset).write((*src.add(offset)).clone());
3194+
self.head -= 1;
3195+
self.len += 1;
3196+
}
3197+
}
3198+
}
3199+
}
3200+
}
3201+
3202+
#[cfg(not(no_global_oom_handling))]
3203+
impl<T: Copy, A: Allocator> SpecExtendFromWithin for VecDeque<T, A> {
3204+
unsafe fn spec_extend_from_within(&mut self, src: Range<usize>) {
3205+
let dst = self.len();
3206+
let count = src.end - src.start;
3207+
let src = src.start;
3208+
3209+
unsafe {
3210+
// SAFETY:
3211+
// - Ranges do not overlap: src entirely spans initialized values, dst entirely spans uninitialized values.
3212+
// - Ranges are in bounds: guaranteed by the caller.
3213+
let ranges = self.nonoverlapping_ranges(src, dst, count, self.head);
3214+
for (src, dst, count) in ranges {
3215+
ptr::copy_nonoverlapping(src, dst, count);
3216+
}
3217+
}
3218+
3219+
// SAFETY:
3220+
// - The elements were just initialized by `copy_nonoverlapping`
3221+
self.len += count;
3222+
}
3223+
3224+
unsafe fn spec_prepend_from_within(&mut self, src: Range<usize>) {
3225+
let dst = 0;
3226+
let count = src.end - src.start;
3227+
let src = src.start + count;
3228+
3229+
let new_head = self.wrap_sub(self.head, count);
3230+
3231+
unsafe {
3232+
// SAFETY:
3233+
// - Ranges do not overlap: src entirely spans initialized values, dst entirely spans uninitialized values.
3234+
// - Ranges are in bounds: guaranteed by the caller.
3235+
let ranges = self.nonoverlapping_ranges(src, dst, count, new_head);
3236+
for (src, dst, count) in ranges {
3237+
ptr::copy_nonoverlapping(src, dst, count);
3238+
}
3239+
}
3240+
3241+
// SAFETY:
3242+
// - The elements were just initialized by `copy_nonoverlapping`
3243+
self.head = new_head;
3244+
self.len += count;
3245+
}
29743246
}
29753247

29763248
/// Returns the index in the underlying buffer for a given logical element index.

library/alloctests/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#![feature(char_max_len)]
77
#![feature(cow_is_borrowed)]
88
#![feature(core_intrinsics)]
9+
#![feature(deque_extend_front)]
910
#![feature(downcast_unchecked)]
1011
#![feature(exact_size_is_empty)]
1112
#![feature(hashmap_internals)]

0 commit comments

Comments
 (0)