/*
* 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.Pointer;
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;
/**
* Common superclass for the implementations of Expression for the operations
* "=" and "!=".
*
* @author Dmitri Plotnikov
* @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $
*/
public abstract class CoreOperationCompare extends CoreOperation {
private boolean invert;
/**
* Create a new CoreOperationCompare.
* @param arg1 left operand
* @param arg2 right operand
*/
public CoreOperationCompare(Expression arg1, Expression arg2) {
this(arg1, arg2, false);
}
/**
* Create a new CoreOperationCompare.
* @param arg1 left operand
* @param arg2 right operand
* @param invert whether to invert (not) the comparison
*/
protected CoreOperationCompare(Expression arg1, Expression arg2, boolean invert) {
super(new Expression[] { arg1, arg2 });
this.invert = invert;
}
public Object computeValue(EvalContext context) {
return equal(context, args[0], args[1]) ? Boolean.TRUE : Boolean.FALSE;
}
protected int getPrecedence() {
return COMPARE_PRECEDENCE;
}
protected boolean isSymmetric() {
return true;
}
/**
* Compares two values.
* @param context evaluation context
* @param left operand
* @param right operand
* @return whether left = right in XPath terms
*/
protected boolean equal(EvalContext context, Expression left,
Expression right) {
Object l = left.compute(context);
Object r = right.compute(context);
if (l instanceof InitialContext) {
((EvalContext) l).reset();
}
if (l instanceof SelfContext) {
l = ((EvalContext) l).getSingleNodePointer();
}
if (r instanceof InitialContext) {
((EvalContext) r).reset();
}
if (r instanceof SelfContext) {
r = ((EvalContext) r).getSingleNodePointer();
}
if (l instanceof Collection) {
l = ((Collection) l).iterator();
}
if (r instanceof Collection) {
r = ((Collection) r).iterator();
}
if (l instanceof Iterator && r instanceof Iterator) {
return findMatch((Iterator) l, (Iterator) r);
}
if (l instanceof Iterator) {
return contains((Iterator) l, r);
}
if (r instanceof Iterator) {
return contains((Iterator) r, l);
}
return equal(l, r);
}
/**
* Learn whether it contains value.
* @param it Iterator to check
* @param value for which to look
* @return whether value was found
*/
protected boolean contains(Iterator it, Object value) {
while (it.hasNext()) {
Object element = it.next();
if (equal(element, value)) {
return true;
}
}
return false;
}
/**
* Learn whether lit intersects rit.
* @param lit left Iterator
* @param rit right Iterator
* @return boolean
*/
protected boolean findMatch(Iterator lit, Iterator rit) {
HashSet left = new HashSet();
while (lit.hasNext()) {
left.add(lit.next());
}
while (rit.hasNext()) {
if (contains(left.iterator(), rit.next())) {
return true;
}
}
return false;
}
/**
* Learn whether l equals r in XPath terms.
* @param l left operand
* @param r right operand
* @return whether l = r
*/
protected boolean equal(Object l, Object r) {
if (l instanceof Pointer) {
l = ((Pointer) l).getValue();
}
if (r instanceof Pointer) {
r = ((Pointer) r).getValue();
}
boolean result;
if (l instanceof Boolean || r instanceof Boolean) {
result = l == r || InfoSetUtil.booleanValue(l) == InfoSetUtil.booleanValue(r);
}
else if (l instanceof Number || r instanceof Number) {
//if either side is NaN, no comparison returns true:
double ld = InfoSetUtil.doubleValue(l);
if (Double.isNaN(ld)) {
return false;
}
double rd = InfoSetUtil.doubleValue(r);
if (Double.isNaN(rd)) {
return false;
}
result = ld == rd;
}
else {
if (l instanceof String || r instanceof String) {
l = InfoSetUtil.stringValue(l);
r = InfoSetUtil.stringValue(r);
}
result = l == r || l != null && l.equals(r);
}
return result ^ invert;
}
}
|