use crate::*;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub(crate) struct LineBytes(pub(crate) usize);
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub(crate) enum RowArrangement {
InOrder,
Swizzled(ChunkSwizzle),
Padded { lines: usize },
}
impl RowArrangement {
pub(crate) fn new(chunks: RowChunks, extents: &[usize], line: LineBytes) -> Self {
let row_bytes = extents.last().copied().unwrap_or(0) * line.0;
let one_chunk = row_bytes <= RowChunks::CHUNK_BYTES.max(line.0);
match (chunks, one_chunk) {
(RowChunks::InOrder, _) | (_, true) => Self::InOrder,
(RowChunks::Swizzled, false) => match ChunkSwizzle::new(extents, line) {
Some(swizzle) => Self::Swizzled(swizzle),
None => Self::InOrder,
},
(RowChunks::Padded, false) => Self::Padded {
lines: RowChunks::CHUNK_BYTES.div_ceil(line.0),
},
}
}
pub(crate) fn is_pitched(&self) -> bool {
match self {
Self::InOrder | Self::Swizzled(_) => false,
Self::Padded { .. } => true,
}
}
pub(crate) fn rows_are_runs(&self) -> bool {
match self {
Self::InOrder | Self::Padded { .. } => true,
Self::Swizzled(_) => false,
}
}
pub(crate) fn assert_in_order(&self, reader: &str, why: &str) {
assert!(
*self == Self::InOrder,
"{reader}: {why}, so a {self:?} stage cannot be read by it; stage it RowChunks::InOrder"
);
}
pub(crate) fn assert_rows_are_runs(&self, reader: &str) {
assert!(
self.rows_are_runs(),
"{reader}: a swizzled stage keeps a row's chunks out of order, so a fragment API \
reading rows off a pointer and a stride (cmma) cannot read it; stage it \
RowChunks::InOrder or RowChunks::Padded"
);
}
pub(crate) fn padding(&self) -> usize {
match self {
Self::InOrder | Self::Swizzled(_) => 0,
Self::Padded { lines } => *lines,
}
}
pub(crate) fn swizzle_along(&self, axis: usize) -> Option<ChunkSwizzle> {
match self {
Self::Swizzled(swizzle) if swizzle.line_axis() == axis => Some(*swizzle),
Self::InOrder | Self::Swizzled(_) | Self::Padded { .. } => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn swizzled() -> RowArrangement {
RowArrangement::new(RowChunks::Swizzled, &[16, 4], LineBytes(16))
}
fn padded() -> RowArrangement {
RowArrangement::new(RowChunks::Padded, &[16, 4], LineBytes(16))
}
#[test]
#[should_panic(expected = "stage it RowChunks::InOrder")]
fn a_dense_reader_refuses_a_swizzled_stage() {
RowArrangement::InOrder.assert_in_order("reader", "why");
swizzled().assert_in_order("reader", "why");
}
#[test]
#[should_panic(expected = "stage it RowChunks::InOrder")]
fn a_dense_reader_refuses_a_padded_stage() {
padded().assert_in_order("reader", "why");
}
#[test]
#[should_panic(expected = "a swizzled stage keeps a row's chunks out of order")]
fn a_fragment_api_refuses_a_swizzled_stage() {
RowArrangement::InOrder.assert_rows_are_runs("cmma");
padded().assert_rows_are_runs("cmma");
swizzled().assert_rows_are_runs("cmma");
}
#[test]
fn a_request_resolves_against_the_rows_it_lays_down() {
let extents = [2, 16, 4];
assert_eq!(
RowArrangement::new(RowChunks::InOrder, &extents, LineBytes(16)),
RowArrangement::InOrder
);
assert!(matches!(
RowArrangement::new(RowChunks::Swizzled, &extents, LineBytes(16)),
RowArrangement::Swizzled(_)
));
assert_eq!(
RowArrangement::new(RowChunks::Padded, &extents, LineBytes(16)),
RowArrangement::Padded { lines: 1 }
);
assert_eq!(
RowArrangement::new(RowChunks::Padded, &[16, 1], LineBytes(16)),
RowArrangement::InOrder
);
assert_eq!(
RowArrangement::new(RowChunks::Padded, &[16, 16], LineBytes(4)),
RowArrangement::Padded { lines: 4 }
);
assert_eq!(
RowArrangement::new(RowChunks::Padded, &[16, 4], LineBytes(32)),
RowArrangement::Padded { lines: 1 }
);
}
}