use std::cell::RefCell;
use super::merge::QueueScratch;
use super::nodes::Node;
#[derive(Default)]
pub(super) struct MergeScratch {
pub(super) nodes: Vec<Node>,
pub(super) queue: QueueScratch,
}
thread_local! {
static MERGE: RefCell<MergeScratch> = RefCell::new(MergeScratch::default());
}
pub(super) fn with_merge_scratch<R>(f: impl FnOnce(&mut MergeScratch) -> R) -> R {
MERGE.with(|cell| match cell.try_borrow_mut() {
Ok(mut s) => {
s.nodes.clear();
s.queue.clear();
f(&mut s)
}
Err(_) => f(&mut MergeScratch::default()),
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_buffers_arrive_empty_however_they_were_left() {
with_merge_scratch(|s| {
s.nodes.push(Node::PLACEHOLDER);
s.queue.cold.push(1);
s.queue.ranks.push(0);
});
with_merge_scratch(|s| {
assert!(s.nodes.is_empty(), "nodes leaked between calls");
assert!(s.queue.is_empty(), "queue leaked between calls");
});
}
#[test]
fn a_nested_call_gets_its_own_buffers() {
with_merge_scratch(|outer| {
outer.nodes.extend([Node::PLACEHOLDER; 3]);
with_merge_scratch(|inner| {
assert!(inner.nodes.is_empty());
inner.nodes.push(Node::PLACEHOLDER);
});
assert_eq!(
outer.nodes.len(),
3,
"a nested call clobbered the outer buffer"
);
});
}
#[test]
fn capacity_survives_between_calls() {
with_merge_scratch(|s| s.nodes.extend([Node::PLACEHOLDER; 256]));
with_merge_scratch(|s| {
assert!(
s.nodes.capacity() >= 256,
"nodes were reallocated instead of reused"
)
});
}
}