mirror of https://github.com/apache/lucene.git
LUCENE-3179: add OpenBitSet.prevSetBit
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1137054 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
d805da14c2
commit
74aac32eb3
|
@ -543,6 +543,8 @@ New Features
|
|||
* LUCENE-3191: Added TopDocs.merge, to facilitate merging results from
|
||||
different shards (Uwe Schindler, Mike McCandless)
|
||||
|
||||
* LUCENE-3179: Added OpenBitSet.prevSetBit (Paul Elschot via Mike McCandless)
|
||||
|
||||
Build
|
||||
|
||||
* LUCENE-1344: Create OSGi bundle using dev-tools/maven.
|
||||
|
|
|
@ -778,6 +778,28 @@ public final class BitUtil {
|
|||
return n - (y & 1);
|
||||
}
|
||||
|
||||
/** table of number of leading zeros in a byte */
|
||||
public static final byte[] nlzTable = {8,7,6,6,5,5,5,5,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
|
||||
/** Returns the number of leading zero bits.
|
||||
*/
|
||||
public static int nlz(long x) {
|
||||
int n = 0;
|
||||
// do the first step as a long
|
||||
int y = (int)(x>>>32);
|
||||
if (y==0) {n+=32; y = (int)(x); }
|
||||
if ((y & 0xFFFF0000) == 0) { n+=16; y<<=16; }
|
||||
if ((y & 0xFF000000) == 0) { n+=8; y<<=8; }
|
||||
return n + nlzTable[y >>> 24];
|
||||
/* implementation without table:
|
||||
if ((y & 0xF0000000) == 0) { n+=4; y<<=4; }
|
||||
if ((y & 0xC0000000) == 0) { n+=2; y<<=2; }
|
||||
if ((y & 0x80000000) == 0) { n+=1; y<<=1; }
|
||||
if ((y & 0x80000000) == 0) { n+=1;}
|
||||
return n;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/** returns true if v is a power of two or zero*/
|
||||
public static boolean isPowerOfTwo(int v) {
|
||||
|
|
|
@ -659,7 +659,34 @@ public class OpenBitSet extends DocIdSet implements Bits, Cloneable {
|
|||
}
|
||||
|
||||
|
||||
/** 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 int prevSetBit(int index) {
|
||||
if (index < 0) {
|
||||
return -1;
|
||||
}
|
||||
int i = index>>6;
|
||||
if (i >= wlen) {
|
||||
i = wlen - 1;
|
||||
}
|
||||
final int subIndex = index & 0x3f; // index within the word
|
||||
long word = (bits[i] << (63-subIndex)); // skip all the bits to the left of index
|
||||
|
||||
if (word != 0) {
|
||||
return (i << 6) + subIndex - Long.numberOfLeadingZeros(word); // See LUCENE-3197
|
||||
}
|
||||
|
||||
while (--i >= 0) {
|
||||
word = bits[i];
|
||||
if (word !=0 ) {
|
||||
return (i << 6) + 63 - Long.numberOfLeadingZeros(word);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.lucene.util;
|
||||
|
||||
public class TestBitUtil extends LuceneTestCase {
|
||||
|
||||
private static int slowNlz(long x) {
|
||||
if (x == 0L) return 64;
|
||||
int nlz = 0;
|
||||
while ( ((x << nlz) & (1L << 63)) == 0) {
|
||||
nlz++;
|
||||
}
|
||||
return nlz;
|
||||
}
|
||||
|
||||
private void checkNlz(long x) {
|
||||
assertEquals(slowNlz(x), BitUtil.nlz(x));
|
||||
assertEquals(Long.numberOfLeadingZeros(x), BitUtil.nlz(x));
|
||||
}
|
||||
|
||||
public void testNlz() {
|
||||
checkNlz(0L);
|
||||
checkNlz(1L);
|
||||
checkNlz(-1L);
|
||||
for (int i = 1; i <= 63; i++) {
|
||||
checkNlz(1L << i);
|
||||
checkNlz((1L << i) + (1L << (i>>1)));
|
||||
}
|
||||
}
|
||||
|
||||
public void testBitUtils() {
|
||||
long num = 100000;
|
||||
assertEquals( 5, BitUtil.ntz(num) );
|
||||
assertEquals( 5, BitUtil.ntz2(num) );
|
||||
assertEquals( 5, BitUtil.ntz3(num) );
|
||||
|
||||
num = 10;
|
||||
assertEquals( 1, BitUtil.ntz(num) );
|
||||
assertEquals( 1, BitUtil.ntz2(num) );
|
||||
assertEquals( 1, BitUtil.ntz3(num) );
|
||||
|
||||
for (int i=0; i<64; i++) {
|
||||
num = 1L << i;
|
||||
assertEquals( i, BitUtil.ntz(num) );
|
||||
assertEquals( i, BitUtil.ntz2(num) );
|
||||
assertEquals( i, BitUtil.ntz3(num) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private long testArg(int shift) {
|
||||
return (1L << shift) + (1L << (shift>>1));
|
||||
}
|
||||
|
||||
private long nlzBitUtilBasicLoop(int iters) {
|
||||
long sumRes = 0;
|
||||
while (iters-- >= 0) {
|
||||
for (int i = 1; i <= 63; i++) {
|
||||
long a = testArg(i);
|
||||
sumRes += BitUtil.nlz(a);
|
||||
sumRes += BitUtil.nlz(a+1);
|
||||
sumRes += BitUtil.nlz(a-1);
|
||||
sumRes += BitUtil.nlz(a+10);
|
||||
sumRes += BitUtil.nlz(a-10);
|
||||
}
|
||||
}
|
||||
return sumRes;
|
||||
}
|
||||
|
||||
private long nlzLongBasicLoop(int iters) {
|
||||
long sumRes = 0;
|
||||
while (iters-- >= 0) {
|
||||
for (int i = 1; i <= 63; i++) {
|
||||
long a = testArg(i);
|
||||
sumRes += Long.numberOfLeadingZeros(a);
|
||||
sumRes += Long.numberOfLeadingZeros(a+1);
|
||||
sumRes += Long.numberOfLeadingZeros(a-1);
|
||||
sumRes += Long.numberOfLeadingZeros(a+10);
|
||||
sumRes += Long.numberOfLeadingZeros(a-10);
|
||||
}
|
||||
}
|
||||
return sumRes;
|
||||
}
|
||||
|
||||
public void tstPerfNlz() { // See LUCENE-3197, prefer to use Long.numberOfLeadingZeros() over BitUtil.nlz().
|
||||
final long measureMilliSecs = 2000;
|
||||
final int basicIters = 100000;
|
||||
long startTime;
|
||||
long endTime;
|
||||
long curTime;
|
||||
long dummy = 0; // avoid optimizing away
|
||||
|
||||
dummy = 0;
|
||||
int bitUtilLoops = 0;
|
||||
startTime = System.currentTimeMillis();
|
||||
endTime = startTime + measureMilliSecs;
|
||||
do {
|
||||
dummy += nlzBitUtilBasicLoop(basicIters);
|
||||
bitUtilLoops++;
|
||||
curTime = System.currentTimeMillis();
|
||||
} while (curTime < endTime);
|
||||
int bitUtilPsTime = (int) (1000000000 * (curTime - startTime) / (basicIters * 5 * 63 * (float) bitUtilLoops));
|
||||
System.out.println("BitUtil nlz time: " + (bitUtilPsTime/1) + " picosec/call, dummy: " + dummy);
|
||||
|
||||
|
||||
dummy = 0;
|
||||
int longLoops = 0;
|
||||
startTime = System.currentTimeMillis();
|
||||
endTime = startTime + measureMilliSecs;
|
||||
do {
|
||||
dummy += nlzLongBasicLoop(basicIters);
|
||||
longLoops++;
|
||||
curTime = System.currentTimeMillis();
|
||||
} while (curTime < endTime);
|
||||
int longPsTime = (int) (1000000000 * (curTime - startTime) / (basicIters * 5 * 63 * (float) longLoops));
|
||||
System.out.println("Long nlz time: " + longPsTime + " picosec/call, dummy: " + dummy);
|
||||
}
|
||||
}
|
|
@ -41,6 +41,20 @@ public class TestOpenBitSet extends LuceneTestCase {
|
|||
} while (aa>=0);
|
||||
}
|
||||
|
||||
void doPrevSetBit(BitSet a, OpenBitSet b) {
|
||||
int aa=a.length();
|
||||
int bb=aa;
|
||||
do {
|
||||
// aa = a.prevSetBit(aa-1);
|
||||
aa--;
|
||||
while ((aa >= 0) && (! a.get(aa))) {
|
||||
aa--;
|
||||
}
|
||||
bb = b.prevSetBit(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);
|
||||
|
@ -123,6 +137,7 @@ public class TestOpenBitSet extends LuceneTestCase {
|
|||
bb = (OpenBitSet)b.clone(); bb.clear(fromIndex,toIndex);
|
||||
|
||||
doNextSetBit(aa,bb); // a problem here is from clear() or nextSetBit
|
||||
doPrevSetBit(aa,bb);
|
||||
|
||||
fromIndex = random.nextInt(sz+80);
|
||||
toIndex = fromIndex + random.nextInt((sz>>1)+1);
|
||||
|
@ -130,6 +145,7 @@ public class TestOpenBitSet extends LuceneTestCase {
|
|||
bb = (OpenBitSet)b.clone(); bb.set(fromIndex,toIndex);
|
||||
|
||||
doNextSetBit(aa,bb); // a problem here is from set() or nextSetBit
|
||||
doPrevSetBit(aa,bb);
|
||||
|
||||
|
||||
if (a0 != null) {
|
||||
|
@ -168,7 +184,7 @@ public class TestOpenBitSet extends LuceneTestCase {
|
|||
b0=b;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// large enough to flush obvious bugs, small enough to run in <.5 sec as part of a
|
||||
// larger testsuite.
|
||||
public void testSmall() {
|
||||
|
@ -176,12 +192,13 @@ public class TestOpenBitSet extends LuceneTestCase {
|
|||
doRandomSets(atLeast(1200), atLeast(1000), 2);
|
||||
}
|
||||
|
||||
// uncomment to run a bigger test (~2 minutes).
|
||||
/*
|
||||
public void testBig() {
|
||||
// uncomment to run a bigger test (~2 minutes).
|
||||
// rand = newRandom();
|
||||
// doRandomSets(2000,200000, 1);
|
||||
// doRandomSets(2000,200000, 2);
|
||||
doRandomSets(2000,200000, 1);
|
||||
doRandomSets(2000,200000, 2);
|
||||
}
|
||||
*/
|
||||
|
||||
public void testEquals() {
|
||||
OpenBitSet b1 = new OpenBitSet(1111);
|
||||
|
@ -205,26 +222,6 @@ public class TestOpenBitSet extends LuceneTestCase {
|
|||
assertFalse(b1.equals(new Object()));
|
||||
}
|
||||
|
||||
public void testBitUtils()
|
||||
{
|
||||
long num = 100000;
|
||||
assertEquals( 5, BitUtil.ntz(num) );
|
||||
assertEquals( 5, BitUtil.ntz2(num) );
|
||||
assertEquals( 5, BitUtil.ntz3(num) );
|
||||
|
||||
num = 10;
|
||||
assertEquals( 1, BitUtil.ntz(num) );
|
||||
assertEquals( 1, BitUtil.ntz2(num) );
|
||||
assertEquals( 1, BitUtil.ntz3(num) );
|
||||
|
||||
for (int i=0; i<64; i++) {
|
||||
num = 1L << i;
|
||||
assertEquals( i, BitUtil.ntz(num) );
|
||||
assertEquals( i, BitUtil.ntz2(num) );
|
||||
assertEquals( i, BitUtil.ntz3(num) );
|
||||
}
|
||||
}
|
||||
|
||||
public void testHashCodeEquals() {
|
||||
OpenBitSet bs1 = new OpenBitSet(200);
|
||||
OpenBitSet bs2 = new OpenBitSet(64);
|
||||
|
@ -233,6 +230,35 @@ public class TestOpenBitSet extends LuceneTestCase {
|
|||
assertEquals(bs1, bs2);
|
||||
assertEquals(bs1.hashCode(), bs2.hashCode());
|
||||
}
|
||||
|
||||
|
||||
private OpenBitSet makeOpenBitSet(int[] a) {
|
||||
OpenBitSet bs = new OpenBitSet();
|
||||
for (int e: a) {
|
||||
bs.set(e);
|
||||
}
|
||||
return bs;
|
||||
}
|
||||
|
||||
private BitSet makeBitSet(int[] a) {
|
||||
BitSet bs = new BitSet();
|
||||
for (int e: a) {
|
||||
bs.set(e);
|
||||
}
|
||||
return bs;
|
||||
}
|
||||
|
||||
private void checkPrevSetBitArray(int [] a) {
|
||||
OpenBitSet obs = makeOpenBitSet(a);
|
||||
BitSet bs = makeBitSet(a);
|
||||
doPrevSetBit(bs, obs);
|
||||
}
|
||||
|
||||
public void testPrevSetBit() {
|
||||
checkPrevSetBitArray(new int[] {});
|
||||
checkPrevSetBitArray(new int[] {0});
|
||||
checkPrevSetBitArray(new int[] {0,2});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue