pub fn replace_outputs_preserving_slots(outputs: &mut Vec<Vec<u8>>, incoming: Vec<Vec<u8>>) {
let mut incoming = incoming.into_iter();
let mut reused = 0usize;
for (slot, mut bytes) in outputs.iter_mut().zip(incoming.by_ref()) {
replace_slot_preserving_capacity(slot, &mut bytes);
reused += 1;
}
outputs.truncate(reused);
outputs.extend(incoming);
}
#[inline]
fn replace_slot_preserving_capacity(slot: &mut Vec<u8>, bytes: &mut Vec<u8>) {
if slot.len() == bytes.len() {
slot.copy_from_slice(bytes);
} else if bytes.len() <= slot.capacity() {
slot.clear();
slot.extend_from_slice(bytes);
} else {
std::mem::swap(slot, bytes);
}
}
pub fn clear_outputs_preserving_slots(outputs: &mut [Vec<u8>]) {
for output in outputs {
output.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn replace_outputs_preserving_slots_reuses_existing_slot_buffers() {
let mut outputs = vec![Vec::with_capacity(16), Vec::with_capacity(8)];
outputs[0].extend_from_slice(&[9, 9]);
outputs[1].extend_from_slice(&[8]);
let outer_ptr = outputs.as_ptr() as usize;
let first_ptr = outputs[0].as_ptr() as usize;
let second_ptr = outputs[1].as_ptr() as usize;
replace_outputs_preserving_slots(&mut outputs, vec![vec![1, 2, 3], vec![4, 5]]);
assert_eq!(outputs, vec![vec![1, 2, 3], vec![4, 5]]);
assert_eq!(outputs.as_ptr() as usize, outer_ptr);
assert_eq!(outputs[0].as_ptr() as usize, first_ptr);
assert_eq!(outputs[1].as_ptr() as usize, second_ptr);
assert!(outputs[0].capacity() >= 16);
assert!(outputs[1].capacity() >= 8);
}
#[test]
fn replace_outputs_preserving_slots_moves_new_tail_slots() {
let mut outputs = vec![Vec::with_capacity(4)];
let first_ptr = outputs[0].as_ptr() as usize;
replace_outputs_preserving_slots(&mut outputs, vec![vec![1], vec![2, 3]]);
assert_eq!(outputs, vec![vec![1], vec![2, 3]]);
assert_eq!(outputs[0].as_ptr() as usize, first_ptr);
}
#[test]
fn replace_outputs_preserving_slots_moves_oversized_incoming_slot() {
let mut outputs = vec![Vec::with_capacity(1)];
let incoming = vec![vec![1, 2, 3, 4]];
let incoming_ptr = incoming[0].as_ptr() as usize;
replace_outputs_preserving_slots(&mut outputs, incoming);
assert_eq!(outputs, vec![vec![1, 2, 3, 4]]);
assert_eq!(
outputs[0].as_ptr() as usize,
incoming_ptr,
"oversized incoming output should be moved into place instead of copied through a too-small retained slot"
);
}
#[test]
fn clear_outputs_preserving_slots_retains_outer_and_inner_allocations() {
let mut outputs = vec![Vec::with_capacity(16), Vec::with_capacity(8)];
outputs[0].extend_from_slice(&[1, 2, 3]);
outputs[1].extend_from_slice(&[4, 5]);
let outer_ptr = outputs.as_ptr() as usize;
let first_ptr = outputs[0].as_ptr() as usize;
let second_ptr = outputs[1].as_ptr() as usize;
clear_outputs_preserving_slots(&mut outputs);
assert_eq!(outputs.len(), 2);
assert!(outputs.iter().all(Vec::is_empty));
assert_eq!(outputs.as_ptr() as usize, outer_ptr);
assert_eq!(outputs[0].as_ptr() as usize, first_ptr);
assert_eq!(outputs[1].as_ptr() as usize, second_ptr);
assert!(outputs[0].capacity() >= 16);
assert!(outputs[1].capacity() >= 8);
}
}