package org.basex.query.expr; import static org.basex.query.QueryText.*; import java.io.IOException; import org.basex.io.serial.Serializer; import org.basex.query.QueryContext; import org.basex.query.QueryException; import org.basex.query.expr.CmpV.Op; import org.basex.query.item.Bln; import org.basex.query.item.Item; import org.basex.query.item.SeqType; import org.basex.util.InputInfo; import org.basex.util.Token; /** * Pos expression. * * @author BaseX Team 2005-12, BSD License * @author Christian Gruen */ public final class Pos extends Simple { /** Minimum position. */ final long min; /** Maximum position. */ final long max; /** * Constructor. * @param mn minimum value * @param mx minimum value * @param ii input info */ private Pos(final long mn, final long mx, final InputInfo ii) { super(ii); min = mn; max = mx; type = SeqType.BLN; } /** * Returns a position expression, or an optimized boolean item. * @param mn minimum value * @param mx minimum value * @param ii input info * @return expression */ public static Expr get(final long mn, final long mx, final InputInfo ii) { // suppose that positions always fit in long values.. return mn > mx || mx < 1 ? Bln.FALSE : mn <= 1 && mx == Long.MAX_VALUE ? Bln.TRUE : new Pos(mn, mx, ii); } /** * Returns an instance of this class, if possible, and the input expression * otherwise. * @param cmp comparator * @param a argument * @param o original expression * @param ii input info * @return resulting expression, or {@code null} * @throws QueryException query exception */ public static Expr get(final Op cmp, final Expr a, final Expr o, final InputInfo ii) throws QueryException { if(a.isItem()) { final Item it = (Item) a; if(it.type.isNumber()) { final long p = it.itr(ii); final boolean ex = p == it.dbl(ii); switch(cmp) { case EQ: return ex ? get(p, p, ii) : Bln.FALSE; case GE: return get(ex ? p : p + 1, Long.MAX_VALUE, ii); case GT: return get(p + 1, Long.MAX_VALUE, ii); case LE: return get(1, p, ii); case LT: return get(1, ex ? p - 1 : p, ii); default: } } } return o; } @Override public Bln item(final QueryContext ctx, final InputInfo ii) throws QueryException { checkCtx(ctx); return Bln.get(ctx.pos >= min && ctx.pos <= max); } /** * Returns false if no more results can be expected. * @param ctx query context * @return result of check */ public boolean skip(final QueryContext ctx) { return ctx.pos >= max; } /** * Creates an intersection of the existing and the specified position * expressions. * @param pos second position expression * @param ii input info * @return resulting expression */ Expr intersect(final Pos pos, final InputInfo ii) { return get(Math.max(min, pos.min), Math.min(max, pos.max), ii); } @Override public boolean uses(final Use u) { return u == Use.POS; } @Override public boolean sameAs(final Expr cmp) { if(!(cmp instanceof Pos)) return false; final Pos p = (Pos) cmp; return min == p.min && max == p.max; } @Override public void plan(final Serializer ser) throws IOException { ser.emptyElement(this, MIN, Token.token(min), MAX, max == Long.MAX_VALUE ? INF : Token.token(max)); } @Override public String toString() { final StringBuilder sb = new StringBuilder("position() "); if(max == Long.MAX_VALUE) sb.append('>'); sb.append("= ").append(min); if(max != Long.MAX_VALUE && min != max) sb.append(" to ").append(max); return sb.toString(); } }