1
Fork 0
This commit is contained in:
Yechan Bae 2021-02-03 16:36:33 -05:00
parent 186f7ae5b0
commit 6d43225bfb
2 changed files with 53 additions and 17 deletions

View file

@ -90,8 +90,8 @@ impl<S: Borrow<str>> Join<&str> for [S] {
}
}
macro_rules! spezialize_for_lengths {
($separator:expr, $target:expr, $iter:expr; $($num:expr),*) => {
macro_rules! specialize_for_lengths {
($separator:expr, $target:expr, $iter:expr; $($num:expr),*) => {{
let mut target = $target;
let iter = $iter;
let sep_bytes = $separator;
@ -102,7 +102,8 @@ macro_rules! spezialize_for_lengths {
$num => {
for s in iter {
copy_slice_and_advance!(target, sep_bytes);
copy_slice_and_advance!(target, s.borrow().as_ref());
let content_bytes = s.borrow().as_ref();
copy_slice_and_advance!(target, content_bytes);
}
},
)*
@ -110,11 +111,13 @@ macro_rules! spezialize_for_lengths {
// arbitrary non-zero size fallback
for s in iter {
copy_slice_and_advance!(target, sep_bytes);
copy_slice_and_advance!(target, s.borrow().as_ref());
let content_bytes = s.borrow().as_ref();
copy_slice_and_advance!(target, content_bytes);
}
}
}
};
target
}}
}
macro_rules! copy_slice_and_advance {
@ -153,7 +156,7 @@ where
// if the `len` calculation overflows, we'll panic
// we would have run out of memory anyway and the rest of the function requires
// the entire Vec pre-allocated for safety
let len = sep_len
let reserved_len = sep_len
.checked_mul(iter.len())
.and_then(|n| {
slice.iter().map(|s| s.borrow().as_ref().len()).try_fold(n, usize::checked_add)
@ -161,22 +164,25 @@ where
.expect("attempt to join into collection with len > usize::MAX");
// crucial for safety
let mut result = Vec::with_capacity(len);
assert!(result.capacity() >= len);
let mut result = Vec::with_capacity(reserved_len);
debug_assert!(result.capacity() >= reserved_len);
result.extend_from_slice(first.borrow().as_ref());
unsafe {
{
let pos = result.len();
let target = result.get_unchecked_mut(pos..len);
let pos = result.len();
let target = result.get_unchecked_mut(pos..reserved_len);
// copy separator and slices over without bounds checks
// generate loops with hardcoded offsets for small separators
// massive improvements possible (~ x2)
spezialize_for_lengths!(sep, target, iter; 0, 1, 2, 3, 4);
}
result.set_len(len);
// copy separator and slices over without bounds checks
// generate loops with hardcoded offsets for small separators
// massive improvements possible (~ x2)
let remain = specialize_for_lengths!(sep, target, iter; 0, 1, 2, 3, 4);
// issue #80335: A weird borrow implementation can return different
// slices for the length calculation and the actual copy, so
// `remain.len()` might be non-zero.
let result_len = reserved_len - remain.len();
result.set_len(result_len);
}
result
}