use std::fmt;
use std::mem;
use std::sync::Arc;
use super::buffer_pool::BufferPool;
use crate::image::Sample;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum BatchLayout {
#[default]
Nchw,
Nhwc,
}
impl BatchLayout {
pub fn name(self) -> &'static str {
match self {
Self::Nchw => "NCHW",
Self::Nhwc => "NHWC",
}
}
}
pub struct ImageBatch<T: Sample> {
shape: [usize; 4],
layout: BatchLayout,
data: Vec<T>,
pool: Option<Arc<BufferPool>>,
}
impl<T: Sample> ImageBatch<T> {
pub(crate) fn new(
shape: [usize; 4],
layout: BatchLayout,
data: Vec<T>,
pool: Option<Arc<BufferPool>>,
) -> Self {
debug_assert_eq!(shape.iter().product::<usize>(), data.len());
Self {
shape,
layout,
data,
pool,
}
}
pub fn shape(&self) -> [usize; 4] {
self.shape
}
pub fn layout(&self) -> BatchLayout {
self.layout
}
pub fn data(&self) -> &[T] {
&self.data
}
pub fn data_mut(&mut self) -> &mut [T] {
&mut self.data
}
pub fn into_vec(mut self) -> Vec<T> {
mem::take(&mut self.data)
}
}
impl<T: Sample> Drop for ImageBatch<T> {
fn drop(&mut self) {
if let Some(pool) = &self.pool {
pool.give(mem::take(&mut self.data));
}
}
}
impl<T: Sample> fmt::Debug for ImageBatch<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let [n, a, b, c] = self.shape;
let layout = self.layout.name();
write!(f, "ImageBatch<{}, {layout}>({n}x{a}x{b}x{c})", T::NAME)
}
}