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

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

import java.util.*;
import java.util.function.*;

import org.basex.query.*;
import org.basex.query.expr.path.*;
import org.basex.query.func.Function;
import org.basex.query.iter.*;
import org.basex.query.util.*;
import org.basex.query.util.list.*;
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.*;
import org.basex.util.hash.*;

/**
 * Union expression.
 *
 * @author BaseX Team 2005-20, BSD License
 * @author <NAME>
 */
public final class Union extends Set {
  /**
   * Constructor.
   * @param info input info
   * @param exprs expressions
   */
  public Union(final InputInfo info, final Expr... exprs) {
    super(info, exprs);
  }

  @Override
  public Expr optimize(final CompileContext cc) throws QueryException {
    super.optimize(cc);

    final ExprList list = new ExprList(exprs.length);
    for(final Expr expr : exprs) {
      if(expr == Empty.VALUE) {
        // remove empty operands
        // example: * union ()  ->  *
        cc.info(OPTREMOVE_X_X, expr, (Supplier<?>) this::description);
      } else if(expr.seqType().type instanceof NodeType && !expr.has(Flag.CNS, Flag.NDT) &&
         ((Checks<Expr>) ex -> ex.equals(expr)).any(list)) {
        // remove duplicate
        // example: * union *  ->  *
        cc.info(OPTREMOVE_X_X, expr, (Supplier<?>) this::description);
      } else {
        list.add(expr);
      }
    }
    exprs = list.finish();

    switch(exprs.length) {
      case 0:  return Empty.VALUE;
      case 1:  return iterative ? exprs[0] : cc.function(Function._UTIL_DDO, info, exprs[0]);
      default: return merge(cc) ? cc.replaceWith(this, exprs[0]) : this;
    }
  }

  /**
   * Tries to merge steps with identical axes and nodes types to a single step.
   * @param cc compilation context
   * @return success flag
   * @throws QueryException query exception
   */
  private boolean merge(final CompileContext cc) throws QueryException {
    Expr root = null;
    Axis axis = null;
    Expr[] preds = null;
    final ArrayList<Test> tests = new ArrayList<>(2);

    for(final Expr expr : exprs) {
      if(!(expr instanceof Path)) return false;
      final Path path = (Path) expr;
      if(path.steps.length > 1) return false;
      if(root != null ? !Objects.equals(root, path.root) :
        path.root != null && path.root.has(Flag.CNS, Flag.NDT, Flag.POS)) return false;

      root = path.root;

      final Step step = (Step) path.steps[0];
      if(axis != null && axis != step.axis || step.has(Flag.CNS, Flag.NDT, Flag.POS)) return false;<commit_msg>[MIN] XQuery: rewrite union to step<commit_after>package org.basex.query.expr;

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

import java.util.*;
import java.util.function.*;

import org.basex.query.*;
import org.basex.query.expr.path.*;
import org.basex.query.func.Function;
import org.basex.query.iter.*;
import org.basex.query.util.*;
import org.basex.query.util.list.*;
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.*;
import org.basex.util.hash.*;

/**
 * Union expression.
 *
 * @author BaseX Team 2005-20, BSD License
 * @author <NAME>
 */
public final class Union extends Set {
  /**
   * Constructor.
   * @param info input info
   * @param exprs expressions
   */
  public Union(final InputInfo info, final Expr... exprs) {
    super(info, exprs);
  }

  @Override
  public Expr optimize(final CompileContext cc) throws QueryException {
    super.optimize(cc);

    final ExprList list = new ExprList(exprs.length);
    for(final Expr expr : exprs) {
      if(expr == Empty.VALUE) {
        // remove empty operands
        // example: * union ()  ->  *
        cc.info(OPTREMOVE_X_X, expr, (Supplier<?>) this::description);
      } else if(expr.seqType().type instanceof NodeType && !expr.has(Flag.CNS, Flag.NDT) &&
         ((Checks<Expr>) ex -> ex.equals(expr)).any(list)) {
        // remove duplicate
        // example: * union *  ->  *
        cc.info(OPTREMOVE_X_X, expr, (Supplier<?>) this::description);
      } else {
        list.add(expr);
      }
    }
    exprs = list.finish();

    switch(exprs.length) {
      case 0:  return Empty.VALUE;
      case 1:  return iterative ? exprs[0] : cc.function(Function._UTIL_DDO, info, exprs[0]);
      default: return merge(cc) ? cc.replaceWith(this, exprs[0]) : this;
    }
  }

  /**
   * Tries to merge steps with identical axes and nodes types to a single step.
   * @param cc compilation context
   * @return success flag
   * @throws QueryException query exception
   */
  private boolean merge(final CompileContext cc) throws QueryException {
    Expr root = null;
    Axis axis = null;
    Expr[] preds = null;
    final ArrayList<Test> tests = new ArrayList<>(2);

    for(final Expr expr : exprs) {
      if(!(expr instanceof AxisPath)) return false;
      final AxisPath path = (AxisPath) expr;
      if(path.steps.length > 1) return false;
      if(root != null ? !Objects.equals(root, path.root) :
        path.root != null && path.root.has(Flag.CNS, Flag.NDT, Flag.POS)) return false;

      root = path.root;

      final Step step = path.step(0);
      if(axis != null && axis != step.axis || step.has(Flag.CNS, Flag.NDT, Flag.POS)) return false;
{'fraction_non_alphanumeric': 0.1464068644976761, 'fraction_numerical': 0.0050053628888094386, 'mean_word_length': 2.9263157894736844, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 23, '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': '6033710', 'n_tokens_mistral': 1853, 'n_tokens_neox': 1805, 'n_words': 463}