package org.exist.xquery.value;
import org.exist.xquery.Constants;
import org.exist.xquery.Constants.Comparison;
import org.exist.xquery.XPathException;
import java.text.Collator;
public abstract class NumericValue extends ComputableValue {
public abstract String getStringValue() throws XPathException;
public abstract AtomicValue convertTo(int requiredType) throws XPathException;
public double getDouble() throws XPathException {
return ((DoubleValue) convertTo(Type.DOUBLE)).getValue();
}
public long getLong() throws XPathException {
return ((IntegerValue) convertTo(Type.INTEGER)).getValue();
}
public int getInt() throws XPathException {
return (int) ((IntegerValue) convertTo(Type.INTEGER)).getValue();
}
public abstract boolean hasFractionalPart();
public abstract boolean isNaN();
public abstract boolean isInfinite();
public abstract boolean isZero();
public abstract boolean isNegative();
public abstract boolean isPositive();
public boolean effectiveBooleanValue() throws XPathException {
//If its operand is a singleton value of any numeric type or derived from a numeric type,
//fn:boolean returns false if the operand value is NaN or is numerically equal to zero;
//otherwise it returns true.
return !(isNaN() || isZero());
}
@Override
public boolean compareTo(Collator collator, Comparison operator, AtomicValue other)
throws XPathException {
if (other.isEmpty()) {
//Never equal, or inequal...
return false;
}
if (Type.subTypeOf(other.getType(), Type.NUMBER)) {
if (isNaN()) {
//NaN does not equal itself.
if (((NumericValue) other).isNaN()) {
return operator == Comparison.NEQ;
}
}
final double otherVal = ((NumericValue) other).getDouble();
final double val = getDouble();
switch (operator) {
case EQ:
return val == otherVal;
case NEQ:
return val != otherVal;
case GT:
return val > otherVal;
case GTEQ:
return val >= otherVal;
case LT:
return val < otherVal;
case LTEQ:
return val <= otherVal;
default:
throw new XPathException("Type error: cannot apply operator to numeric value");
}
}
throw new XPathException("Type error: cannot compare operands: " +
Type.getTypeName(getType()) + " and " +
Type.getTypeName(other.getType()));
}
@Override
public int compareTo(Collator collator, AtomicValue other) throws XPathException {
if (Type.subTypeOf(other.getType(), Type.NUMBER)) {
if (isNaN()) {
//NaN does not equal itself.
if (((NumericValue) other).isNaN()) {
return Constants.INFERIOR;
}
}
final double otherVal = ((NumericValue) other).getDouble();
final double val = getDouble();
if (val == otherVal) {
return Constants.EQUAL;
} else if (val > otherVal) {
return Constants.SUPERIOR;
} else {
return Constants.INFERIOR;
}
} else {
throw new XPathException("cannot compare numeric value to non-numeric value");
}
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (NumericValue.class.isAssignableFrom(obj.getClass()))
try {
return compareTo(null, Comparison.EQ, (NumericValue) obj);
} catch (final XPathException e) {
// should not be possible due to type check
}
return false;
}
public abstract NumericValue negate() throws XPathException;
public abstract NumericValue ceiling() throws XPathException;
public abstract NumericValue floor() throws XPathException;
public abstract NumericValue round() throws XPathException;
public abstract NumericValue round(IntegerValue precision) throws XPathException;
public abstract NumericValue mod(NumericValue other) throws XPathException;
//TODO : implement here ?
public abstract IntegerValue idiv(NumericValue other) throws XPathException;
public abstract NumericValue abs() throws XPathException;
public abstract AtomicValue max(Collator collator, AtomicValue other) throws XPathException;
public abstract AtomicValue min(Collator collator, AtomicValue other) throws XPathException;
}