use crate::perf_optimizations::ContiguousVectors;
pub(crate) const PDX_BLOCK_SIZE: usize = 64;
#[derive(Debug)]
pub(crate) struct ColumnarVectors {
data: Vec<f32>,
dimension: usize,
count: usize,
num_blocks: usize,
}
impl ColumnarVectors {
#[must_use]
pub(crate) fn from_contiguous(vectors: &ContiguousVectors) -> Self {
let count = vectors.len();
let dimension = vectors.dimension();
if count == 0 {
return Self {
data: Vec::new(),
dimension,
count: 0,
num_blocks: 0,
};
}
let num_blocks = count.div_ceil(PDX_BLOCK_SIZE);
let total = num_blocks * PDX_BLOCK_SIZE * dimension;
let mut data = vec![0.0_f32; total];
transpose_aos_to_pdx(vectors, &mut data, dimension, num_blocks);
Self {
data,
dimension,
count,
num_blocks,
}
}
#[inline]
#[must_use]
pub(crate) fn block_count(&self) -> usize {
self.num_blocks
}
#[inline]
#[must_use]
pub(crate) fn block_size(&self, block_idx: usize) -> usize {
debug_assert!(block_idx < self.num_blocks, "block index out of bounds");
if block_idx + 1 < self.num_blocks {
PDX_BLOCK_SIZE
} else {
let remainder = self.count % PDX_BLOCK_SIZE;
if remainder == 0 {
PDX_BLOCK_SIZE
} else {
remainder
}
}
}
#[inline]
#[must_use]
pub(crate) fn block_ptr(&self, block_idx: usize) -> &[f32] {
debug_assert!(block_idx < self.num_blocks, "block index out of bounds");
let block_len = PDX_BLOCK_SIZE * self.dimension;
let start = block_idx * block_len;
&self.data[start..start + block_len]
}
#[inline]
#[must_use]
pub(crate) fn dimension(&self) -> usize {
self.dimension
}
#[inline]
#[must_use]
pub(crate) fn len(&self) -> usize {
self.count
}
#[inline]
#[must_use]
pub(crate) fn is_empty(&self) -> bool {
self.count == 0
}
}
fn transpose_aos_to_pdx(
vectors: &ContiguousVectors,
pdx: &mut [f32],
dimension: usize,
num_blocks: usize,
) {
let block_stride = PDX_BLOCK_SIZE * dimension;
let flat = vectors.as_flat_slice();
for block_idx in 0..num_blocks {
let block_offset = block_idx * block_stride;
let base_vec = block_idx * PDX_BLOCK_SIZE;
let block_count = vectors.len().saturating_sub(base_vec).min(PDX_BLOCK_SIZE);
for d in 0..dimension {
let dim_offset = block_offset + d * PDX_BLOCK_SIZE;
for local in 0..block_count {
let vec_idx = base_vec + local;
pdx[dim_offset + local] = flat[vec_idx * dimension + d];
}
}
}
}