Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sean/list to string #3371

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use rayexec_error::{not_implemented, RayexecError, Result};

use super::{get_inner_array_selection, get_inner_array_storage};
use crate::array::{Array, ArrayData};
use crate::bitmap::Bitmap;
use crate::executor::builder::{ArrayBuilder, ArrayDataBuffer};
Expand All @@ -14,9 +15,11 @@ pub trait BinaryListReducer<T, O> {
fn finish(self) -> O;
}

// TODO: Cleanup

/// List executor that allows for different list lengths, and nulls inside of
/// lists.
pub type FlexibleListExecutor = ListExecutor<true, true>;
pub type FlexibleBinaryListExecutor = BinaryListExecutor<true, true>;

/// Execute reductions on lists.
///
Expand All @@ -25,10 +28,10 @@ pub type FlexibleListExecutor = ListExecutor<true, true>;
///
/// `ALLOW_NULLS` controls if this allows nulls in lists.
#[derive(Debug, Clone, Copy)]
pub struct ListExecutor<const ALLOW_DIFFERENT_LENS: bool, const ALLOW_NULLS: bool>;
pub struct BinaryListExecutor<const ALLOW_DIFFERENT_LENS: bool, const ALLOW_NULLS: bool>;

impl<const ALLOW_DIFFERENT_LENS: bool, const ALLOW_NULLS: bool>
ListExecutor<ALLOW_DIFFERENT_LENS, ALLOW_NULLS>
BinaryListExecutor<ALLOW_DIFFERENT_LENS, ALLOW_NULLS>
{
/// Execute a reducer on two list arrays.
pub fn binary_reduce<'a, S, B, R>(
Expand Down Expand Up @@ -161,26 +164,3 @@ impl<const ALLOW_DIFFERENT_LENS: bool, const ALLOW_NULLS: bool>
}
}
}

/// Gets the inner array storage. Checks to ensure the inner array does not
/// contain NULLs.
fn get_inner_array_storage<S>(array: &Array) -> Result<(S::Storage<'_>, Option<&Bitmap>)>
where
S: PhysicalStorage,
{
match array.array_data() {
ArrayData::List(d) => {
let storage = S::get_storage(d.array.array_data())?;
let validity = d.array.validity();
Ok((storage, validity))
}
_ => Err(RayexecError::new("Expected list array data")),
}
}

fn get_inner_array_selection(array: &Array) -> Result<Option<&SelectionVector>> {
match array.array_data() {
ArrayData::List(d) => Ok(d.array.selection_vector()),
_ => Err(RayexecError::new("Expected list array data")),
}
}
34 changes: 34 additions & 0 deletions crates/rayexec_bullet/src/executor/scalar/list/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
mod binary;
pub use binary::*;

mod unary;
use rayexec_error::{RayexecError, Result};
pub use unary::*;

use crate::array::{Array, ArrayData};
use crate::bitmap::Bitmap;
use crate::executor::physical_type::PhysicalStorage;
use crate::selection::SelectionVector;

/// Gets the inner array storage. Checks to ensure the inner array does not
/// contain NULLs.
fn get_inner_array_storage<S>(array: &Array) -> Result<(S::Storage<'_>, Option<&Bitmap>)>
where
S: PhysicalStorage,
{
match array.array_data() {
ArrayData::List(d) => {
let storage = S::get_storage(d.array.array_data())?;
let validity = d.array.validity();
Ok((storage, validity))
}
_ => Err(RayexecError::new("Expected list array data")),
}
}

fn get_inner_array_selection(array: &Array) -> Result<Option<&SelectionVector>> {
match array.array_data() {
ArrayData::List(d) => Ok(d.array.selection_vector()),
_ => Err(RayexecError::new("Expected list array data")),
}
}
158 changes: 158 additions & 0 deletions crates/rayexec_bullet/src/executor/scalar/list/unary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
use rayexec_error::Result;

use crate::array::Array;
use crate::executor::physical_type::{PhysicalList, PhysicalStorage};
use crate::executor::scalar::list::{get_inner_array_selection, get_inner_array_storage};
use crate::selection;
use crate::storage::AddressableStorage;

#[derive(Debug)]
pub struct ListEntry<T> {
/// Index of the entry within the list.
pub inner_idx: i32,
/// Then entry, None if not valid
pub entry: Option<T>,
}

#[derive(Debug, Clone, Copy)]
pub struct UnaryListExecutor;

impl UnaryListExecutor {
pub fn for_each<'a, S, Op>(array: &'a Array, mut op: Op) -> Result<()>
where
Op: FnMut(usize, Option<ListEntry<S::Type<'a>>>),
S: PhysicalStorage,
{
let selection = array.selection_vector();
let metadata = PhysicalList::get_storage(array.array_data())?;

let (values, inner_validity) = get_inner_array_storage::<S>(array)?;
let inner_sel = get_inner_array_selection(array)?;

match (array.validity(), inner_validity) {
(None, None) => {
// No validities for parent array or child array.

for row_idx in 0..array.logical_len() {
let sel = unsafe { selection::get_unchecked(selection, row_idx) };
let m = unsafe { metadata.get_unchecked(sel) };

for inner_idx in 0..m.len {
let sel =
unsafe { selection::get_unchecked(inner_sel, inner_idx as usize) };
let v = unsafe { values.get_unchecked(sel) };

op(
row_idx,
Some(ListEntry {
inner_idx,
entry: Some(v),
}),
);
}
}
}
(Some(outer_validity), None) => {
// Outer validity, no child validity.
for row_idx in 0..array.logical_len() {
let sel = unsafe { selection::get_unchecked(selection, row_idx) };

if !outer_validity.value(row_idx) {
op(row_idx, None);
continue;
}

let m = unsafe { metadata.get_unchecked(sel) };

for inner_idx in 0..m.len {
let sel =
unsafe { selection::get_unchecked(inner_sel, inner_idx as usize) };
let v = unsafe { values.get_unchecked(sel) };

op(
row_idx,
Some(ListEntry {
inner_idx,
entry: Some(v),
}),
);
}
}
}
(None, Some(inner_validity)) => {
// Outer all valid, inner contains validities.
for row_idx in 0..array.logical_len() {
let sel = unsafe { selection::get_unchecked(selection, row_idx) };
let m = unsafe { metadata.get_unchecked(sel) };

for inner_idx in 0..m.len {
let sel =
unsafe { selection::get_unchecked(inner_sel, inner_idx as usize) };

if !inner_validity.value(sel) {
op(
row_idx,
Some(ListEntry {
inner_idx,
entry: None,
}),
);
continue;
}

let v = unsafe { values.get_unchecked(sel) };

op(
row_idx,
Some(ListEntry {
inner_idx,
entry: Some(v),
}),
);
}
}
}
(Some(outer_validity), Some(inner_validity)) => {
// Need to check everything.
for row_idx in 0..array.logical_len() {
let sel = unsafe { selection::get_unchecked(selection, row_idx) };

if !outer_validity.value(row_idx) {
op(row_idx, None);
continue;
}

let m = unsafe { metadata.get_unchecked(sel) };

for inner_idx in 0..m.len {
let sel =
unsafe { selection::get_unchecked(inner_sel, inner_idx as usize) };

if !inner_validity.value(sel) {
op(
row_idx,
Some(ListEntry {
inner_idx,
entry: None,
}),
);
continue;
}

let v = unsafe { values.get_unchecked(sel) };

op(
row_idx,
Some(ListEntry {
inner_idx,
entry: Some(v),
}),
);
}
}
}
}

Ok(())
}
}
Loading
Loading