package client.net.sf.saxon.ce.functions;
import client.net.sf.saxon.ce.expr.*;
import client.net.sf.saxon.ce.om.SequenceIterator;
import client.net.sf.saxon.ce.tree.iter.EmptyIterator;
import client.net.sf.saxon.ce.trans.XPathException;
import client.net.sf.saxon.ce.type.ItemType;
import client.net.sf.saxon.ce.type.TypeHierarchy;
import client.net.sf.saxon.ce.value.*;
/**
* Implements the XPath 2.0 subsequence() function
*/
public class Subsequence extends SystemFunction {
public Subsequence newInstance() {
return new Subsequence();
}
/**
* Determine the data type of the items in the sequence
* @return the type of the argument
* @param th the type hierarchy cache
*/
public ItemType getItemType(TypeHierarchy th) {
return argument[0].getItemType(th);
}
/**
* Get the static properties of this expression (other than its type). The result is
* bit-significant. These properties are used for optimizations. In general, if
* property bit is set, it is true, but if it is unset, the value is unknown.
*/
public int computeSpecialProperties() {
return argument[0].getSpecialProperties();
}
/**
* Determine the cardinality of the function.
*/
public int computeCardinality() {
if (getNumberOfArguments() == 3 && Literal.isConstantOne(argument[2])) {
return StaticProperty.ALLOWS_ZERO_OR_ONE;
}
return argument[0].getCardinality() | StaticProperty.ALLOWS_ZERO;
}
/**
* Perform optimisation of an expression and its subexpressions.
* <p/>
* <p>This method is called after all references to functions and variables have been resolved
* to the declaration of the function or variable, and after all type checking has been done.</p>
*
* @param visitor an expression visitor
* @param contextItemType the static type of "." at the point where this expression is invoked.
* The parameter is set to null if it is known statically that the context item will be undefined.
* If the type of the context item is not known statically, the argument is set to
* {@link client.net.sf.saxon.ce.type.Type#ITEM_TYPE}
* @return the original expression, rewritten if appropriate to optimize execution
* @throws client.net.sf.saxon.ce.trans.XPathException
* if an error is discovered during this phase
* (typically a type error)
*/
public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException {
Expression e = super.optimize(visitor, contextItemType);
if (e != this) {
return e;
}
return this;
}
/**
* Evaluate the function to return an iteration of selected nodes.
*/
public SequenceIterator iterate(XPathContext context) throws XPathException {
SequenceIterator seq = argument[0].iterate(context);
DoubleValue startVal = (DoubleValue)argument[1].evaluateItem(context);
if (startVal.isNaN()) {
return EmptyIterator.getInstance();
}
if (startVal.compareTo(IntegerValue.MAX_LONG) > 0) {
return EmptyIterator.getInstance();
}
startVal = (DoubleValue)startVal.round();
int lstart;
if (startVal.compareTo(IntegerValue.PLUS_ONE) <= 0) {
lstart = 1;
} else {
lstart = startVal.intValue();
}
int lend;
if (argument.length == 2) {
lend = Integer.MAX_VALUE;
} else {
DoubleValue lengthVal = (DoubleValue)argument[2].evaluateItem(context);
if (lengthVal.isNaN()) {
return EmptyIterator.getInstance();
}
lengthVal = (DoubleValue)lengthVal.round();
if (lengthVal.compareTo(IntegerValue.ZERO) <= 0) {
return EmptyIterator.getInstance();
}
NumericValue rend = (NumericValue)ArithmeticExpression.compute(
startVal, Calculator.PLUS, lengthVal, context);
if (rend.isNaN()) {
// Can happen when start = -INF, length = +INF
return EmptyIterator.getInstance();
}
rend = (NumericValue)ArithmeticExpression.compute(
rend, Calculator.MINUS, IntegerValue.PLUS_ONE, context);
if (rend.compareTo(IntegerValue.ZERO) <= 0) {
return EmptyIterator.getInstance();
}
lend = rend.intValue();
}
return SubsequenceIterator.make(seq, lstart, lend);
}
}
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.