Path: blob/main/crates/polars-plan/src/plans/optimizer/slice_pushdown_expr.rs
8416 views
use std::borrow::BorrowMut;12use super::*;34/// Returns whether slice was pushed5fn pushdown<T>(inputs: &mut [T], offset: Node, length: Node, arena: &mut Arena<AExpr>) -> bool6where7T: BorrowMut<Node>,8{9if inputs.is_empty() {10return false;11}1213let mut has_column_height_projection = false;1415macro_rules! is_column_height {16($node:expr) => {{17let node = $node;18is_length_preserving_ae(node, arena)19&& aexpr_to_leaf_names_iter(node, arena).next().is_some()20}};21}2223for node in inputs.iter().map(|x| x.borrow()).copied() {24if is_scalar_ae(node, arena) {25continue;26}2728let column_height = is_column_height!(node);2930if column_height {31has_column_height_projection = true;32} else {33// Unknown non-scalar height34// TODO: Can technically still push slices with offset >=0.35return false;36}37}3839if !has_column_height_projection {40return false;41}4243for node in inputs {44let n = *node.borrow();4546if is_scalar_ae(n, arena) {47continue;48}4950if is_column_height!(n) {51*node.borrow_mut() = arena.add(AExpr::Slice {52input: n,53offset,54length,55})56}57}5859true60}6162impl OptimizationRule for SlicePushDown {63fn optimize_expr(64&mut self,65expr_arena: &mut Arena<AExpr>,66expr_node: Node,67_schema: &Schema,68_ctx: OptimizeExprContext,69) -> PolarsResult<Option<AExpr>> {70if let AExpr::Slice {71input,72offset,73length,74} = expr_arena.get(expr_node)75{76let offset = *offset;77let length = *length;7879use AExpr::*;80let out = match expr_arena.get(*input) {81ae @ Cast { .. } => {82let ae = ae.clone();83let scratch = self.empty_nodes_scratch_mut();8485ae.inputs_rev(scratch);86assert_eq!(scratch.len(), 1);8788pushdown(scratch, offset, length, expr_arena)89.then(|| ae.replace_inputs(scratch))90},91BinaryExpr { left, right, op } => {92let left = *left;93let right = *right;94let op = *op;9596let mut inputs = [left, right];9798pushdown(&mut inputs[..], offset, length, expr_arena).then(|| BinaryExpr {99left: inputs[0],100op,101right: inputs[1],102})103},104Ternary {105truthy,106falsy,107predicate,108} => {109let mut inputs = [*truthy, *falsy, *predicate];110111pushdown(&mut inputs[..], offset, length, expr_arena).then(|| Ternary {112truthy: inputs[0],113falsy: inputs[1],114predicate: inputs[2],115})116},117m @ AnonymousFunction { options, .. } if options.is_elementwise() => {118if let AnonymousFunction {119mut input,120function,121options,122fmt_str,123} = m.clone()124{125pushdown(input.as_mut_slice(), offset, length, expr_arena).then(|| {126AnonymousFunction {127input,128function,129options,130fmt_str,131}132})133} else {134unreachable!()135}136},137m @ Function { options, .. } if options.is_elementwise() => {138if let Function {139mut input,140function,141options,142} = m.clone()143{144pushdown(input.as_mut_slice(), offset, length, expr_arena).then(|| {145Function {146input,147function,148options,149}150})151} else {152unreachable!()153}154},155_ => None,156};157Ok(out)158} else {159Ok(None)160}161}162}163164165