1+ use core:: { cmp:: min, mem:: MaybeUninit , ptr:: copy_nonoverlapping} ;
2+
13use super :: constants:: CUMULATIVE_CAPACITIES ;
2- use crate :: { Doubling , Fragment , SplitVec } ;
4+ use crate :: { Doubling , Fragment , SplitVec , growth :: doubling :: constants :: CAPACITIES } ;
35use alloc:: vec:: Vec ;
46
5- impl < T : Clone > From < Vec < T > > for SplitVec < T , Doubling > {
7+ impl < T > From < Vec < T > > for SplitVec < T , Doubling > {
68 /// Converts a `Vec` into a `SplitVec`.
79 ///
810 /// # Examples
@@ -19,8 +21,9 @@ impl<T: Clone> From<Vec<T>> for SplitVec<T, Doubling> {
1921 /// assert_eq!(1, split_vec.fragments().len());
2022 /// assert!(vec_capacity <= split_vec.capacity());
2123 /// ```
22- fn from ( value : Vec < T > ) -> Self {
24+ fn from ( mut value : Vec < T > ) -> Self {
2325 let len = value. len ( ) ;
26+ // Number of fragments to create
2427 let f = CUMULATIVE_CAPACITIES
2528 . iter ( )
2629 . enumerate ( )
@@ -29,26 +32,33 @@ impl<T: Clone> From<Vec<T>> for SplitVec<T, Doubling> {
2932 . expect ( "overflow" ) ;
3033
3134 let mut fragments = Vec :: with_capacity ( f + 1 ) ;
32- let mut original_idx = 0 ;
35+ let fragments_init = fragments . spare_capacity_mut ( ) ;
3336 let mut remaining_len = len;
34- let mut curr_f = 1 ;
37+ let mut curr_f = f ;
3538 while remaining_len > 0 {
36- let capacity = & CUMULATIVE_CAPACITIES [ curr_f] ;
37- let mut fragment = Fragment :: new ( * capacity) ;
38-
39- let copy_len = if capacity <= & remaining_len {
40- * capacity
41- } else {
42- remaining_len
43- } ;
44-
45- fragment. extend_from_slice ( & value[ original_idx..( original_idx + copy_len) ] ) ;
46-
47- original_idx += copy_len;
39+ curr_f -= 1 ;
40+ let capacity = CAPACITIES [ curr_f] ;
41+ // for example, if the current fragment has a capacity of 8 but there are only 5 elements to copy,
42+ // we want the copy length to only be 1
43+ let copy_len = min ( remaining_len - CUMULATIVE_CAPACITIES [ curr_f] , capacity) ;
4844 remaining_len -= copy_len;
49- fragments. push ( fragment) ;
50- curr_f += 1 ;
45+
46+ // This is adapted from Vec::split_off, with the difference that it
47+ // reserves the full capacity first to avoid extra allocations
48+ let mut fragment_data = Vec :: with_capacity ( capacity) ;
49+ unsafe {
50+ value. set_len ( remaining_len) ;
51+ fragment_data. set_len ( copy_len) ;
52+ copy_nonoverlapping (
53+ value. as_ptr ( ) . add ( remaining_len) ,
54+ fragment_data. as_mut_ptr ( ) ,
55+ copy_len,
56+ ) ;
57+ }
58+ fragments_init[ curr_f] = MaybeUninit :: new ( Fragment :: from ( fragment_data) ) ;
5159 }
60+ debug_assert_eq ! ( curr_f, 0 ) ;
61+ unsafe { fragments. set_len ( f) } ;
5262
5363 Self :: from_raw_parts ( len, fragments, Doubling )
5464 }
0 commit comments