use std::collections::HashMap;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use std::path::PathBuf;
use std::sync::Arc;
use burn_tensor::DType;
use crate::ir::{DataId, TensorData};
#[derive(Debug, Clone)]
pub enum TensorDataSource {
Embedded(bytes::Bytes),
External {
file_path: PathBuf,
offset: u64,
length: u64,
},
}
#[derive(Debug, Clone)]
pub struct TensorDataRef {
shape: Vec<usize>,
dtype: DType,
source: TensorDataSource,
}
impl TensorDataRef {
pub fn new(raw_bytes: bytes::Bytes, shape: Vec<usize>, dtype: DType) -> Self {
Self {
shape,
dtype,
source: TensorDataSource::Embedded(raw_bytes),
}
}
pub fn new_external(
file_path: PathBuf,
offset: u64,
length: u64,
shape: Vec<usize>,
dtype: DType,
) -> Self {
Self {
shape,
dtype,
source: TensorDataSource::External {
file_path,
offset,
length,
},
}
}
pub fn shape(&self) -> &[usize] {
&self.shape
}
pub fn dtype(&self) -> DType {
self.dtype
}
pub fn to_tensor_data(&self) -> TensorData {
let bytes = match &self.source {
TensorDataSource::Embedded(raw_bytes) => raw_bytes.to_vec(),
TensorDataSource::External {
file_path,
offset,
length,
} => Self::load_external_data(file_path, *offset, *length),
};
TensorData::from_bytes_vec(bytes, self.shape.clone(), self.dtype)
}
fn load_external_data(file_path: &PathBuf, offset: u64, length: u64) -> Vec<u8> {
#[cfg(feature = "mmap")]
{
if let Ok(data) = Self::load_external_mmap(file_path, offset, length) {
return data;
}
log::debug!(
"mmap failed for {}, falling back to standard I/O",
file_path.display()
);
}
Self::load_external_read(file_path, offset, length)
}
#[cfg(feature = "mmap")]
fn load_external_mmap(
file_path: &PathBuf,
offset: u64,
length: u64,
) -> std::io::Result<Vec<u8>> {
let file = File::open(file_path)?;
let mmap = unsafe { memmap2::Mmap::map(&file)? };
let start = offset as usize;
let end = start + length as usize;
if end > mmap.len() {
return Err(std::io::Error::new(
std::io::ErrorKind::UnexpectedEof,
format!(
"External data range {}..{} exceeds file size {}",
start,
end,
mmap.len()
),
));
}
Ok(mmap[start..end].to_vec())
}
fn load_external_read(file_path: &PathBuf, offset: u64, length: u64) -> Vec<u8> {
let mut file = File::open(file_path).unwrap_or_else(|e| {
panic!(
"Failed to open external data file '{}': {}",
file_path.display(),
e
)
});
file.seek(SeekFrom::Start(offset)).unwrap_or_else(|e| {
panic!(
"Failed to seek to offset {} in '{}': {}",
offset,
file_path.display(),
e
)
});
let mut buffer = vec![0u8; length as usize];
file.read_exact(&mut buffer).unwrap_or_else(|e| {
panic!(
"Failed to read {} bytes from '{}': {}",
length,
file_path.display(),
e
)
});
buffer
}
}
impl From<TensorData> for TensorDataRef {
fn from(tensor_data: TensorData) -> Self {
let raw_bytes = bytes::Bytes::copy_from_slice(&tensor_data.bytes);
Self {
shape: tensor_data.shape.to_vec(),
dtype: tensor_data.dtype,
source: TensorDataSource::Embedded(raw_bytes),
}
}
}
#[derive(Debug, Clone)]
pub struct TensorStore {
data: HashMap<DataId, TensorDataRef>,
next_id: DataId,
}
impl TensorStore {
pub fn new() -> Self {
Self {
data: HashMap::new(),
next_id: 0,
}
}
pub fn store(&mut self, data: TensorDataRef) -> DataId {
let id = self.next_id;
self.next_id += 1;
self.data.insert(id, data);
id
}
pub fn get(&self, id: DataId) -> Option<TensorData> {
self.data.get(&id).map(|data_ref| data_ref.to_tensor_data())
}
pub fn len(&self) -> usize {
self.data.len()
}
}
impl Default for TensorStore {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct ValueStore {
tensor_store: Arc<TensorStore>,
constant_map: Arc<HashMap<String, DataId>>,
}
impl ValueStore {
pub fn new(tensor_store: Arc<TensorStore>, constant_map: Arc<HashMap<String, DataId>>) -> Self {
Self {
tensor_store,
constant_map,
}
}
pub fn get_tensor_data(&self, id: DataId) -> Option<TensorData> {
self.tensor_store.get(id)
}
pub fn get_constant_data_id(&self, output_name: &str) -> Option<DataId> {
self.constant_map.get(output_name).copied()
}
pub fn constant_map_len(&self) -> usize {
self.constant_map.len()
}
pub fn tensor_count(&self) -> usize {
self.tensor_store.len()
}
}