@@ -92,8 +92,8 @@ impl<S: Borrow<str>> Join<&str> for [S] {
92
92
}
93
93
}
94
94
95
- macro_rules! spezialize_for_lengths {
96
- ( $separator: expr, $target: expr, $iter: expr; $( $num: expr) ,* ) => {
95
+ macro_rules! specialize_for_lengths {
96
+ ( $separator: expr, $target: expr, $iter: expr; $( $num: expr) ,* ) => { {
97
97
let mut target = $target;
98
98
let iter = $iter;
99
99
let sep_bytes = $separator;
@@ -104,19 +104,22 @@ macro_rules! spezialize_for_lengths {
104
104
$num => {
105
105
for s in iter {
106
106
copy_slice_and_advance!( target, sep_bytes) ;
107
- copy_slice_and_advance!( target, s. borrow( ) . as_ref( ) ) ;
107
+ let content_bytes = s. borrow( ) . as_ref( ) ;
108
+ copy_slice_and_advance!( target, content_bytes) ;
108
109
}
109
110
} ,
110
111
) *
111
112
_ => {
112
113
// arbitrary non-zero size fallback
113
114
for s in iter {
114
115
copy_slice_and_advance!( target, sep_bytes) ;
115
- copy_slice_and_advance!( target, s. borrow( ) . as_ref( ) ) ;
116
+ let content_bytes = s. borrow( ) . as_ref( ) ;
117
+ copy_slice_and_advance!( target, content_bytes) ;
116
118
}
117
119
}
118
120
}
119
- } ;
121
+ target
122
+ } }
120
123
}
121
124
122
125
macro_rules! copy_slice_and_advance {
@@ -155,30 +158,33 @@ where
155
158
// if the `len` calculation overflows, we'll panic
156
159
// we would have run out of memory anyway and the rest of the function requires
157
160
// the entire Vec pre-allocated for safety
158
- let len = sep_len
161
+ let reserved_len = sep_len
159
162
. checked_mul ( iter. len ( ) )
160
163
. and_then ( |n| {
161
164
slice. iter ( ) . map ( |s| s. borrow ( ) . as_ref ( ) . len ( ) ) . try_fold ( n, usize:: checked_add)
162
165
} )
163
166
. expect ( "attempt to join into collection with len > usize::MAX" ) ;
164
167
165
- // crucial for safety
166
- let mut result = Vec :: with_capacity ( len ) ;
167
- assert ! ( result. capacity( ) >= len ) ;
168
+ // prepare an uninitialized buffer
169
+ let mut result = Vec :: with_capacity ( reserved_len ) ;
170
+ debug_assert ! ( result. capacity( ) >= reserved_len ) ;
168
171
169
172
result. extend_from_slice ( first. borrow ( ) . as_ref ( ) ) ;
170
173
171
174
unsafe {
172
- {
173
- let pos = result. len ( ) ;
174
- let target = result. get_unchecked_mut ( pos..len) ;
175
-
176
- // copy separator and slices over without bounds checks
177
- // generate loops with hardcoded offsets for small separators
178
- // massive improvements possible (~ x2)
179
- spezialize_for_lengths ! ( sep, target, iter; 0 , 1 , 2 , 3 , 4 ) ;
180
- }
181
- result. set_len ( len) ;
175
+ let pos = result. len ( ) ;
176
+ let target = result. get_unchecked_mut ( pos..reserved_len) ;
177
+
178
+ // copy separator and slices over without bounds checks
179
+ // generate loops with hardcoded offsets for small separators
180
+ // massive improvements possible (~ x2)
181
+ let remain = specialize_for_lengths ! ( sep, target, iter; 0 , 1 , 2 , 3 , 4 ) ;
182
+
183
+ // A weird borrow implementation may return different
184
+ // slices for the length calculation and the actual copy.
185
+ // Make sure we don't expose uninitialized bytes to the caller.
186
+ let result_len = reserved_len - remain. len ( ) ;
187
+ result. set_len ( result_len) ;
182
188
}
183
189
result
184
190
}
0 commit comments