mirror of https://github.com/apache/lucene.git
LUCENE-6010: Remove dead code.
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1632305 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
6a790d5b25
commit
e1b7594cd0
|
@ -46,7 +46,6 @@ import org.apache.lucene.util.ArrayUtil;
|
|||
import org.apache.lucene.util.Bits;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.BytesRefBuilder;
|
||||
import org.apache.lucene.util.DoubleBarrelLRUCache;
|
||||
import org.apache.lucene.util.RamUsageEstimator;
|
||||
|
||||
/** Handles a terms dict, but decouples all details of
|
||||
|
@ -76,7 +75,7 @@ public class BlockTermsReader extends FieldsProducer {
|
|||
private TermsIndexReaderBase indexReader;
|
||||
|
||||
// Used as key for the terms cache
|
||||
private static class FieldAndTerm extends DoubleBarrelLRUCache.CloneableKey {
|
||||
private static class FieldAndTerm implements Cloneable {
|
||||
String field;
|
||||
BytesRef term;
|
||||
|
||||
|
|
|
@ -61,32 +61,9 @@ public abstract class FilterDirectoryReader extends DirectoryReader {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* A no-op SubReaderWrapper that simply returns the parent
|
||||
* DirectoryReader's original subreaders.
|
||||
*/
|
||||
public static class StandardReaderWrapper extends SubReaderWrapper {
|
||||
|
||||
/** Constructor */
|
||||
public StandardReaderWrapper() {}
|
||||
|
||||
@Override
|
||||
public LeafReader wrap(LeafReader reader) {
|
||||
return reader;
|
||||
}
|
||||
}
|
||||
|
||||
/** The filtered DirectoryReader */
|
||||
protected final DirectoryReader in;
|
||||
|
||||
/**
|
||||
* Create a new FilterDirectoryReader that filters a passed in DirectoryReader.
|
||||
* @param in the DirectoryReader to filter
|
||||
*/
|
||||
public FilterDirectoryReader(DirectoryReader in) {
|
||||
this(in, new StandardReaderWrapper());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new FilterDirectoryReader that filters a passed in DirectoryReader,
|
||||
* using the supplied SubReaderWrapper to wrap its subreader.
|
||||
|
|
|
@ -20,7 +20,6 @@ import java.io.IOException;
|
|||
|
||||
import org.apache.lucene.util.Bits;
|
||||
import org.apache.lucene.util.FixedBitSet;
|
||||
import org.apache.lucene.util.OpenBitSet;
|
||||
|
||||
/**
|
||||
* Base class for DocIdSet to be used with DocValues. The implementation
|
||||
|
@ -114,8 +113,8 @@ public abstract class DocValuesDocIdSet extends DocIdSet {
|
|||
return maxDoc;
|
||||
}
|
||||
};
|
||||
} else if (acceptDocs instanceof FixedBitSet || acceptDocs instanceof OpenBitSet) {
|
||||
// special case for FixedBitSet / OpenBitSet: use the iterator and filter it
|
||||
} else if (acceptDocs instanceof FixedBitSet) {
|
||||
// special case for FixedBitSet: use the iterator and filter it
|
||||
// (used e.g. when Filters are chained by FilteredQuery)
|
||||
return new FilteredDocIdSetIterator(((DocIdSet) acceptDocs).iterator()) {
|
||||
@Override
|
||||
|
|
|
@ -1,122 +0,0 @@
|
|||
package org.apache.lucene.util;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Simple concurrent LRU cache, using a "double barrel"
|
||||
* approach where two ConcurrentHashMaps record entries.
|
||||
*
|
||||
* <p>At any given time, one hash is primary and the other
|
||||
* is secondary. {@link #get} first checks primary, and if
|
||||
* that's a miss, checks secondary. If secondary has the
|
||||
* entry, it's promoted to primary (<b>NOTE</b>: the key is
|
||||
* cloned at this point). Once primary is full, the
|
||||
* secondary is cleared and the two are swapped.</p>
|
||||
*
|
||||
* <p>This is not as space efficient as other possible
|
||||
* concurrent approaches (see LUCENE-2075): to achieve
|
||||
* perfect LRU(N) it requires 2*N storage. But, this
|
||||
* approach is relatively simple and seems in practice to
|
||||
* not grow unbounded in size when under hideously high
|
||||
* load.</p>
|
||||
*
|
||||
* @lucene.internal
|
||||
*/
|
||||
|
||||
final public class DoubleBarrelLRUCache<K extends DoubleBarrelLRUCache.CloneableKey,V> {
|
||||
|
||||
/** Object providing clone(); the key class must subclass this. */
|
||||
public static abstract class CloneableKey {
|
||||
@Override
|
||||
abstract public CloneableKey clone();
|
||||
}
|
||||
|
||||
private final Map<K,V> cache1;
|
||||
private final Map<K,V> cache2;
|
||||
private final AtomicInteger countdown;
|
||||
private volatile boolean swapped;
|
||||
private final int maxSize;
|
||||
|
||||
public DoubleBarrelLRUCache(int maxSize) {
|
||||
this.maxSize = maxSize;
|
||||
countdown = new AtomicInteger(maxSize);
|
||||
cache1 = new ConcurrentHashMap<>();
|
||||
cache2 = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public V get(K key) {
|
||||
final Map<K,V> primary;
|
||||
final Map<K,V> secondary;
|
||||
if (swapped) {
|
||||
primary = cache2;
|
||||
secondary = cache1;
|
||||
} else {
|
||||
primary = cache1;
|
||||
secondary = cache2;
|
||||
}
|
||||
|
||||
// Try primary first
|
||||
V result = primary.get(key);
|
||||
if (result == null) {
|
||||
// Not found -- try secondary
|
||||
result = secondary.get(key);
|
||||
if (result != null) {
|
||||
// Promote to primary
|
||||
put((K) key.clone(), result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void put(K key, V value) {
|
||||
final Map<K,V> primary;
|
||||
final Map<K,V> secondary;
|
||||
if (swapped) {
|
||||
primary = cache2;
|
||||
secondary = cache1;
|
||||
} else {
|
||||
primary = cache1;
|
||||
secondary = cache2;
|
||||
}
|
||||
primary.put(key, value);
|
||||
|
||||
if (countdown.decrementAndGet() == 0) {
|
||||
// Time to swap
|
||||
|
||||
// NOTE: there is saturation risk here, that the
|
||||
// thread that's doing the clear() takes too long to
|
||||
// do so, while other threads continue to add to
|
||||
// primary, but in practice this seems not to be an
|
||||
// issue (see LUCENE-2075 for benchmark & details)
|
||||
|
||||
// First, clear secondary
|
||||
secondary.clear();
|
||||
|
||||
// Second, swap
|
||||
swapped = !swapped;
|
||||
|
||||
// Third, reset countdown
|
||||
countdown.set(maxSize);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -325,13 +325,7 @@ public final class FixedBitSet extends DocIdSet implements MutableBits {
|
|||
/** Does in-place OR of the bits provided by the
|
||||
* iterator. */
|
||||
public void or(DocIdSetIterator iter) throws IOException {
|
||||
if (iter instanceof OpenBitSetIterator && iter.docID() == -1) {
|
||||
final OpenBitSetIterator obs = (OpenBitSetIterator) iter;
|
||||
or(obs.arr, obs.words);
|
||||
// advance after last doc that would be accepted if standard
|
||||
// iteration is used (to exhaust it):
|
||||
obs.advance(numBits);
|
||||
} else if (iter instanceof FixedBitSetIterator && iter.docID() == -1) {
|
||||
if (iter instanceof FixedBitSetIterator && iter.docID() == -1) {
|
||||
final FixedBitSetIterator fbs = (FixedBitSetIterator) iter;
|
||||
or(fbs.bits, fbs.numWords);
|
||||
// advance after last doc that would be accepted if standard
|
||||
|
@ -381,13 +375,7 @@ public final class FixedBitSet extends DocIdSet implements MutableBits {
|
|||
/** Does in-place AND of the bits provided by the
|
||||
* iterator. */
|
||||
public void and(DocIdSetIterator iter) throws IOException {
|
||||
if (iter instanceof OpenBitSetIterator && iter.docID() == -1) {
|
||||
final OpenBitSetIterator obs = (OpenBitSetIterator) iter;
|
||||
and(obs.arr, obs.words);
|
||||
// advance after last doc that would be accepted if standard
|
||||
// iteration is used (to exhaust it):
|
||||
obs.advance(numBits);
|
||||
} else if (iter instanceof FixedBitSetIterator && iter.docID() == -1) {
|
||||
if (iter instanceof FixedBitSetIterator && iter.docID() == -1) {
|
||||
final FixedBitSetIterator fbs = (FixedBitSetIterator) iter;
|
||||
and(fbs.bits, fbs.numWords);
|
||||
// advance after last doc that would be accepted if standard
|
||||
|
@ -435,13 +423,7 @@ public final class FixedBitSet extends DocIdSet implements MutableBits {
|
|||
/** Does in-place AND NOT of the bits provided by the
|
||||
* iterator. */
|
||||
public void andNot(DocIdSetIterator iter) throws IOException {
|
||||
if (iter instanceof OpenBitSetIterator && iter.docID() == -1) {
|
||||
final OpenBitSetIterator obs = (OpenBitSetIterator) iter;
|
||||
andNot(obs.arr, obs.words);
|
||||
// advance after last doc that would be accepted if standard
|
||||
// iteration is used (to exhaust it):
|
||||
obs.advance(numBits);
|
||||
} else if (iter instanceof FixedBitSetIterator && iter.docID() == -1) {
|
||||
if (iter instanceof FixedBitSetIterator && iter.docID() == -1) {
|
||||
final FixedBitSetIterator fbs = (FixedBitSetIterator) iter;
|
||||
andNot(fbs.bits, fbs.numWords);
|
||||
// advance after last doc that would be accepted if standard
|
||||
|
|
|
@ -1,890 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.lucene.search.DocIdSet;
|
||||
import org.apache.lucene.search.DocIdSetIterator;
|
||||
|
||||
/** An "open" BitSet implementation that allows direct access to the array of words
|
||||
* storing the bits.
|
||||
* <p/>
|
||||
* Unlike java.util.bitset, the fact that bits are packed into an array of longs
|
||||
* is part of the interface. This allows efficient implementation of other algorithms
|
||||
* by someone other than the author. It also allows one to efficiently implement
|
||||
* alternate serialization or interchange formats.
|
||||
* <p/>
|
||||
* <code>OpenBitSet</code> is faster than <code>java.util.BitSet</code> in most operations
|
||||
* and *much* faster at calculating cardinality of sets and results of set operations.
|
||||
* It can also handle sets of larger cardinality (up to 64 * 2**32-1)
|
||||
* <p/>
|
||||
* The goals of <code>OpenBitSet</code> are the fastest implementation possible, and
|
||||
* maximum code reuse. Extra safety and encapsulation
|
||||
* may always be built on top, but if that's built in, the cost can never be removed (and
|
||||
* hence people re-implement their own version in order to get better performance).
|
||||
* If you want a "safe", totally encapsulated (and slower and limited) BitSet
|
||||
* class, use <code>java.util.BitSet</code>.
|
||||
* <p/>
|
||||
* <h3>Performance Results</h3>
|
||||
*
|
||||
Test system: Pentium 4, Sun Java 1.5_06 -server -Xbatch -Xmx64M
|
||||
<br/>BitSet size = 1,000,000
|
||||
<br/>Results are java.util.BitSet time divided by OpenBitSet time.
|
||||
<table border="1">
|
||||
<tr>
|
||||
<th></th> <th>cardinality</th> <th>intersect_count</th> <th>union</th> <th>nextSetBit</th> <th>get</th> <th>iterator</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>50% full</th> <td>3.36</td> <td>3.96</td> <td>1.44</td> <td>1.46</td> <td>1.99</td> <td>1.58</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>1% full</th> <td>3.31</td> <td>3.90</td> <td> </td> <td>1.04</td> <td> </td> <td>0.99</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
Test system: AMD Opteron, 64 bit linux, Sun Java 1.5_06 -server -Xbatch -Xmx64M
|
||||
<br/>BitSet size = 1,000,000
|
||||
<br/>Results are java.util.BitSet time divided by OpenBitSet time.
|
||||
<table border="1">
|
||||
<tr>
|
||||
<th></th> <th>cardinality</th> <th>intersect_count</th> <th>union</th> <th>nextSetBit</th> <th>get</th> <th>iterator</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>50% full</th> <td>2.50</td> <td>3.50</td> <td>1.00</td> <td>1.03</td> <td>1.12</td> <td>1.25</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>1% full</th> <td>2.51</td> <td>3.49</td> <td> </td> <td>1.00</td> <td> </td> <td>1.02</td>
|
||||
</tr>
|
||||
</table>
|
||||
*/
|
||||
|
||||
public class OpenBitSet extends DocIdSet implements Bits, Cloneable {
|
||||
|
||||
private static final long BASE_RAM_BYTES_USED = RamUsageEstimator.shallowSizeOfInstance(OpenBitSet.class);
|
||||
|
||||
protected long[] bits;
|
||||
protected int wlen; // number of words (elements) used in the array
|
||||
|
||||
// Used only for assert:
|
||||
private long numBits;
|
||||
|
||||
/** Constructs an OpenBitSet large enough to hold {@code numBits}. */
|
||||
public OpenBitSet(long numBits) {
|
||||
this.numBits = numBits;
|
||||
bits = new long[bits2words(numBits)];
|
||||
wlen = bits.length;
|
||||
}
|
||||
|
||||
/** Constructor: allocates enough space for 64 bits. */
|
||||
public OpenBitSet() {
|
||||
this(64);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an OpenBitSet from an existing long[].
|
||||
* <p>
|
||||
* The first 64 bits are in long[0], with bit index 0 at the least significant
|
||||
* bit, and bit index 63 at the most significant. Given a bit index, the word
|
||||
* containing it is long[index/64], and it is at bit number index%64 within
|
||||
* that word.
|
||||
* <p>
|
||||
* numWords are the number of elements in the array that contain set bits
|
||||
* (non-zero longs). numWords should be <= bits.length, and any existing
|
||||
* words in the array at position >= numWords should be zero.
|
||||
*
|
||||
*/
|
||||
public OpenBitSet(long[] bits, int numWords) {
|
||||
if (numWords > bits.length) {
|
||||
throw new IllegalArgumentException("numWords cannot exceed bits.length");
|
||||
}
|
||||
this.bits = bits;
|
||||
this.wlen = numWords;
|
||||
this.numBits = wlen * 64;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocIdSetIterator iterator() {
|
||||
return new OpenBitSetIterator(bits, wlen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bits bits() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** This DocIdSet implementation is cacheable. */
|
||||
@Override
|
||||
public boolean isCacheable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long ramBytesUsed() {
|
||||
return BASE_RAM_BYTES_USED + RamUsageEstimator.sizeOf(bits);
|
||||
}
|
||||
|
||||
/** Returns the current capacity in bits (1 greater than the index of the last bit) */
|
||||
public long capacity() { return bits.length << 6; }
|
||||
|
||||
/**
|
||||
* Returns the current capacity of this set. Included for
|
||||
* compatibility. This is *not* equal to {@link #cardinality}
|
||||
*/
|
||||
public long size() {
|
||||
return capacity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return bits.length << 6;
|
||||
}
|
||||
|
||||
/** Returns true if there are no set bits */
|
||||
public boolean isEmpty() { return cardinality()==0; }
|
||||
|
||||
/** Expert: returns the long[] storing the bits */
|
||||
public long[] getBits() { return bits; }
|
||||
|
||||
/** Expert: gets the number of longs in the array that are in use */
|
||||
public int getNumWords() { return wlen; }
|
||||
|
||||
/** Returns true or false for the specified bit index. */
|
||||
@Override
|
||||
public boolean get(int index) {
|
||||
int i = index >> 6; // div 64
|
||||
// signed shift will keep a negative index and force an
|
||||
// array-index-out-of-bounds-exception, removing the need for an explicit check.
|
||||
if (i>=bits.length) return false;
|
||||
|
||||
long bitmask = 1L << index;
|
||||
return (bits[i] & bitmask) != 0;
|
||||
}
|
||||
|
||||
|
||||
/** Returns true or false for the specified bit index.
|
||||
* The index should be less than the OpenBitSet size
|
||||
*/
|
||||
public boolean fastGet(int index) {
|
||||
assert index >= 0 && index < numBits;
|
||||
int i = index >> 6; // div 64
|
||||
// signed shift will keep a negative index and force an
|
||||
// array-index-out-of-bounds-exception, removing the need for an explicit check.
|
||||
long bitmask = 1L << index;
|
||||
return (bits[i] & bitmask) != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Returns true or false for the specified bit index
|
||||
*/
|
||||
public boolean get(long index) {
|
||||
int i = (int)(index >> 6); // div 64
|
||||
if (i>=bits.length) return false;
|
||||
long bitmask = 1L << index;
|
||||
return (bits[i] & bitmask) != 0;
|
||||
}
|
||||
|
||||
/** Returns true or false for the specified bit index.
|
||||
* The index should be less than the OpenBitSet size.
|
||||
*/
|
||||
public boolean fastGet(long index) {
|
||||
assert index >= 0 && index < numBits;
|
||||
int i = (int)(index >> 6); // div 64
|
||||
long bitmask = 1L << index;
|
||||
return (bits[i] & bitmask) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
// alternate implementation of get()
|
||||
public boolean get1(int index) {
|
||||
int i = index >> 6; // div 64
|
||||
int bit = index & 0x3f; // mod 64
|
||||
return ((bits[i]>>>bit) & 0x01) != 0;
|
||||
// this does a long shift and a bittest (on x86) vs
|
||||
// a long shift, and a long AND, (the test for zero is prob a no-op)
|
||||
// testing on a P4 indicates this is slower than (bits[i] & bitmask) != 0;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/** returns 1 if the bit is set, 0 if not.
|
||||
* The index should be less than the OpenBitSet size
|
||||
*/
|
||||
public int getBit(int index) {
|
||||
assert index >= 0 && index < numBits;
|
||||
int i = index >> 6; // div 64
|
||||
return ((int)(bits[i]>>>index)) & 0x01;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
public boolean get2(int index) {
|
||||
int word = index >> 6; // div 64
|
||||
int bit = index & 0x0000003f; // mod 64
|
||||
return (bits[word] << bit) < 0; // hmmm, this would work if bit order were reversed
|
||||
// we could right shift and check for parity bit, if it was available to us.
|
||||
}
|
||||
*/
|
||||
|
||||
/** sets a bit, expanding the set size if necessary */
|
||||
public void set(long index) {
|
||||
int wordNum = expandingWordNum(index);
|
||||
long bitmask = 1L << index;
|
||||
bits[wordNum] |= bitmask;
|
||||
}
|
||||
|
||||
|
||||
/** Sets the bit at the specified index.
|
||||
* The index should be less than the OpenBitSet size.
|
||||
*/
|
||||
public void fastSet(int index) {
|
||||
assert index >= 0 && index < numBits;
|
||||
int wordNum = index >> 6; // div 64
|
||||
long bitmask = 1L << index;
|
||||
bits[wordNum] |= bitmask;
|
||||
}
|
||||
|
||||
/** Sets the bit at the specified index.
|
||||
* The index should be less than the OpenBitSet size.
|
||||
*/
|
||||
public void fastSet(long index) {
|
||||
assert index >= 0 && index < numBits;
|
||||
int wordNum = (int)(index >> 6);
|
||||
long bitmask = 1L << index;
|
||||
bits[wordNum] |= bitmask;
|
||||
}
|
||||
|
||||
/** Sets a range of bits, expanding the set size if necessary
|
||||
*
|
||||
* @param startIndex lower index
|
||||
* @param endIndex one-past the last bit to set
|
||||
*/
|
||||
public void set(long startIndex, long endIndex) {
|
||||
if (endIndex <= startIndex) return;
|
||||
|
||||
int startWord = (int)(startIndex>>6);
|
||||
|
||||
// since endIndex is one past the end, this is index of the last
|
||||
// word to be changed.
|
||||
int endWord = expandingWordNum(endIndex-1);
|
||||
|
||||
long startmask = -1L << startIndex;
|
||||
long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex due to wrap
|
||||
|
||||
if (startWord == endWord) {
|
||||
bits[startWord] |= (startmask & endmask);
|
||||
return;
|
||||
}
|
||||
|
||||
bits[startWord] |= startmask;
|
||||
Arrays.fill(bits, startWord+1, endWord, -1L);
|
||||
bits[endWord] |= endmask;
|
||||
}
|
||||
|
||||
protected int expandingWordNum(long index) {
|
||||
int wordNum = (int)(index >> 6);
|
||||
if (wordNum >= wlen) {
|
||||
ensureCapacity(index + 1);
|
||||
}
|
||||
return wordNum;
|
||||
}
|
||||
|
||||
/** clears a bit.
|
||||
* The index should be less than the OpenBitSet size.
|
||||
*/
|
||||
public void fastClear(int index) {
|
||||
assert index >= 0 && index < numBits;
|
||||
int wordNum = index >> 6;
|
||||
long bitmask = 1L << index;
|
||||
bits[wordNum] &= ~bitmask;
|
||||
// hmmm, it takes one more instruction to clear than it does to set... any
|
||||
// way to work around this? If there were only 63 bits per word, we could
|
||||
// use a right shift of 10111111...111 in binary to position the 0 in the
|
||||
// correct place (using sign extension).
|
||||
// Could also use Long.rotateRight() or rotateLeft() *if* they were converted
|
||||
// by the JVM into a native instruction.
|
||||
// bits[word] &= Long.rotateLeft(0xfffffffe,bit);
|
||||
}
|
||||
|
||||
/** clears a bit.
|
||||
* The index should be less than the OpenBitSet size.
|
||||
*/
|
||||
public void fastClear(long index) {
|
||||
assert index >= 0 && index < numBits;
|
||||
int wordNum = (int)(index >> 6); // div 64
|
||||
long bitmask = 1L << index;
|
||||
bits[wordNum] &= ~bitmask;
|
||||
}
|
||||
|
||||
/** clears a bit, allowing access beyond the current set size without changing the size.*/
|
||||
public void clear(long index) {
|
||||
int wordNum = (int)(index >> 6); // div 64
|
||||
if (wordNum>=wlen) return;
|
||||
long bitmask = 1L << index;
|
||||
bits[wordNum] &= ~bitmask;
|
||||
}
|
||||
|
||||
/** Clears a range of bits. Clearing past the end does not change the size of the set.
|
||||
*
|
||||
* @param startIndex lower index
|
||||
* @param endIndex one-past the last bit to clear
|
||||
*/
|
||||
public void clear(int startIndex, int endIndex) {
|
||||
if (endIndex <= startIndex) return;
|
||||
|
||||
int startWord = (startIndex>>6);
|
||||
if (startWord >= wlen) return;
|
||||
|
||||
// since endIndex is one past the end, this is index of the last
|
||||
// word to be changed.
|
||||
int endWord = ((endIndex-1)>>6);
|
||||
|
||||
long startmask = -1L << startIndex;
|
||||
long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex due to wrap
|
||||
|
||||
// invert masks since we are clearing
|
||||
startmask = ~startmask;
|
||||
endmask = ~endmask;
|
||||
|
||||
if (startWord == endWord) {
|
||||
bits[startWord] &= (startmask | endmask);
|
||||
return;
|
||||
}
|
||||
|
||||
bits[startWord] &= startmask;
|
||||
|
||||
int middle = Math.min(wlen, endWord);
|
||||
Arrays.fill(bits, startWord+1, middle, 0L);
|
||||
if (endWord < wlen) {
|
||||
bits[endWord] &= endmask;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Clears a range of bits. Clearing past the end does not change the size of the set.
|
||||
*
|
||||
* @param startIndex lower index
|
||||
* @param endIndex one-past the last bit to clear
|
||||
*/
|
||||
public void clear(long startIndex, long endIndex) {
|
||||
if (endIndex <= startIndex) return;
|
||||
|
||||
int startWord = (int)(startIndex>>6);
|
||||
if (startWord >= wlen) return;
|
||||
|
||||
// since endIndex is one past the end, this is index of the last
|
||||
// word to be changed.
|
||||
int endWord = (int)((endIndex-1)>>6);
|
||||
|
||||
long startmask = -1L << startIndex;
|
||||
long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex due to wrap
|
||||
|
||||
// invert masks since we are clearing
|
||||
startmask = ~startmask;
|
||||
endmask = ~endmask;
|
||||
|
||||
if (startWord == endWord) {
|
||||
bits[startWord] &= (startmask | endmask);
|
||||
return;
|
||||
}
|
||||
|
||||
bits[startWord] &= startmask;
|
||||
|
||||
int middle = Math.min(wlen, endWord);
|
||||
Arrays.fill(bits, startWord+1, middle, 0L);
|
||||
if (endWord < wlen) {
|
||||
bits[endWord] &= endmask;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Sets a bit and returns the previous value.
|
||||
* The index should be less than the OpenBitSet size.
|
||||
*/
|
||||
public boolean getAndSet(int index) {
|
||||
assert index >= 0 && index < numBits;
|
||||
int wordNum = index >> 6; // div 64
|
||||
long bitmask = 1L << index;
|
||||
boolean val = (bits[wordNum] & bitmask) != 0;
|
||||
bits[wordNum] |= bitmask;
|
||||
return val;
|
||||
}
|
||||
|
||||
/** Sets a bit and returns the previous value.
|
||||
* The index should be less than the OpenBitSet size.
|
||||
*/
|
||||
public boolean getAndSet(long index) {
|
||||
assert index >= 0 && index < numBits;
|
||||
int wordNum = (int)(index >> 6); // div 64
|
||||
long bitmask = 1L << index;
|
||||
boolean val = (bits[wordNum] & bitmask) != 0;
|
||||
bits[wordNum] |= bitmask;
|
||||
return val;
|
||||
}
|
||||
|
||||
/** flips a bit.
|
||||
* The index should be less than the OpenBitSet size.
|
||||
*/
|
||||
public void fastFlip(int index) {
|
||||
assert index >= 0 && index < numBits;
|
||||
int wordNum = index >> 6; // div 64
|
||||
long bitmask = 1L << index;
|
||||
bits[wordNum] ^= bitmask;
|
||||
}
|
||||
|
||||
/** flips a bit.
|
||||
* The index should be less than the OpenBitSet size.
|
||||
*/
|
||||
public void fastFlip(long index) {
|
||||
assert index >= 0 && index < numBits;
|
||||
int wordNum = (int)(index >> 6); // div 64
|
||||
long bitmask = 1L << index;
|
||||
bits[wordNum] ^= bitmask;
|
||||
}
|
||||
|
||||
/** flips a bit, expanding the set size if necessary */
|
||||
public void flip(long index) {
|
||||
int wordNum = expandingWordNum(index);
|
||||
long bitmask = 1L << index;
|
||||
bits[wordNum] ^= bitmask;
|
||||
}
|
||||
|
||||
/** flips a bit and returns the resulting bit value.
|
||||
* The index should be less than the OpenBitSet size.
|
||||
*/
|
||||
public boolean flipAndGet(int index) {
|
||||
assert index >= 0 && index < numBits;
|
||||
int wordNum = index >> 6; // div 64
|
||||
long bitmask = 1L << index;
|
||||
bits[wordNum] ^= bitmask;
|
||||
return (bits[wordNum] & bitmask) != 0;
|
||||
}
|
||||
|
||||
/** flips a bit and returns the resulting bit value.
|
||||
* The index should be less than the OpenBitSet size.
|
||||
*/
|
||||
public boolean flipAndGet(long index) {
|
||||
assert index >= 0 && index < numBits;
|
||||
int wordNum = (int)(index >> 6); // div 64
|
||||
long bitmask = 1L << index;
|
||||
bits[wordNum] ^= bitmask;
|
||||
return (bits[wordNum] & bitmask) != 0;
|
||||
}
|
||||
|
||||
/** Flips a range of bits, expanding the set size if necessary
|
||||
*
|
||||
* @param startIndex lower index
|
||||
* @param endIndex one-past the last bit to flip
|
||||
*/
|
||||
public void flip(long startIndex, long endIndex) {
|
||||
if (endIndex <= startIndex) return;
|
||||
int startWord = (int)(startIndex>>6);
|
||||
|
||||
// since endIndex is one past the end, this is index of the last
|
||||
// word to be changed.
|
||||
int endWord = expandingWordNum(endIndex-1);
|
||||
|
||||
/*** Grrr, java shifting wraps around so -1L>>>64 == -1
|
||||
* for that reason, make sure not to use endmask if the bits to flip will
|
||||
* be zero in the last word (redefine endWord to be the last changed...)
|
||||
long startmask = -1L << (startIndex & 0x3f); // example: 11111...111000
|
||||
long endmask = -1L >>> (64-(endIndex & 0x3f)); // example: 00111...111111
|
||||
***/
|
||||
|
||||
long startmask = -1L << startIndex;
|
||||
long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex due to wrap
|
||||
|
||||
if (startWord == endWord) {
|
||||
bits[startWord] ^= (startmask & endmask);
|
||||
return;
|
||||
}
|
||||
|
||||
bits[startWord] ^= startmask;
|
||||
|
||||
for (int i=startWord+1; i<endWord; i++) {
|
||||
bits[i] = ~bits[i];
|
||||
}
|
||||
|
||||
bits[endWord] ^= endmask;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
public static int pop(long v0, long v1, long v2, long v3) {
|
||||
// derived from pop_array by setting last four elems to 0.
|
||||
// exchanges one pop() call for 10 elementary operations
|
||||
// saving about 7 instructions... is there a better way?
|
||||
long twosA=v0 & v1;
|
||||
long ones=v0^v1;
|
||||
|
||||
long u2=ones^v2;
|
||||
long twosB =(ones&v2)|(u2&v3);
|
||||
ones=u2^v3;
|
||||
|
||||
long fours=(twosA&twosB);
|
||||
long twos=twosA^twosB;
|
||||
|
||||
return (pop(fours)<<2)
|
||||
+ (pop(twos)<<1)
|
||||
+ pop(ones);
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/** @return the number of set bits */
|
||||
public long cardinality() {
|
||||
return BitUtil.pop_array(bits,0,wlen);
|
||||
}
|
||||
|
||||
/** Returns the popcount or cardinality of the intersection of the two sets.
|
||||
* Neither set is modified.
|
||||
*/
|
||||
public static long intersectionCount(OpenBitSet a, OpenBitSet b) {
|
||||
return BitUtil.pop_intersect(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen));
|
||||
}
|
||||
|
||||
/** Returns the popcount or cardinality of the union of the two sets.
|
||||
* Neither set is modified.
|
||||
*/
|
||||
public static long unionCount(OpenBitSet a, OpenBitSet b) {
|
||||
long tot = BitUtil.pop_union(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen));
|
||||
if (a.wlen < b.wlen) {
|
||||
tot += BitUtil.pop_array(b.bits, a.wlen, b.wlen-a.wlen);
|
||||
} else if (a.wlen > b.wlen) {
|
||||
tot += BitUtil.pop_array(a.bits, b.wlen, a.wlen-b.wlen);
|
||||
}
|
||||
return tot;
|
||||
}
|
||||
|
||||
/** Returns the popcount or cardinality of "a and not b"
|
||||
* or "intersection(a, not(b))".
|
||||
* Neither set is modified.
|
||||
*/
|
||||
public static long andNotCount(OpenBitSet a, OpenBitSet b) {
|
||||
long tot = BitUtil.pop_andnot(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen));
|
||||
if (a.wlen > b.wlen) {
|
||||
tot += BitUtil.pop_array(a.bits, b.wlen, a.wlen-b.wlen);
|
||||
}
|
||||
return tot;
|
||||
}
|
||||
|
||||
/** Returns the popcount or cardinality of the exclusive-or of the two sets.
|
||||
* Neither set is modified.
|
||||
*/
|
||||
public static long xorCount(OpenBitSet a, OpenBitSet b) {
|
||||
long tot = BitUtil.pop_xor(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen));
|
||||
if (a.wlen < b.wlen) {
|
||||
tot += BitUtil.pop_array(b.bits, a.wlen, b.wlen-a.wlen);
|
||||
} else if (a.wlen > b.wlen) {
|
||||
tot += BitUtil.pop_array(a.bits, b.wlen, a.wlen-b.wlen);
|
||||
}
|
||||
return tot;
|
||||
}
|
||||
|
||||
|
||||
/** Returns the index of the first set bit starting at the index specified.
|
||||
* -1 is returned if there are no more set bits.
|
||||
*/
|
||||
public int nextSetBit(int index) {
|
||||
int i = index>>6;
|
||||
if (i>=wlen) return -1;
|
||||
int subIndex = index & 0x3f; // index within the word
|
||||
long word = bits[i] >> subIndex; // skip all the bits to the right of index
|
||||
|
||||
if (word!=0) {
|
||||
return (i<<6) + subIndex + Long.numberOfTrailingZeros(word);
|
||||
}
|
||||
|
||||
while(++i < wlen) {
|
||||
word = bits[i];
|
||||
if (word!=0) return (i<<6) + Long.numberOfTrailingZeros(word);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Returns the index of the first set bit starting at the index specified.
|
||||
* -1 is returned if there are no more set bits.
|
||||
*/
|
||||
public long nextSetBit(long index) {
|
||||
int i = (int)(index>>>6);
|
||||
if (i>=wlen) return -1;
|
||||
int subIndex = (int)index & 0x3f; // index within the word
|
||||
long word = bits[i] >>> subIndex; // skip all the bits to the right of index
|
||||
|
||||
if (word!=0) {
|
||||
return (((long)i)<<6) + (subIndex + Long.numberOfTrailingZeros(word));
|
||||
}
|
||||
|
||||
while(++i < wlen) {
|
||||
word = bits[i];
|
||||
if (word!=0) return (((long)i)<<6) + Long.numberOfTrailingZeros(word);
|
||||
}
|
||||
|
||||
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 int prevSetBit(int index) {
|
||||
int i = 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 = index & 0x3f; // index within the word
|
||||
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;
|
||||
}
|
||||
|
||||
/** 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 OpenBitSet clone() {
|
||||
try {
|
||||
OpenBitSet obs = (OpenBitSet)super.clone();
|
||||
obs.bits = obs.bits.clone(); // hopefully an array clone is as fast(er) than arraycopy
|
||||
return obs;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** this = this AND other */
|
||||
public void intersect(OpenBitSet other) {
|
||||
int newLen= Math.min(this.wlen,other.wlen);
|
||||
long[] thisArr = this.bits;
|
||||
long[] otherArr = other.bits;
|
||||
// testing against zero can be more efficient
|
||||
int pos=newLen;
|
||||
while(--pos>=0) {
|
||||
thisArr[pos] &= otherArr[pos];
|
||||
}
|
||||
if (this.wlen > newLen) {
|
||||
// fill zeros from the new shorter length to the old length
|
||||
Arrays.fill(bits,newLen,this.wlen,0);
|
||||
}
|
||||
this.wlen = newLen;
|
||||
}
|
||||
|
||||
/** this = this OR other */
|
||||
public void union(OpenBitSet other) {
|
||||
int newLen = Math.max(wlen,other.wlen);
|
||||
ensureCapacityWords(newLen);
|
||||
assert (numBits = Math.max(other.numBits, numBits)) >= 0;
|
||||
|
||||
long[] thisArr = this.bits;
|
||||
long[] otherArr = other.bits;
|
||||
int pos=Math.min(wlen,other.wlen);
|
||||
while(--pos>=0) {
|
||||
thisArr[pos] |= otherArr[pos];
|
||||
}
|
||||
if (this.wlen < newLen) {
|
||||
System.arraycopy(otherArr, this.wlen, thisArr, this.wlen, newLen-this.wlen);
|
||||
}
|
||||
this.wlen = newLen;
|
||||
}
|
||||
|
||||
|
||||
/** Remove all elements set in other. this = this AND_NOT other */
|
||||
public void remove(OpenBitSet other) {
|
||||
int idx = Math.min(wlen,other.wlen);
|
||||
long[] thisArr = this.bits;
|
||||
long[] otherArr = other.bits;
|
||||
while(--idx>=0) {
|
||||
thisArr[idx] &= ~otherArr[idx];
|
||||
}
|
||||
}
|
||||
|
||||
/** this = this XOR other */
|
||||
public void xor(OpenBitSet other) {
|
||||
int newLen = Math.max(wlen,other.wlen);
|
||||
ensureCapacityWords(newLen);
|
||||
assert (numBits = Math.max(other.numBits, numBits)) >= 0;
|
||||
|
||||
long[] thisArr = this.bits;
|
||||
long[] otherArr = other.bits;
|
||||
int pos=Math.min(wlen,other.wlen);
|
||||
while(--pos>=0) {
|
||||
thisArr[pos] ^= otherArr[pos];
|
||||
}
|
||||
if (this.wlen < newLen) {
|
||||
System.arraycopy(otherArr, this.wlen, thisArr, this.wlen, newLen-this.wlen);
|
||||
}
|
||||
this.wlen = newLen;
|
||||
}
|
||||
|
||||
|
||||
// some BitSet compatability methods
|
||||
|
||||
//** see {@link intersect} */
|
||||
public void and(OpenBitSet other) {
|
||||
intersect(other);
|
||||
}
|
||||
|
||||
//** see {@link union} */
|
||||
public void or(OpenBitSet other) {
|
||||
union(other);
|
||||
}
|
||||
|
||||
//** see {@link andNot} */
|
||||
public void andNot(OpenBitSet other) {
|
||||
remove(other);
|
||||
}
|
||||
|
||||
/** returns true if the sets have any elements in common */
|
||||
public boolean intersects(OpenBitSet other) {
|
||||
int pos = Math.min(this.wlen, other.wlen);
|
||||
long[] thisArr = this.bits;
|
||||
long[] otherArr = other.bits;
|
||||
while (--pos>=0) {
|
||||
if ((thisArr[pos] & otherArr[pos])!=0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Expand the long[] with the size given as a number of words (64 bit longs). */
|
||||
public void ensureCapacityWords(int numWords) {
|
||||
bits = ArrayUtil.grow(bits, numWords);
|
||||
wlen = numWords;
|
||||
assert (this.numBits = Math.max(this.numBits, numWords << 6)) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the long[] is big enough to hold numBits, expanding it if
|
||||
* necessary.
|
||||
*/
|
||||
public void ensureCapacity(long numBits) {
|
||||
ensureCapacityWords(bits2words(numBits));
|
||||
// ensureCapacityWords sets numBits to a multiple of 64, but we want to set
|
||||
// it to exactly what the app asked.
|
||||
assert (this.numBits = Math.max(this.numBits, numBits)) >= 0;
|
||||
}
|
||||
|
||||
/** Lowers numWords, the number of words in use,
|
||||
* by checking for trailing zero words.
|
||||
*/
|
||||
public void trimTrailingZeros() {
|
||||
int idx = wlen-1;
|
||||
while (idx>=0 && bits[idx]==0) idx--;
|
||||
wlen = idx+1;
|
||||
}
|
||||
|
||||
/** returns the number of 64 bit words it would take to hold numBits */
|
||||
public static int bits2words(long numBits) {
|
||||
return (int)(((numBits-1)>>>6)+1);
|
||||
}
|
||||
|
||||
/** returns true if both sets have the same bits set */
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof OpenBitSet)) return false;
|
||||
OpenBitSet a;
|
||||
OpenBitSet b = (OpenBitSet)o;
|
||||
// make a the larger set.
|
||||
if (b.wlen > this.wlen) {
|
||||
a = b; b=this;
|
||||
} else {
|
||||
a=this;
|
||||
}
|
||||
|
||||
// check for any set bits out of the range of b
|
||||
for (int i=a.wlen-1; i>=b.wlen; i--) {
|
||||
if (a.bits[i]!=0) return false;
|
||||
}
|
||||
|
||||
for (int i=b.wlen-1; i>=0; i--) {
|
||||
if (a.bits[i] != b.bits[i]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// Start with a zero hash and use a mix that results in zero if the input is zero.
|
||||
// This effectively truncates trailing zeros without an explicit check.
|
||||
long h = 0;
|
||||
for (int i = bits.length; --i>=0;) {
|
||||
h ^= bits[i];
|
||||
h = (h << 1) | (h >>> 63); // rotate left
|
||||
}
|
||||
// fold leftmost bits into right and add a constant to prevent
|
||||
// empty sets from returning 0, which is too common.
|
||||
return (int)((h>>32) ^ h) + 0x98761234;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
package org.apache.lucene.util;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import org.apache.lucene.search.DocIdSetIterator;
|
||||
|
||||
/** OpenBitSet with added methods to bulk-update the bits
|
||||
* from a {@link DocIdSetIterator}. */
|
||||
public class OpenBitSetDISI extends OpenBitSet {
|
||||
|
||||
/** Construct an OpenBitSetDISI with its bits set
|
||||
* from the doc ids of the given DocIdSetIterator.
|
||||
* Also give a maximum size one larger than the largest doc id for which a
|
||||
* bit may ever be set on this OpenBitSetDISI.
|
||||
*/
|
||||
public OpenBitSetDISI(DocIdSetIterator disi, int maxSize) throws IOException {
|
||||
super(maxSize);
|
||||
inPlaceOr(disi);
|
||||
}
|
||||
|
||||
/** Construct an OpenBitSetDISI with no bits set, and a given maximum size
|
||||
* one larger than the largest doc id for which a bit may ever be set
|
||||
* on this OpenBitSetDISI.
|
||||
*/
|
||||
public OpenBitSetDISI(int maxSize) {
|
||||
super(maxSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an inplace OR with the doc ids from a given DocIdSetIterator,
|
||||
* setting the bit for each such doc id.
|
||||
* These doc ids should be smaller than the maximum size passed to the
|
||||
* constructor.
|
||||
*/
|
||||
public void inPlaceOr(DocIdSetIterator disi) throws IOException {
|
||||
int doc;
|
||||
long size = size();
|
||||
while ((doc = disi.nextDoc()) < size) {
|
||||
fastSet(doc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an inplace AND with the doc ids from a given DocIdSetIterator,
|
||||
* leaving only the bits set for which the doc ids are in common.
|
||||
* These doc ids should be smaller than the maximum size passed to the
|
||||
* constructor.
|
||||
*/
|
||||
public void inPlaceAnd(DocIdSetIterator disi) throws IOException {
|
||||
int bitSetDoc = nextSetBit(0);
|
||||
int disiDoc;
|
||||
while (bitSetDoc != -1 && (disiDoc = disi.advance(bitSetDoc)) != DocIdSetIterator.NO_MORE_DOCS) {
|
||||
clear(bitSetDoc, disiDoc);
|
||||
bitSetDoc = nextSetBit(disiDoc + 1);
|
||||
}
|
||||
if (bitSetDoc != -1) {
|
||||
clear(bitSetDoc, size());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an inplace NOT with the doc ids from a given DocIdSetIterator,
|
||||
* clearing all the bits for each such doc id.
|
||||
* These doc ids should be smaller than the maximum size passed to the
|
||||
* constructor.
|
||||
*/
|
||||
public void inPlaceNot(DocIdSetIterator disi) throws IOException {
|
||||
int doc;
|
||||
long size = size();
|
||||
while ((doc = disi.nextDoc()) < size) {
|
||||
fastClear(doc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an inplace XOR with the doc ids from a given DocIdSetIterator,
|
||||
* flipping all the bits for each such doc id.
|
||||
* These doc ids should be smaller than the maximum size passed to the
|
||||
* constructor.
|
||||
*/
|
||||
public void inPlaceXor(DocIdSetIterator disi) throws IOException {
|
||||
int doc;
|
||||
long size = size();
|
||||
while ((doc = disi.nextDoc()) < size) {
|
||||
fastFlip(doc);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,148 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.lucene.search.DocIdSetIterator;
|
||||
|
||||
/** An iterator to iterate over set bits in an OpenBitSet.
|
||||
* This is faster than nextSetBit() for iterating over the complete set of bits,
|
||||
* especially when the density of the bits set is high.
|
||||
*/
|
||||
public class OpenBitSetIterator extends DocIdSetIterator {
|
||||
|
||||
// hmmm, what about an iterator that finds zeros though,
|
||||
// or a reverse iterator... should they be separate classes
|
||||
// for efficiency, or have a common root interface? (or
|
||||
// maybe both? could ask for a SetBitsIterator, etc...
|
||||
|
||||
final long[] arr;
|
||||
final int words;
|
||||
private int i=-1;
|
||||
private long word;
|
||||
private int wordShift;
|
||||
private int indexArray;
|
||||
private int curDocId = -1;
|
||||
|
||||
public OpenBitSetIterator(OpenBitSet obs) {
|
||||
this(obs.getBits(), obs.getNumWords());
|
||||
}
|
||||
|
||||
public OpenBitSetIterator(long[] bits, int numWords) {
|
||||
arr = bits;
|
||||
words = numWords;
|
||||
}
|
||||
|
||||
// 64 bit shifts
|
||||
private void shift() {
|
||||
if ((int)word ==0) {wordShift +=32; word = word >>>32; }
|
||||
if ((word & 0x0000FFFF) == 0) { wordShift +=16; word >>>=16; }
|
||||
if ((word & 0x000000FF) == 0) { wordShift +=8; word >>>=8; }
|
||||
indexArray = BitUtil.bitList((byte) word);
|
||||
}
|
||||
|
||||
/***** alternate shift implementations
|
||||
// 32 bit shifts, but a long shift needed at the end
|
||||
private void shift2() {
|
||||
int y = (int)word;
|
||||
if (y==0) {wordShift +=32; y = (int)(word >>>32); }
|
||||
if ((y & 0x0000FFFF) == 0) { wordShift +=16; y>>>=16; }
|
||||
if ((y & 0x000000FF) == 0) { wordShift +=8; y>>>=8; }
|
||||
indexArray = bitlist[y & 0xff];
|
||||
word >>>= (wordShift +1);
|
||||
}
|
||||
|
||||
private void shift3() {
|
||||
int lower = (int)word;
|
||||
int lowByte = lower & 0xff;
|
||||
if (lowByte != 0) {
|
||||
indexArray=bitlist[lowByte];
|
||||
return;
|
||||
}
|
||||
shift();
|
||||
}
|
||||
******/
|
||||
|
||||
@Override
|
||||
public int nextDoc() {
|
||||
if (indexArray == 0) {
|
||||
if (word != 0) {
|
||||
word >>>= 8;
|
||||
wordShift += 8;
|
||||
}
|
||||
|
||||
while (word == 0) {
|
||||
if (++i >= words) {
|
||||
return curDocId = NO_MORE_DOCS;
|
||||
}
|
||||
word = arr[i];
|
||||
wordShift = -1; // loop invariant code motion should move this
|
||||
}
|
||||
|
||||
// after the first time, should I go with a linear search, or
|
||||
// stick with the binary search in shift?
|
||||
shift();
|
||||
}
|
||||
|
||||
int bitIndex = (indexArray & 0x0f) + wordShift;
|
||||
indexArray >>>= 4;
|
||||
// should i<<6 be cached as a separate variable?
|
||||
// it would only save one cycle in the best circumstances.
|
||||
return curDocId = (i<<6) + bitIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int advance(int target) {
|
||||
indexArray = 0;
|
||||
i = target >> 6;
|
||||
if (i >= words) {
|
||||
word = 0; // setup so next() will also return -1
|
||||
return curDocId = NO_MORE_DOCS;
|
||||
}
|
||||
wordShift = target & 0x3f;
|
||||
word = arr[i] >>> wordShift;
|
||||
if (word != 0) {
|
||||
wordShift--; // compensate for 1 based arrIndex
|
||||
} else {
|
||||
while (word == 0) {
|
||||
if (++i >= words) {
|
||||
return curDocId = NO_MORE_DOCS;
|
||||
}
|
||||
word = arr[i];
|
||||
}
|
||||
wordShift = -1;
|
||||
}
|
||||
|
||||
shift();
|
||||
|
||||
int bitIndex = (indexArray & 0x0f) + wordShift;
|
||||
indexArray >>>= 4;
|
||||
// should i<<6 be cached as a separate variable?
|
||||
// it would only save one cycle in the best circumstances.
|
||||
return curDocId = (i<<6) + bitIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int docID() {
|
||||
return curDocId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long cost() {
|
||||
return words / 64;
|
||||
}
|
||||
}
|
|
@ -1376,16 +1376,6 @@ public final class FST<T> implements Accountable {
|
|||
public abstract boolean reversed();
|
||||
}
|
||||
|
||||
private static class ArcAndState<T> {
|
||||
final Arc<T> arc;
|
||||
final IntsRef chain;
|
||||
|
||||
public ArcAndState(Arc<T> arc, IntsRef chain) {
|
||||
this.arc = arc;
|
||||
this.chain = chain;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public void countSingleChains() throws IOException {
|
||||
// TODO: must assert this FST was built with
|
||||
|
|
|
@ -815,22 +815,6 @@ public class PackedInts {
|
|||
throw new AssertionError("Unknown Writer format: " + format);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expert: Restore a {@link Reader} from a stream without reading metadata at
|
||||
* the beginning of the stream. This method is useful to restore data when
|
||||
* metadata has been previously read using {@link #readHeader(DataInput)}.
|
||||
*
|
||||
* @param in the stream to read data from, positioned at the beginning of the packed values
|
||||
* @param header metadata result from <code>readHeader()</code>
|
||||
* @return a Reader
|
||||
* @throws IOException If there is a low-level I/O error
|
||||
* @see #readHeader(DataInput)
|
||||
* @lucene.internal
|
||||
*/
|
||||
public static Reader getReaderNoHeader(DataInput in, Header header) throws IOException {
|
||||
return getReaderNoHeader(in, header.format, header.version, header.valueCount, header.bitsPerValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore a {@link Reader} from a stream.
|
||||
|
@ -943,23 +927,6 @@ public class PackedInts {
|
|||
throw new AssertionError("Unknwown format: " + format);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expert: Construct a direct {@link Reader} from an {@link IndexInput}
|
||||
* without reading metadata at the beginning of the stream. This method is
|
||||
* useful to restore data when metadata has been previously read using
|
||||
* {@link #readHeader(DataInput)}.
|
||||
*
|
||||
* @param in the stream to read data from, positioned at the beginning of the packed values
|
||||
* @param header metadata result from <code>readHeader()</code>
|
||||
* @return a Reader
|
||||
* @throws IOException If there is a low-level I/O error
|
||||
* @see #readHeader(DataInput)
|
||||
* @lucene.internal
|
||||
*/
|
||||
public static Reader getDirectReaderNoHeader(IndexInput in, Header header) throws IOException {
|
||||
return getDirectReaderNoHeader(in, header.format, header.version, header.valueCount, header.bitsPerValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a direct {@link Reader} from an {@link IndexInput}. This method
|
||||
|
@ -1216,42 +1183,6 @@ public class PackedInts {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expert: reads only the metadata from a stream. This is useful to later
|
||||
* restore a stream or open a direct reader via
|
||||
* {@link #getReaderNoHeader(DataInput, Header)}
|
||||
* or {@link #getDirectReaderNoHeader(IndexInput, Header)}.
|
||||
* @param in the stream to read data
|
||||
* @return packed integer metadata.
|
||||
* @throws IOException If there is a low-level I/O error
|
||||
* @see #getReaderNoHeader(DataInput, Header)
|
||||
* @see #getDirectReaderNoHeader(IndexInput, Header)
|
||||
*/
|
||||
public static Header readHeader(DataInput in) throws IOException {
|
||||
final int version = CodecUtil.checkHeader(in, CODEC_NAME, VERSION_START, VERSION_CURRENT);
|
||||
final int bitsPerValue = in.readVInt();
|
||||
assert bitsPerValue > 0 && bitsPerValue <= 64: "bitsPerValue=" + bitsPerValue;
|
||||
final int valueCount = in.readVInt();
|
||||
final Format format = Format.byId(in.readVInt());
|
||||
return new Header(format, valueCount, bitsPerValue, version);
|
||||
}
|
||||
|
||||
/** Header identifying the structure of a packed integer array. */
|
||||
public static class Header {
|
||||
|
||||
private final Format format;
|
||||
private final int valueCount;
|
||||
private final int bitsPerValue;
|
||||
private final int version;
|
||||
|
||||
public Header(Format format, int valueCount, int bitsPerValue, int version) {
|
||||
this.format = format;
|
||||
this.valueCount = valueCount;
|
||||
this.bitsPerValue = bitsPerValue;
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
|
||||
/** Check that the block size is a power of 2, in the right bounds, and return
|
||||
* its log in base 2. */
|
||||
static int checkBlockSize(int blockSize, int minBlockSize, int maxBlockSize) {
|
||||
|
|
|
@ -118,7 +118,7 @@ which implements files as memory-resident data structures.</li>
|
|||
|
||||
<li>
|
||||
<b>{@link org.apache.lucene.util}</b>
|
||||
contains a few handy data structures and util classes, ie {@link org.apache.lucene.util.OpenBitSet OpenBitSet}
|
||||
contains a few handy data structures and util classes, ie {@link org.apache.lucene.util.FixedBitSet FixedBitSet}
|
||||
and {@link org.apache.lucene.util.PriorityQueue PriorityQueue}.</li>
|
||||
</ul>
|
||||
To use Lucene, an application should:
|
||||
|
|
|
@ -1,188 +0,0 @@
|
|||
package org.apache.lucene.util;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import org.apache.lucene.util.LuceneTestCase;
|
||||
|
||||
public class TestDoubleBarrelLRUCache extends LuceneTestCase {
|
||||
|
||||
private void testCache(DoubleBarrelLRUCache<CloneableInteger,Object> cache, int n) throws Exception {
|
||||
Object dummy = new Object();
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
cache.put(new CloneableInteger(i), dummy);
|
||||
}
|
||||
|
||||
// access every 2nd item in cache
|
||||
for (int i = 0; i < n; i+=2) {
|
||||
assertNotNull(cache.get(new CloneableInteger(i)));
|
||||
}
|
||||
|
||||
// add n/2 elements to cache, the ones that weren't
|
||||
// touched in the previous loop should now be thrown away
|
||||
for (int i = n; i < n + (n / 2); i++) {
|
||||
cache.put(new CloneableInteger(i), dummy);
|
||||
}
|
||||
|
||||
// access every 4th item in cache
|
||||
for (int i = 0; i < n; i+=4) {
|
||||
assertNotNull(cache.get(new CloneableInteger(i)));
|
||||
}
|
||||
|
||||
// add 3/4n elements to cache, the ones that weren't
|
||||
// touched in the previous loops should now be thrown away
|
||||
for (int i = n; i < n + (n * 3 / 4); i++) {
|
||||
cache.put(new CloneableInteger(i), dummy);
|
||||
}
|
||||
|
||||
// access every 4th item in cache
|
||||
for (int i = 0; i < n; i+=4) {
|
||||
assertNotNull(cache.get(new CloneableInteger(i)));
|
||||
}
|
||||
}
|
||||
|
||||
public void testLRUCache() throws Exception {
|
||||
final int n = 100;
|
||||
testCache(new DoubleBarrelLRUCache<CloneableInteger,Object>(n), n);
|
||||
}
|
||||
|
||||
private class CacheThread extends Thread {
|
||||
private final CloneableObject[] objs;
|
||||
private final DoubleBarrelLRUCache<CloneableObject,Object> c;
|
||||
private final long endTime;
|
||||
volatile boolean failed;
|
||||
|
||||
public CacheThread(DoubleBarrelLRUCache<CloneableObject,Object> c,
|
||||
CloneableObject[] objs, long endTime) {
|
||||
this.c = c;
|
||||
this.objs = objs;
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
long count = 0;
|
||||
long miss = 0;
|
||||
long hit = 0;
|
||||
final int limit = objs.length;
|
||||
|
||||
while(true) {
|
||||
final CloneableObject obj = objs[(int) ((count/2) % limit)];
|
||||
Object v = c.get(obj);
|
||||
if (v == null) {
|
||||
c.put(new CloneableObject(obj), obj);
|
||||
miss++;
|
||||
} else {
|
||||
assert obj == v;
|
||||
hit++;
|
||||
}
|
||||
if ((++count % 10000) == 0) {
|
||||
if (System.currentTimeMillis() >= endTime) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addResults(miss, hit);
|
||||
} catch (Throwable t) {
|
||||
failed = true;
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long totMiss, totHit;
|
||||
void addResults(long miss, long hit) {
|
||||
totMiss += miss;
|
||||
totHit += hit;
|
||||
}
|
||||
|
||||
public void testThreadCorrectness() throws Exception {
|
||||
final int NUM_THREADS = 4;
|
||||
final int CACHE_SIZE = 512;
|
||||
final int OBJ_COUNT = 3*CACHE_SIZE;
|
||||
|
||||
DoubleBarrelLRUCache<CloneableObject,Object> c = new DoubleBarrelLRUCache<>(1024);
|
||||
|
||||
CloneableObject[] objs = new CloneableObject[OBJ_COUNT];
|
||||
for(int i=0;i<OBJ_COUNT;i++) {
|
||||
objs[i] = new CloneableObject(new Object());
|
||||
}
|
||||
|
||||
final CacheThread[] threads = new CacheThread[NUM_THREADS];
|
||||
final long endTime = System.currentTimeMillis()+1000L;
|
||||
for(int i=0;i<NUM_THREADS;i++) {
|
||||
threads[i] = new CacheThread(c, objs, endTime);
|
||||
threads[i].start();
|
||||
}
|
||||
for(int i=0;i<NUM_THREADS;i++) {
|
||||
threads[i].join();
|
||||
assert !threads[i].failed;
|
||||
}
|
||||
//System.out.println("hits=" + totHit + " misses=" + totMiss);
|
||||
}
|
||||
|
||||
private static class CloneableObject extends DoubleBarrelLRUCache.CloneableKey {
|
||||
private Object value;
|
||||
|
||||
public CloneableObject(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return this.value.equals(((CloneableObject) other).value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CloneableObject clone() {
|
||||
return new CloneableObject(value);
|
||||
}
|
||||
}
|
||||
|
||||
protected static class CloneableInteger extends DoubleBarrelLRUCache.CloneableKey {
|
||||
private Integer value;
|
||||
|
||||
public CloneableInteger(Integer value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return this.value.equals(((CloneableInteger) other).value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CloneableInteger clone() {
|
||||
return new CloneableInteger(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,369 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.BitSet;
|
||||
|
||||
import org.apache.lucene.search.DocIdSetIterator;
|
||||
|
||||
public class TestOpenBitSet extends BaseDocIdSetTestCase<OpenBitSet> {
|
||||
|
||||
@Override
|
||||
public OpenBitSet copyOf(BitSet bs, int length) throws IOException {
|
||||
final OpenBitSet set = new OpenBitSet(length);
|
||||
for (int doc = bs.nextSetBit(0); doc != -1; doc = bs.nextSetBit(doc + 1)) {
|
||||
set.set(doc);
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
void doGet(BitSet a, OpenBitSet b) {
|
||||
int max = a.size();
|
||||
for (int i=0; i<max; i++) {
|
||||
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<max; i++) {
|
||||
if (a.get(i) != b.fastGet(i)) {
|
||||
fail("mismatch: BitSet=["+i+"]="+a.get(i));
|
||||
}
|
||||
if (a.get(i) != b.fastGet((long) i)) {
|
||||
fail("mismatch: BitSet=["+i+"]="+a.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void doNextSetBit(BitSet a, OpenBitSet b) {
|
||||
int aa=-1,bb=-1;
|
||||
do {
|
||||
aa = a.nextSetBit(aa+1);
|
||||
bb = b.nextSetBit(bb+1);
|
||||
assertEquals(aa,bb);
|
||||
} while (aa>=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;
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
if (mode==2) doIterate2(a, b);
|
||||
}
|
||||
|
||||
void doIterate1(BitSet a, OpenBitSet b) {
|
||||
int aa=-1,bb=-1;
|
||||
OpenBitSetIterator iterator = new OpenBitSetIterator(b);
|
||||
do {
|
||||
aa = a.nextSetBit(aa+1);
|
||||
bb = random().nextBoolean() ? iterator.nextDoc() : iterator.advance(bb + 1);
|
||||
assertEquals(aa == -1 ? DocIdSetIterator.NO_MORE_DOCS : aa, bb);
|
||||
} while (aa>=0);
|
||||
}
|
||||
|
||||
void doIterate2(BitSet a, OpenBitSet b) {
|
||||
int aa=-1,bb=-1;
|
||||
OpenBitSetIterator iterator = new OpenBitSetIterator(b);
|
||||
do {
|
||||
aa = a.nextSetBit(aa+1);
|
||||
bb = random().nextBoolean() ? iterator.nextDoc() : iterator.advance(bb + 1);
|
||||
assertEquals(aa == -1 ? DocIdSetIterator.NO_MORE_DOCS : aa, bb);
|
||||
} while (aa>=0);
|
||||
}
|
||||
|
||||
void doRandomSets(int maxSize, int iter, int mode) {
|
||||
BitSet a0=null;
|
||||
OpenBitSet b0=null;
|
||||
|
||||
for (int i=0; i<iter; i++) {
|
||||
int sz = random().nextInt(maxSize);
|
||||
BitSet a = new BitSet(sz);
|
||||
OpenBitSet b = new OpenBitSet(sz);
|
||||
|
||||
// test the various ways of setting bits
|
||||
if (sz>0) {
|
||||
int nOper = random().nextInt(sz);
|
||||
for (int j=0; j<nOper; j++) {
|
||||
int idx;
|
||||
|
||||
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);
|
||||
|
||||
boolean val = b.flipAndGet(idx);
|
||||
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));
|
||||
|
||||
if (!val) b.fastClear(idx);
|
||||
assertTrue(b.get(idx) == val);
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
fromIndex = random().nextInt(sz+80);
|
||||
toIndex = fromIndex + random().nextInt((sz>>1)+1);
|
||||
BitSet aa = (BitSet)a.clone(); aa.flip(fromIndex,toIndex);
|
||||
OpenBitSet bb = b.clone(); bb.flip(fromIndex,toIndex);
|
||||
|
||||
doIterate(aa,bb, mode); // a problem here is from flip or doIterate
|
||||
|
||||
fromIndex = random().nextInt(sz+80);
|
||||
toIndex = fromIndex + random().nextInt((sz>>1)+1);
|
||||
aa = (BitSet)a.clone(); aa.clear(fromIndex,toIndex);
|
||||
bb = b.clone(); bb.clear(fromIndex,toIndex);
|
||||
|
||||
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 = b.clone(); bb.set(fromIndex,toIndex);
|
||||
|
||||
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));
|
||||
|
||||
assertEquals(a.cardinality(), b.cardinality());
|
||||
|
||||
BitSet a_and = (BitSet)a.clone(); a_and.and(a0);
|
||||
BitSet a_or = (BitSet)a.clone(); a_or.or(a0);
|
||||
BitSet a_xor = (BitSet)a.clone(); a_xor.xor(a0);
|
||||
BitSet a_andn = (BitSet)a.clone(); a_andn.andNot(a0);
|
||||
|
||||
OpenBitSet b_and = b.clone(); assertEquals(b,b_and); b_and.and(b0);
|
||||
OpenBitSet b_or = b.clone(); b_or.or(b0);
|
||||
OpenBitSet b_xor = b.clone(); b_xor.xor(b0);
|
||||
OpenBitSet b_andn = b.clone(); b_andn.andNot(b0);
|
||||
|
||||
doIterate(a_and,b_and, mode);
|
||||
doIterate(a_or,b_or, mode);
|
||||
doIterate(a_xor,b_xor, mode);
|
||||
doIterate(a_andn,b_andn, mode);
|
||||
|
||||
assertEquals(a_and.cardinality(), b_and.cardinality());
|
||||
assertEquals(a_or.cardinality(), b_or.cardinality());
|
||||
assertEquals(a_xor.cardinality(), b_xor.cardinality());
|
||||
assertEquals(a_andn.cardinality(), b_andn.cardinality());
|
||||
|
||||
// test non-mutating popcounts
|
||||
assertEquals(b_and.cardinality(), OpenBitSet.intersectionCount(b,b0));
|
||||
assertEquals(b_or.cardinality(), OpenBitSet.unionCount(b,b0));
|
||||
assertEquals(b_xor.cardinality(), OpenBitSet.xorCount(b,b0));
|
||||
assertEquals(b_andn.cardinality(), OpenBitSet.andNotCount(b,b0));
|
||||
}
|
||||
|
||||
a0=a;
|
||||
b0=b;
|
||||
}
|
||||
}
|
||||
|
||||
// large enough to flush obvious bugs, small enough to run in <.5 sec as part of a
|
||||
// larger testsuite.
|
||||
public void testSmall() {
|
||||
doRandomSets(atLeast(1200), atLeast(1000), 1);
|
||||
doRandomSets(atLeast(1200), atLeast(1000), 2);
|
||||
}
|
||||
|
||||
// uncomment to run a bigger test (~2 minutes).
|
||||
/*
|
||||
public void testBig() {
|
||||
doRandomSets(2000,200000, 1);
|
||||
doRandomSets(2000,200000, 2);
|
||||
}
|
||||
*/
|
||||
|
||||
public void testEquals() {
|
||||
OpenBitSet b1 = new OpenBitSet(1111);
|
||||
OpenBitSet b2 = new OpenBitSet(2222);
|
||||
assertTrue(b1.equals(b2));
|
||||
assertTrue(b2.equals(b1));
|
||||
b1.set(10);
|
||||
assertFalse(b1.equals(b2));
|
||||
assertFalse(b2.equals(b1));
|
||||
b2.set(10);
|
||||
assertTrue(b1.equals(b2));
|
||||
assertTrue(b2.equals(b1));
|
||||
b2.set(2221);
|
||||
assertFalse(b1.equals(b2));
|
||||
assertFalse(b2.equals(b1));
|
||||
b1.set(2221);
|
||||
assertTrue(b1.equals(b2));
|
||||
assertTrue(b2.equals(b1));
|
||||
|
||||
// try different type of object
|
||||
assertFalse(b1.equals(new Object()));
|
||||
}
|
||||
|
||||
public void testHashCodeEquals() {
|
||||
OpenBitSet bs1 = new OpenBitSet(200);
|
||||
OpenBitSet bs2 = new OpenBitSet(64);
|
||||
bs1.set(3);
|
||||
bs2.set(3);
|
||||
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});
|
||||
}
|
||||
|
||||
public void testEnsureCapacity() {
|
||||
OpenBitSet bits = new OpenBitSet(1);
|
||||
int bit = random().nextInt(100) + 10;
|
||||
bits.ensureCapacity(bit); // make room for more bits
|
||||
bits.fastSet(bit-1);
|
||||
assertTrue(bits.fastGet(bit-1));
|
||||
bits.ensureCapacity(bit + 1);
|
||||
bits.fastSet(bit);
|
||||
assertTrue(bits.fastGet(bit));
|
||||
bits.ensureCapacity(3); // should not change numBits nor grow the array
|
||||
bits.fastSet(3);
|
||||
assertTrue(bits.fastGet(3));
|
||||
bits.fastSet(bit-1);
|
||||
assertTrue(bits.fastGet(bit-1));
|
||||
|
||||
// test ensureCapacityWords
|
||||
int numWords = random().nextInt(10) + 2; // make sure we grow the array (at least 128 bits)
|
||||
bits.ensureCapacityWords(numWords);
|
||||
bit = TestUtil.nextInt(random(), 127, (numWords << 6) - 1); // pick a bit >= to 128, but still within range
|
||||
bits.fastSet(bit);
|
||||
assertTrue(bits.fastGet(bit));
|
||||
bits.fastClear(bit);
|
||||
assertFalse(bits.fastGet(bit));
|
||||
bits.fastFlip(bit);
|
||||
assertTrue(bits.fastGet(bit));
|
||||
bits.ensureCapacityWords(2); // should not change numBits nor grow the array
|
||||
bits.fastSet(3);
|
||||
assertTrue(bits.fastGet(3));
|
||||
bits.fastSet(bit-1);
|
||||
assertTrue(bits.fastGet(bit-1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -172,7 +172,7 @@ public class BoolField extends PrimitiveFieldType {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO - this can be much more efficient - use OpenBitSet or Bits
|
||||
// TODO - this can be much more efficient - use FixedBitSet or Bits
|
||||
class BoolFieldSource extends ValueSource {
|
||||
protected String field;
|
||||
|
||||
|
|
Loading…
Reference in New Issue