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