/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.jxpath.ri.compiler;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import org.apache.commons.jxpath.ri.EvalContext;
import org.apache.commons.jxpath.ri.InfoSetUtil;
import org.apache.commons.jxpath.ri.axes.InitialContext;
import org.apache.commons.jxpath.ri.axes.SelfContext;
/**
* Base implementation of Expression for the operations ">", ">=", "<", "<=".
* @since JXPath 1.3
*
* @author Matt Benson
* @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $
*/
public abstract class CoreOperationRelationalExpression extends CoreOperation {
/**
* Create a new CoreOperationRelationalExpression.
* @param args arguments
*/
protected CoreOperationRelationalExpression(Expression[] args) {
super(args);
}
public final Object computeValue(EvalContext context) {
return compute(args[0].compute(context), args[1].compute(context))
? Boolean.TRUE : Boolean.FALSE;
}
protected final int getPrecedence() {
return RELATIONAL_EXPR_PRECEDENCE;
}
protected final boolean isSymmetric() {
return false;
}
/**
* Template method for subclasses to evaluate the result of a comparison.
* @param compare result of comparison to evaluate
* @return ultimate operation success/failure
*/
protected abstract boolean evaluateCompare(int compare);
/**
* Compare left to right.
* @param left left operand
* @param right right operand
* @return operation success/failure
*/
private boolean compute(Object left, Object right) {
left = reduce(left);
right = reduce(right);
if (left instanceof InitialContext) {
((InitialContext) left).reset();
}
if (right instanceof InitialContext) {
((InitialContext) right).reset();
}
if (left instanceof Iterator && right instanceof Iterator) {
return findMatch((Iterator) left, (Iterator) right);
}
if (left instanceof Iterator) {
return containsMatch((Iterator) left, right);
}
if (right instanceof Iterator) {
return containsMatch((Iterator) right, left);
}
double ld = InfoSetUtil.doubleValue(left);
if (Double.isNaN(ld)) {
return false;
}
double rd = InfoSetUtil.doubleValue(right);
if (Double.isNaN(rd)) {
return false;
}
return evaluateCompare(ld == rd ? 0 : ld < rd ? -1 : 1);
}
/**
* Reduce an operand for comparison.
* @param o Object to reduce
* @return reduced operand
*/
private Object reduce(Object o) {
if (o instanceof SelfContext) {
o = ((EvalContext) o).getSingleNodePointer();
}
if (o instanceof Collection) {
o = ((Collection) o).iterator();
}
return o;
}
/**
* Learn whether any element returned from an Iterator matches a given value.
* @param it Iterator
* @param value to look for
* @return whether a match was found
*/
private boolean containsMatch(Iterator it, Object value) {
while (it.hasNext()) {
Object element = it.next();
if (compute(element, value)) {
return true;
}
}
return false;
}
/**
* Learn whether there is an intersection between two Iterators.
* @param lit left Iterator
* @param rit right Iterator
* @return whether a match was found
*/
private boolean findMatch(Iterator lit, Iterator rit) {
HashSet left = new HashSet();
while (lit.hasNext()) {
left.add(lit.next());
}
while (rit.hasNext()) {
if (containsMatch(left.iterator(), rit.next())) {
return true;
}
}
return false;
}
}
|