<commit_before>package org.basex.query.path;

import static org.basex.query.QueryText.*;
import static org.basex.query.util.Err.*;

import java.util.*;

import org.basex.data.*;
import org.basex.index.path.*;
import org.basex.index.stats.*;
import org.basex.query.*;
import org.basex.query.expr.*;
import org.basex.query.path.Test.Mode;
import org.basex.query.util.*;
import org.basex.query.value.*;
import org.basex.query.value.item.*;
import org.basex.query.value.node.*;
import org.basex.query.value.seq.*;
import org.basex.query.value.type.*;
import org.basex.query.var.*;
import org.basex.util.*;

/**
 * Abstract axis path expression.
 *
 * @author BaseX Team 2005-12, BSD License
 * @author <NAME>
 */
public abstract class AxisPath extends Path {
  /**
   * Constructor.
   * @param ii input info
   * @param r root expression; can be a {@code null} reference
   * @param s axis steps
   */
  AxisPath(final InputInfo ii, final Expr r, final Expr... s) {
    super(ii, r, s);
  }

  /**
   * If possible, converts this path expression to a path iterator.
   * @param ctx query context
   * @return resulting operator
   */
  final AxisPath finish(final QueryContext ctx) {
    // evaluate number of results
    size = size(ctx);
    type = SeqType.get(steps[steps.length - 1].type().type, size);
    return useIterator() ? new IterPath(info, root, steps, type, size) : this;
  }

  /**
   * Checks if the path can be rewritten for iterative evaluation.
   * @return resulting operator
   */
  private boolean useIterator() {
    if(root == null || root.hasFreeVars() || !root.iterable()) return false;

    final int sl = steps.length;
    for(int s = 0; s < sl; ++s) {
      switch(step(s).axis) {
        // reverse axes - don't iterate
        case ANC: case ANCORSELF: case PREC: case PRECSIBL:
          return false;
        // multiple, unsorted results - only iterate at last step,
        // or if last step uses attribute axis
        case DESC: case DESCORSELF: case FOLL: case FOLLSIBL:
          return s + 1 == sl || s + 2 == sl && step(s + 1).axis == Axis.ATTR;
        // allow iteration for CHILD, ATTR, PARENT and SELF
        default:
      }
    }
    return true;
  }

  @Override
  protected final Expr compilePath(final QueryContext ctx, final VarScope scp)
      throws QueryException {
    // merge two axis paths
    if(root instanceof AxisPath) {
      Expr[] st = ((AxisPath) root).steps;
      root = ((AxisPath) root).root;
      for(final Expr s : steps) st = Array.add(st, s);
      steps = st;
      // refresh root context
      ctx.compInfo(OPTMERGE);
      ctx.value = root(ctx);
    }

    final Step s = voidStep(steps);
    if(s != null) COMPSELF.thrw(info, s);

    for(int i = 0; i != steps.length; ++i) {
      final Expr e = steps[i].compile(ctx, scp);
      if(!(e instanceof Step)) return e;
      steps[i] = e;
    }
    optSteps(ctx);

    final Expr path = optimize(ctx, scp);

    // heuristics: wrap with filter expression if only one result is expected
    return size() != 1 ? path :
      Filter.get(info, this, Pos.get(1, size(), info)).optimize(ctx, scp);
  }<commit_msg>[MIN] XQuery: skip size()=1 path optimization<commit_after>package org.basex.query.path;

import static org.basex.query.QueryText.*;
import static org.basex.query.util.Err.*;

import java.util.*;

import org.basex.data.*;
import org.basex.index.path.*;
import org.basex.index.stats.*;
import org.basex.query.*;
import org.basex.query.expr.*;
import org.basex.query.path.Test.Mode;
import org.basex.query.util.*;
import org.basex.query.value.*;
import org.basex.query.value.item.*;
import org.basex.query.value.node.*;
import org.basex.query.value.seq.*;
import org.basex.query.value.type.*;
import org.basex.query.var.*;
import org.basex.util.*;

/**
 * Abstract axis path expression.
 *
 * @author BaseX Team 2005-12, BSD License
 * @author <NAME>
 */
public abstract class AxisPath extends Path {
  /**
   * Constructor.
   * @param ii input info
   * @param r root expression; can be a {@code null} reference
   * @param s axis steps
   */
  AxisPath(final InputInfo ii, final Expr r, final Expr... s) {
    super(ii, r, s);
  }

  /**
   * If possible, converts this path expression to a path iterator.
   * @param ctx query context
   * @return resulting operator
   */
  final AxisPath finish(final QueryContext ctx) {
    // evaluate number of results
    size = size(ctx);
    type = SeqType.get(steps[steps.length - 1].type().type, size);
    return useIterator() ? new IterPath(info, root, steps, type, size) : this;
  }

  /**
   * Checks if the path can be rewritten for iterative evaluation.
   * @return resulting operator
   */
  private boolean useIterator() {
    if(root == null || root.hasFreeVars() || !root.iterable()) return false;

    final int sl = steps.length;
    for(int s = 0; s < sl; ++s) {
      switch(step(s).axis) {
        // reverse axes - don't iterate
        case ANC: case ANCORSELF: case PREC: case PRECSIBL:
          return false;
        // multiple, unsorted results - only iterate at last step,
        // or if last step uses attribute axis
        case DESC: case DESCORSELF: case FOLL: case FOLLSIBL:
          return s + 1 == sl || s + 2 == sl && step(s + 1).axis == Axis.ATTR;
        // allow iteration for CHILD, ATTR, PARENT and SELF
        default:
      }
    }
    return true;
  }

  @Override
  protected final Expr compilePath(final QueryContext ctx, final VarScope scp)
      throws QueryException {
    // merge two axis paths
    if(root instanceof AxisPath) {
      Expr[] st = ((AxisPath) root).steps;
      root = ((AxisPath) root).root;
      for(final Expr s : steps) st = Array.add(st, s);
      steps = st;
      // refresh root context
      ctx.compInfo(OPTMERGE);
      ctx.value = root(ctx);
    }

    final Step s = voidStep(steps);
    if(s != null) COMPSELF.thrw(info, s);

    for(int i = 0; i != steps.length; ++i) {
      final Expr e = steps[i].compile(ctx, scp);
      if(!(e instanceof Step)) return e;
      steps[i] = e;
    }
    optSteps(ctx);

    return optimize(ctx, scp);
  }
{'fraction_non_alphanumeric': 0.1355071276421432, 'fraction_numerical': 0.0044240537440602985, 'mean_word_length': 2.7083839611178613, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6264469', 'n_tokens_mistral': 2028, 'n_tokens_neox': 1957, 'n_words': 608}