use std::mem::size_of;
use vortex_buffer::BitBuffer;
use vortex_compute::lane_kernels::IndexedSource;
use vortex_error::VortexResult;
use vortex_error::vortex_bail;
use super::DenseAttempt;
use crate::ArrayRef;
use crate::ExecutionCtx;
use crate::IntoArray;
use crate::arrays::BoolArray;
use crate::scalar_fn::ExecutionArgs;
use crate::scalar_fn::unstable::row::FailureEvidence;
use crate::scalar_fn::unstable::row::IndexedElementTuple;
use crate::scalar_fn::unstable::row::types::decoded_source;
use crate::validity::Validity;
pub(crate) fn execute_owned_infallible_bool<Args, const MULTIVERSIONED: bool>(
args: &dyn ExecutionArgs,
ctx: &mut ExecutionCtx,
apply: impl Fn(Args::Elems<'_>) -> bool,
) -> VortexResult<ArrayRef>
where
Args: IndexedElementTuple,
{
let columns = Args::decode(args, ctx)?;
let row_count = args.row_count();
let Some(source) = decoded_source::<Args>(&columns, row_count) else {
vortex_bail!("a decoded row input does not address exactly {row_count} rows");
};
let collect = |index| {
apply(unsafe { source.get_unchecked(index) })
};
let values = if MULTIVERSIONED {
BitBuffer::collect_bool_multiversioned_in(row_count, collect, ctx.allocator().clone())
} else {
BitBuffer::collect_bool_in(row_count, collect, ctx.allocator().clone())
};
Ok(BoolArray::new(values, Validity::NonNullable).into_array())
}
pub(crate) fn execute_owned_bool<Args, Prepared, Fail, const MULTIVERSIONED: bool>(
args: &dyn ExecutionArgs,
ctx: &mut ExecutionCtx,
prepare: impl FnOnce(Args::ConstElems<'_>) -> Prepared,
apply: impl Fn(&Prepared, Args::Elems<'_>) -> (bool, Fail),
finish_failure: impl FnOnce(Fail) -> VortexResult<()>,
) -> VortexResult<ArrayRef>
where
Args: IndexedElementTuple,
Fail: FailureEvidence,
{
const {
assert!(
size_of::<Fail>() <= size_of::<bool>(),
"failure evidence must be no wider than the value, or it bounds the vector width"
)
};
let columns = Args::decode(args, ctx)?;
let prepared = prepare(Args::const_values(&columns));
let row_count = args.row_count();
let Some(source) = decoded_source::<Args>(&columns, row_count) else {
vortex_bail!("a decoded row input does not address exactly {row_count} rows");
};
let mut failure = Fail::default();
let collect = |index| {
let elements = unsafe { source.get_unchecked(index) };
let (value, row_failure) = apply(&prepared, elements);
failure |= row_failure;
value
};
let values = if MULTIVERSIONED {
BitBuffer::collect_bool_multiversioned_in(row_count, collect, ctx.allocator().clone())
} else {
BitBuffer::collect_bool_in(row_count, collect, ctx.allocator().clone())
};
finish_failure(failure)?;
Ok(BoolArray::new(values, Validity::NonNullable).into_array())
}
pub(crate) fn execute_bool_dense_attempt<Args, Prepared, Fail, const MULTIVERSIONED: bool>(
args: &dyn ExecutionArgs,
ctx: &mut ExecutionCtx,
prepare: impl FnOnce(Args::ConstElems<'_>) -> Prepared,
apply: impl Fn(&Prepared, Args::Elems<'_>) -> (bool, Fail),
finish_failure: impl FnOnce(Fail) -> VortexResult<()>,
) -> VortexResult<DenseAttempt>
where
Args: IndexedElementTuple,
Fail: FailureEvidence,
{
const {
assert!(
size_of::<Fail>() <= size_of::<bool>(),
"failure evidence must be no wider than the value, or it bounds the vector width"
)
};
let columns = Args::decode(args, ctx)?;
let prepared = prepare(Args::const_values(&columns));
let row_count = args.row_count();
let Some(source) = decoded_source::<Args>(&columns, row_count) else {
vortex_bail!("a decoded row input does not address exactly {row_count} rows");
};
let mut state = DeferredBoolState {
source,
prepared,
apply,
failure: Fail::default(),
};
let state_ref = &mut state;
let collect = move |index| {
let state = &mut *state_ref;
let elements = unsafe { state.source.get_unchecked(index) };
let (value, row_failure) = (state.apply)(&state.prepared, elements);
state.failure |= row_failure;
value
};
let values = if MULTIVERSIONED {
BitBuffer::collect_bool_multiversioned_in(row_count, collect, ctx.allocator().clone())
} else {
BitBuffer::collect_bool_in(row_count, collect, ctx.allocator().clone())
};
match finish_failure(state.failure) {
Ok(()) => Ok(DenseAttempt::Values(
BoolArray::new(values, Validity::NonNullable).into_array(),
)),
Err(error) => Ok(DenseAttempt::DeferredError(error)),
}
}
struct DeferredBoolState<Source, Prepared, Apply, Fail> {
source: Source,
prepared: Prepared,
apply: Apply,
failure: Fail,
}