Removes unused expressions from `self.expressions`. Expressions are "used" if they are relied upon by any output columns or any predicates, even transitively. Any expressions that are not relied upon in this way can be discarded. # Example ```rust use mz_expr::{func, MapFilterProject, MirScalarExpr, UnaryFunc, BinaryFunc}; // Use the output from `inline_expression` example. let mut map_filter_p
(&mut self)
| 1381 | /// ); |
| 1382 | /// ``` |
| 1383 | pub fn remove_undemanded(&mut self) { |
| 1384 | // Determine the demanded expressions to remove irrelevant ones. |
| 1385 | let mut demand = BTreeSet::new(); |
| 1386 | for (_index, pred) in self.predicates.iter() { |
| 1387 | demand.extend(pred.support()); |
| 1388 | } |
| 1389 | // Start from the output columns as presumed demanded. |
| 1390 | // If this is not the case, the caller should project some away. |
| 1391 | demand.extend(self.projection.iter().cloned()); |
| 1392 | // Proceed in *reverse* order, as expressions may depend on other |
| 1393 | // expressions that precede them. |
| 1394 | for index in (0..self.expressions.len()).rev() { |
| 1395 | if demand.contains(&(self.input_arity + index)) { |
| 1396 | demand.extend(self.expressions[index].support()); |
| 1397 | } |
| 1398 | } |
| 1399 | |
| 1400 | // Maintain a map from initial column identifiers to locations |
| 1401 | // once we have removed undemanded expressions. |
| 1402 | let mut remap = BTreeMap::new(); |
| 1403 | // This map only needs to map elements of `demand` to a new location, |
| 1404 | // but the logic is easier if we include all input columns (as the |
| 1405 | // new position is then determined by the size of the map). |
| 1406 | for index in 0..self.input_arity { |
| 1407 | remap.insert(index, index); |
| 1408 | } |
| 1409 | // Retain demanded expressions, and record their new locations. |
| 1410 | let mut new_expressions = Vec::new(); |
| 1411 | for (index, expr) in self.expressions.drain(..).enumerate() { |
| 1412 | if demand.contains(&(index + self.input_arity)) { |
| 1413 | remap.insert(index + self.input_arity, remap.len()); |
| 1414 | new_expressions.push(expr); |
| 1415 | } |
| 1416 | } |
| 1417 | self.expressions = new_expressions; |
| 1418 | |
| 1419 | // Update column identifiers; rebuild `Self` to re-establish any invariants. |
| 1420 | // We mirror `self.permute(&remap)` but we specifically want to remap columns |
| 1421 | // that are produced by `self.expressions` after the input columns. |
| 1422 | let (expressions, predicates, projection) = self.as_map_filter_project(); |
| 1423 | *self = Self::new(self.input_arity) |
| 1424 | .map(expressions.into_iter().map(|mut e| { |
| 1425 | e.permute_map(&remap); |
| 1426 | e |
| 1427 | })) |
| 1428 | .filter(predicates.into_iter().map(|mut p| { |
| 1429 | p.permute_map(&remap); |
| 1430 | p |
| 1431 | })) |
| 1432 | .project(projection.into_iter().map(|c| remap[&c])); |
| 1433 | } |
| 1434 | } |
| 1435 | |
| 1436 | // TODO: move this elsewhere? |
no test coverage detected