package org.infinispan.objectfilter.impl.predicateindex;
import java.util.Arrays;
import org.infinispan.objectfilter.impl.FilterSubscriptionImpl;
import org.infinispan.objectfilter.impl.aggregation.FieldAccumulator;
import org.infinispan.objectfilter.impl.predicateindex.be.BENode;
import org.infinispan.objectfilter.impl.predicateindex.be.BETree;
/**
* @author anistor@redhat.com
* @since 7.0
*/
public final class FilterEvalContext {
private static final int[] FALSE_TREE = {BETree.EXPR_FALSE};
public final BETree beTree;
public final int[] treeCounters;
public final MatcherEvalContext<?, ?, ?> matcherContext;
private final Object[] projection;
private final Comparable[] sortProjection;
public FieldAccumulator[] acc;
public FilterEvalContext(MatcherEvalContext<?, ?, ?> matcherContext, FilterSubscriptionImpl filterSubscription) {
this.matcherContext = matcherContext;
this.beTree = filterSubscription.getBETree();
// check if event type is matching
if (checkEventType(matcherContext.getEventType(), filterSubscription.getEventTypes())) {
int[] childCounters = beTree.getChildCounters();
this.treeCounters = Arrays.copyOf(childCounters, childCounters.length);
} else {
this.treeCounters = FALSE_TREE;
for (BENode node : beTree.getNodes()) {
node.suspendSubscription(this);
}
}
projection = filterSubscription.getProjection() != null ? new Object[filterSubscription.getProjection().length] : null;
sortProjection = filterSubscription.getSortFields() != null ? new Comparable[filterSubscription.getSortFields().length] : null;
}
private boolean checkEventType(Object eventType, Object[] eventTypes) {
if (eventTypes == null) {
return true;
}
if (eventType == null) {
return false;
}
for (Object t : eventTypes) {
if (eventType.equals(t)) {
return true;
}
}
return false;
}
/**
* Returns the result of the filter. This method should be called only after the evaluation of all predicates (except
* the ones that were suspended).
*
* @return {@code true} if the filter matches the given input, {@code false} otherwise
*/
public boolean isMatching() {
return treeCounters[0] == BETree.EXPR_TRUE;
}
public Object[] getProjection() {
return projection;
}
public Comparable[] getSortProjection() {
return sortProjection;
}
void processProjection(int position, Object value) {
Object[] projection = this.projection;
if (projection == null) {
projection = this.sortProjection;
} else {
if (position >= projection.length) {
position -= projection.length;
projection = this.sortProjection;
}
}
if (acc != null) {
FieldAccumulator a = acc[position];
if (a != null) {
a.update(projection, value);
return;
}
}
// if this is a repeated attribute and no accumulator is used then keep the first occurrence in order to be consistent with the Lucene based implementation
if (projection[position] == null) {
projection[position] = value;
}
}
}