From 7fb26938b1b88d9f3c0d3046712375e48aeb91ae Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Mon, 6 Jul 2020 10:33:24 -0400 Subject: [PATCH 1/3] Add VecDeque::range* methods This patch adds `VecDeque::range` and `VecDeque::range_mut` to provide iterators over a sub-range of a `VecDeque`. This behavior can be emulated with `skip` and `take`, but directly providing a `Range` is more ergonomic. This also partially makes up for `VecDeque`'s lack of `SliceIndex` support. --- src/liballoc/collections/vec_deque.rs | 112 +++++++++++++++++--- src/liballoc/collections/vec_deque/tests.rs | 59 +++++++++++ 2 files changed, 158 insertions(+), 13 deletions(-) diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 15f3a94ca2d6a..08ab6a69ce85c 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -1084,6 +1084,104 @@ 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 + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let v: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); + /// let range = v.iter_rage(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 = "none")] + 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 + /// + /// ``` + /// 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 = "none")] + 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 +1227,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..4473ce8719e13 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 drain_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 drain_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).copied().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); From 8872ec37600114e3e1a07c18443a119788bbb052 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Mon, 6 Jul 2020 11:52:20 -0400 Subject: [PATCH 2/3] fixups --- src/liballoc/collections/vec_deque.rs | 6 +++++- src/liballoc/collections/vec_deque/tests.rs | 6 +++--- src/liballoc/lib.rs | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 08ab6a69ce85c..4efa7ef6f5e9d 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -1114,10 +1114,12 @@ impl VecDeque { /// # Examples /// /// ``` + /// #![feature(deque_range)] + /// /// use std::collections::VecDeque; /// /// let v: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); - /// let range = v.iter_rage(2..).copied().collect::>(); + /// let range = v.range(2..).copied().collect::>(); /// assert_eq!(range, [3]); /// /// // A full range covers all contents @@ -1151,6 +1153,8 @@ impl VecDeque { /// # Examples /// /// ``` + /// #![feature(deque_range)] + /// /// use std::collections::VecDeque; /// /// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); diff --git a/src/liballoc/collections/vec_deque/tests.rs b/src/liballoc/collections/vec_deque/tests.rs index 4473ce8719e13..e5edfe02a525f 100644 --- a/src/liballoc/collections/vec_deque/tests.rs +++ b/src/liballoc/collections/vec_deque/tests.rs @@ -254,7 +254,7 @@ fn test_range() { for len in 0..=cap { for tail in 0..=cap { for start in 0..=len { - for end in drain_start..=len { + for end in start..=len { tester.tail = tail; tester.head = tail; for i in 0..len { @@ -279,7 +279,7 @@ fn test_range_mut() { for len in 0..=cap { for tail in 0..=cap { for start in 0..=len { - for end in drain_start..=len { + for end in start..=len { tester.tail = tail; tester.head = tail; for i in 0..len { @@ -290,7 +290,7 @@ fn test_range_mut() { let tail_was = tester.tail; // Check that we iterate over the correct values - let range: VecDeque<_> = tester.range_mut(start..end).copied().collect(); + let range: VecDeque<_> = tester.range_mut(start..end).map(|v| *v).collect(); let expected: VecDeque<_> = (start..end).collect(); assert_eq!(range, expected); 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)] From a1a19cbbe1c17dc03ca689db002181c9bd95f529 Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Fri, 10 Jul 2020 09:23:52 -0400 Subject: [PATCH 3/3] Add tracking issue --- src/liballoc/collections/vec_deque.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 4efa7ef6f5e9d..2efb94e8afe57 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -1127,7 +1127,7 @@ impl VecDeque { /// assert_eq!(all.len(), 3); /// ``` #[inline] - #[unstable(feature = "deque_range", issue = "none")] + #[unstable(feature = "deque_range", issue = "74217")] pub fn range(&self, range: R) -> Iter<'_, T> where R: RangeBounds, @@ -1170,7 +1170,7 @@ impl VecDeque { /// assert_eq!(v, vec![2, 4, 12]); /// ``` #[inline] - #[unstable(feature = "deque_range", issue = "none")] + #[unstable(feature = "deque_range", issue = "74217")] pub fn range_mut(&mut self, range: R) -> IterMut<'_, T> where R: RangeBounds,