Skip to content

Commit 5b66d03

Browse files
committed
implement VecDeque extend_from_within and prepend_from_within, add tests, TODO 4 more tests
1 parent 21a13b8 commit 5b66d03

File tree

3 files changed

+289
-0
lines changed

3 files changed

+289
-0
lines changed

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

Lines changed: 255 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,191 @@ 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+
3169+
unsafe {
3170+
// SAFETY:
3171+
// - Ranges do not overlap: src entirely spans initialized values, dst entirely spans uninitialized values.
3172+
// - Ranges are in bounds: guaranteed by the caller.
3173+
let ranges = self.nonoverlapping_ranges(src, dst, count, new_head);
3174+
for (src, dst, count) in ranges.into_iter().rev() {
3175+
for offset in (0..count).rev() {
3176+
dst.add(offset).write((*src.add(offset)).clone());
3177+
self.head -= 1;
3178+
self.len += 1;
3179+
}
3180+
}
3181+
}
3182+
}
3183+
}
3184+
3185+
#[cfg(not(no_global_oom_handling))]
3186+
impl<T: Copy, A: Allocator> SpecExtendFromWithin for VecDeque<T, A> {
3187+
unsafe fn spec_extend_from_within(&mut self, src: Range<usize>) {
3188+
let dst = self.len();
3189+
let count = src.end - src.start;
3190+
let src = src.start;
3191+
3192+
unsafe {
3193+
// SAFETY:
3194+
// - Ranges do not overlap: src entirely spans initialized values, dst entirely spans uninitialized values.
3195+
// - Ranges are in bounds: guaranteed by the caller.
3196+
let ranges = self.nonoverlapping_ranges(src, dst, count, self.head);
3197+
for (src, dst, count) in ranges {
3198+
ptr::copy_nonoverlapping(src, dst, count);
3199+
}
3200+
}
3201+
3202+
// SAFETY:
3203+
// - The elements were just initialized by `copy_nonoverlapping`
3204+
self.len += count;
3205+
}
3206+
3207+
unsafe fn spec_prepend_from_within(&mut self, src: Range<usize>) {
3208+
let dst = 0;
3209+
let count = src.end - src.start;
3210+
let src = src.start + count;
3211+
3212+
let new_head = self.wrap_sub(self.head, count);
3213+
3214+
unsafe {
3215+
// SAFETY:
3216+
// - Ranges do not overlap: src entirely spans initialized values, dst entirely spans uninitialized values.
3217+
// - Ranges are in bounds: guaranteed by the caller.
3218+
let ranges = self.nonoverlapping_ranges(src, dst, count, new_head);
3219+
for (src, dst, count) in ranges {
3220+
ptr::copy_nonoverlapping(src, dst, count);
3221+
}
3222+
}
3223+
3224+
// SAFETY:
3225+
// - The elements were just initialized by `copy_nonoverlapping`
3226+
self.head = new_head;
3227+
self.len += count;
3228+
}
29743229
}
29753230

29763231
/// 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)]

library/alloctests/tests/vec_deque.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1849,3 +1849,36 @@ fn test_truncate_front() {
18491849
v.truncate_front(5);
18501850
assert_eq!(v.as_slices(), ([2, 3, 4, 5, 6].as_slice(), [].as_slice()));
18511851
}
1852+
1853+
#[test]
1854+
fn test_extend_from_within() {
1855+
let mut v = VecDeque::with_capacity(8);
1856+
v.extend(0..6);
1857+
v.truncate_front(4);
1858+
v.extend_from_within(1..4);
1859+
assert_eq!(v.as_slices(), ([2, 3, 4, 5, 3, 4].as_slice(), [5].as_slice()));
1860+
v.extend_from_within(1..=2);
1861+
assert_eq!(v, [2, 3, 4, 5, 3, 4, 5, 3, 4]);
1862+
v.extend_from_within(..3);
1863+
assert_eq!(v, [2, 3, 4, 5, 3, 4, 5, 3, 4, 2, 3, 4]);
1864+
}
1865+
1866+
#[test]
1867+
fn test_extend_from_within_clone() {
1868+
// keep track of clone count and correct dropping when clone impl panics
1869+
}
1870+
1871+
#[test]
1872+
fn test_prepend_from_within() {
1873+
// like test_extend_from_within
1874+
}
1875+
1876+
#[test]
1877+
fn test_prepend_from_within_clone() {
1878+
// like test_extend_from_within_clone
1879+
}
1880+
1881+
#[test]
1882+
fn test_extend_and_prepend_from_within() {
1883+
// mix extend_from_within and prepend_from_within
1884+
}

0 commit comments

Comments
 (0)