Skip to content

Commit 1c966e7

Browse files
committed
Extract the logic for TrustedLen to a named method that can be called directly
1 parent 341d8b8 commit 1c966e7

File tree

2 files changed

+37
-32
lines changed

2 files changed

+37
-32
lines changed

library/alloc/src/vec/mod.rs

+35
Original file line numberDiff line numberDiff line change
@@ -2870,6 +2870,41 @@ impl<T, A: Allocator> Vec<T, A> {
28702870
}
28712871
}
28722872

2873+
// specific extend for `TrustedLen` iterators, called both by the specializations
2874+
// and internal places where resolving specialization makes compilation slower
2875+
#[cfg(not(no_global_oom_handling))]
2876+
fn extend_trusted(&mut self, iterator: impl iter::TrustedLen<Item = T>) {
2877+
let (low, high) = iterator.size_hint();
2878+
if let Some(additional) = high {
2879+
debug_assert_eq!(
2880+
low,
2881+
additional,
2882+
"TrustedLen iterator's size hint is not exact: {:?}",
2883+
(low, high)
2884+
);
2885+
self.reserve(additional);
2886+
unsafe {
2887+
let mut ptr = self.as_mut_ptr().add(self.len());
2888+
let mut local_len = SetLenOnDrop::new(&mut self.len);
2889+
iterator.for_each(move |element| {
2890+
ptr::write(ptr, element);
2891+
ptr = ptr.add(1);
2892+
// Since the loop executes user code which can panic we have to bump the pointer
2893+
// after each step.
2894+
// NB can't overflow since we would have had to alloc the address space
2895+
local_len.increment_len(1);
2896+
});
2897+
}
2898+
} else {
2899+
// Per TrustedLen contract a `None` upper bound means that the iterator length
2900+
// truly exceeds usize::MAX, which would eventually lead to a capacity overflow anyway.
2901+
// Since the other branch already panics eagerly (via `reserve()`) we do the same here.
2902+
// This avoids additional codegen for a fallback code path which would eventually
2903+
// panic anyway.
2904+
panic!("capacity overflow");
2905+
}
2906+
}
2907+
28732908
/// Creates a splicing iterator that replaces the specified range in the vector
28742909
/// with the given `replace_with` iterator and yields the removed items.
28752910
/// `replace_with` does not need to be the same length as `range`.

library/alloc/src/vec/spec_extend.rs

+2-32
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use crate::alloc::Allocator;
22
use core::iter::TrustedLen;
3-
use core::ptr::{self};
43
use core::slice::{self};
54

6-
use super::{IntoIter, SetLenOnDrop, Vec};
5+
use super::{IntoIter, Vec};
76

87
// Specialization trait used for Vec::extend
98
pub(super) trait SpecExtend<T, I> {
@@ -24,36 +23,7 @@ where
2423
I: TrustedLen<Item = T>,
2524
{
2625
default fn spec_extend(&mut self, iterator: I) {
27-
// This is the case for a TrustedLen iterator.
28-
let (low, high) = iterator.size_hint();
29-
if let Some(additional) = high {
30-
debug_assert_eq!(
31-
low,
32-
additional,
33-
"TrustedLen iterator's size hint is not exact: {:?}",
34-
(low, high)
35-
);
36-
self.reserve(additional);
37-
unsafe {
38-
let mut ptr = self.as_mut_ptr().add(self.len());
39-
let mut local_len = SetLenOnDrop::new(&mut self.len);
40-
iterator.for_each(move |element| {
41-
ptr::write(ptr, element);
42-
ptr = ptr.add(1);
43-
// Since the loop executes user code which can panic we have to bump the pointer
44-
// after each step.
45-
// NB can't overflow since we would have had to alloc the address space
46-
local_len.increment_len(1);
47-
});
48-
}
49-
} else {
50-
// Per TrustedLen contract a `None` upper bound means that the iterator length
51-
// truly exceeds usize::MAX, which would eventually lead to a capacity overflow anyway.
52-
// Since the other branch already panics eagerly (via `reserve()`) we do the same here.
53-
// This avoids additional codegen for a fallback code path which would eventually
54-
// panic anyway.
55-
panic!("capacity overflow");
56-
}
26+
self.extend_trusted(iterator)
5727
}
5828
}
5929

0 commit comments

Comments
 (0)