class RowFilter implements Predicate<Row> {

    private final Input<Boolean> filterCondition;
    private final List<CollectExpression<Row, ?>> expressions;

    public static Predicate<Row> create(TransactionContext txnCtx, InputFactory inputFactory, @Nullable Symbol filterSymbol) {<FILL_FUNCTION_BODY>}

    private RowFilter(TransactionContext txnCtx, InputFactory inputFactory, Symbol filterSymbol) {
        InputFactory.Context<CollectExpression<Row, ?>> ctx = inputFactory.ctxForInputColumns(txnCtx);
        //noinspection unchecked
        filterCondition = (Input) ctx.add(filterSymbol);
        expressions = ctx.expressions();
    }

    @Override
    public boolean test(@Nullable Row row) {
        //noinspection ForLoopReplaceableByForEach // avoids iterator allocation - rowFilter test is invoked per row
        for (int i = 0, expressionsSize = expressions.size(); i < expressionsSize; i++) {
            CollectExpression<Row, ?> expression = expressions.get(i);
            expression.setNextRow(row);
        }
        return InputCondition.matches(filterCondition);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        RowFilter rowFilter = (RowFilter) o;

        if (!filterCondition.equals(rowFilter.filterCondition)) return false;
        return expressions.equals(rowFilter.expressions);
    }

    @Override
    public int hashCode() {
        int result = filterCondition.hashCode();
        result = 31 * result + expressions.hashCode();
        return result;
    }
}

        if (filterSymbol == null) {
            return i -> true;
        }
        return new RowFilter(txnCtx, inputFactory, filterSymbol);
    
<no_super_class>