Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4ced370
Make `missing_copy_implementations` more cautious
Sep 28, 2022
b209ff2
Update trait check
Nov 19, 2022
34277fc
Rebase
Nov 29, 2022
17766c1
Skip test on s390x as LLD does not support the platform
uweigand Dec 6, 2022
58e60ac
Make `VecDeque::from_iter` O(1) from `vec(_deque)::IntoIter`
scottmcm Dec 8, 2022
98ae83d
Mangle "main" as "__main_void" on wasm32-wasi
sunfishcode Dec 8, 2022
5626df9
Add `rustc_on_unimplemented` to `Sum` and `Product` trait.
aDotInTheVoid Dec 4, 2022
90da11d
rustdoc: remove no-op mobile CSS `#sidebar-toggle { text-align }`
notriddle Dec 9, 2022
6648134
Apply review feedback; Fix no_global_oom_handling build
scottmcm Dec 9, 2022
f41576b
Fix typo in apple_base.rs
eltociear Dec 9, 2022
d60967b
rustdoc: make stability badge CSS more consistent
notriddle Dec 9, 2022
b3b17bd
Tweak `rustc_must_implement_one_of` diagnostic output
estebank Dec 9, 2022
4fae589
Rollup merge of #102406 - mejrs:missing_copy, r=wesleywiser
matthiaskrgr Dec 9, 2022
856027a
Rollup merge of #105265 - aDotInTheVoid:sum-product-on-unimplemented,…
matthiaskrgr Dec 9, 2022
c44326e
Rollup merge of #105385 - uweigand:s390x-test-lld, r=Mark-Simulacrum
matthiaskrgr Dec 9, 2022
5156fbd
Rollup merge of #105453 - scottmcm:vecdeque_from_iter, r=the8472
matthiaskrgr Dec 9, 2022
320d018
Rollup merge of #105468 - sunfishcode:sunfishcode/main-void-wasi, r=e…
matthiaskrgr Dec 9, 2022
d477386
Rollup merge of #105480 - notriddle:notriddle/sidebar-toggle-mobile-c…
matthiaskrgr Dec 9, 2022
f78babd
Rollup merge of #105489 - eltociear:patch-17, r=Dylan-DPC
matthiaskrgr Dec 9, 2022
d0563c6
Rollup merge of #105504 - notriddle:notriddle/stab-css, r=GuillaumeGomez
matthiaskrgr Dec 9, 2022
376b0bc
Rollup merge of #105506 - estebank:rustc_must_implement_one_of, r=com…
matthiaskrgr Dec 9, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Make VecDeque::from_iter O(1) from vec(_deque)::IntoIter
  • Loading branch information
scottmcm committed Dec 8, 2022
commit 58e60ac211aa7555b949016cb795989ccedd8939
4 changes: 4 additions & 0 deletions library/alloc/src/collections/vec_deque/into_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ impl<T, A: Allocator> IntoIter<T, A> {
pub(super) fn new(inner: VecDeque<T, A>) -> Self {
IntoIter { inner }
}

pub(super) fn into_vecdeque(self) -> VecDeque<T, A> {
self.inner
}
}

#[stable(feature = "collection_debug", since = "1.17.0")]
Expand Down
45 changes: 34 additions & 11 deletions library/alloc/src/collections/vec_deque/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ use self::spec_extend::SpecExtend;

mod spec_extend;

use self::spec_from_iter::SpecFromIter;

mod spec_from_iter;

#[cfg(test)]
mod tests;

Expand Down Expand Up @@ -586,6 +590,35 @@ impl<T, A: Allocator> VecDeque<T, A> {
VecDeque { head: 0, len: 0, buf: RawVec::with_capacity_in(capacity, alloc) }
}

/// For use by `vec::IntoIter::into_vecdeque`
///
/// # Safety
///
/// All the usual requirements on the allocated memory like in
/// `Vec::from_raw_parts_in`, but takes a *range* of elements that are
/// initialized rather than only supporting `0..len`. Requires that
/// `initialized.start` ≤ `initialized.end` ≤ `capacity`.
#[inline]
pub(crate) unsafe fn from_contiguous_raw_parts_in(
ptr: *mut T,
initialized: Range<usize>,
capacity: usize,
alloc: A,
) -> Self {
debug_assert!(initialized.start <= initialized.end);
debug_assert!(initialized.end <= capacity);

// SAFETY: Our safety precondition guarantees the range length won't wrap,
// and that the allocation is valid for use in `RawVec`.
unsafe {
VecDeque {
head: initialized.start,
len: initialized.end.unchecked_sub(initialized.start),
buf: RawVec::from_raw_parts_in(ptr, capacity, alloc),
}
}
}

