use std::any::Any;
use std::fmt::Debug;
use std::ops::Range;
use std::sync::Arc;
use roaring::RoaringBitmap;
use vortex_array::ArrayRef;
use vortex_array::ExecutionCtx;
use vortex_array::dtype::DType;
use vortex_array::expr::BoundExpression;
use vortex_buffer::BitBufferMut;
use vortex_error::VortexResult;
use vortex_mask::Mask;
use vortex_session::VortexSession;
use vortex_session::registry::Id;
use crate::layouts::indexed::reader::OpenArgs;
use crate::layouts::indexed::reader::OpenIndex;
use crate::layouts::indexed::reader::open_index;
use crate::layouts::indexed::writer::IndexWriter;
use crate::layouts::indexed::writer::TypedIndexWriter;
pub type IndexId = Id;
pub trait IndexVTable: 'static + Send + Sync + Debug {
type Options: 'static + Send + Sync;
type Builder: IndexBuilder<Options = Self::Options, Chunk = Self::Chunk> + 'static;
type Query: 'static + Send + Sync;
type Chunk: 'static + Send + Sync;
fn id(&self) -> IndexId;
fn serialize_options(&self, options: &Self::Options) -> Vec<u8>;
fn deserialize_options(&self, options: &[u8]) -> VortexResult<Self::Options>;
fn index_dtype(&self, dtype: &DType, options: &Self::Options) -> Option<DType>;
fn builder(
&self,
dtype: &DType,
options: &Self::Options,
data_block_len: Option<u64>,
session: &VortexSession,
) -> VortexResult<Self::Builder>;
fn plan(
&self,
expr: &BoundExpression,
dtype: &DType,
index_dtype: &DType,
options: &Self::Options,
) -> VortexResult<Option<IndexQueryPlan<Self::Query>>>;
fn encode(
&self,
chunk: &Self::Chunk,
options: &Self::Options,
ctx: &mut ExecutionCtx,
) -> VortexResult<ArrayRef>;
fn decode(
&self,
chunk: ArrayRef,
options: &Self::Options,
ctx: &mut ExecutionCtx,
) -> VortexResult<Self::Chunk>;
fn resolve(
&self,
query: &Self::Query,
chunks: &[Arc<Self::Chunk>],
data_row_count: u64,
options: &Self::Options,
ctx: &mut ExecutionCtx,
) -> VortexResult<RowLocator>;
}
#[derive(Clone)]
pub struct IndexVTableRef(Arc<dyn DynIndexVTable>);
impl IndexVTableRef {
pub fn new<V: IndexVTable>(vtable: V) -> Self {
Self(Arc::new(vtable))
}
pub fn id(&self) -> IndexId {
self.0.id()
}
pub fn as_opt<V: IndexVTable>(&self) -> Option<&V> {
self.0.as_any().downcast_ref()
}
pub(crate) fn open_writer(&self, options: &[u8]) -> VortexResult<Arc<dyn IndexWriter>> {
Arc::clone(&self.0).open_writer(options)
}
pub(crate) fn open_reader(
&self,
args: OpenArgs<'_>,
) -> VortexResult<Option<Arc<dyn OpenIndex>>> {
Arc::clone(&self.0).open_reader(args)
}
}
impl Debug for IndexVTableRef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
pub(crate) trait DynIndexVTable: 'static + Send + Sync + Debug {
fn id(&self) -> IndexId;
fn as_any(&self) -> &dyn Any;
fn open_writer(self: Arc<Self>, options: &[u8]) -> VortexResult<Arc<dyn IndexWriter>>;
fn open_reader(self: Arc<Self>, args: OpenArgs<'_>)
-> VortexResult<Option<Arc<dyn OpenIndex>>>;
}
impl<V: IndexVTable> DynIndexVTable for V {
fn id(&self) -> IndexId {
IndexVTable::id(self)
}
fn as_any(&self) -> &dyn Any {
self
}
fn open_writer(self: Arc<Self>, options: &[u8]) -> VortexResult<Arc<dyn IndexWriter>> {
Ok(Arc::new(TypedIndexWriter::try_new(self, options)?))
}
fn open_reader(
self: Arc<Self>,
args: OpenArgs<'_>,
) -> VortexResult<Option<Arc<dyn OpenIndex>>> {
open_index(self, args)
}
}
pub type BuiltIndex<B> = (
Vec<<B as IndexBuilder>::Chunk>,
<B as IndexBuilder>::Options,
);
pub trait IndexBuilder: Send {
type Options;
type Chunk;
fn push(
&mut self,
chunk: &ArrayRef,
row_offset: u64,
ctx: &mut ExecutionCtx,
) -> VortexResult<()>;
fn finish(self) -> VortexResult<Option<BuiltIndex<Self>>>;
fn buffered_bytes(&self) -> u64;
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum IndexExactness {
Exact,
Superset,
}
#[derive(Clone, Debug)]
pub enum RowLocator {
Rows(RoaringBitmap),
Blocks { block_len: u64, ids: RoaringBitmap },
}
impl RowLocator {
pub fn empty_rows() -> Self {
RowLocator::Rows(RoaringBitmap::new())
}
pub fn mask_for(&self, row_range: &Range<u64>) -> VortexResult<Mask> {
let len = usize::try_from(row_range.end - row_range.start)?;
let mut bits = BitBufferMut::with_capacity(len);
self.append_to(row_range, &mut bits)?;
Ok(Mask::from(bits.freeze()))
}
pub fn append_to(&self, row_range: &Range<u64>, bits: &mut BitBufferMut) -> VortexResult<()> {
match self {
RowLocator::Rows(rows) => {
let start = u32::try_from(row_range.start)?;
let end = u32::try_from(row_range.end)?;
let mut pos = row_range.start;
for row in rows.range(start..end) {
let row = u64::from(row);
bits.append_n(false, usize::try_from(row - pos)?);
bits.append_n(true, 1);
pos = row + 1;
}
bits.append_n(false, usize::try_from(row_range.end - pos)?);
}
RowLocator::Blocks { block_len, ids } => {
let mut row = row_range.start;
while row < row_range.end {
let block = row / block_len;
let block_end = ((block + 1) * block_len).min(row_range.end);
let hit = ids.contains(u32::try_from(block)?);
bits.append_n(hit, usize::try_from(block_end - row)?);
row = block_end;
}
}
}
Ok(())
}
}
pub struct IndexQueryPlan<Q> {
pub exactness: IndexExactness,
pub filter: BoundExpression,
pub query: Q,
}