diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 15f3a94ca2d6a..2efb94e8afe57 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -1084,6 +1084,108 @@ impl VecDeque { self.tail == self.head } + fn range_start_end(&self, range: R) -> (usize, usize) + where + R: RangeBounds, + { + let len = self.len(); + let start = match range.start_bound() { + Included(&n) => n, + Excluded(&n) => n + 1, + Unbounded => 0, + }; + let end = match range.end_bound() { + Included(&n) => n + 1, + Excluded(&n) => n, + Unbounded => len, + }; + assert!(start <= end, "lower bound was too large"); + assert!(end <= len, "upper bound was too large"); + (start, end) + } + + /// Creates an iterator that covers the specified range in the `VecDeque`. + /// + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. + /// + /// # Examples + /// + /// ``` + /// #![feature(deque_range)] + /// + /// use std::collections::VecDeque; + /// + /// let v: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); + /// let range = v.range(2..).copied().collect::>(); + /// assert_eq!(range, [3]); + /// + /// // A full range covers all contents + /// let all = v.range(..); + /// assert_eq!(all.len(), 3); + /// ``` + #[inline] + #[unstable(feature = "deque_range", issue = "74217")] + pub fn range(&self, range: R) -> Iter<'_, T> + where + R: RangeBounds, + { + let (start, end) = self.range_start_end(range); + let tail = self.wrap_add(self.tail, start); + let head = self.wrap_add(self.tail, end); + Iter { + tail, + head, + // The shared reference we have in &self is maintained in the '_ of Iter. + ring: unsafe { self.buffer_as_slice() }, + } + } + + /// Creates an iterator that covers the specified mutable range in the `VecDeque`. + /// + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. + /// + /// # Examples + /// + /// ``` + /// #![feature(deque_range)] + /// + /// use std::collections::VecDeque; + /// + /// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); + /// for v in v.range_mut(2..) { + /// *v *= 2; + /// } + /// assert_eq!(v, vec![1, 2, 6]); + /// + /// // A full range covers all contents + /// for v in v.range_mut(..) { + /// *v *= 2; + /// } + /// assert_eq!(v, vec![2, 4, 12]); + /// ``` + #[inline] + #[unstable(feature = "deque_range", issue = "74217")] + pub fn range_mut(&mut self, range: R) -> IterMut<'_, T> + where + R: RangeBounds, + { + let (start, end) = self.range_start_end(range); + let tail = self.wrap_add(self.tail, start); + let head = self.wrap_add(self.tail, end); + IterMut { + tail, + head, + // The shared reference we have in &mut self is maintained in the '_ of IterMut. + ring: unsafe { self.buffer_as_mut_slice() }, + } + } + /// Creates a draining iterator that removes the specified range in the /// `VecDeque` and yields the removed items. /// @@ -1129,19 +1231,7 @@ impl VecDeque { // When finished, the remaining data will be copied back to cover the hole, // and the head/tail values will be restored correctly. // - let len = self.len(); - let start = match range.start_bound() { - Included(&n) => n, - Excluded(&n) => n + 1, - Unbounded => 0, - }; - let end = match range.end_bound() { - Included(&n) => n + 1, - Excluded(&n) => n, - Unbounded => len, - }; - assert!(start <= end, "drain lower bound was too large"); - assert!(end <= len, "drain upper bound was too large"); + let (start, end) = self.range_start_end(range); // The deque's elements are parted into three segments: // * self.tail -> drain_tail diff --git a/src/liballoc/collections/vec_deque/tests.rs b/src/liballoc/collections/vec_deque/tests.rs index 960af4bfda053..e5edfe02a525f 100644 --- a/src/liballoc/collections/vec_deque/tests.rs +++ b/src/liballoc/collections/vec_deque/tests.rs @@ -246,6 +246,65 @@ fn test_remove() { } } +#[test] +fn test_range() { + let mut tester: VecDeque = VecDeque::with_capacity(7); + + let cap = tester.capacity(); + for len in 0..=cap { + for tail in 0..=cap { + for start in 0..=len { + for end in start..=len { + tester.tail = tail; + tester.head = tail; + for i in 0..len { + tester.push_back(i); + } + + // Check that we iterate over the correct values + let range: VecDeque<_> = tester.range(start..end).copied().collect(); + let expected: VecDeque<_> = (start..end).collect(); + assert_eq!(range, expected); + } + } + } + } +} + +#[test] +fn test_range_mut() { + let mut tester: VecDeque = VecDeque::with_capacity(7); + + let cap = tester.capacity(); + for len in 0..=cap { + for tail in 0..=cap { + for start in 0..=len { + for end in start..=len { + tester.tail = tail; + tester.head = tail; + for i in 0..len { + tester.push_back(i); + } + + let head_was = tester.head; + let tail_was = tester.tail; + + // Check that we iterate over the correct values + let range: VecDeque<_> = tester.range_mut(start..end).map(|v| *v).collect(); + let expected: VecDeque<_> = (start..end).collect(); + assert_eq!(range, expected); + + // We shouldn't have changed the capacity or made the + // head or tail out of bounds + assert_eq!(tester.capacity(), cap); + assert_eq!(tester.tail, tail_was); + assert_eq!(tester.head, head_was); + } + } + } + } +} + #[test] fn test_drain() { let mut tester: VecDeque = VecDeque::with_capacity(7); diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 79bfd57a00fa9..2ec777ac85c66 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -89,6 +89,7 @@ #![feature(const_in_array_repeat_expressions)] #![cfg_attr(bootstrap, feature(const_if_match))] #![feature(cow_is_borrowed)] +#![feature(deque_range)] #![feature(dispatch_from_dyn)] #![feature(core_intrinsics)] #![feature(container_error_extra)]