/**
   * {@inheritDoc}
   *
   * <p>Creating a new query result with an empty binding to handle an empty BIND statement
   */
  @Override
  public QueryResult process(final Dataset dataset) {
    final QueryResult queryResult = QueryResult.createInstance();
    if (this.rdfGraph != null && this.rdfGraph.isVariable()) {
      final Variable graphConstraint = (Variable) this.rdfGraph;
      if (this.root.namedGraphs != null && this.root.namedGraphs.size() > 0) {
        // Convert the named graphs' names into URILiterals
        // to be applicable later on
        for (final String name : this.root.namedGraphs) {
          final Bindings graphConstraintBindings = this.bindingsFactory.createInstance();
          try {
            graphConstraintBindings.add(
                graphConstraint, LiteralFactory.createURILiteralWithoutLazyLiteral(name));
          } catch (final URISyntaxException e) {
            System.err.println(e);
            e.printStackTrace();
          }
          queryResult.add(graphConstraintBindings);
        }
      } else {
        final Collection<Indices> dataSetIndices = dataset.getNamedGraphIndices();
        if (dataSetIndices != null) {
          for (final Indices indices : dataSetIndices) {
            final Bindings graphConstraintBindings = this.bindingsFactory.createInstance();
            graphConstraintBindings.add(graphConstraint, indices.getRdfName());
            queryResult.add(graphConstraintBindings);
          }
        }
      }
    } else {
      queryResult.add(this.bindingsFactory.createInstance());
    }

    return queryResult;
  }
 /** {@inheritDoc} */
 @Override
 public void consume(final Triple triple) {
   if (this.firstTime) {
     this.firstTime = false;
     this.processAtSucceedingOperators(
         QueryResult.createInstance(this.bindingsFactory.createInstance()));
   }
 }
  /** {@inheritDoc} */
  @Override
  public QueryResult process(final QueryResult _bindings, final int operandID) {
    final Iterator<Bindings> itb = _bindings.oneTimeIterator();
    if (!itb.hasNext()) {
      return null;
    } else {
      return QueryResult.createInstance(
          new ImmutableIterator<Bindings>() {
            Bindings next = null;

            @Override
            public boolean hasNext() {
              if (this.next != null) {
                return true;
              }
              if (itb.hasNext()) {
                this.next = this.next();
                if (this.next != null) {
                  return true;
                }
              }
              return false;
            }

            @Override
            public Bindings next() {
              if (this.next != null) {
                final Bindings znext = this.next;
                this.next = null;
                return znext;
              }
              while (itb.hasNext()) {
                final Bindings b = itb.next();
                if (!NonBlockingDistinct.this.bindings.contains(b)) {
                  NonBlockingDistinct.this.bindings.add(b);
                  return b;
                }
              }
              return null;
            }
          });
    }
  }
  @Override
  public QueryResult process(final QueryResult bindings, final int operandID) {
    if (operandID < this.operandResults.length) {
      this.operandResults[operandID] = bindings;
    } else
      System.err.println(
          "NAryMergeJoin is a "
              + this.operandResults.length
              + "-ary operator, but received the operand number "
              + operandID);
    boolean go = true;
    for (int i = 0; i < this.operandResults.length; i++) {
      if (this.operandResults[i] == null) {
        go = false;
        break;
      }
    }
    if (go) {

      this.comp.setVariables(this.intersectionVariables);

      if (this.minimum == null) return null;

      @SuppressWarnings("unchecked")
      final Iterator<Bindings>[] itb = new Iterator[this.operandResults.length];
      for (int i = 0; i < this.operandResults.length; i++) {
        itb[i] = this.operandResults[i].oneTimeIterator();
      }

      final ParallelIterator<Bindings> currentResult =
          (this.intersectionVariables.size() == 0)
              ? MergeJoin.cartesianProductIterator(this.operandResults)
              : MergeJoin.mergeJoinIterator(
                  itb, this.comp, this.intersectionVariables, this.minimum, this.maximum);
      if (currentResult != null && currentResult.hasNext()) {
        final QueryResult result =
            QueryResult.createInstance(
                new SIPParallelIterator<Bindings, Bindings>() {

                  int number = 0;

                  @Override
                  public void close() {
                    currentResult.close();
                  }

                  @Override
                  public boolean hasNext() {
                    if (!currentResult.hasNext()) {
                      NAryMergeJoinWithoutSorting.this.realCardinality = this.number;
                      close();
                    }
                    return currentResult.hasNext();
                  }

                  @Override
                  public Bindings next() {
                    final Bindings b = currentResult.next();
                    if (b != null) this.number++;
                    if (!currentResult.hasNext()) {
                      NAryMergeJoinWithoutSorting.this.realCardinality = this.number;
                      close();
                    }
                    return b;
                  }

                  public Bindings getNext(final Bindings k) {
                    @SuppressWarnings("unchecked")
                    final Bindings b =
                        ((SIPParallelIterator<Bindings, Bindings>) currentResult).next(k);
                    if (b != null) this.number++;
                    if (!currentResult.hasNext()) {
                      NAryMergeJoinWithoutSorting.this.realCardinality = this.number;
                      close();
                    }
                    return b;
                  }

                  @Override
                  public void remove() {
                    currentResult.remove();
                  }

                  @Override
                  public void finalize() {
                    close();
                  }

                  @Override
                  public Bindings next(final Bindings k) {
                    if (currentResult instanceof SIPParallelIterator) return getNext(k);
                    else return next();
                  }
                });

        return result;
      } else {
        for (int i = 0; i < this.operandResults.length; i++) {
          if (this.operandResults[i] != null) {
            this.operandResults[i].release();
            this.operandResults[i] = null;
          }
        }
        return null;
      }
    } else {
      return null;
    }
  }
  /** {@inheritDoc} */
  @Override
  public QueryResult process(final QueryResult _bindings, final int operandID) {
    if (_bindings.isEmpty()) {
      return null;
    }

    final BoundedBuffer<Bindings> distinctElements = new BoundedBuffer<Bindings>();
    final BoundedBuffer<Bindings> toBeChecked = new BoundedBuffer<Bindings>();
    final BoundedBuffer<Tuple<Bindings, Boolean>> toBeAddedToSet =
        new BoundedBuffer<Tuple<Bindings, Boolean>>();

    final Feeder feeder = new Feeder(_bindings, toBeChecked);
    final FastDecider fastDecider =
        new FastDecider(distinctElements, toBeChecked, toBeAddedToSet, this.bindings);
    final DetailedDecider detailedDecider =
        new DetailedDecider(distinctElements, toBeAddedToSet, this.bindings);

    feeder.start();
    fastDecider.start();
    detailedDecider.start();

    return QueryResult.createInstance(
        new ParallelIterator<Bindings>() {
          @Override
          public boolean hasNext() {
            try {
              return distinctElements.hasNext();
            } catch (final InterruptedException e) {
              System.err.println(e);
              e.printStackTrace();
            }
            return false;
          }

          @Override
          public Bindings next() {
            if (this.hasNext()) {
              try {
                return distinctElements.get();
              } catch (final InterruptedException e) {
                System.err.println(e);
                e.printStackTrace();
              }
            }
            return null;
          }

          @Override
          public void remove() {
            throw new UnsupportedOperationException();
          }

          @Override
          public void close() {
            feeder.stopIt();
            distinctElements.stopIt();
            toBeChecked.stopIt();
            toBeAddedToSet.stopIt();
          }

          @Override
          public void finalize() {
            this.close();
          }
        });
  }
  @SuppressWarnings("unchecked")
  @Override
  public QueryResult process(final QueryResult bindings, final int operandID) {
    bindings.materialize();
    this.comp.setVariables(this.intersectionVariables);
    final QueryResult oldLeft = this.left;
    final QueryResult oldRight = this.right;
    if (operandID == 0) {
      if (this.left == null) this.left = bindings;
      else
        this.left =
            QueryResult.createInstance(
                new MergeIterator<Bindings>(this.comp, this.left.iterator(), bindings.iterator()));
    } else if (operandID == 1) {
      if (this.right == null) this.right = bindings;
      else
        this.right =
            QueryResult.createInstance(
                new MergeIterator<Bindings>(this.comp, this.right.iterator(), bindings.iterator()));
    } else
      System.err.println(
          "MergeJoin is a binary operator, but received the operand number " + operandID);
    if (this.left != null && this.right != null) {
      this.left.materialize();
      this.right.materialize();

      final Iterator<Bindings> leftIterator =
          (operandID == 0 && oldLeft != null)
              ? new MinusIterator(bindings.iterator(), oldLeft.iterator())
              : this.left.iterator();
      final QueryResult rightLocal =
          (operandID == 1 && oldRight != null)
              ? QueryResult.createInstance(
                  new MinusIterator(bindings.iterator(), oldRight.iterator()))
              : this.right;

      final ParallelIterator<Bindings> currentResult =
          (this.intersectionVariables.size() == 0)
              ? MergeJoin.cartesianProductIterator(leftIterator, rightLocal)
              : MergeJoin.mergeJoinIterator(
                  leftIterator, rightLocal.iterator(), this.comp, this.intersectionVariables);
      if (currentResult != null && currentResult.hasNext()) {
        final QueryResult result =
            QueryResult.createInstance(
                new ParallelIterator<Bindings>() {

                  int number = 0;

                  @Override
                  public void close() {
                    currentResult.close();
                  }

                  @Override
                  public boolean hasNext() {
                    if (!currentResult.hasNext()) {
                      MergeJoinWithoutSortingSeveralIterations.this.realCardinality = this.number;
                      close();
                    }
                    return currentResult.hasNext();
                  }

                  @Override
                  public Bindings next() {
                    final Bindings b = currentResult.next();
                    if (!currentResult.hasNext()) {
                      MergeJoinWithoutSortingSeveralIterations.this.realCardinality = this.number;
                      close();
                    }
                    if (b != null) this.number++;
                    return b;
                  }

                  @Override
                  public void remove() {
                    currentResult.remove();
                  }

                  @Override
                  public void finalize() {
                    close();
                  }
                });
        return result;
      } else {
        return null;
      }
    } else {
      return null;
    }
  }