summaryrefslogtreecommitdiffstats
path: root/library/alloc/src/vec/spec_from_iter_nested.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/alloc/src/vec/spec_from_iter_nested.rs')
-rw-r--r--library/alloc/src/vec/spec_from_iter_nested.rs65
1 files changed, 65 insertions, 0 deletions
diff --git a/library/alloc/src/vec/spec_from_iter_nested.rs b/library/alloc/src/vec/spec_from_iter_nested.rs
new file mode 100644
index 000000000..f915ebb86
--- /dev/null
+++ b/library/alloc/src/vec/spec_from_iter_nested.rs
@@ -0,0 +1,65 @@
+use core::cmp;
+use core::iter::TrustedLen;
+use core::ptr;
+
+use crate::raw_vec::RawVec;
+
+use super::{SpecExtend, Vec};
+
+/// Another specialization trait for Vec::from_iter
+/// necessary to manually prioritize overlapping specializations
+/// see [`SpecFromIter`](super::SpecFromIter) for details.
+pub(super) trait SpecFromIterNested<T, I> {
+ fn from_iter(iter: I) -> Self;
+}
+
+impl<T, I> SpecFromIterNested<T, I> for Vec<T>
+where
+ I: Iterator<Item = T>,
+{
+ default fn from_iter(mut iterator: I) -> Self {
+ // Unroll the first iteration, as the vector is going to be
+ // expanded on this iteration in every case when the iterable is not
+ // empty, but the loop in extend_desugared() is not going to see the
+ // vector being full in the few subsequent loop iterations.
+ // So we get better branch prediction.
+ let mut vector = match iterator.next() {
+ None => return Vec::new(),
+ Some(element) => {
+ let (lower, _) = iterator.size_hint();
+ let initial_capacity =
+ cmp::max(RawVec::<T>::MIN_NON_ZERO_CAP, lower.saturating_add(1));
+ let mut vector = Vec::with_capacity(initial_capacity);
+ unsafe {
+ // SAFETY: We requested capacity at least 1
+ ptr::write(vector.as_mut_ptr(), element);
+ vector.set_len(1);
+ }
+ vector
+ }
+ };
+ // must delegate to spec_extend() since extend() itself delegates
+ // to spec_from for empty Vecs
+ <Vec<T> as SpecExtend<T, I>>::spec_extend(&mut vector, iterator);
+ vector
+ }
+}
+
+impl<T, I> SpecFromIterNested<T, I> for Vec<T>
+where
+ I: TrustedLen<Item = T>,
+{
+ fn from_iter(iterator: I) -> Self {
+ let mut vector = match iterator.size_hint() {
+ (_, Some(upper)) => Vec::with_capacity(upper),
+ // TrustedLen contract guarantees that `size_hint() == (_, None)` means that there
+ // are more than `usize::MAX` elements.
+ // Since the previous branch would eagerly panic if the capacity is too large
+ // (via `with_capacity`) we do the same here.
+ _ => panic!("capacity overflow"),
+ };
+ // reuse extend specialization for TrustedLen
+ vector.spec_extend(iterator);
+ vector
+ }
+}