Add VecDeque::extend from TrustedLen specialization

This commit is contained in:
Paolo Barbolini 2022-06-12 00:54:20 +02:00
parent ac2c21a623
commit bc3fae4dc1
3 changed files with 175 additions and 0 deletions

View File

@ -453,6 +453,25 @@ impl<T, A: Allocator> VecDeque<T, A> {
}
}
/// Writes all values from `iter` to `dst`.
///
/// # Safety
///
/// Assumes no wrapping around happens.
/// Assumes capacity is sufficient.
#[inline]
unsafe fn write_iter(
&mut self,
dst: usize,
iter: impl Iterator<Item = T>,
written: &mut usize,
) {
iter.enumerate().for_each(|(i, element)| unsafe {
self.buffer_write(dst + i, element);
*written += 1;
});
}
/// Frobs the head and tail sections around to handle the fact that we
/// just reallocated. Unsafe because it trusts old_capacity.
#[inline]

View File

@ -1,5 +1,6 @@
use crate::alloc::Allocator;
use crate::vec;
use core::iter::TrustedLen;
use core::slice;
use super::VecDeque;
@ -34,6 +35,64 @@ where
}
}
impl<T, I, A: Allocator> SpecExtend<T, I> for VecDeque<T, A>
where
I: TrustedLen<Item = T>,
{
default fn spec_extend(&mut self, mut iter: I) {
// This is the case for a TrustedLen iterator.
let (low, high) = iter.size_hint();
if let Some(additional) = high {
debug_assert_eq!(
low,
additional,
"TrustedLen iterator's size hint is not exact: {:?}",
(low, high)
);
self.reserve(additional);
struct WrapAddOnDrop<'a, T, A: Allocator> {
vec_deque: &'a mut VecDeque<T, A>,
written: usize,
}
impl<'a, T, A: Allocator> Drop for WrapAddOnDrop<'a, T, A> {
fn drop(&mut self) {
self.vec_deque.head =
self.vec_deque.wrap_add(self.vec_deque.head, self.written);
}
}
let mut wrapper = WrapAddOnDrop { vec_deque: self, written: 0 };
let head_room = wrapper.vec_deque.cap() - wrapper.vec_deque.head;
unsafe {
wrapper.vec_deque.write_iter(
wrapper.vec_deque.head,
ByRefSized(&mut iter).take(head_room),
&mut wrapper.written,
);
if additional > head_room {
wrapper.vec_deque.write_iter(0, iter, &mut wrapper.written);
}
}
debug_assert_eq!(
additional, wrapper.written,
"The number of items written to VecDeque doesn't match the TrustedLen size hint"
);
} else {
// Per TrustedLen contract a `None` upper bound means that the iterator length
// truly exceeds usize::MAX, which would eventually lead to a capacity overflow anyway.
// Since the other branch already panics eagerly (via `reserve()`) we do the same here.
// This avoids additional codegen for a fallback code path which would eventually
// panic anyway.
panic!("capacity overflow");
}
}
}
impl<T, A: Allocator> SpecExtend<T, vec::IntoIter<T>> for VecDeque<T, A> {
fn spec_extend(&mut self, mut iterator: vec::IntoIter<T>) {
let slice = iterator.as_slice();

View File

@ -1,3 +1,5 @@
use core::iter::TrustedLen;
use super::*;
#[bench]
@ -791,6 +793,101 @@ fn test_from_vec() {
assert_eq!(vd.len(), vec.len());
}
#[test]
fn test_extend_basic() {
test_extend_impl(false);
}
#[test]
fn test_extend_trusted_len() {
test_extend_impl(true);
}
fn test_extend_impl(trusted_len: bool) {
struct VecDequeTester {
test: VecDeque<usize>,
expected: VecDeque<usize>,
trusted_len: bool,
}
impl VecDequeTester {
fn new(trusted_len: bool) -> Self {
Self { test: VecDeque::new(), expected: VecDeque::new(), trusted_len }
}
fn test_extend<I>(&mut self, iter: I)
where
I: Iterator<Item = usize> + TrustedLen + Clone,
{
struct BasicIterator<I>(I);
impl<I> Iterator for BasicIterator<I>
where
I: Iterator<Item = usize>,
{
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
if self.trusted_len {
self.test.extend(iter.clone());
} else {
self.test.extend(BasicIterator(iter.clone()));
}
for item in iter {
self.expected.push_back(item)
}
assert_eq!(self.test, self.expected);
let (a1, b1) = self.test.as_slices();
let (a2, b2) = self.expected.as_slices();
assert_eq!(a1, a2);
assert_eq!(b1, b2);
}
fn drain<R: RangeBounds<usize> + Clone>(&mut self, range: R) {
self.test.drain(range.clone());
self.expected.drain(range);
assert_eq!(self.test, self.expected);
}
fn clear(&mut self) {
self.test.clear();
self.expected.clear();
}
fn remaining_capacity(&self) -> usize {
self.test.capacity() - self.test.len()
}
}
let mut tester = VecDequeTester::new(trusted_len);
// Initial capacity
tester.test_extend(0..tester.remaining_capacity() - 1);
// Grow
tester.test_extend(1024..2048);
// Wrap around
tester.drain(..128);
tester.test_extend(0..tester.remaining_capacity() - 1);
// Continue
tester.drain(256..);
tester.test_extend(4096..8196);
tester.clear();
// Start again
tester.test_extend(0..32);
}
#[test]
#[should_panic = "capacity overflow"]
fn test_from_vec_zst_overflow() {