Open Source Repository

Home /commons-jxpath/commons-jxpath-1.3 | Repository Home


org/apache/commons/jxpath/ri/compiler/CoreOperationCompare.java
/*
 * 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 (instanceof InitialContext) {
            ((EvalContextl).reset();
        }

        if (instanceof SelfContext) {
            l = ((EvalContextl).getSingleNodePointer();
        }

        if (instanceof InitialContext) {
            ((EvalContextr).reset();
        }

        if (instanceof SelfContext) {
            r = ((EvalContextr).getSingleNodePointer();
        }

        if (instanceof Collection) {
            l = ((Collectionl).iterator();
        }

        if (instanceof Collection) {
            r = ((Collectionr).iterator();
        }

        if (instanceof Iterator && r instanceof Iterator) {
            return findMatch((Iteratorl, (Iteratorr);
        }
        if (instanceof Iterator) {
            return contains((Iteratorl, r);
        }
        if (instanceof Iterator) {
            return contains((Iteratorr, 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 (instanceof Pointer) {
            l = ((Pointerl).getValue();
        }

        if (instanceof Pointer) {
            r = ((Pointerr).getValue();
        }

        boolean result;
        if (instanceof Boolean || r instanceof Boolean) {
            result = l == r || InfoSetUtil.booleanValue(l== InfoSetUtil.booleanValue(r);
        }
        else if (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 (instanceof String || r instanceof String) {
                l = InfoSetUtil.stringValue(l);
                r = InfoSetUtil.stringValue(r);
            }
            result = l == r || l != null && l.equals(r);
        }
        return result ^ invert;
    }

}