Index: lucene/src/java/org/apache/lucene/util/OpenBitSet.java =================================================================== --- lucene/src/java/org/apache/lucene/util/OpenBitSet.java (revision 1139572) +++ lucene/src/java/org/apache/lucene/util/OpenBitSet.java (working copy) @@ -626,12 +626,12 @@ long word = bits[i] >> subIndex; // skip all the bits to the right of index if (word!=0) { - return (i<<6) + subIndex + BitUtil.ntz(word); + return (i<<6) + subIndex + Long.numberOfTrailingZeros(word); } while(++i < wlen) { word = bits[i]; - if (word!=0) return (i<<6) + BitUtil.ntz(word); + if (word!=0) return (i<<6) + Long.numberOfTrailingZeros(word); } return -1; @@ -647,12 +647,12 @@ long word = bits[i] >>> subIndex; // skip all the bits to the right of index if (word!=0) { - return (((long)i)<<6) + (subIndex + BitUtil.ntz(word)); + return (((long)i)<<6) + (subIndex + Long.numberOfTrailingZeros(word)); } while(++i < wlen) { word = bits[i]; - if (word!=0) return (((long)i)<<6) + BitUtil.ntz(word); + if (word!=0) return (((long)i)<<6) + Long.numberOfTrailingZeros(word); } return -1; @@ -692,6 +692,39 @@ return -1; } + /** Returns the index of the first set bit starting downwards at + * the index specified. + * -1 is returned if there are no more set bits. + */ + public long prevSetBit(long index) { + int i = (int) (index >> 6); + final int subIndex; + long word; + if (i >= wlen) { + i = wlen - 1; + if (i < 0) return -1; + subIndex = 63; // last possible bit + word = bits[i]; + } else { + if (i < 0) return -1; + subIndex = (int)index & 0x3f; // index within the word + word = (bits[i] << (63-subIndex)); // skip all the bits to the left of index + } + + if (word != 0) { + return (((long)i)<<6) + subIndex - Long.numberOfLeadingZeros(word); // See LUCENE-3197 + } + + while (--i >= 0) { + word = bits[i]; + if (word !=0 ) { + return (((long)i)<<6) + 63 - Long.numberOfLeadingZeros(word); + } + } + + return -1; + } + @Override public Object clone() { try { Index: lucene/src/test/org/apache/lucene/util/TestOpenBitSet.java =================================================================== --- lucene/src/test/org/apache/lucene/util/TestOpenBitSet.java (revision 1139572) +++ lucene/src/test/org/apache/lucene/util/TestOpenBitSet.java (working copy) @@ -29,9 +29,23 @@ if (a.get(i) != b.get(i)) { fail("mismatch: BitSet=["+i+"]="+a.get(i)); } + if (a.get(i) != b.get((long) i)) { + fail("mismatch: BitSet=["+i+"]="+a.get(i)); + } } } + void doGetFast(BitSet a, OpenBitSet b, int max) { + for (int i=0; i=0); } + void doNextSetBitLong(BitSet a, OpenBitSet b) { + int aa=-1,bb=-1; + do { + aa = a.nextSetBit(aa+1); + bb = (int) b.nextSetBit((long) (bb+1)); + assertEquals(aa,bb); + } while (aa>=0); + } + void doPrevSetBit(BitSet a, OpenBitSet b) { int aa = a.size() + random.nextInt(100); int bb = aa; @@ -55,6 +78,20 @@ } while (aa>=0); } + void doPrevSetBitLong(BitSet a, OpenBitSet b) { + int aa = a.size() + random.nextInt(100); + int bb = aa; + do { + // aa = a.prevSetBit(aa-1); + aa--; + while ((aa >= 0) && (! a.get(aa))) { + aa--; + } + bb = (int) b.prevSetBit((long) (bb-1)); + assertEquals(aa,bb); + } while (aa>=0); + } + // test interleaving different OpenBitSetIterator.next()/skipTo() void doIterate(BitSet a, OpenBitSet b, int mode) { if (mode==1) doIterate1(a, b); @@ -99,10 +136,20 @@ idx = random.nextInt(sz); a.set(idx); b.fastSet(idx); + idx = random.nextInt(sz); + a.set(idx); + b.fastSet((long) idx); + + idx = random.nextInt(sz); a.clear(idx); b.fastClear(idx); + idx = random.nextInt(sz); + a.clear(idx); + b.fastClear((long) idx); + + idx = random.nextInt(sz); a.flip(idx); b.fastFlip(idx); @@ -110,6 +157,14 @@ boolean val2 = b.flipAndGet(idx); assertTrue(val != val2); + idx = random.nextInt(sz); + a.flip(idx); + b.fastFlip((long) idx); + + val = b.flipAndGet((long) idx); + val2 = b.flipAndGet((long) idx); + assertTrue(val != val2); + val = b.getAndSet(idx); assertTrue(val2 == val); assertTrue(b.get(idx)); @@ -121,6 +176,7 @@ // test that the various ways of accessing the bits are equivalent doGet(a,b); + doGetFast(a, b, sz); // test ranges, including possible extension int fromIndex, toIndex; @@ -136,18 +192,23 @@ aa = (BitSet)a.clone(); aa.clear(fromIndex,toIndex); bb = (OpenBitSet)b.clone(); bb.clear(fromIndex,toIndex); - doNextSetBit(aa,bb); // a problem here is from clear() or nextSetBit + doNextSetBit(aa,bb); // a problem here is from clear() or nextSetBit + doNextSetBitLong(aa,bb); + doPrevSetBit(aa,bb); + doPrevSetBitLong(aa,bb); fromIndex = random.nextInt(sz+80); toIndex = fromIndex + random.nextInt((sz>>1)+1); aa = (BitSet)a.clone(); aa.set(fromIndex,toIndex); bb = (OpenBitSet)b.clone(); bb.set(fromIndex,toIndex); - doNextSetBit(aa,bb); // a problem here is from set() or nextSetBit + doNextSetBit(aa,bb); // a problem here is from set() or nextSetBit + doNextSetBitLong(aa,bb); + doPrevSetBit(aa,bb); + doPrevSetBitLong(aa,bb); - if (a0 != null) { assertEquals( a.equals(a0), b.equals(b0));