package org.basex.query.expr; import org.basex.query.QueryContext; import org.basex.query.QueryException; import org.basex.query.item.Item; import org.basex.query.item.Value; import org.basex.query.iter.Iter; /** * Iterative filter expression with numeric predicates. * * @author BaseX Team 2005-12, BSD License * @author Christian Gruen */ final class IterPosFilter extends Filter { /** Offset flag. */ final boolean off; /** * Constructor. * @param f original filter * @param o offset flag */ IterPosFilter(final Filter f, final boolean o) { super(f.input, f.root, f.preds); type = f.type; last = f.last; size = f.size; pos = f.pos; off = o; } @Override public Iter iter(final QueryContext ctx) { return new Iter() { boolean skip, direct; Iter iter; long cpos; @Override public Item next() throws QueryException { if(skip) return null; // first call - initialize iterator if(iter == null) { if(off) { // evaluate offset and create position expression final Item it = preds[0].ebv(ctx, input); final long l = it.itr(input); final Expr e = Pos.get(l, l, input); // don't accept fractional numbers if(l != it.dbl(input) || !(e instanceof Pos)) return null; pos = (Pos) e; } iter = ctx.iter(root); cpos = 1; if(pos != null || last) { // runtime optimization: // items can be directly accessed if the iterator size is known final long s = iter.size(); if(s == 0) return null; if(s != -1) { cpos = last ? s : pos.min; if(cpos > s) return null; direct = preds.length == 1; } } } // cache context final Value cv = ctx.value; final long cp = ctx.pos; final long cs = ctx.size; try { Item item; if(direct) { // directly access relevant items item = iter.size() < cpos ? null : iter.get(cpos - 1); ctx.pos = cpos++; } else { // loop through all items Item lnode = null; while((item = iter.next()) != null) { // evaluate predicates ctx.checkStop(); ctx.size = 0; ctx.pos = cpos++; if(preds(item, ctx)) break; // remember last node lnode = item; ctx.pos = cp; ctx.size = cs; } // returns the last item if(last) item = lnode; } // check if more items can be expected skip = last || pos != null && pos.skip(ctx); if(skip && direct) iter.reset(); return item; } finally { // reset context and return result ctx.value = cv; ctx.pos = cp; ctx.size = cs; } } }; } }