@@ -22,21 +22,39 @@ where
22
22
// empty, but the loop in extend_desugared() is not going to see the
23
23
// vector being full in the few subsequent loop iterations.
24
24
// So we get better branch prediction.
25
- let mut vector = match iterator. next ( ) {
26
- None => return Vec :: new ( ) ,
27
- Some ( element) => {
28
- let ( lower, _) = iterator. size_hint ( ) ;
29
- let initial_capacity =
30
- cmp:: max ( RawVec :: < T > :: MIN_NON_ZERO_CAP , lower. saturating_add ( 1 ) ) ;
31
- let mut vector = Vec :: with_capacity ( initial_capacity) ;
32
- unsafe {
33
- // SAFETY: We requested capacity at least 1
34
- ptr:: write ( vector. as_mut_ptr ( ) , element) ;
35
- vector. set_len ( 1 ) ;
36
- }
37
- vector
38
- }
25
+ let ( low, high) = iterator. size_hint ( ) ;
26
+ let Some ( first) = iterator. next ( ) else {
27
+ return Vec :: new ( ) ;
39
28
} ;
29
+ // `push`'s growth strategy is (currently) to double the capacity if
30
+ // there's no space available, so it can have up to 50% "wasted" space.
31
+ // Thus if the upper-bound on the size_hint also wouldn't waste more
32
+ // than that, just allocate it from the start. (After all, it's silly
33
+ // to allocate 254 for a hint of `(254, Some(255)`.)
34
+ let initial_capacity = {
35
+ // This is written like this to not overflow on any well-behaved iterator,
36
+ // even things like `repeat_n(val, isize::MAX as usize + 10)`
37
+ // where `low * 2` would need checking.
38
+ // A bad (but safe) iterator might have `low > high`, but if so it'll
39
+ // produce a huge `extra` that'll probably fail the following check.
40
+ let hint = if let Some ( high) = high
41
+ && let extra = high - low
42
+ && extra < low
43
+ {
44
+ high
45
+ } else {
46
+ low
47
+ } ;
48
+ cmp:: max ( RawVec :: < T > :: MIN_NON_ZERO_CAP , hint)
49
+ } ;
50
+ let mut vector = Vec :: with_capacity ( initial_capacity) ;
51
+ // SAFETY: We requested capacity at least MIN_NON_ZERO_CAP, which
52
+ // is never zero, so there's space for at least one element.
53
+ unsafe {
54
+ ptr:: write ( vector. as_mut_ptr ( ) , first) ;
55
+ vector. set_len ( 1 ) ;
56
+ }
57
+
40
58
// must delegate to spec_extend() since extend() itself delegates
41
59
// to spec_from for empty Vecs
42
60
<Vec < T > as SpecExtend < T , I > >:: spec_extend ( & mut vector, iterator) ;
0 commit comments