about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJubilee <46493976+workingjubilee@users.noreply.github.com>2021-10-04 13:58:08 -0700
committerGitHub <noreply@github.com>2021-10-04 13:58:08 -0700
commit19d9a147bef8dfaf5c718c0cb4008accd86e7a5e (patch)
tree267098e6b130065344aacf2d9f744cd27ead12a5
parenta2c6075dfff58626afc9ab57c2c6b284c5612ec7 (diff)
parentc3cff0a75412f18971a325640a5dd7bd67b28972 (diff)
downloadrust-19d9a147bef8dfaf5c718c0cb4008accd86e7a5e.tar.gz
rust-19d9a147bef8dfaf5c718c0cb4008accd86e7a5e.zip
Rollup merge of #88452 - xu-cheng:vecdeque-from-array, r=m-ou-se
VecDeque: improve performance for From<[T; N]>

Create `VecDeque` directly from the array instead of inserting items one-by-one.

Benchmark
```
./x.py bench library/alloc --test-args vec_deque::bench_from_array_1000
```

* Before
```
test vec_deque::bench_from_array_1000                    ... bench:       3,991 ns/iter (+/- 717)
```

* After
```
test vec_deque::bench_from_array_1000                    ... bench:         268 ns/iter (+/- 37)
```
-rw-r--r--library/alloc/benches/vec_deque.rs15
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs12
-rw-r--r--library/alloc/src/collections/vec_deque/tests.rs30
3 files changed, 56 insertions, 1 deletions
diff --git a/library/alloc/benches/vec_deque.rs b/library/alloc/benches/vec_deque.rs
index bf2dffd1e93..404cfa6addb 100644
--- a/library/alloc/benches/vec_deque.rs
+++ b/library/alloc/benches/vec_deque.rs
@@ -52,3 +52,18 @@ fn bench_try_fold(b: &mut Bencher) {
 
     b.iter(|| black_box(ring.iter().try_fold(0, |a, b| Some(a + b))))
 }
+
+#[bench]
+fn bench_from_array_1000(b: &mut Bencher) {
+    const N: usize = 1000;
+    let mut array: [usize; N] = [0; N];
+
+    for i in 0..N {
+        array[i] = i;
+    }
+
+    b.iter(|| {
+        let deq: VecDeque<_> = array.into();
+        black_box(deq);
+    })
+}
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 4a2b0b33bf2..007548ad1ab 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -3004,6 +3004,16 @@ impl<T, const N: usize> From<[T; N]> for VecDeque<T> {
     /// assert_eq!(deq1, deq2);
     /// ```
     fn from(arr: [T; N]) -> Self {
-        core::array::IntoIter::new(arr).collect()
+        let mut deq = VecDeque::with_capacity(N);
+        let arr = ManuallyDrop::new(arr);
+        if mem::size_of::<T>() != 0 {
+            // SAFETY: VecDeque::with_capacity ensures that there is enough capacity.
+            unsafe {
+                ptr::copy_nonoverlapping(arr.as_ptr(), deq.ptr(), N);
+            }
+        }
+        deq.tail = 0;
+        deq.head = N;
+        deq
     }
 }
diff --git a/library/alloc/src/collections/vec_deque/tests.rs b/library/alloc/src/collections/vec_deque/tests.rs
index 56257e43462..2be83f68f01 100644
--- a/library/alloc/src/collections/vec_deque/tests.rs
+++ b/library/alloc/src/collections/vec_deque/tests.rs
@@ -508,6 +508,36 @@ fn test_from_vec_zst_overflow() {
 }
 
 #[test]
+fn test_from_array() {
+    fn test<const N: usize>() {
+        let mut array: [usize; N] = [0; N];
+
+        for i in 0..N {
+            array[i] = i;
+        }
+
+        let deq: VecDeque<_> = array.into();
+
+        for i in 0..N {
+            assert_eq!(deq[i], i);
+        }
+
+        assert!(deq.cap().is_power_of_two());
+        assert_eq!(deq.len(), N);
+    }
+    test::<0>();
+    test::<1>();
+    test::<2>();
+    test::<32>();
+    test::<35>();
+
+    let array = [(); MAXIMUM_ZST_CAPACITY - 1];
+    let deq = VecDeque::from(array);
+    assert!(deq.cap().is_power_of_two());
+    assert_eq!(deq.len(), MAXIMUM_ZST_CAPACITY - 1);
+}
+
+#[test]
 fn test_vec_from_vecdeque() {
     use crate::vec::Vec;