@@ -1857,19 +1857,40 @@ impl<T, I> SpecExtend<T, I> for Vec<T>
1857
1857
// empty, but the loop in extend_desugared() is not going to see the
1858
1858
// vector being full in the few subsequent loop iterations.
1859
1859
// So we get better branch prediction.
1860
- let mut vector = match iterator. next ( ) {
1861
- None => return Vec :: new ( ) ,
1862
- Some ( element) => {
1863
- let ( lower, _) = iterator. size_hint ( ) ;
1864
- let mut vector = Vec :: with_capacity ( lower. saturating_add ( 1 ) ) ;
1865
- unsafe {
1866
- ptr:: write ( vector. get_unchecked_mut ( 0 ) , element) ;
1867
- vector. set_len ( 1 ) ;
1860
+ let element =
1861
+ if let Some ( x) = iterator. next ( ) { x }
1862
+ else { return Vec :: new ( ) } ;
1863
+ let ( lower, upper) = iterator. size_hint ( ) ;
1864
+ let upper = upper. unwrap_or ( lower) ;
1865
+ let mut vector =
1866
+ if lower >= upper / 2 {
1867
+ // This branch covers three main cases:
1868
+ // - There was no upper bound, so we just use the lower.
1869
+ // - The hint turned out to be exact, so we use it.
1870
+ // - Picking the upper won't waste more that the doubling
1871
+ // strategy might anyway, so go directly there.
1872
+ Vec :: with_capacity ( upper. saturating_add ( 1 ) )
1873
+ } else {
1874
+ // Try to start near the geometric mean of the range. That's
1875
+ // never all that high -- even 0B..1GB will only allocate 32kB --
1876
+ // but it's much more useful than the lower bound, especially
1877
+ // for iterator adapters like filter that have lower == 0.
1878
+ let mut v = Vec :: new ( ) ;
1879
+ let mag_diff = lower. leading_zeros ( ) - upper. leading_zeros ( ) ;
1880
+ let guess = upper >> ( mag_diff / 2 ) ;
1881
+ match v. try_reserve ( guess. saturating_add ( 1 ) ) {
1882
+ Ok ( _) => v,
1883
+ Err ( _) => Vec :: with_capacity ( lower. saturating_add ( 1 ) ) ,
1868
1884
}
1869
- vector
1870
- }
1871
- } ;
1885
+ } ;
1886
+ unsafe {
1887
+ ptr:: write ( vector. get_unchecked_mut ( 0 ) , element) ;
1888
+ vector. set_len ( 1 ) ;
1889
+ }
1872
1890
<Vec < T > as SpecExtend < T , I > >:: spec_extend ( & mut vector, iterator) ;
1891
+ if vector. len ( ) < vector. capacity ( ) / 2 {
1892
+ vector. shrink_to_fit ( ) ;
1893
+ }
1873
1894
vector
1874
1895
}
1875
1896
0 commit comments