use crate::{Error, Result};
use byteorder::{ByteOrder, LittleEndian};
use memmap2::Mmap;
use std::sync::Arc;
pub struct ConnectionMatrix {
_mmap: Arc<Mmap>,
matrix_ptr: *const i16,
lsize: usize,
rsize: usize,
}
unsafe impl Send for ConnectionMatrix {}
unsafe impl Sync for ConnectionMatrix {}
impl std::fmt::Debug for ConnectionMatrix {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ConnectionMatrix")
.field("lsize", &self.lsize)
.field("rsize", &self.rsize)
.finish()
}
}
impl ConnectionMatrix {
pub fn from_mmap(mmap: Arc<Mmap>) -> Result<Self> {
let data = &mmap[..];
if data.len() < 4 {
return Err(Error::MatrixError(
"Matrix file too small for header".to_string(),
));
}
let lsize = LittleEndian::read_u16(&data[0..2]) as usize;
let rsize = LittleEndian::read_u16(&data[2..4]) as usize;
let expected_size = 4 + lsize * rsize * 2;
if data.len() != expected_size {
return Err(Error::MatrixError(format!(
"Matrix file size mismatch: expected {} bytes ({}x{} matrix + 4), got {}",
expected_size,
lsize,
rsize,
data.len()
)));
}
let matrix_ptr = data[4..].as_ptr() as *const i16;
Ok(Self {
_mmap: mmap,
matrix_ptr,
lsize,
rsize,
})
}
#[inline]
pub fn cost(&self, right_id: u16, left_id: u16) -> i16 {
let rc = right_id as usize;
let lc = left_id as usize;
if rc >= self.rsize || lc >= self.lsize {
return i16::MAX;
}
let index = rc + self.lsize * lc;
unsafe { *self.matrix_ptr.add(index) }
}
#[inline]
pub unsafe fn cost_unchecked(&self, right_id: u16, left_id: u16) -> i16 {
let rc = right_id as usize;
let lc = left_id as usize;
let index = rc + self.lsize * lc;
unsafe { *self.matrix_ptr.add(index) }
}
#[inline]
pub fn left_size(&self) -> usize {
self.lsize
}
#[inline]
pub fn right_size(&self) -> usize {
self.rsize
}
#[inline]
pub fn size(&self) -> usize {
self.lsize * self.rsize
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_out_of_bounds() {
assert_eq!(i16::MAX, 32767);
}
}