/// Provides a reference to the element at the given index.
///
/// Element at index 0 is the front of the queue.
Expand Down Expand Up @@ -2699,18 +2732,8 @@ impl<T, A: Allocator> IndexMut<usize> for VecDeque<T, A> {

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> FromIterator<T> for VecDeque<T> {
#[inline]
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> VecDeque<T> {
// Since converting is O(1) now, might as well re-use that logic
// (including things like the `vec::IntoIter`→`Vec` specialization)
// especially as that could save us some monomorphiziation work
// if one uses the same iterators (like slice ones) with both.
return from_iter_via_vec(iter.into_iter());

#[inline]
fn from_iter_via_vec<U>(iter: impl Iterator<Item = U>) -> VecDeque<U> {
Vec::from_iter(iter).into()
}
SpecFromIter::spec_from_iter(iter.into_iter())
}
}

Expand Down
33 changes: 33 additions & 0 deletions library/alloc/src/collections/vec_deque/spec_from_iter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use super::{IntoIter, VecDeque};

/// Specialization trait used for `VecDeque::from_iter`
pub(super) trait SpecFromIter<T, I> {
fn spec_from_iter(iter: I) -> Self;
}

impl<T, I> SpecFromIter<T, I> for VecDeque<T>
where
I: Iterator<Item = T>,
{
default fn spec_from_iter(iterator: I) -> Self {
// Since converting is O(1) now, just re-use the `Vec` logic for
// anything where we can't do something extra-special for `VecDeque`,
// especially as that could save us some monomorphiziation work
// if one uses the same iterators (like slice ones) with both.
crate::vec::Vec::from_iter(iterator).into()
}
}

impl<T> SpecFromIter<T, crate::vec::IntoIter<T>> for VecDeque<T> {
#[inline]
fn spec_from_iter(iterator: crate::vec::IntoIter<T>) -> Self {
iterator.into_vecdeque()
}
}

impl<T> SpecFromIter<T, IntoIter<T>> for VecDeque<T> {
#[inline]
fn spec_from_iter(iterator: IntoIter<T>) -> Self {
iterator.into_vecdeque()
}
}
27 changes: 27 additions & 0 deletions library/alloc/src/vec/into_iter.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#[cfg(not(no_global_oom_handling))]
use super::AsVecIntoIter;
use crate::alloc::{Allocator, Global};
use crate::collections::VecDeque;
use crate::raw_vec::RawVec;
use core::array;
use core::fmt;
Expand Down Expand Up @@ -132,6 +133,32 @@ impl<T, A: Allocator> IntoIter<T, A> {
pub(crate) fn forget_remaining_elements(&mut self) {
self.ptr = self.end;
}

#[inline]
pub(crate) fn into_vecdeque(self) -> VecDeque<T, A> {
// Keep our `Drop` impl from dropping the elements and the allocator
let mut this = ManuallyDrop::new(self);

// SAFETY: This allocation originally came from a `Vec`, so it passes
// all those checks. We have `this.buf` ≤ `this.ptr` ≤ `this.end`,
// so the `sub_ptr`s below cannot wrap, and will produce a well-formed
// range. `end` ≤ `buf + cap`, so the range will be in-bounds.
// Taking `alloc` is ok because nothing else is going to look at it,
// since our `Drop` impl isn't going to run so there's no more code.
unsafe {
let buf = this.buf.as_ptr();
let initialized = if T::IS_ZST {
// All the pointers are the same for ZSTs, so it's fine to
// say that they're all at the beginning of the "allocation".
0..this.len()
} else {
this.ptr.sub_ptr(buf)..this.end.sub_ptr(buf)
};
let cap = this.cap;
let alloc = ManuallyDrop::take(&mut this.alloc);
VecDeque::from_contiguous_raw_parts_in(buf, initialized, cap, alloc)
}
}
}

#[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")]
Expand Down
26 changes: 26 additions & 0 deletions library/alloc/tests/vec_deque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1736,3 +1736,29 @@ fn test_resize_keeps_reserved_space_from_item() {
d.resize(1, v);
assert_eq!(d[0].capacity(), 1234);
}

#[test]
fn test_collect_from_into_iter_keeps_allocation() {
let mut v = Vec::with_capacity(13);
v.extend(0..7);
check(v.into_iter());

let mut v = VecDeque::with_capacity(13);
v.extend(0..7);
check(v.into_iter());

fn check(mut it: impl Iterator<Item = i32>) {
assert_eq!(it.next(), Some(0));
assert_eq!(it.next(), Some(1));
let mut v: VecDeque<i32> = it.collect();
assert_eq!(v.capacity(), 13);
assert_eq!(v.as_slices(), ([2, 3, 4, 5, 6].as_slice(), [].as_slice()));
v.push_front(7);
assert_eq!(v.as_slices(), ([7, 2, 3, 4, 5, 6].as_slice(), [].as_slice()));
v.push_front(8);
assert_eq!(v.as_slices(), ([8, 7, 2, 3, 4, 5, 6].as_slice(), [].as_slice()));
v.push_front(9);
assert_eq!(v.as_slices(), ([9].as_slice(), [8, 7, 2, 3, 4, 5, 6].as_slice()));
assert_eq!(v.capacity(), 13);
}
}