use std::env::VarError;
use std::sync::LazyLock;
use vortex_dtype::DType;
use vortex_error::VortexResult;
use vortex_error::vortex_bail;
use vortex_error::vortex_panic;
use crate::AnyCanonical;
use crate::Array;
use crate::ArrayRef;
use crate::Canonical;
use crate::CanonicalView;
use crate::Executable;
use crate::ExecutionCtx;
use crate::IntoArray;
use crate::arrays::ConstantArray;
use crate::arrays::ConstantVTable;
use crate::matcher::Matcher;
use crate::scalar::Scalar;
pub enum Columnar {
Canonical(Canonical),
Constant(ConstantArray),
}
impl Columnar {
pub fn constant<S: Into<Scalar>>(scalar: S, len: usize) -> Self {
Columnar::Constant(ConstantArray::new(scalar.into(), len))
}
pub fn len(&self) -> usize {
match self {
Columnar::Canonical(canonical) => canonical.len(),
Columnar::Constant(constant) => constant.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn dtype(&self) -> &DType {
match self {
Columnar::Canonical(canonical) => canonical.dtype(),
Columnar::Constant(constant) => constant.dtype(),
}
}
}
impl IntoArray for Columnar {
fn into_array(self) -> ArrayRef {
match self {
Columnar::Canonical(canonical) => canonical.into_array(),
Columnar::Constant(constant) => constant.into_array(),
}
}
}
impl Executable for Columnar {
fn execute(mut array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
static MAX_ITERATIONS: LazyLock<usize> =
LazyLock::new(|| match std::env::var("VORTEX_MAX_ITERATIONS") {
Ok(val) => val.parse::<usize>().unwrap_or_else(|e| {
vortex_panic!("VORTEX_MAX_ITERATIONS is not a valid usize: {e}")
}),
Err(VarError::NotPresent) => 128,
Err(VarError::NotUnicode(_)) => {
vortex_panic!("VORTEX_MAX_ITERATIONS is not a valid unicode string")
}
});
for _ in 0..*MAX_ITERATIONS {
if let Some(constant) = array.as_opt::<ConstantVTable>() {
ctx.log(format_args!("-> constant({})", constant.scalar()));
return Ok(Columnar::Constant(constant.clone()));
}
if let Some(canonical) = array.as_opt::<AnyCanonical>() {
ctx.log(format_args!("-> canonical {}", array));
return Ok(Columnar::Canonical(canonical.into()));
}
array = array.execute(ctx)?;
}
vortex_bail!("Exceeded maximum execution iterations while executing to Columnar")
}
}
pub enum ColumnarView<'a> {
Canonical(CanonicalView<'a>),
Constant(&'a ConstantArray),
}
impl<'a> AsRef<dyn Array> for ColumnarView<'a> {
fn as_ref(&self) -> &dyn Array {
match self {
ColumnarView::Canonical(canonical) => canonical.as_ref(),
ColumnarView::Constant(constant) => constant.as_ref(),
}
}
}
pub struct AnyColumnar;
impl Matcher for AnyColumnar {
type Match<'a> = ColumnarView<'a>;
fn try_match<'a>(array: &'a dyn Array) -> Option<Self::Match<'a>> {
if let Some(constant) = array.as_opt::<ConstantVTable>() {
Some(ColumnarView::Constant(constant))
} else {
array.as_opt::<AnyCanonical>().map(ColumnarView::Canonical)
}
}
}