diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 5d28a1d2072..8cf32e91431 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -19,6 +19,10 @@ Changes in backwards compatibility policy
(Nikola Tanković, Uwe Schindler, Chris Male, Mike McCandless,
Robert Muir)
+* LUCENE-4924: DocIdSetIterator.docID() must now return -1 when the iterator is
+ not positioned. This change affects all classes that inherit from
+ DocIdSetIterator, including DocsEnum and DocsAndPositionsEnum. (Adrien Grand)
+
New Features
* LUCENE-4747: Move to Java 7 as minimum Java version.
diff --git a/lucene/core/src/java/org/apache/lucene/search/DocIdSet.java b/lucene/core/src/java/org/apache/lucene/search/DocIdSet.java
index 6df23b17bd2..901fe7f2364 100644
--- a/lucene/core/src/java/org/apache/lucene/search/DocIdSet.java
+++ b/lucene/core/src/java/org/apache/lucene/search/DocIdSet.java
@@ -29,20 +29,36 @@ public abstract class DocIdSet {
/** An empty {@code DocIdSet} instance for easy use, e.g. in Filters that hit no documents. */
public static final DocIdSet EMPTY_DOCIDSET = new DocIdSet() {
- private final DocIdSetIterator iterator = new DocIdSetIterator() {
- @Override
- public int advance(int target) { return NO_MORE_DOCS; }
- @Override
- public int docID() { return NO_MORE_DOCS; }
- @Override
- public int nextDoc() { return NO_MORE_DOCS; }
- @Override
- public long cost() { return 0; }
- };
-
@Override
public DocIdSetIterator iterator() {
- return iterator;
+ return new DocIdSetIterator() {
+ boolean exhausted = false;
+
+ @Override
+ public int advance(int target) {
+ assert !exhausted;
+ assert target >= 0;
+ exhausted = true;
+ return NO_MORE_DOCS;
+ }
+
+ @Override
+ public int docID() {
+ return exhausted ? NO_MORE_DOCS : -1;
+ }
+
+ @Override
+ public int nextDoc() {
+ assert !exhausted;
+ exhausted = true;
+ return NO_MORE_DOCS;
+ }
+
+ @Override
+ public long cost() {
+ return 0;
+ }
+ };
}
@Override
@@ -56,7 +72,7 @@ public abstract class DocIdSet {
return null;
}
};
-
+
/** Provides a {@link DocIdSetIterator} to access the set.
* This implementation can return null
or
* {@linkplain #EMPTY_DOCIDSET}.iterator()
if there
diff --git a/lucene/core/src/java/org/apache/lucene/search/DocIdSetIterator.java b/lucene/core/src/java/org/apache/lucene/search/DocIdSetIterator.java
index 6aa870ee411..e1e328b7129 100644
--- a/lucene/core/src/java/org/apache/lucene/search/DocIdSetIterator.java
+++ b/lucene/core/src/java/org/apache/lucene/search/DocIdSetIterator.java
@@ -37,7 +37,7 @@ public abstract class DocIdSetIterator {
/**
* Returns the following:
*
- * - -1 or {@link #NO_MORE_DOCS} if {@link #nextDoc()} or
+ *
-1
if {@link #nextDoc()} or
* {@link #advance(int)} were not called yet.
* - {@link #NO_MORE_DOCS} if the iterator has exhausted.
*
- Otherwise it should return the doc ID it is currently on.
@@ -96,8 +96,7 @@ public abstract class DocIdSetIterator {
/** Slow (linear) implementation of {@link #advance} relying on
* {@link #nextDoc()} to advance beyond the target position. */
protected final int slowAdvance(int target) throws IOException {
- assert docID() == NO_MORE_DOCS // can happen when the enum is not positioned yet
- || docID() < target;
+ assert docID() < target;
int doc;
do {
doc = nextDoc();
diff --git a/lucene/core/src/java/org/apache/lucene/search/Scorer.java b/lucene/core/src/java/org/apache/lucene/search/Scorer.java
index 8ece8c3cc6d..47fef12cebe 100644
--- a/lucene/core/src/java/org/apache/lucene/search/Scorer.java
+++ b/lucene/core/src/java/org/apache/lucene/search/Scorer.java
@@ -58,7 +58,7 @@ public abstract class Scorer extends DocsEnum {
* @param collector The collector to which all matching documents are passed.
*/
public void score(Collector collector) throws IOException {
- assert docID() == -1 || docID() == NO_MORE_DOCS; // not started
+ assert docID() == -1; // not started
collector.setScorer(this);
int doc;
while ((doc = nextDoc()) != NO_MORE_DOCS) {
diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanScorer.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanScorer.java
index b1428c3615c..a362763febf 100644
--- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanScorer.java
+++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanScorer.java
@@ -42,12 +42,8 @@ public class SpanScorer extends Scorer {
this.docScorer = docScorer;
this.spans = spans;
- if (this.spans.next()) {
- doc = -1;
- } else {
- doc = NO_MORE_DOCS;
- more = false;
- }
+ doc = -1;
+ more = spans.next();
}
@Override
diff --git a/lucene/core/src/test/org/apache/lucene/codecs/lucene41/TestBlockPostingsFormat3.java b/lucene/core/src/test/org/apache/lucene/codecs/lucene41/TestBlockPostingsFormat3.java
index cff6b0aa608..19d8a1a0a50 100644
--- a/lucene/core/src/test/org/apache/lucene/codecs/lucene41/TestBlockPostingsFormat3.java
+++ b/lucene/core/src/test/org/apache/lucene/codecs/lucene41/TestBlockPostingsFormat3.java
@@ -394,8 +394,8 @@ public class TestBlockPostingsFormat3 extends LuceneTestCase {
assertNull(rightDocs);
return;
}
- assertTrue(leftDocs.docID() == -1 || leftDocs.docID() == DocIdSetIterator.NO_MORE_DOCS);
- assertTrue(rightDocs.docID() == -1 || rightDocs.docID() == DocIdSetIterator.NO_MORE_DOCS);
+ assertEquals(-1, leftDocs.docID());
+ assertEquals(-1, rightDocs.docID());
int docid;
while ((docid = leftDocs.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
assertEquals(docid, rightDocs.nextDoc());
@@ -417,8 +417,8 @@ public class TestBlockPostingsFormat3 extends LuceneTestCase {
assertNull(rightDocs);
return;
}
- assertTrue(leftDocs.docID() == -1 || leftDocs.docID() == DocIdSetIterator.NO_MORE_DOCS);
- assertTrue(rightDocs.docID() == -1 || rightDocs.docID() == DocIdSetIterator.NO_MORE_DOCS);
+ assertEquals(-1, leftDocs.docID());
+ assertEquals(-1, rightDocs.docID());
int docid;
while ((docid = leftDocs.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
assertEquals(docid, rightDocs.nextDoc());
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestDocsAndPositions.java b/lucene/core/src/test/org/apache/lucene/index/TestDocsAndPositions.java
index c0d297ab084..80d0d7375ba 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestDocsAndPositions.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestDocsAndPositions.java
@@ -336,7 +336,7 @@ public class TestDocsAndPositions extends LuceneTestCase {
AtomicReader r = getOnlySegmentReader(reader);
DocsEnum disi = _TestUtil.docs(random(), r, "foo", new BytesRef("bar"), null, null, DocsEnum.FLAG_NONE);
int docid = disi.docID();
- assertTrue(docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS);
+ assertEquals(-1, docid);
assertTrue(disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
// now reuse and check again
@@ -344,7 +344,7 @@ public class TestDocsAndPositions extends LuceneTestCase {
assertTrue(te.seekExact(new BytesRef("bar"), true));
disi = _TestUtil.docs(random(), te, null, disi, DocsEnum.FLAG_NONE);
docid = disi.docID();
- assertTrue(docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS);
+ assertEquals(-1, docid);
assertTrue(disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
writer.close();
r.close();
@@ -361,7 +361,7 @@ public class TestDocsAndPositions extends LuceneTestCase {
AtomicReader r = getOnlySegmentReader(reader);
DocsAndPositionsEnum disi = r.termPositionsEnum(new Term("foo", "bar"));
int docid = disi.docID();
- assertTrue(docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS);
+ assertEquals(-1, docid);
assertTrue(disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
// now reuse and check again
@@ -369,7 +369,7 @@ public class TestDocsAndPositions extends LuceneTestCase {
assertTrue(te.seekExact(new BytesRef("bar"), true));
disi = te.docsAndPositions(null, disi);
docid = disi.docID();
- assertTrue(docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS);
+ assertEquals(-1, docid);
assertTrue(disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
writer.close();
r.close();
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestTermVectorsReader.java b/lucene/core/src/test/org/apache/lucene/index/TestTermVectorsReader.java
index 1fbbdd72f68..a57ace2a7ce 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestTermVectorsReader.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestTermVectorsReader.java
@@ -229,7 +229,7 @@ public class TestTermVectorsReader extends LuceneTestCase {
docsEnum = _TestUtil.docs(random(), termsEnum, null, docsEnum, DocsEnum.FLAG_NONE);
assertNotNull(docsEnum);
int doc = docsEnum.docID();
- assertTrue(doc == -1 || doc == DocIdSetIterator.NO_MORE_DOCS);
+ assertEquals(-1, doc);
assertTrue(docsEnum.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
assertEquals(DocIdSetIterator.NO_MORE_DOCS, docsEnum.nextDoc());
}
@@ -256,7 +256,7 @@ public class TestTermVectorsReader extends LuceneTestCase {
dpEnum = termsEnum.docsAndPositions(null, dpEnum);
assertNotNull(dpEnum);
int doc = dpEnum.docID();
- assertTrue(doc == -1 || doc == DocIdSetIterator.NO_MORE_DOCS);
+ assertEquals(-1, doc);
assertTrue(dpEnum.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
assertEquals(dpEnum.freq(), positions[i].length);
for (int j = 0; j < positions[i].length; j++) {
@@ -266,7 +266,7 @@ public class TestTermVectorsReader extends LuceneTestCase {
dpEnum = termsEnum.docsAndPositions(null, dpEnum);
doc = dpEnum.docID();
- assertTrue(doc == -1 || doc == DocIdSetIterator.NO_MORE_DOCS);
+ assertEquals(-1, doc);
assertTrue(dpEnum.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
assertNotNull(dpEnum);
assertEquals(dpEnum.freq(), positions[i].length);
diff --git a/lucene/join/src/java/org/apache/lucene/search/join/TermsIncludingScoreQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/TermsIncludingScoreQuery.java
index df3520aef4f..3d1f91268e5 100644
--- a/lucene/join/src/java/org/apache/lucene/search/join/TermsIncludingScoreQuery.java
+++ b/lucene/join/src/java/org/apache/lucene/search/join/TermsIncludingScoreQuery.java
@@ -193,29 +193,22 @@ class TermsIncludingScoreQuery extends Query {
DocsEnum docsEnum;
DocsEnum reuse;
int scoreUpto;
+ int doc;
SVInnerScorer(Weight weight, Bits acceptDocs, TermsEnum termsEnum, long cost) {
super(weight);
this.acceptDocs = acceptDocs;
this.termsEnum = termsEnum;
this.cost = cost;
+ this.doc = -1;
}
@Override
public void score(Collector collector) throws IOException {
- score(collector, NO_MORE_DOCS, nextDocOutOfOrder());
- }
-
- @Override
- public boolean score(Collector collector, int max, int firstDocID)
- throws IOException {
- assert collector.acceptsDocsOutOfOrder();
collector.setScorer(this);
- int doc;
- for (doc = firstDocID; doc < max; doc = nextDocOutOfOrder()) {
+ for (int doc = nextDocOutOfOrder(); doc != NO_MORE_DOCS; doc = nextDocOutOfOrder()) {
collector.collect(doc);
}
- return doc != NO_MORE_DOCS;
}
@Override
@@ -229,7 +222,7 @@ class TermsIncludingScoreQuery extends Query {
@Override
public int docID() {
- return docsEnum != null ? docsEnum.docID() : DocIdSetIterator.NO_MORE_DOCS;
+ return doc;
}
int nextDocOutOfOrder() throws IOException {
@@ -238,13 +231,13 @@ class TermsIncludingScoreQuery extends Query {
if (docId == DocIdSetIterator.NO_MORE_DOCS) {
docsEnum = null;
} else {
- return docId;
+ return doc = docId;
}
}
do {
if (upto == terms.size()) {
- return DocIdSetIterator.NO_MORE_DOCS;
+ return doc = DocIdSetIterator.NO_MORE_DOCS;
}
scoreUpto = upto;
@@ -253,7 +246,7 @@ class TermsIncludingScoreQuery extends Query {
}
} while (docsEnum == null);
- return docsEnum.nextDoc();
+ return doc = docsEnum.nextDoc();
}
@Override
diff --git a/lucene/memory/src/test/org/apache/lucene/index/memory/MemoryIndexTest.java b/lucene/memory/src/test/org/apache/lucene/index/memory/MemoryIndexTest.java
index 0a26bea34dd..5b1ff01997a 100644
--- a/lucene/memory/src/test/org/apache/lucene/index/memory/MemoryIndexTest.java
+++ b/lucene/memory/src/test/org/apache/lucene/index/memory/MemoryIndexTest.java
@@ -323,7 +323,7 @@ public class MemoryIndexTest extends BaseTokenStreamTestCase {
AtomicReader reader = (AtomicReader) memory.createSearcher().getIndexReader();
DocsEnum disi = _TestUtil.docs(random(), reader, "foo", new BytesRef("bar"), null, null, DocsEnum.FLAG_NONE);
int docid = disi.docID();
- assertTrue(docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS);
+ assertEquals(-1, docid);
assertTrue(disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
// now reuse and check again
@@ -331,7 +331,7 @@ public class MemoryIndexTest extends BaseTokenStreamTestCase {
assertTrue(te.seekExact(new BytesRef("bar"), true));
disi = te.docs(null, disi, DocsEnum.FLAG_NONE);
docid = disi.docID();
- assertTrue(docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS);
+ assertEquals(-1, docid);
assertTrue(disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
reader.close();
}
@@ -354,7 +354,7 @@ public class MemoryIndexTest extends BaseTokenStreamTestCase {
assertEquals(1, reader.terms("foo").getSumTotalTermFreq());
DocsAndPositionsEnum disi = reader.termPositionsEnum(new Term("foo", "bar"));
int docid = disi.docID();
- assertTrue(docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS);
+ assertEquals(-1, docid);
assertTrue(disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
assertEquals(0, disi.nextPosition());
assertEquals(0, disi.startOffset());
@@ -365,7 +365,7 @@ public class MemoryIndexTest extends BaseTokenStreamTestCase {
assertTrue(te.seekExact(new BytesRef("bar"), true));
disi = te.docsAndPositions(null, disi);
docid = disi.docID();
- assertTrue(docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS);
+ assertEquals(-1, docid);
assertTrue(disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
reader.close();
memory.reset();
diff --git a/lucene/test-framework/src/java/org/apache/lucene/index/AssertingAtomicReader.java b/lucene/test-framework/src/java/org/apache/lucene/index/AssertingAtomicReader.java
index 2a991205fdc..bbcec7aaa40 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/index/AssertingAtomicReader.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/index/AssertingAtomicReader.java
@@ -237,7 +237,7 @@ public class AssertingAtomicReader extends FilterAtomicReader {
super(in);
try {
int docid = in.docID();
- assert docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS : in.getClass() + ": invalid initial doc id: " + docid;
+ assert docid == -1 : in.getClass() + ": invalid initial doc id: " + docid;
} catch (UnsupportedOperationException e) {
if (failOnUnsupportedDocID) {
throw e;
@@ -256,7 +256,7 @@ public class AssertingAtomicReader extends FilterAtomicReader {
} else {
state = DocsEnumState.ITERATING;
}
- assert docID() == nextDoc;
+ assert super.docID() == nextDoc;
return doc = nextDoc;
}
@@ -271,13 +271,15 @@ public class AssertingAtomicReader extends FilterAtomicReader {
} else {
state = DocsEnumState.ITERATING;
}
- assert docID() == advanced;
+ assert super.docID() == advanced;
return doc = advanced;
}
- // NOTE: We don't assert anything for docId(). Specifically DocsEnum javadocs
- // are ambiguous with DocIdSetIterator here, DocIdSetIterator says its ok
- // to call this method before nextDoc(), just that it must be -1 or NO_MORE_DOCS!
+ @Override
+ public int docID() {
+ assert doc == super.docID() : " invalid docID() in " + in.getClass() + " " + super.docID() + " instead of " + doc;
+ return doc;
+ }
@Override
public int freq() throws IOException {
@@ -298,7 +300,7 @@ public class AssertingAtomicReader extends FilterAtomicReader {
public AssertingDocsAndPositionsEnum(DocsAndPositionsEnum in) {
super(in);
int docid = in.docID();
- assert docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS : "invalid initial doc id: " + docid;
+ assert docid == -1 : "invalid initial doc id: " + docid;
doc = -1;
}
@@ -315,7 +317,7 @@ public class AssertingAtomicReader extends FilterAtomicReader {
state = DocsEnumState.ITERATING;
positionMax = super.freq();
}
- assert docID() == nextDoc;
+ assert super.docID() == nextDoc;
return doc = nextDoc;
}
@@ -333,10 +335,16 @@ public class AssertingAtomicReader extends FilterAtomicReader {
state = DocsEnumState.ITERATING;
positionMax = super.freq();
}
- assert docID() == advanced;
+ assert super.docID() == advanced;
return doc = advanced;
}
+ @Override
+ public int docID() {
+ assert doc == super.docID() : " invalid docID() in " + in.getClass() + " " + super.docID() + " instead of " + doc;
+ return doc;
+ }
+
@Override
public int freq() throws IOException {
assert state != DocsEnumState.START : "freq() called before nextDoc()/advance()";
diff --git a/lucene/test-framework/src/java/org/apache/lucene/index/BasePostingsFormatTestCase.java b/lucene/test-framework/src/java/org/apache/lucene/index/BasePostingsFormatTestCase.java
index de0fcc008c0..fd3f90be826 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/index/BasePostingsFormatTestCase.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/index/BasePostingsFormatTestCase.java
@@ -66,9 +66,6 @@ import org.junit.BeforeClass;
// TODO test when you reuse after skipping a term or two, eg the block reuse case
-// TODO hmm contract says .doc() can return NO_MORE_DOCS
-// before nextDoc too...?
-
/* TODO
- threads
- assert doc=-1 before any nextDoc
@@ -699,7 +696,7 @@ public abstract class BasePostingsFormatTestCase extends LuceneTestCase {
assertNotNull("null DocsEnum", docsEnum);
int initialDocID = docsEnum.docID();
- assertTrue("inital docID should be -1 or NO_MORE_DOCS: " + docsEnum, initialDocID == -1 || initialDocID == DocsEnum.NO_MORE_DOCS);
+ assertEquals("inital docID should be -1" + docsEnum, -1, initialDocID);
if (VERBOSE) {
if (prevDocsEnum == null) {
diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java b/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java
index 447d1e465f5..1efa453817f 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java
@@ -1534,8 +1534,8 @@ public abstract class LuceneTestCase extends Assert {
assertNull(rightDocs);
return;
}
- assertTrue(info, leftDocs.docID() == -1 || leftDocs.docID() == DocIdSetIterator.NO_MORE_DOCS);
- assertTrue(info, rightDocs.docID() == -1 || rightDocs.docID() == DocIdSetIterator.NO_MORE_DOCS);
+ assertEquals(info, -1, leftDocs.docID());
+ assertEquals(info, -1, rightDocs.docID());
int docid;
while ((docid = leftDocs.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
assertEquals(info, docid, rightDocs.nextDoc());
@@ -1559,8 +1559,8 @@ public abstract class LuceneTestCase extends Assert {
assertNull(rightDocs);
return;
}
- assertTrue(info, leftDocs.docID() == -1 || leftDocs.docID() == DocIdSetIterator.NO_MORE_DOCS);
- assertTrue(info, rightDocs.docID() == -1 || rightDocs.docID() == DocIdSetIterator.NO_MORE_DOCS);
+ assertEquals(info, -1, leftDocs.docID());
+ assertEquals(info, -1, rightDocs.docID());
int docid;
while ((docid = leftDocs.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
assertEquals(info, docid, rightDocs.nextDoc());