use std::io::Write;
pub(crate) fn coalesce_and_emit<R, F, D, I>(
tagged: &[(u64, u64, u64)],
inner_bound: usize,
make_triplet: F,
mut retrieve: R,
) -> anyhow::Result<Vec<(u64, u64, f32)>>
where
R: FnMut(u64, u64) -> anyhow::Result<(D, I)>,
D: std::ops::Index<usize, Output = f32>,
I: std::ops::Index<usize, Output = u64>,
F: Fn(u64, u64, f32) -> (u64, u64, f32),
{
let total: u64 = tagged.iter().map(|&(_, s, e)| e - s).sum();
let mut ret: Vec<(u64, u64, f32)> = Vec::with_capacity(total as usize);
const GAP_FUSE: u64 = 65_536;
const MERGED_SPAN_CAP: u64 = 4_000_000;
let mut i = 0;
while i < tagged.len() {
let merged_start = tagged[i].1;
let mut merged_end = tagged[i].2;
let mut j = i + 1;
while j < tagged.len()
&& tagged[j].1 <= merged_end.saturating_add(GAP_FUSE)
&& tagged[j].2.max(merged_end) - merged_start <= MERGED_SPAN_CAP
{
merged_end = merged_end.max(tagged[j].2);
j += 1;
}
let (data_buf, indices_buf) = retrieve(merged_start, merged_end)?;
for &(tag, start, end) in &tagged[i..j] {
let off = (start - merged_start) as usize;
let len = (end - start) as usize;
for k in 0..len {
let inner = indices_buf[off + k];
let val = data_buf[off + k];
debug_assert!((inner as usize) < inner_bound);
ret.push(make_triplet(tag, inner, val));
}
}
i = j;
}
Ok(ret)
}
pub(crate) fn write_mtx_header<W: Write>(
buf: &mut W,
nrow: usize,
ncol: usize,
nnz: usize,
) -> anyhow::Result<()> {
writeln!(buf, "%%MatrixMarket matrix coordinate real general")?;
writeln!(buf, "{}\t{}\t{}", nrow, ncol, nnz)?;
Ok(())
}
#[cfg(test)]
#[path = "shared_tests.rs"]
mod tests;