vortex-array 0.88.0

Vortex in memory columnar data format
Documentation
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright the Vortex contributors

use vortex_error::VortexResult;
use vortex_error::vortex_err;

use crate::ExecutionCtx;
use crate::array::ArrayView;
use crate::array::OperationsVTable;
use crate::array::ProbeState;
use crate::arrays::Chunked;
use crate::arrays::chunked::ChunkedArrayExt;
use crate::arrays::chunked::ChunkedSlots;
use crate::scalar::Scalar;

impl OperationsVTable<Chunked> for Chunked {
    type ProbeState = ();

    fn probe_scalar(
        state: &mut ProbeState<'_, Chunked>,
        index: usize,
        ctx: &mut ExecutionCtx,
    ) -> VortexResult<Scalar> {
        let (chunk_index, chunk_offset) = state.array().find_chunk_idx(index)?;
        let slot = ChunkedSlots::CHUNKS_OFFSET + chunk_index;
        state
            .slot(slot)?
            .ok_or_else(|| vortex_err!("Chunked chunk slot {slot} is missing"))?
            .execute_scalar(chunk_offset, ctx)
    }

    fn scalar_at(
        array: ArrayView<'_, Chunked>,
        index: usize,
        ctx: &mut ExecutionCtx,
    ) -> VortexResult<Scalar> {
        Self::probe_scalar(&mut ProbeState::once(array), index, ctx)
    }
}

#[cfg(test)]
mod tests {
    use std::ops::Range;

    use rstest::rstest;
    use vortex_buffer::Buffer;
    use vortex_buffer::buffer;

    use crate::IntoArray;
    use crate::VortexSessionExecute;
    use crate::array_session;
    use crate::arrays::ChunkedArray;
    use crate::arrays::PrimitiveArray;
    use crate::assert_arrays_eq;
    use crate::dtype::DType;
    use crate::dtype::Nullability;
    use crate::dtype::PType;

    fn chunked_array() -> ChunkedArray {
        ChunkedArray::try_new(
            vec![
                buffer![1u64, 2, 3].into_array(),
                buffer![4u64, 5, 6].into_array(),
                buffer![7u64, 8, 9].into_array(),
            ],
            DType::Primitive(PType::U64, Nullability::NonNullable),
        )
        .unwrap()
    }

    #[rstest]
    #[case::middle(2..5, &[3u64, 4, 5])]
    #[case::begin(1..3, &[2u64, 3])]
    #[case::aligned(3..6, &[4u64, 5, 6])]
    #[case::many_aligned(0..6, &[1u64, 2, 3, 4, 5, 6])]
    #[case::end(7..8, &[8u64])]
    #[case::exactly_end(6..9, &[7u64, 8, 9])]
    fn slice(#[case] range: Range<usize>, #[case] expected: &[u64]) {
        let mut ctx = array_session().create_execution_ctx();
        assert_arrays_eq!(
            chunked_array().slice(range).unwrap(),
            PrimitiveArray::from_iter(expected.iter().copied()),
            &mut ctx
        );
    }

    #[test]
    fn slice_empty() {
        let chunked = ChunkedArray::try_new(vec![], PType::U32.into()).unwrap();
        let sliced = chunked.slice(0..0).unwrap();

        assert!(sliced.is_empty());
    }

    #[test]
    fn scalar_at_empty_children_both_sides() {
        let mut ctx = array_session().create_execution_ctx();
        let array = ChunkedArray::try_new(
            vec![
                Buffer::<u64>::empty().into_array(),
                Buffer::<u64>::empty().into_array(),
                buffer![1u64, 2].into_array(),
                Buffer::<u64>::empty().into_array(),
                Buffer::<u64>::empty().into_array(),
            ],
            DType::Primitive(PType::U64, Nullability::NonNullable),
        )
        .unwrap();
        assert_arrays_eq!(array, PrimitiveArray::from_iter([1u64, 2]), &mut ctx);
    }

    #[test]
    fn scalar_at_empty_children_trailing() {
        let mut ctx = array_session().create_execution_ctx();
        let array = ChunkedArray::try_new(
            vec![
                buffer![1u64, 2].into_array(),
                Buffer::<u64>::empty().into_array(),
                Buffer::<u64>::empty().into_array(),
                buffer![3u64, 4].into_array(),
            ],
            DType::Primitive(PType::U64, Nullability::NonNullable),
        )
        .unwrap();
        assert_arrays_eq!(array, PrimitiveArray::from_iter([1u64, 2, 3, 4]), &mut ctx);
    }

    #[test]
    fn scalar_at_empty_children_leading() {
        let mut ctx = array_session().create_execution_ctx();
        let array = ChunkedArray::try_new(
            vec![
                Buffer::<u64>::empty().into_array(),
                Buffer::<u64>::empty().into_array(),
                buffer![1u64, 2].into_array(),
                buffer![3u64, 4].into_array(),
            ],
            DType::Primitive(PType::U64, Nullability::NonNullable),
        )
        .unwrap();
        assert_arrays_eq!(array, PrimitiveArray::from_iter([1u64, 2, 3, 4]), &mut ctx);
    }
}