private int doNext(int doc) throws IOException {
    for (; ; ) {
      // doc may already be NO_MORE_DOCS here, but we don't check explicitly
      // since all scorers should advance to NO_MORE_DOCS, match, then
      // return that value.
      advanceHead:
      for (; ; ) {
        for (int i = 1; i < docsAndFreqs.length; i++) {
          // invariant: docsAndFreqs[i].doc <= doc at this point.

          // docsAndFreqs[i].doc may already be equal to doc if we "broke advanceHead"
          // on the previous iteration and the advance on the lead scorer exactly matched.
          if (docsAndFreqs[i].doc < doc) {
            docsAndFreqs[i].doc = docsAndFreqs[i].scorer.advance(doc);

            if (docsAndFreqs[i].doc > doc) {
              // DocsEnum beyond the current doc - break and advance lead to the new highest doc.
              doc = docsAndFreqs[i].doc;
              break advanceHead;
            }
          }
        }
        // success - all DocsEnums are on the same doc
        return doc;
      }
      // advance head for next iteration
      doc = lead.doc = lead.scorer.advance(doc);
    }
  }
 @Override
 public int nextDoc() throws IOException {
   lead.doc = lead.scorer.nextDoc();
   return lastDoc = doNext(lead.doc);
 }
 @Override
 public int advance(int target) throws IOException {
   lead.doc = lead.scorer.advance(target);
   return lastDoc = doNext(lead.doc);
 }