/* // $Id: //guest/julian_hyde/saffron/src/main/saffron/BuiltinAggregator.java#1 $ // Saffron preprocessor and data engine // Copyright (C) 2002 Julian Hyde <julian.hyde@mail.com> // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this library; if not, write to the // Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. // // See the COPYING file located in the top-level-directory of // the archive of this library for complete text of license. */ package saffron; import openjava.mop.OJClass; import openjava.mop.OJSystem; import openjava.mop.Toolbox; import openjava.ptree.*; import saffron.opt.Implementor; import saffron.rel.Aggregation; import saffron.rel.Rel; import saffron.util.Util; /** * <code>BuiltinAggregator</code> is a basic aggregator for which special code * is generated. * * @author jhyde * @since 3 February, 2002 * @version $Id: //guest/julian_hyde/saffron/src/main/saffron/BuiltinAggregator.java#1 $ **/ public abstract class BuiltinAggregator implements Aggregation { abstract String getName(); // implement Aggregation public boolean canMerge() { return false; } // implement Aggregation public void implementMerge( Implementor implementor, Rel rel, Expression accumulator, Expression otherAccumulator) { throw Util.newInternal( "This method shouldn't have been called, because canMerge " + "returned " + canMerge()); } /** * Returns the builtin aggregator with a given name, if there is one. Note * that there is only one builtin aggregator with a particular name ("sum", * say), but a particular instance may have different parameter types. **/ public static BuiltinAggregator lookup(String name, OJClass[] argTypes) { if (name.equals("sum") && argTypes.length == 1) { return new Sum(argTypes[0]); } if (name.equals("count")) { return new Count(); } if ((name.equals("min") || name.equals("max")) && MinMax.getKind(argTypes) != MinMax.MINMAX_INVALID) { return new MinMax(argTypes, name.equals("min")); } return null; } /** * <code>Count</code> is an aggregator which returns the number of rows * which have gone into it. With one argument (or more), it returns the * number of rows for which that argument (or all) is not * <code>null</code>. **/ static class Count extends BuiltinAggregator { OJClass[] argTypes; static final OJClass type = OJSystem.INT; Count() { this.argTypes = argTypes; } String getName() { return "count"; } public boolean canMerge() { return true; } public OJClass getReturnType() { return type; } public OJClass[] getStartParameterTypes() { return new OJClass[0]; } public OJClass[] getParameterTypes() { return argTypes; } public Expression implementStart( Implementor implementor, Rel rel, int[] args) { // e.g. "new saffron.runtime.Holder.int_Holder(0)" return new AllocationExpression( new TypeName("saffron.runtime.Holder." + type + "_Holder"), new ExpressionList( Literal.constantZero())); } public void implementNext( Implementor implementor, Rel rel, Expression accumulator, int[] args) { StatementList stmtList = implementor.getStatementList(); ExpressionStatement stmt = new ExpressionStatement( new UnaryExpression( UnaryExpression.POST_INCREMENT, new FieldAccess( new CastExpression( new TypeName("saffron.runtime.Holder." + type + "_Holder"), accumulator), "value"))); if (args.length == 0) { // e.g. "((saffron.runtime.Holder.int_Holder) acc).value++;" stmtList.add(stmt); } else { // if (arg1 != null && arg2 != null) { // ((saffron.runtime.Holder.int_Holder) acc).value++; // } Expression condition = null; for (int i = 0; i < args.length; i++) { Expression term = new BinaryExpression( implementor.translateInputField(rel, 0, args[i]), BinaryExpression.NOTEQUAL, Literal.constantNull()); if (condition == null) { condition = term; } else { condition = new BinaryExpression( condition, BinaryExpression.LOGICAL_AND, term); } } stmtList.add( new IfStatement( condition, new StatementList(stmt))); } } public Expression implementResult(Expression accumulator) { // e.g. "o" becomes "((saffron.runtime.Holder.int_Holder) o).value" return new FieldAccess( new CastExpression( new TypeName("saffron.runtime.Holder." + type + "_Holder"), accumulator), "value"); } }; /** * <code>Sum</code> is an aggregator which returns the sum of the values * which go into it. It has precisely one argument of numeric type * (<code>int</code>, <code>long</code>, <code>float</code>, * <code>double</code>), and the result is the same type. **/ static class Sum extends BuiltinAggregator { private OJClass type; Sum(OJClass type) { this.type = type; } String getName() { return "sum"; } public boolean canMerge() { return true; } public OJClass getReturnType() { return type; } public OJClass[] getStartParameterTypes() { return new OJClass[0]; } public OJClass[] getParameterTypes() { return new OJClass[] {type}; } public Expression implementStart( Implementor implementor, Rel rel, int[] args) { // e.g. "new saffron.runtime.Holder.int_Holder(0)" return new AllocationExpression( new TypeName("saffron.runtime.Holder." + type + "_Holder"), new ExpressionList( Literal.constantZero())); } public void implementNext( Implementor implementor, Rel rel, Expression accumulator, int[] args) { Util.assert(args.length == 1); StatementList stmtList = implementor.getStatementList(); Expression arg = implementor.translateInputField(rel, 0, args[0]); // e.g. "((saffron.runtime.Holder.int_Holder) acc).value += arg" stmtList.add( new ExpressionStatement( new AssignmentExpression( new FieldAccess( new CastExpression( new TypeName("saffron.runtime.Holder." + type + "_Holder"), accumulator), "value"), AssignmentExpression.ADD, arg))); } public Expression implementResult(Expression accumulator) { // e.g. "o" becomes "((saffron.runtime.Holder.int_Holder) o).value" return new FieldAccess( new CastExpression( new TypeName("saffron.runtime.Holder." + type + "_Holder"), accumulator), "value"); } }; /** * <code>MinMax</code> implements the "min" and "max" aggregator functions, * returning the returns the smallest/largest of the values which go into * it. There are 3 forms:<dl> * <dt>sum(<em>primitive type</em>)</dt> * <dd>values are compared using <</dd> * <dt>sum({@link Comparable})</dt> * <dd>values are compared using {@link Comparable#compareTo}</dd> * <dt>sum({@link Comparator}, {@link Object})</dt> * <dd>the {@link Comparator#compare} method of the comparator is used to * compare pairs of objects. The comparator is a startup argument, and * must therefore be constant for the duration of the aggregation.</dd> * </dl> **/ static class MinMax extends BuiltinAggregator { private OJClass[] argTypes; private boolean isMin; private int kind; static final int MINMAX_INVALID = -1; static final int MINMAX_PRIMITIVE = 0; static final int MINMAX_COMPARABLE = 1; static final int MINMAX_COMPARATOR = 2; MinMax(OJClass[] argTypes, boolean isMin) { this.argTypes = argTypes; this.isMin = isMin; this.kind = getKind(argTypes); } static int getKind(OJClass[] argTypes) { if (argTypes.length == 1 && argTypes[0].isPrimitive()) { return MINMAX_PRIMITIVE; } else if (argTypes.length == 1 && Toolbox.clazzComparable.isAssignableFrom(argTypes[0])) { return MINMAX_COMPARABLE; } else if (argTypes.length == 2 && Toolbox.clazzComparator.isAssignableFrom(argTypes[0]) && Toolbox.clazzObject.isAssignableFrom(argTypes[1])) { return MINMAX_COMPARATOR; } else { return MINMAX_INVALID; } } String getName() { return isMin ? "min" : "max"; } public boolean canMerge() { return true; } public OJClass getReturnType() { switch (kind) { case MINMAX_PRIMITIVE: case MINMAX_COMPARABLE: return argTypes[0]; case MINMAX_COMPARATOR: return argTypes[1]; default: throw Toolbox.newInternal("bad kind: " + kind); } } public OJClass[] getStartParameterTypes() { switch (kind) { case MINMAX_PRIMITIVE: case MINMAX_COMPARABLE: return new OJClass[0]; case MINMAX_COMPARATOR: return new OJClass[] {Toolbox.clazzComparator}; default: throw Toolbox.newInternal("bad kind: " + kind); } } public OJClass[] getParameterTypes() { switch (kind) { case MINMAX_PRIMITIVE: case MINMAX_COMPARABLE: return argTypes; case MINMAX_COMPARATOR: return new OJClass[] {argTypes[1]}; default: throw Toolbox.newInternal("bad kind: " + kind); } } public Expression implementStart( Implementor implementor, Rel rel, int[] args) { switch (kind) { case MINMAX_PRIMITIVE: // "new saffron.runtime.Holder.int_Holder(Integer.MAX_VALUE)" if // the type is "int" and the function is "min" return new AllocationExpression( new TypeName( "saffron.runtime.Holder." + argTypes[0] + "_Holder"), new ExpressionList( new FieldAccess( TypeName.forOJClass( argTypes[0].primitiveWrapper()), isMin ? "MAX_VALUE" : "MIN_VALUE"))); case MINMAX_COMPARABLE: // "null" return Literal.constantNull(); case MINMAX_COMPARATOR: // "new saffron.runtime.ComparatorAndObject(comparator, null)" Expression arg = implementor.translateInputField( rel, 0, args[0]); return new AllocationExpression( new TypeName("saffron.runtime.ComparatorAndObject"), new ExpressionList( arg, Literal.constantNull())); default: throw Toolbox.newInternal("bad kind: " + kind); } } public void implementNext( Implementor implementor, Rel rel, Expression accumulator, int[] args) { StatementList stmtList = implementor.getStatementList(); switch (kind) { case MINMAX_PRIMITIVE: // "((saffron.runtime.Holder.int_Holder) acc).setLesser(arg)" Expression arg = implementor.translateInputField( rel, 0, args[0]); stmtList.add( new ExpressionStatement( new MethodCall( new CastExpression( new TypeName("saffron.runtime.Holder." + argTypes[0] + "_Holder"), accumulator), isMin ? "setLesser" : "setGreater", new ExpressionList(arg)))); return; case MINMAX_COMPARABLE: // T t = arg; // if (acc == null || (t != null && t.compareTo(acc) < 0)) { // acc = t; // } arg = implementor.translateInputField(rel, 0, args[0]); Variable var_t = implementor.newVariable(); stmtList.add( new VariableDeclaration( TypeName.forOJClass(argTypes[0]), var_t.toString(), arg)); stmtList.add( new IfStatement( new BinaryExpression( new BinaryExpression( accumulator, BinaryExpression.EQUAL, Literal.constantNull()), BinaryExpression.LOGICAL_OR, new BinaryExpression( new BinaryExpression( var_t, BinaryExpression.NOTEQUAL, Literal.constantNull()), BinaryExpression.LOGICAL_AND, new BinaryExpression( new MethodCall( var_t, "compareTo", new ExpressionList(accumulator)), BinaryExpression.LESS, Literal.constantZero()))), new StatementList( new ExpressionStatement( new AssignmentExpression( accumulator, AssignmentExpression.EQUALS, var_t))))); return; case MINMAX_COMPARATOR: // "((saffron.runtime.Holder.ComparatorHolder) // acc).setLesser(arg)" arg = implementor.translateInputField(rel, 0, args[1]); stmtList.add( new ExpressionStatement( new MethodCall( new CastExpression( new TypeName( "saffron.runtime.Holder." + argTypes[1] + "_Holder"), accumulator), isMin ? "setLesser" : "setGreater", new ExpressionList(arg)))); return; default: throw Toolbox.newInternal("bad kind: " + kind); } } public Expression implementResult(Expression accumulator) { switch (kind) { case MINMAX_PRIMITIVE: // ((saffron.runtime.Holder.int_Holder) acc).value return new FieldAccess( new CastExpression( new TypeName( "saffron.runtime.Holder." + argTypes[1] + "_Holder"), accumulator), "value"); case MINMAX_COMPARABLE: // (T) acc return new CastExpression( TypeName.forOJClass(argTypes[0]), accumulator); case MINMAX_COMPARATOR: // (T) ((saffron.runtime.Holder.int_Holder) acc).value return new CastExpression( TypeName.forOJClass(argTypes[1]), new FieldAccess( new CastExpression( new TypeName( "saffron.runtime.Holder.ComparatorHolder"), accumulator), "value")); default: throw Toolbox.newInternal("bad kind: " + kind); } } }; } // End BuiltinAggregator.java
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 1474 | Julian Hyde |
saffron: Aggregations are working. Renamed 'aggregator' to 'aggregation'. |
||
#1 | 1467 | Julian Hyde |
saffron: First saffron check-in; incorporate my changes to openjava. |