From 5138498f1bfd35e83d609eedf6a334c2e315e31f Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Wed, 31 Oct 2012 16:31:51 +0000 Subject: Support range filtering of array types. --- .../carbonado/cursor/FilteredCursorGenerator.java | 70 +++++++++++++++++++--- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/amazon/carbonado/cursor/FilteredCursorGenerator.java b/src/main/java/com/amazon/carbonado/cursor/FilteredCursorGenerator.java index 404908e..b2172d3 100644 --- a/src/main/java/com/amazon/carbonado/cursor/FilteredCursorGenerator.java +++ b/src/main/java/com/amazon/carbonado/cursor/FilteredCursorGenerator.java @@ -23,6 +23,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; @@ -58,6 +59,7 @@ import com.amazon.carbonado.filter.Visitor; import com.amazon.carbonado.info.ChainedProperty; import com.amazon.carbonado.info.StorableProperty; +import com.amazon.carbonado.util.Comparators; import com.amazon.carbonado.util.QuickConstructorGenerator; import com.amazon.carbonado.gen.CodeBuilderUtil; @@ -227,7 +229,10 @@ class FilteredCursorGenerator { default: TypeDesc typeDesc = TypeDesc.forClass(chained.getType()).toObjectType(); - if (!Comparable.class.isAssignableFrom(typeDesc.toClass())) { + if (!Comparable.class.isAssignableFrom(typeDesc.toClass()) && + (!typeDesc.isArray() || + Comparators.arrayComparator(typeDesc.toClass(), true) == null)) + { throw new UnsupportedOperationException ("Property \"" + chained + "\" does not implement Comparable"); } @@ -263,6 +268,7 @@ class FilteredCursorGenerator { private static class CodeGen extends Visitor { private static final String FIELD_PREFIX = "value$"; private static final String FILTER_FIELD_PREFIX = "filter$"; + private static final String COMPARATOR_FIELD_PREFIX = "comparator$"; private final Map mPropertyOrdinalMap; private final ClassFile mClassFile; @@ -278,6 +284,9 @@ class FilteredCursorGenerator { private Map mGeneratedSubFilters; private CodeBuilder mSubFilterInitBuilder; + private Map mComparatorFields; + private CodeBuilder mStaticInitBuilder; + CodeGen(Map propertyOrdinalMap, ClassFile cf, CodeBuilder ctorBuilder, @@ -295,6 +304,10 @@ class FilteredCursorGenerator { } public List finishSubFilterInit() { + if (mStaticInitBuilder != null) { + mStaticInitBuilder.returnVoid(); + } + if (mSubFilterInitBuilder != null) { mSubFilterInitBuilder.returnVoid(); } @@ -472,6 +485,37 @@ class FilteredCursorGenerator { return fieldName; } + private String addStaticComparatorField(TypeDesc type) { + if (mComparatorFields == null) { + mComparatorFields = new IdentityHashMap(); + } + + String fieldName = mComparatorFields.get(type); + if (fieldName != null) { + return fieldName; + } + + fieldName = COMPARATOR_FIELD_PREFIX + mComparatorFields.size(); + TypeDesc comparatorType = TypeDesc.forClass(Comparator.class); + mClassFile.addField(Modifiers.PRIVATE.toStatic(true).toFinal(true), + fieldName, comparatorType); + + if (mStaticInitBuilder == null) { + mStaticInitBuilder = new CodeBuilder(mClassFile.addInitializer()); + } + + mStaticInitBuilder.loadConstant(type); + mStaticInitBuilder.loadConstant(true); + mStaticInitBuilder.invokeStatic + (TypeDesc.forClass(Comparators.class), + "arrayComparator", comparatorType, + new TypeDesc[] {TypeDesc.forClass(Class.class), BOOLEAN}); + mStaticInitBuilder.storeStaticField(fieldName, comparatorType); + + mComparatorFields.put(type, fieldName); + return fieldName; + } + private Scope getScope() { return mScopeStack.peek(); } @@ -603,12 +647,11 @@ class FilteredCursorGenerator { TypeDesc primitiveType = type.toPrimitiveType(); if (primitiveType == null) { - b.loadThis(); - b.loadField(fieldName, fieldType); - // Do object comparison switch (relOp) { case EQ: case NE: default: + b.loadThis(); + b.loadField(fieldName, fieldType); if (fieldType.isArray()) { TypeDesc arraysDesc = TypeDesc.forClass(Arrays.class); TypeDesc componentType = fieldType.getComponentType(); @@ -633,9 +676,22 @@ class FilteredCursorGenerator { break; case GT: case GE: case LE: case LT: - // Compare method exists because it was checked for earlier - b.invokeInterface(TypeDesc.forClass(Comparable.class), "compareTo", - INT, new TypeDesc[] {OBJECT}); + // Comparison works because it was checked for earlier. + if (Comparable.class.isAssignableFrom(type.toClass())) { + b.loadThis(); + b.loadField(fieldName, fieldType); + b.invokeInterface(TypeDesc.forClass(Comparable.class), "compareTo", + INT, new TypeDesc[] {OBJECT}); + } else { + String comparatorFieldName = addStaticComparatorField(type); + TypeDesc comparatorType = TypeDesc.forClass(Comparator.class); + b.loadStaticField(comparatorFieldName, comparatorType); + b.swap(); + b.loadThis(); + b.loadField(fieldName, fieldType); + b.invokeInterface(comparatorType, "compare", INT, + new TypeDesc[] {OBJECT, OBJECT}); + } getScope().successIfZeroComparisonElseFail(b, relOp); break; } -- cgit v1.2.3