mirror of https://github.com/apache/lucene.git
LUCENE-7966: Build Multi-Release JARs to enable usage of optimized intrinsic methods from Java 9 for index bounds checking and array comparison/mismatch
This commit is contained in:
parent
ce5932fc37
commit
9c0797d9f4
|
@ -874,4 +874,5 @@ Test args: [${args}]</echo>
|
|||
|
||||
<!-- useless targets (override common-build.xml): -->
|
||||
<target name="generate-test-reports"/>
|
||||
<target name="patch-mrjar-classes"/>
|
||||
</project>
|
||||
|
|
|
@ -135,6 +135,12 @@ Improvements
|
|||
* LUCENE-8129: A Unicode set filter can now be specified when using ICUFoldingFilter.
|
||||
(Ere Maijala)
|
||||
|
||||
* LUCENE-7966: Build Multi-Release JARs to enable usage of optimized intrinsic methods
|
||||
from Java 9 for index bounds checking and array comparison/mismatch. This change
|
||||
introduces Java 8 replacements for those Java 9 methods and patches the compiled
|
||||
classes to use the optimized variants through the MR-JAR mechanism.
|
||||
(Uwe Schindler, Robert Muir, Adrien Grand, Mike McCandless)
|
||||
|
||||
Bug Fixes
|
||||
|
||||
* LUCENE-8077: Fixed bug in how CheckIndex verifies doc-value iterators.
|
||||
|
|
|
@ -557,7 +557,7 @@
|
|||
</target>
|
||||
|
||||
<!-- Override common-build.xml definition to check for the jar already being up-to-date -->
|
||||
<target name="jar-core" depends="check-lucene-core-uptodate,compile-lucene-core" unless="lucene-core.uptodate">
|
||||
<target name="jar-core" depends="resolve-groovy,check-lucene-core-uptodate,compile-lucene-core" unless="lucene-core.uptodate">
|
||||
<ant dir="${common.dir}/core" target="jar-core" inheritAll="false">
|
||||
<propertyset refid="uptodate.and.compiled.properties"/>
|
||||
</ant>
|
||||
|
|
|
@ -150,7 +150,13 @@ public class FixedGapTermsIndexWriter extends TermsIndexWriterBase {
|
|||
|
||||
@Override
|
||||
public void add(BytesRef text, TermStats stats, long termsFilePointer) throws IOException {
|
||||
final int indexedTermLength = indexedTermPrefixLength(lastTerm.get(), text);
|
||||
final int indexedTermLength;
|
||||
if (numIndexTerms == 0) {
|
||||
// no previous term: no bytes to write
|
||||
indexedTermLength = 0;
|
||||
} else {
|
||||
indexedTermLength = indexedTermPrefixLength(lastTerm.get(), text);
|
||||
}
|
||||
//System.out.println("FGW: add text=" + text.utf8ToString() + " " + text + " fp=" + termsFilePointer);
|
||||
|
||||
// write only the min prefix that shows the diff
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.apache.lucene.util.BytesRef;
|
|||
import org.apache.lucene.util.BytesRefBuilder;
|
||||
import org.apache.lucene.util.CharsRef;
|
||||
import org.apache.lucene.util.CharsRefBuilder;
|
||||
import org.apache.lucene.util.FutureArrays;
|
||||
import org.apache.lucene.util.IOUtils;
|
||||
import org.apache.lucene.util.RamUsageEstimator;
|
||||
import org.apache.lucene.util.StringHelper;
|
||||
|
@ -202,8 +203,8 @@ public class SimpleTextStoredFieldsReader extends StoredFieldsReader {
|
|||
}
|
||||
|
||||
private boolean equalsAt(BytesRef a, BytesRef b, int bOffset) {
|
||||
return a.length == b.length - bOffset &&
|
||||
ArrayUtil.equals(a.bytes, a.offset, b.bytes, b.offset + bOffset, b.length - bOffset);
|
||||
return a.length == b.length - bOffset &&
|
||||
FutureArrays.equals(a.bytes, a.offset, a.offset + a.length, b.bytes, b.offset + bOffset, b.offset + b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -160,6 +160,10 @@
|
|||
|
||||
<!-- Display at most this many failures as a summary at the end of junit4 run. -->
|
||||
<property name="tests.showNumFailures" value="10" />
|
||||
|
||||
<!-- If we detect Java 9+, should we test the patched classes of the
|
||||
multi-release JAR or still run with our own classes? -->
|
||||
<property name="tests.withJava9Patches" value="true" />
|
||||
|
||||
<property name="javac.deprecation" value="off"/>
|
||||
<property name="javac.debug" value="on"/>
|
||||
|
@ -546,10 +550,48 @@
|
|||
<!-- convenience target to compile core -->
|
||||
</target>
|
||||
|
||||
<target name="jar-core" depends="compile-core">
|
||||
<!-- Special targets to patch all class files by replacing some method calls with new Java 9 methods: -->
|
||||
<target name="-mrjar-classes-uptodate">
|
||||
<uptodate property="mrjar-classes-uptodate" targetfile="${build.dir}/patch-mrjar.stamp">
|
||||
<srcfiles dir= "${build.dir}/classes/java" includes="**/*.class"/>
|
||||
</uptodate>
|
||||
</target>
|
||||
|
||||
<target xmlns:ivy="antlib:org.apache.ivy.ant" name="patch-mrjar-classes" depends="-mrjar-classes-uptodate,ivy-availability-check,ivy-configure,resolve-groovy,compile-core"
|
||||
unless="mrjar-classes-uptodate" description="Patches compiled class files for usage with Java 9 in MR-JAR">
|
||||
<loadproperties prefix="ivyversions" srcFile="${common.dir}/ivy-versions.properties"/>
|
||||
<ivy:cachepath organisation="org.ow2.asm" module="asm-commons" revision="${ivyversions./org.ow2.asm/asm-commons}"
|
||||
inline="true" conf="default" transitive="true" log="download-only" pathid="asm.classpath"/>
|
||||
<groovy classpathref="asm.classpath" src="${common.dir}/tools/src/groovy/patch-mrjar-classes.groovy"/>
|
||||
<touch file="${build.dir}/patch-mrjar.stamp"/>
|
||||
</target>
|
||||
|
||||
<target name="-mrjar-check" depends="patch-mrjar-classes">
|
||||
<zipfileset id="mrjar-patched-files" prefix="META-INF/versions/9" dir="${build.dir}/classes/java9"/>
|
||||
<condition property="has-mrjar-patched-files">
|
||||
<resourcecount refid="mrjar-patched-files" when="greater" count="0" />
|
||||
</condition>
|
||||
</target>
|
||||
|
||||
<target name="-mrjar-core" depends="-mrjar-check" if="has-mrjar-patched-files">
|
||||
<jarify>
|
||||
<filesets>
|
||||
<zipfileset refid="mrjar-patched-files"/>
|
||||
</filesets>
|
||||
<jarify-additional-manifest-attributes>
|
||||
<attribute name="Multi-Release" value="true"/>
|
||||
</jarify-additional-manifest-attributes>
|
||||
</jarify>
|
||||
</target>
|
||||
|
||||
<target name="-jar-core" depends="-mrjar-check" unless="has-mrjar-patched-files">
|
||||
<jarify/>
|
||||
</target>
|
||||
|
||||
<target name="jar-core" depends="-mrjar-core,-jar-core"/>
|
||||
|
||||
<!-- Packaging targets: -->
|
||||
|
||||
<property name="lucene.tgz.file" location="${common.dir}/dist/lucene-${version}.tgz"/>
|
||||
<available file="${lucene.tgz.file}" property="lucene.tgz.exists"/>
|
||||
<property name="lucene.tgz.unpack.dir" location="${common.build.dir}/lucene.tgz.unpacked"/>
|
||||
|
@ -1453,8 +1495,8 @@ ${tests-output}/junit4-*.suites - per-JVM executed suites
|
|||
</taskdef>
|
||||
</target>
|
||||
|
||||
<target name="test" depends="clover,compile-test,install-junit4-taskdef,validate,-init-totals,-test,-check-totals" description="Runs unit tests"/>
|
||||
<target name="beast" depends="clover,compile-test,install-junit4-taskdef,validate,-init-totals,-beast,-check-totals" description="Runs unit tests in a loop (-Dbeast.iters=n)"/>
|
||||
<target name="test" depends="clover,compile-test,patch-mrjar-classes,install-junit4-taskdef,validate,-init-totals,-test,-check-totals" description="Runs unit tests"/>
|
||||
<target name="beast" depends="clover,compile-test,patch-mrjar-classes,install-junit4-taskdef,validate,-init-totals,-beast,-check-totals" description="Runs unit tests in a loop (-Dbeast.iters=n)"/>
|
||||
|
||||
<target name="test-nocompile" depends="-clover.disable,install-junit4-taskdef,-init-totals,-test,-check-totals"
|
||||
description="Only runs unit tests. Jars are not downloaded; compilation is not updated; and Clover is not enabled."/>
|
||||
|
|
|
@ -31,10 +31,19 @@
|
|||
|
||||
<path id="classpath"/>
|
||||
|
||||
<!-- if we run with Java 9+, we refer to the java9 classes directory and insert this before the main classpath (to "emulate" a MR-JAR): -->
|
||||
<condition property="-test.classpath.java9.addon" value="${build.dir}/classes/java9" else="${build.dir}/classes/java">
|
||||
<and>
|
||||
<not><equals arg1="${build.java.runtime}" arg2="1.8"/></not>
|
||||
<istrue value="${tests.withJava9Patches}"/>
|
||||
</and>
|
||||
</condition>
|
||||
|
||||
<path id="test.classpath">
|
||||
<pathelement location="${common.dir}/build/codecs/classes/java"/>
|
||||
<pathelement location="${common.dir}/build/test-framework/classes/java"/>
|
||||
<path refid="junit-path"/>
|
||||
<pathelement location="${-test.classpath.java9.addon}"/><!-- if it's a duplicate it gets removed by Ant! -->
|
||||
<pathelement location="${build.dir}/classes/java"/>
|
||||
<pathelement location="${build.dir}/classes/test"/>
|
||||
</path>
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.lucene.util.AttributeImpl;
|
|||
import org.apache.lucene.util.AttributeReflector;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.BytesRefBuilder;
|
||||
import org.apache.lucene.util.FutureObjects;
|
||||
|
||||
/** Default implementation of {@link CharTermAttribute}. */
|
||||
public class CharTermAttributeImpl extends AttributeImpl implements CharTermAttribute, TermToBytesRefAttribute, Cloneable {
|
||||
|
@ -71,11 +72,7 @@ public class CharTermAttributeImpl extends AttributeImpl implements CharTermAttr
|
|||
|
||||
@Override
|
||||
public final CharTermAttribute setLength(int length) {
|
||||
if (length < 0) {
|
||||
throw new IllegalArgumentException("length " + length + " must not be negative");
|
||||
}
|
||||
if (length > termBuffer.length)
|
||||
throw new IllegalArgumentException("length " + length + " exceeds the size of the termBuffer (" + termBuffer.length + ")");
|
||||
FutureObjects.checkFromIndexSize(0, length, termBuffer.length);
|
||||
termLength = length;
|
||||
return this;
|
||||
}
|
||||
|
@ -102,15 +99,13 @@ public class CharTermAttributeImpl extends AttributeImpl implements CharTermAttr
|
|||
|
||||
@Override
|
||||
public final char charAt(int index) {
|
||||
if (index >= termLength)
|
||||
throw new IndexOutOfBoundsException();
|
||||
FutureObjects.checkIndex(index, termLength);
|
||||
return termBuffer[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public final CharSequence subSequence(final int start, final int end) {
|
||||
if (start > termLength || end > termLength)
|
||||
throw new IndexOutOfBoundsException();
|
||||
FutureObjects.checkFromToIndex(start, end, termLength);
|
||||
return new String(termBuffer, start, end - start);
|
||||
}
|
||||
|
||||
|
@ -127,9 +122,9 @@ public class CharTermAttributeImpl extends AttributeImpl implements CharTermAttr
|
|||
public final CharTermAttribute append(CharSequence csq, int start, int end) {
|
||||
if (csq == null) // needed for Appendable compliance
|
||||
csq = "null";
|
||||
final int len = end - start, csqlen = csq.length();
|
||||
if (len < 0 || start > csqlen || end > csqlen)
|
||||
throw new IndexOutOfBoundsException();
|
||||
// TODO: the optimized cases (jdk methods) will already do such checks, maybe re-organize this?
|
||||
FutureObjects.checkFromToIndex(start, end, csq.length());
|
||||
final int len = end - start;
|
||||
if (len == 0)
|
||||
return this;
|
||||
resizeBuffer(termLength + len);
|
||||
|
|
|
@ -293,7 +293,13 @@ public final class CompressingTermVectorsWriter extends TermVectorsWriter {
|
|||
@Override
|
||||
public void startTerm(BytesRef term, int freq) throws IOException {
|
||||
assert freq >= 1;
|
||||
final int prefix = StringHelper.bytesDifference(lastTerm, term);
|
||||
final int prefix;
|
||||
if (lastTerm.length == 0) {
|
||||
// no previous term: no bytes to write
|
||||
prefix = 0;
|
||||
} else {
|
||||
prefix = StringHelper.bytesDifference(lastTerm, term);
|
||||
}
|
||||
curField.addTerm(freq, prefix, term.length - prefix);
|
||||
termSuffixes.writeBytes(term.bytes, term.offset + prefix, term.length - prefix);
|
||||
// copy last term
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.Arrays;
|
|||
|
||||
import org.apache.lucene.store.DataInput;
|
||||
import org.apache.lucene.store.DataOutput;
|
||||
import org.apache.lucene.util.FutureArrays;
|
||||
import org.apache.lucene.util.packed.PackedInts;
|
||||
|
||||
/**
|
||||
|
@ -61,11 +62,8 @@ final class LZ4 {
|
|||
|
||||
private static int commonBytes(byte[] b, int o1, int o2, int limit) {
|
||||
assert o1 < o2;
|
||||
int count = 0;
|
||||
while (o2 < limit && b[o1++] == b[o2++]) {
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
// never -1 because lengths always differ
|
||||
return FutureArrays.mismatch(b, o1, limit, b, o2, limit);
|
||||
}
|
||||
|
||||
private static int commonBytesBackward(byte[] b, int o1, int o2, int l1, int l2) {
|
||||
|
|
|
@ -504,7 +504,13 @@ final class Lucene70DocValuesConsumer extends DocValuesConsumer implements Close
|
|||
for (BytesRef term = iterator.next(); term != null; term = iterator.next()) {
|
||||
if ((ord & Lucene70DocValuesFormat.TERMS_DICT_REVERSE_INDEX_MASK) == 0) {
|
||||
writer.add(offset);
|
||||
int sortKeyLength = StringHelper.sortKeyLength(previous.get(), term);
|
||||
final int sortKeyLength;
|
||||
if (ord == 0) {
|
||||
// no previous term: no bytes to write
|
||||
sortKeyLength = 0;
|
||||
} else {
|
||||
sortKeyLength = StringHelper.sortKeyLength(previous.get(), term);
|
||||
}
|
||||
offset += sortKeyLength;
|
||||
data.writeBytes(term.bytes, term.offset, sortKeyLength);
|
||||
} else if ((ord & Lucene70DocValuesFormat.TERMS_DICT_REVERSE_INDEX_MASK) == Lucene70DocValuesFormat.TERMS_DICT_REVERSE_INDEX_MASK) {
|
||||
|
|
|
@ -26,7 +26,7 @@ import org.apache.lucene.search.PointInSetQuery;
|
|||
import org.apache.lucene.search.PointRangeQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.StringHelper;
|
||||
import org.apache.lucene.util.FutureArrays;
|
||||
|
||||
/**
|
||||
* An indexed binary field for fast range filters. If you also
|
||||
|
@ -222,7 +222,7 @@ public final class BinaryPoint extends Field {
|
|||
new Comparator<byte[]>() {
|
||||
@Override
|
||||
public int compare(byte[] a, byte[] b) {
|
||||
return StringHelper.compare(a.length, a, 0, b, 0);
|
||||
return FutureArrays.compareUnsigned(a, 0, a.length, b, 0, b.length);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.lucene.document;
|
|||
import org.apache.lucene.document.RangeFieldQuery.QueryType;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.FutureObjects;
|
||||
import org.apache.lucene.util.NumericUtils;
|
||||
|
||||
/**
|
||||
|
@ -147,10 +148,7 @@ public class DoubleRange extends Field {
|
|||
* @return the decoded min value
|
||||
*/
|
||||
public double getMin(int dimension) {
|
||||
if (dimension < 0 || dimension >= type.pointDimensionCount()/2) {
|
||||
throw new IllegalArgumentException("dimension request (" + dimension +
|
||||
") out of bounds for field (name=" + name + " dimensions=" + type.pointDimensionCount()/2 + "). ");
|
||||
}
|
||||
FutureObjects.checkIndex(dimension, type.pointDimensionCount()/2);
|
||||
return decodeMin(((BytesRef)fieldsData).bytes, dimension);
|
||||
}
|
||||
|
||||
|
@ -160,10 +158,7 @@ public class DoubleRange extends Field {
|
|||
* @return the decoded max value
|
||||
*/
|
||||
public double getMax(int dimension) {
|
||||
if (dimension < 0 || dimension >= type.pointDimensionCount()/2) {
|
||||
throw new IllegalArgumentException("dimension request (" + dimension +
|
||||
") out of bounds for field (name=" + name + " dimensions=" + type.pointDimensionCount()/2 + "). ");
|
||||
}
|
||||
FutureObjects.checkIndex(dimension, type.pointDimensionCount()/2);
|
||||
return decodeMax(((BytesRef)fieldsData).bytes, dimension);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.lucene.document;
|
|||
import org.apache.lucene.document.RangeFieldQuery.QueryType;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.FutureObjects;
|
||||
import org.apache.lucene.util.NumericUtils;
|
||||
|
||||
/**
|
||||
|
@ -147,10 +148,7 @@ public class FloatRange extends Field {
|
|||
* @return the decoded min value
|
||||
*/
|
||||
public float getMin(int dimension) {
|
||||
if (dimension < 0 || dimension >= type.pointDimensionCount()/2) {
|
||||
throw new IllegalArgumentException("dimension request (" + dimension +
|
||||
") out of bounds for field (name=" + name + " dimensions=" + type.pointDimensionCount()/2 + "). ");
|
||||
}
|
||||
FutureObjects.checkIndex(dimension, type.pointDimensionCount()/2);
|
||||
return decodeMin(((BytesRef)fieldsData).bytes, dimension);
|
||||
}
|
||||
|
||||
|
@ -160,10 +158,7 @@ public class FloatRange extends Field {
|
|||
* @return the decoded max value
|
||||
*/
|
||||
public float getMax(int dimension) {
|
||||
if (dimension < 0 || dimension >= type.pointDimensionCount()/2) {
|
||||
throw new IllegalArgumentException("dimension request (" + dimension +
|
||||
") out of bounds for field (name=" + name + " dimensions=" + type.pointDimensionCount()/2 + "). ");
|
||||
}
|
||||
FutureObjects.checkIndex(dimension, type.pointDimensionCount()/2);
|
||||
return decodeMax(((BytesRef)fieldsData).bytes, dimension);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.lucene.document;
|
|||
import org.apache.lucene.document.RangeFieldQuery.QueryType;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.FutureObjects;
|
||||
import org.apache.lucene.util.NumericUtils;
|
||||
|
||||
/**
|
||||
|
@ -147,10 +148,7 @@ public class IntRange extends Field {
|
|||
* @return the decoded min value
|
||||
*/
|
||||
public int getMin(int dimension) {
|
||||
if (dimension < 0 || dimension >= type.pointDimensionCount()/2) {
|
||||
throw new IllegalArgumentException("dimension request (" + dimension +
|
||||
") out of bounds for field (name=" + name + " dimensions=" + type.pointDimensionCount()/2 + "). ");
|
||||
}
|
||||
FutureObjects.checkIndex(dimension, type.pointDimensionCount()/2);
|
||||
return decodeMin(((BytesRef)fieldsData).bytes, dimension);
|
||||
}
|
||||
|
||||
|
@ -160,10 +158,7 @@ public class IntRange extends Field {
|
|||
* @return the decoded max value
|
||||
*/
|
||||
public int getMax(int dimension) {
|
||||
if (dimension < 0 || dimension >= type.pointDimensionCount()/2) {
|
||||
throw new IllegalArgumentException("dimension request (" + dimension +
|
||||
") out of bounds for field (name=" + name + " dimensions=" + type.pointDimensionCount()/2 + "). ");
|
||||
}
|
||||
FutureObjects.checkIndex(dimension, type.pointDimensionCount()/2);
|
||||
return decodeMax(((BytesRef)fieldsData).bytes, dimension);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.lucene.document;
|
|||
import org.apache.lucene.document.RangeFieldQuery.QueryType;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.FutureObjects;
|
||||
import org.apache.lucene.util.NumericUtils;
|
||||
|
||||
/**
|
||||
|
@ -145,10 +146,7 @@ public class LongRange extends Field {
|
|||
* @return the decoded min value
|
||||
*/
|
||||
public long getMin(int dimension) {
|
||||
if (dimension < 0 || dimension >= type.pointDimensionCount()/2) {
|
||||
throw new IllegalArgumentException("dimension request (" + dimension +
|
||||
") out of bounds for field (name=" + name + " dimensions=" + type.pointDimensionCount()/2 + "). ");
|
||||
}
|
||||
FutureObjects.checkIndex(dimension, type.pointDimensionCount()/2);
|
||||
return decodeMin(((BytesRef)fieldsData).bytes, dimension);
|
||||
}
|
||||
|
||||
|
@ -158,10 +156,7 @@ public class LongRange extends Field {
|
|||
* @return the decoded max value
|
||||
*/
|
||||
public long getMax(int dimension) {
|
||||
if (dimension < 0 || dimension >= type.pointDimensionCount()/2) {
|
||||
throw new IllegalArgumentException("dimension request (" + dimension +
|
||||
") out of bounds for field (name=" + name + " dimensions=" + type.pointDimensionCount()/2 + "). ");
|
||||
}
|
||||
FutureObjects.checkIndex(dimension, type.pointDimensionCount()/2);
|
||||
return decodeMax(((BytesRef)fieldsData).bytes, dimension);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.apache.lucene.index;
|
||||
|
||||
import org.apache.lucene.util.Bits;
|
||||
import org.apache.lucene.util.FutureObjects;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -39,10 +40,7 @@ final class BitsSlice implements Bits {
|
|||
|
||||
@Override
|
||||
public boolean get(int doc) {
|
||||
if (doc >= length) {
|
||||
throw new RuntimeException("doc " + doc + " is out of bounds 0 .. " + (length-1));
|
||||
}
|
||||
assert doc < length: "doc=" + doc + " length=" + length;
|
||||
FutureObjects.checkIndex(doc, length);
|
||||
return parent.get(doc+start);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.apache.lucene.codecs.StoredFieldsReader;
|
|||
import org.apache.lucene.codecs.TermVectorsReader;
|
||||
import org.apache.lucene.util.Accountable;
|
||||
import org.apache.lucene.util.Accountables;
|
||||
import org.apache.lucene.util.FutureObjects;
|
||||
|
||||
/**
|
||||
* LeafReader implemented by codec APIs.
|
||||
|
@ -94,9 +95,7 @@ public abstract class CodecReader extends LeafReader implements Accountable {
|
|||
}
|
||||
|
||||
private void checkBounds(int docID) {
|
||||
if (docID < 0 || docID >= maxDoc()) {
|
||||
throw new IndexOutOfBoundsException("docID must be >= 0 and < maxDoc=" + maxDoc() + " (got docID=" + docID + ")");
|
||||
}
|
||||
FutureObjects.checkIndex(docID, maxDoc());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.apache.lucene.codecs.NormsProducer;
|
|||
import org.apache.lucene.codecs.StoredFieldsReader;
|
||||
import org.apache.lucene.codecs.TermVectorsReader;
|
||||
import org.apache.lucene.util.Bits;
|
||||
import org.apache.lucene.util.FutureObjects;
|
||||
|
||||
/** This is a hack to make index sorting fast, with a {@link LeafReader} that always returns merge instances when you ask for the codec readers. */
|
||||
class MergeReaderWrapper extends LeafReader {
|
||||
|
@ -226,9 +227,7 @@ class MergeReaderWrapper extends LeafReader {
|
|||
}
|
||||
|
||||
private void checkBounds(int docID) {
|
||||
if (docID < 0 || docID >= maxDoc()) {
|
||||
throw new IndexOutOfBoundsException("docID must be >= 0 and < maxDoc=" + maxDoc() + " (got docID=" + docID + ")");
|
||||
}
|
||||
FutureObjects.checkIndex(docID, maxDoc());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.apache.lucene.store.RAMOutputStream;
|
|||
import org.apache.lucene.util.Accountable;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.BytesRefBuilder;
|
||||
import org.apache.lucene.util.StringHelper;
|
||||
|
||||
/**
|
||||
* Prefix codes term instances (prefixes are shared). This is expected to be
|
||||
|
@ -74,14 +75,19 @@ public class PrefixCodedTerms implements Accountable {
|
|||
assert lastTerm.equals(new Term("")) || new Term(field, bytes).compareTo(lastTerm) > 0;
|
||||
|
||||
try {
|
||||
int prefix = sharedPrefix(lastTerm.bytes, bytes);
|
||||
int suffix = bytes.length - prefix;
|
||||
if (field.equals(lastTerm.field)) {
|
||||
final int prefix;
|
||||
if (size > 0 && field.equals(lastTerm.field)) {
|
||||
// same field as the last term
|
||||
prefix = StringHelper.bytesDifference(lastTerm.bytes, bytes);
|
||||
output.writeVInt(prefix << 1);
|
||||
} else {
|
||||
output.writeVInt(prefix << 1 | 1);
|
||||
// field change
|
||||
prefix = 0;
|
||||
output.writeVInt(1);
|
||||
output.writeString(field);
|
||||
}
|
||||
|
||||
int suffix = bytes.length - prefix;
|
||||
output.writeVInt(suffix);
|
||||
output.writeBytes(bytes.bytes, bytes.offset + prefix, suffix);
|
||||
lastTermBytes.copyBytes(bytes);
|
||||
|
@ -102,20 +108,6 @@ public class PrefixCodedTerms implements Accountable {
|
|||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private int sharedPrefix(BytesRef term1, BytesRef term2) {
|
||||
int pos1 = 0;
|
||||
int pos1End = pos1 + Math.min(term1.length, term2.length);
|
||||
int pos2 = 0;
|
||||
while(pos1 < pos1End) {
|
||||
if (term1.bytes[term1.offset + pos1] != term2.bytes[term2.offset + pos2]) {
|
||||
return pos1;
|
||||
}
|
||||
pos1++;
|
||||
pos2++;
|
||||
}
|
||||
return pos1;
|
||||
}
|
||||
}
|
||||
|
||||
/** An iterator over the list of terms stored in a {@link PrefixCodedTerms}. */
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.Arrays;
|
|||
import java.util.Collection;
|
||||
|
||||
import org.apache.lucene.util.Bits;
|
||||
import org.apache.lucene.util.FutureObjects;
|
||||
import org.apache.lucene.util.PriorityQueue;
|
||||
|
||||
/**
|
||||
|
@ -105,9 +106,7 @@ final class BooleanScorer extends BulkScorer {
|
|||
}
|
||||
|
||||
public BulkScorerAndDoc get(int i) {
|
||||
if (i < 0 || i >= size()) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
FutureObjects.checkIndex(i, size());
|
||||
return (BulkScorerAndDoc) getHeapArray()[1 + i];
|
||||
}
|
||||
|
||||
|
|
|
@ -313,58 +313,6 @@ public final class ArrayUtil {
|
|||
code = code * 31 + array[i];
|
||||
return code;
|
||||
}
|
||||
|
||||
// Since Arrays.equals doesn't implement offsets for equals
|
||||
/**
|
||||
* See if two array slices are the same.
|
||||
*
|
||||
* @param left The left array to compare
|
||||
* @param offsetLeft The offset into the array. Must be positive
|
||||
* @param right The right array to compare
|
||||
* @param offsetRight the offset into the right array. Must be positive
|
||||
* @param length The length of the section of the array to compare
|
||||
* @return true if the two arrays, starting at their respective offsets, are equal
|
||||
*
|
||||
* @see java.util.Arrays#equals(byte[], byte[])
|
||||
*/
|
||||
public static boolean equals(byte[] left, int offsetLeft, byte[] right, int offsetRight, int length) {
|
||||
if ((offsetLeft + length <= left.length) && (offsetRight + length <= right.length)) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (left[offsetLeft + i] != right[offsetRight + i]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Since Arrays.equals doesn't implement offsets for equals
|
||||
/**
|
||||
* See if two array slices are the same.
|
||||
*
|
||||
* @param left The left array to compare
|
||||
* @param offsetLeft The offset into the array. Must be positive
|
||||
* @param right The right array to compare
|
||||
* @param offsetRight the offset into the right array. Must be positive
|
||||
* @param length The length of the section of the array to compare
|
||||
* @return true if the two arrays, starting at their respective offsets, are equal
|
||||
*
|
||||
* @see java.util.Arrays#equals(char[], char[])
|
||||
*/
|
||||
public static boolean equals(int[] left, int offsetLeft, int[] right, int offsetRight, int length) {
|
||||
if ((offsetLeft + length <= left.length) && (offsetRight + length <= right.length)) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (left[offsetLeft + i] != right[offsetRight + i]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Swap values stored in slots <code>i</code> and <code>j</code> */
|
||||
public static <T> void swap(T[] arr, int i, int j) {
|
||||
|
|
|
@ -96,20 +96,8 @@ public final class BytesRef implements Comparable<BytesRef>,Cloneable {
|
|||
* @lucene.internal
|
||||
*/
|
||||
public boolean bytesEquals(BytesRef other) {
|
||||
assert other != null;
|
||||
if (length == other.length) {
|
||||
int otherUpto = other.offset;
|
||||
final byte[] otherBytes = other.bytes;
|
||||
final int end = offset + length;
|
||||
for(int upto=offset;upto<end;upto++,otherUpto++) {
|
||||
if (bytes[upto] != otherBytes[otherUpto]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return FutureArrays.equals(this.bytes, this.offset, this.offset + this.length,
|
||||
other.bytes, other.offset, other.offset + other.length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -172,27 +160,8 @@ public final class BytesRef implements Comparable<BytesRef>,Cloneable {
|
|||
/** Unsigned byte order comparison */
|
||||
@Override
|
||||
public int compareTo(BytesRef other) {
|
||||
// TODO: Once we are on Java 9 replace this by java.util.Arrays#compareUnsigned()
|
||||
// which is implemented by a Hotspot intrinsic! Also consider building a
|
||||
// Multi-Release-JAR!
|
||||
final byte[] aBytes = this.bytes;
|
||||
int aUpto = this.offset;
|
||||
final byte[] bBytes = other.bytes;
|
||||
int bUpto = other.offset;
|
||||
|
||||
final int aStop = aUpto + Math.min(this.length, other.length);
|
||||
while(aUpto < aStop) {
|
||||
int aByte = aBytes[aUpto++] & 0xff;
|
||||
int bByte = bBytes[bUpto++] & 0xff;
|
||||
|
||||
int diff = aByte - bByte;
|
||||
if (diff != 0) {
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
|
||||
// One is a prefix of the other, or, they are equal:
|
||||
return this.length - other.length;
|
||||
return FutureArrays.compareUnsigned(this.bytes, this.offset, this.offset + this.length,
|
||||
other.bytes, other.offset, other.offset + other.length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -93,34 +93,28 @@ public final class BytesRefArray implements SortableBytesRefArray {
|
|||
* @return the <i>n'th</i> element of this {@link BytesRefArray}
|
||||
*/
|
||||
public BytesRef get(BytesRefBuilder spare, int index) {
|
||||
if (lastElement > index) {
|
||||
int offset = offsets[index];
|
||||
int length = index == lastElement - 1 ? currentOffset - offset
|
||||
: offsets[index + 1] - offset;
|
||||
spare.grow(length);
|
||||
spare.setLength(length);
|
||||
pool.readBytes(offset, spare.bytes(), 0, spare.length());
|
||||
return spare.get();
|
||||
}
|
||||
throw new IndexOutOfBoundsException("index " + index
|
||||
+ " must be less than the size: " + lastElement);
|
||||
FutureObjects.checkIndex(index, lastElement);
|
||||
int offset = offsets[index];
|
||||
int length = index == lastElement - 1 ? currentOffset - offset
|
||||
: offsets[index + 1] - offset;
|
||||
spare.grow(length);
|
||||
spare.setLength(length);
|
||||
pool.readBytes(offset, spare.bytes(), 0, spare.length());
|
||||
return spare.get();
|
||||
}
|
||||
|
||||
/** Used only by sort below, to set a {@link BytesRef} with the specified slice, avoiding copying bytes in the common case when the slice
|
||||
* is contained in a single block in the byte block pool. */
|
||||
private void setBytesRef(BytesRefBuilder spare, BytesRef result, int index) {
|
||||
if (index < lastElement) {
|
||||
int offset = offsets[index];
|
||||
int length;
|
||||
if (index == lastElement - 1) {
|
||||
length = currentOffset - offset;
|
||||
} else {
|
||||
length = offsets[index + 1] - offset;
|
||||
}
|
||||
pool.setBytesRef(spare, result, offset, length);
|
||||
FutureObjects.checkIndex(index, lastElement);
|
||||
int offset = offsets[index];
|
||||
int length;
|
||||
if (index == lastElement - 1) {
|
||||
length = currentOffset - offset;
|
||||
} else {
|
||||
throw new IndexOutOfBoundsException("index " + index + " must be less than the size: " + lastElement);
|
||||
length = offsets[index + 1] - offset;
|
||||
}
|
||||
pool.setBytesRef(spare, result, offset, length);
|
||||
}
|
||||
|
||||
private int[] sort(final Comparator<BytesRef> comp) {
|
||||
|
|
|
@ -107,46 +107,15 @@ public final class CharsRef implements Comparable<CharsRef>, CharSequence, Clone
|
|||
}
|
||||
|
||||
public boolean charsEquals(CharsRef other) {
|
||||
if (length == other.length) {
|
||||
int otherUpto = other.offset;
|
||||
final char[] otherChars = other.chars;
|
||||
final int end = offset + length;
|
||||
for (int upto = offset; upto < end; upto++, otherUpto++) {
|
||||
if (chars[upto] != otherChars[otherUpto]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return FutureArrays.equals(this.chars, this.offset, this.offset + this.length,
|
||||
other.chars, other.offset, other.offset + other.length);
|
||||
}
|
||||
|
||||
/** Signed int order comparison */
|
||||
@Override
|
||||
public int compareTo(CharsRef other) {
|
||||
if (this == other)
|
||||
return 0;
|
||||
|
||||
final char[] aChars = this.chars;
|
||||
int aUpto = this.offset;
|
||||
final char[] bChars = other.chars;
|
||||
int bUpto = other.offset;
|
||||
|
||||
final int aStop = aUpto + Math.min(this.length, other.length);
|
||||
|
||||
while (aUpto < aStop) {
|
||||
int aInt = aChars[aUpto++];
|
||||
int bInt = bChars[bUpto++];
|
||||
if (aInt > bInt) {
|
||||
return 1;
|
||||
} else if (aInt < bInt) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// One is a prefix of the other, or, they are equal:
|
||||
return this.length - other.length;
|
||||
return FutureArrays.compare(this.chars, this.offset, this.offset + this.length,
|
||||
other.chars, other.offset, other.offset + other.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -162,18 +131,14 @@ public final class CharsRef implements Comparable<CharsRef>, CharSequence, Clone
|
|||
@Override
|
||||
public char charAt(int index) {
|
||||
// NOTE: must do a real check here to meet the specs of CharSequence
|
||||
if (index < 0 || index >= length) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
FutureObjects.checkIndex(index, length);
|
||||
return chars[offset + index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
// NOTE: must do a real check here to meet the specs of CharSequence
|
||||
if (start < 0 || end > length || start > end) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
FutureObjects.checkFromToIndex(start, end, length);
|
||||
return new CharsRef(chars, offset + start, end - start);
|
||||
}
|
||||
|
||||
|
@ -195,40 +160,33 @@ public final class CharsRef implements Comparable<CharsRef>, CharSequence, Clone
|
|||
|
||||
@Override
|
||||
public int compare(CharsRef a, CharsRef b) {
|
||||
if (a == b)
|
||||
return 0;
|
||||
int aEnd = a.offset + a.length;
|
||||
int bEnd = b.offset + b.length;
|
||||
int i = FutureArrays.mismatch(a.chars, a.offset, aEnd,
|
||||
b.chars, b.offset, bEnd);
|
||||
|
||||
final char[] aChars = a.chars;
|
||||
int aUpto = a.offset;
|
||||
final char[] bChars = b.chars;
|
||||
int bUpto = b.offset;
|
||||
if (i >= 0 && i < Math.min(a.length, b.length)) {
|
||||
// http://icu-project.org/docs/papers/utf16_code_point_order.html
|
||||
|
||||
final int aStop = aUpto + Math.min(a.length, b.length);
|
||||
|
||||
while (aUpto < aStop) {
|
||||
char aChar = aChars[aUpto++];
|
||||
char bChar = bChars[bUpto++];
|
||||
if (aChar != bChar) {
|
||||
// http://icu-project.org/docs/papers/utf16_code_point_order.html
|
||||
|
||||
/* aChar != bChar, fix up each one if they're both in or above the surrogate range, then compare them */
|
||||
if (aChar >= 0xd800 && bChar >= 0xd800) {
|
||||
if (aChar >= 0xe000) {
|
||||
aChar -= 0x800;
|
||||
} else {
|
||||
aChar += 0x2000;
|
||||
}
|
||||
|
||||
if (bChar >= 0xe000) {
|
||||
bChar -= 0x800;
|
||||
} else {
|
||||
bChar += 0x2000;
|
||||
}
|
||||
char aChar = a.chars[a.offset + i];
|
||||
char bChar = b.chars[b.offset + i];
|
||||
/* aChar != bChar, fix up each one if they're both in or above the surrogate range, then compare them */
|
||||
if (aChar >= 0xd800 && bChar >= 0xd800) {
|
||||
if (aChar >= 0xe000) {
|
||||
aChar -= 0x800;
|
||||
} else {
|
||||
aChar += 0x2000;
|
||||
}
|
||||
|
||||
/* now aChar and bChar are in code point order */
|
||||
return (int)aChar - (int)bChar; /* int must be 32 bits wide */
|
||||
if (bChar >= 0xe000) {
|
||||
bChar -= 0x800;
|
||||
} else {
|
||||
bChar += 0x2000;
|
||||
}
|
||||
}
|
||||
|
||||
/* now aChar and bChar are in code point order */
|
||||
return (int)aChar - (int)bChar; /* int must be 32 bits wide */
|
||||
}
|
||||
|
||||
// One is a prefix of the other, or, they are equal:
|
||||
|
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Additional methods from Java 9's <a href="https://docs.oracle.com/javase/9/docs/api/java/util/Arrays.html">
|
||||
* {@code java.util.Arrays}</a>.
|
||||
* <p>
|
||||
* This class will be removed when Java 9 is minimum requirement.
|
||||
* Currently any bytecode is patched to use the Java 9 native
|
||||
* classes through MR-JAR (Multi-Release JAR) mechanism.
|
||||
* In Java 8 it will use THIS implementation.
|
||||
* Because of patching, inside the Java source files we always
|
||||
* refer to the Lucene implementations, but the final Lucene
|
||||
* JAR files will use the native Java 9 class names when executed
|
||||
* with Java 9.
|
||||
* @lucene.internal
|
||||
*/
|
||||
public final class FutureArrays {
|
||||
|
||||
private FutureArrays() {} // no instance
|
||||
|
||||
// methods in Arrays are defined stupid: they cannot use Objects.checkFromToIndex
|
||||
// they throw IAE (vs IOOBE) in the case of fromIndex > toIndex.
|
||||
// so this method works just like checkFromToIndex, but with that stupidity added.
|
||||
private static void checkFromToIndex(int fromIndex, int toIndex, int length) {
|
||||
if (fromIndex > toIndex) {
|
||||
throw new IllegalArgumentException("fromIndex " + fromIndex + " > toIndex " + toIndex);
|
||||
}
|
||||
if (fromIndex < 0 || toIndex > length) {
|
||||
throw new IndexOutOfBoundsException("Range [" + fromIndex + ", " + toIndex + ") out-of-bounds for length " + length);
|
||||
}
|
||||
}
|
||||
|
||||
// byte[]
|
||||
|
||||
/**
|
||||
* Behaves like Java 9's Arrays.mismatch
|
||||
* @see <a href="http://download.java.net/java/jdk9/docs/api/java/util/Arrays.html#mismatch-byte:A-int-int-byte:A-int-int-">Arrays.mismatch</a>
|
||||
*/
|
||||
public static int mismatch(byte[] a, int aFromIndex, int aToIndex, byte[] b, int bFromIndex, int bToIndex) {
|
||||
checkFromToIndex(aFromIndex, aToIndex, a.length);
|
||||
checkFromToIndex(bFromIndex, bToIndex, b.length);
|
||||
int aLen = aToIndex - aFromIndex;
|
||||
int bLen = bToIndex - bFromIndex;
|
||||
int len = Math.min(aLen, bLen);
|
||||
for (int i = 0; i < len; i++)
|
||||
if (a[i+aFromIndex] != b[i+bFromIndex])
|
||||
return i;
|
||||
return aLen == bLen ? -1 : len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Behaves like Java 9's Arrays.compareUnsigned
|
||||
* @see <a href="http://download.java.net/java/jdk9/docs/api/java/util/Arrays.html#compareUnsigned-byte:A-int-int-byte:A-int-int-">Arrays.compareUnsigned</a>
|
||||
*/
|
||||
public static int compareUnsigned(byte[] a, int aFromIndex, int aToIndex, byte[] b, int bFromIndex, int bToIndex) {
|
||||
checkFromToIndex(aFromIndex, aToIndex, a.length);
|
||||
checkFromToIndex(bFromIndex, bToIndex, b.length);
|
||||
int aLen = aToIndex - aFromIndex;
|
||||
int bLen = bToIndex - bFromIndex;
|
||||
int len = Math.min(aLen, bLen);
|
||||
for (int i = 0; i < len; i++) {
|
||||
int aByte = a[i+aFromIndex] & 0xFF;
|
||||
int bByte = b[i+bFromIndex] & 0xFF;
|
||||
int diff = aByte - bByte;
|
||||
if (diff != 0) {
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
|
||||
// One is a prefix of the other, or, they are equal:
|
||||
return aLen - bLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Behaves like Java 9's Arrays.equals
|
||||
* @see <a href="http://download.java.net/java/jdk9/docs/api/java/util/Arrays.html#equals-byte:A-int-int-byte:A-int-int-">Arrays.equals</a>
|
||||
*/
|
||||
public static boolean equals(byte[] a, int aFromIndex, int aToIndex, byte[] b, int bFromIndex, int bToIndex) {
|
||||
checkFromToIndex(aFromIndex, aToIndex, a.length);
|
||||
checkFromToIndex(bFromIndex, bToIndex, b.length);
|
||||
int aLen = aToIndex - aFromIndex;
|
||||
int bLen = bToIndex - bFromIndex;
|
||||
// lengths differ: cannot be equal
|
||||
if (aLen != bLen) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < aLen; i++) {
|
||||
if (a[i+aFromIndex] != b[i+bFromIndex]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// char[]
|
||||
|
||||
/**
|
||||
* Behaves like Java 9's Arrays.mismatch
|
||||
* @see <a href="http://download.java.net/java/jdk9/docs/api/java/util/Arrays.html#mismatch-char:A-int-int-char:A-int-int-">Arrays.mismatch</a>
|
||||
*/
|
||||
public static int mismatch(char[] a, int aFromIndex, int aToIndex, char[] b, int bFromIndex, int bToIndex) {
|
||||
checkFromToIndex(aFromIndex, aToIndex, a.length);
|
||||
checkFromToIndex(bFromIndex, bToIndex, b.length);
|
||||
int aLen = aToIndex - aFromIndex;
|
||||
int bLen = bToIndex - bFromIndex;
|
||||
int len = Math.min(aLen, bLen);
|
||||
for (int i = 0; i < len; i++)
|
||||
if (a[i+aFromIndex] != b[i+bFromIndex])
|
||||
return i;
|
||||
return aLen == bLen ? -1 : len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Behaves like Java 9's Arrays.compare
|
||||
* @see <a href="http://download.java.net/java/jdk9/docs/api/java/util/Arrays.html#compare-char:A-int-int-char:A-int-int-">Arrays.compare</a>
|
||||
*/
|
||||
public static int compare(char[] a, int aFromIndex, int aToIndex, char[] b, int bFromIndex, int bToIndex) {
|
||||
checkFromToIndex(aFromIndex, aToIndex, a.length);
|
||||
checkFromToIndex(bFromIndex, bToIndex, b.length);
|
||||
int aLen = aToIndex - aFromIndex;
|
||||
int bLen = bToIndex - bFromIndex;
|
||||
int len = Math.min(aLen, bLen);
|
||||
for (int i = 0; i < len; i++) {
|
||||
int aInt = a[i+aFromIndex];
|
||||
int bInt = b[i+bFromIndex];
|
||||
if (aInt > bInt) {
|
||||
return 1;
|
||||
} else if (aInt < bInt) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// One is a prefix of the other, or, they are equal:
|
||||
return aLen - bLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Behaves like Java 9's Arrays.equals
|
||||
* @see <a href="http://download.java.net/java/jdk9/docs/api/java/util/Arrays.html#equals-char:A-int-int-char:A-int-int-">Arrays.equals</a>
|
||||
*/
|
||||
public static boolean equals(char[] a, int aFromIndex, int aToIndex, char[] b, int bFromIndex, int bToIndex) {
|
||||
checkFromToIndex(aFromIndex, aToIndex, a.length);
|
||||
checkFromToIndex(bFromIndex, bToIndex, b.length);
|
||||
int aLen = aToIndex - aFromIndex;
|
||||
int bLen = bToIndex - bFromIndex;
|
||||
// lengths differ: cannot be equal
|
||||
if (aLen != bLen) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < aLen; i++) {
|
||||
if (a[i+aFromIndex] != b[i+bFromIndex]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// int[]
|
||||
|
||||
/**
|
||||
* Behaves like Java 9's Arrays.compare
|
||||
* @see <a href="http://download.java.net/java/jdk9/docs/api/java/util/Arrays.html#compare-int:A-int-int-int:A-int-int-">Arrays.compare</a>
|
||||
*/
|
||||
public static int compare(int[] a, int aFromIndex, int aToIndex, int[] b, int bFromIndex, int bToIndex) {
|
||||
checkFromToIndex(aFromIndex, aToIndex, a.length);
|
||||
checkFromToIndex(bFromIndex, bToIndex, b.length);
|
||||
int aLen = aToIndex - aFromIndex;
|
||||
int bLen = bToIndex - bFromIndex;
|
||||
int len = Math.min(aLen, bLen);
|
||||
for (int i = 0; i < len; i++) {
|
||||
int aInt = a[i+aFromIndex];
|
||||
int bInt = b[i+bFromIndex];
|
||||
if (aInt > bInt) {
|
||||
return 1;
|
||||
} else if (aInt < bInt) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// One is a prefix of the other, or, they are equal:
|
||||
return aLen - bLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Behaves like Java 9's Arrays.equals
|
||||
* @see <a href="http://download.java.net/java/jdk9/docs/api/java/util/Arrays.html#equals-int:A-int-int-int:A-int-int-">Arrays.equals</a>
|
||||
*/
|
||||
public static boolean equals(int[] a, int aFromIndex, int aToIndex, int[] b, int bFromIndex, int bToIndex) {
|
||||
checkFromToIndex(aFromIndex, aToIndex, a.length);
|
||||
checkFromToIndex(bFromIndex, bToIndex, b.length);
|
||||
int aLen = aToIndex - aFromIndex;
|
||||
int bLen = bToIndex - bFromIndex;
|
||||
// lengths differ: cannot be equal
|
||||
if (aLen != bLen) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < aLen; i++) {
|
||||
if (a[i+aFromIndex] != b[i+bFromIndex]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// long[]
|
||||
|
||||
/**
|
||||
* Behaves like Java 9's Arrays.compare
|
||||
* @see <a href="http://download.java.net/java/jdk9/docs/api/java/util/Arrays.html#compare-long:A-int-int-long:A-int-int-">Arrays.compare</a>
|
||||
*/
|
||||
public static int compare(long[] a, int aFromIndex, int aToIndex, long[] b, int bFromIndex, int bToIndex) {
|
||||
checkFromToIndex(aFromIndex, aToIndex, a.length);
|
||||
checkFromToIndex(bFromIndex, bToIndex, b.length);
|
||||
int aLen = aToIndex - aFromIndex;
|
||||
int bLen = bToIndex - bFromIndex;
|
||||
int len = Math.min(aLen, bLen);
|
||||
for (int i = 0; i < len; i++) {
|
||||
long aInt = a[i+aFromIndex];
|
||||
long bInt = b[i+bFromIndex];
|
||||
if (aInt > bInt) {
|
||||
return 1;
|
||||
} else if (aInt < bInt) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// One is a prefix of the other, or, they are equal:
|
||||
return aLen - bLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Behaves like Java 9's Arrays.equals
|
||||
* @see <a href="http://download.java.net/java/jdk9/docs/api/java/util/Arrays.html#equals-long:A-int-int-long:A-int-int-">Arrays.equals</a>
|
||||
*/
|
||||
public static boolean equals(long[] a, int aFromIndex, int aToIndex, long[] b, int bFromIndex, int bToIndex) {
|
||||
checkFromToIndex(aFromIndex, aToIndex, a.length);
|
||||
checkFromToIndex(bFromIndex, bToIndex, b.length);
|
||||
int aLen = aToIndex - aFromIndex;
|
||||
int bLen = bToIndex - bFromIndex;
|
||||
// lengths differ: cannot be equal
|
||||
if (aLen != bLen) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < aLen; i++) {
|
||||
if (a[i+aFromIndex] != b[i+bFromIndex]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Additional methods from Java 9's <a href="https://docs.oracle.com/javase/9/docs/api/java/util/Objects.html">
|
||||
* {@code java.util.Objects}</a>.
|
||||
* <p>
|
||||
* This class will be removed when Java 9 is minimum requirement.
|
||||
* Currently any bytecode is patched to use the Java 9 native
|
||||
* classes through MR-JAR (Multi-Release JAR) mechanism.
|
||||
* In Java 8 it will use THIS implementation.
|
||||
* Because of patching, inside the Java source files we always
|
||||
* refer to the Lucene implementations, but the final Lucene
|
||||
* JAR files will use the native Java 9 class names when executed
|
||||
* with Java 9.
|
||||
* @lucene.internal
|
||||
*/
|
||||
public final class FutureObjects {
|
||||
|
||||
private FutureObjects() {} // no instance
|
||||
|
||||
/**
|
||||
* Behaves like Java 9's Objects.checkIndex
|
||||
* @see <a href="http://download.java.net/java/jdk9/docs/api/java/util/Objects.html#checkIndex-int-int-">Objects.checkIndex</a>
|
||||
*/
|
||||
public static int checkIndex(int index, int length) {
|
||||
if (index < 0 || index >= length) {
|
||||
throw new IndexOutOfBoundsException("Index " + index + " out-of-bounds for length " + length);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Behaves like Java 9's Objects.checkFromToIndex
|
||||
* @see <a href="http://download.java.net/java/jdk9/docs/api/java/util/Objects.html#checkFromToIndex-int-int-int-">Objects.checkFromToIndex</a>
|
||||
*/
|
||||
public static int checkFromToIndex(int fromIndex, int toIndex, int length) {
|
||||
if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) {
|
||||
throw new IndexOutOfBoundsException("Range [" + fromIndex + ", " + toIndex + ") out-of-bounds for length " + length);
|
||||
}
|
||||
return fromIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Behaves like Java 9's Objects.checkFromIndexSize
|
||||
* @see <a href="http://download.java.net/java/jdk9/docs/api/java/util/Objects.html#checkFromIndexSize-int-int-int-">Objects.checkFromIndexSize</a>
|
||||
*/
|
||||
public static int checkFromIndexSize(int fromIndex, int size, int length) {
|
||||
int end = fromIndex + size;
|
||||
if (fromIndex < 0 || fromIndex > end || end > length) {
|
||||
throw new IndexOutOfBoundsException("Range [" + fromIndex + ", " + fromIndex + " + " + size + ") out-of-bounds for length " + length);
|
||||
}
|
||||
return fromIndex;
|
||||
}
|
||||
}
|
|
@ -93,45 +93,15 @@ public final class IntsRef implements Comparable<IntsRef>, Cloneable {
|
|||
}
|
||||
|
||||
public boolean intsEquals(IntsRef other) {
|
||||
if (length == other.length) {
|
||||
int otherUpto = other.offset;
|
||||
final int[] otherInts = other.ints;
|
||||
final int end = offset + length;
|
||||
for(int upto=offset;upto<end;upto++,otherUpto++) {
|
||||
if (ints[upto] != otherInts[otherUpto]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return FutureArrays.equals(this.ints, this.offset, this.offset + this.length,
|
||||
other.ints, other.offset, other.offset + other.length);
|
||||
}
|
||||
|
||||
/** Signed int order comparison */
|
||||
@Override
|
||||
public int compareTo(IntsRef other) {
|
||||
if (this == other) return 0;
|
||||
|
||||
final int[] aInts = this.ints;
|
||||
int aUpto = this.offset;
|
||||
final int[] bInts = other.ints;
|
||||
int bUpto = other.offset;
|
||||
|
||||
final int aStop = aUpto + Math.min(this.length, other.length);
|
||||
|
||||
while(aUpto < aStop) {
|
||||
int aInt = aInts[aUpto++];
|
||||
int bInt = bInts[bUpto++];
|
||||
if (aInt > bInt) {
|
||||
return 1;
|
||||
} else if (aInt < bInt) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// One is a prefix of the other, or, they are equal:
|
||||
return this.length - other.length;
|
||||
return FutureArrays.compare(this.ints, this.offset, this.offset + this.length,
|
||||
other.ints, other.offset, other.offset + other.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -92,45 +92,15 @@ public final class LongsRef implements Comparable<LongsRef>, Cloneable {
|
|||
}
|
||||
|
||||
public boolean longsEquals(LongsRef other) {
|
||||
if (length == other.length) {
|
||||
int otherUpto = other.offset;
|
||||
final long[] otherInts = other.longs;
|
||||
final long end = offset + length;
|
||||
for(int upto=offset; upto<end; upto++,otherUpto++) {
|
||||
if (longs[upto] != otherInts[otherUpto]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return FutureArrays.equals(this.longs, this.offset, this.offset + this.length,
|
||||
other.longs, other.offset, other.offset + other.length);
|
||||
}
|
||||
|
||||
/** Signed int order comparison */
|
||||
@Override
|
||||
public int compareTo(LongsRef other) {
|
||||
if (this == other) return 0;
|
||||
|
||||
final long[] aInts = this.longs;
|
||||
int aUpto = this.offset;
|
||||
final long[] bInts = other.longs;
|
||||
int bUpto = other.offset;
|
||||
|
||||
final long aStop = aUpto + Math.min(this.length, other.length);
|
||||
|
||||
while(aUpto < aStop) {
|
||||
long aInt = aInts[aUpto++];
|
||||
long bInt = bInts[bUpto++];
|
||||
if (aInt > bInt) {
|
||||
return 1;
|
||||
} else if (aInt < bInt) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// One is a prefix of the other, or, they are equal:
|
||||
return this.length - other.length;
|
||||
return FutureArrays.compare(this.longs, this.offset, this.offset + this.length,
|
||||
other.longs, other.offset, other.offset + other.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -34,21 +34,19 @@ public abstract class StringHelper {
|
|||
/**
|
||||
* Compares two {@link BytesRef}, element by element, and returns the
|
||||
* number of elements common to both arrays (from the start of each).
|
||||
* This method assumes currentTerm comes after priorTerm.
|
||||
*
|
||||
* @param left The first {@link BytesRef} to compare
|
||||
* @param right The second {@link BytesRef} to compare
|
||||
* @param priorTerm The first {@link BytesRef} to compare
|
||||
* @param currentTerm The second {@link BytesRef} to compare
|
||||
* @return The number of common elements (from the start of each).
|
||||
*/
|
||||
public static int bytesDifference(BytesRef left, BytesRef right) {
|
||||
int len = left.length < right.length ? left.length : right.length;
|
||||
final byte[] bytesLeft = left.bytes;
|
||||
final int offLeft = left.offset;
|
||||
byte[] bytesRight = right.bytes;
|
||||
final int offRight = right.offset;
|
||||
for (int i = 0; i < len; i++)
|
||||
if (bytesLeft[i+offLeft] != bytesRight[i+offRight])
|
||||
return i;
|
||||
return len;
|
||||
public static int bytesDifference(BytesRef priorTerm, BytesRef currentTerm) {
|
||||
int mismatch = FutureArrays.mismatch(priorTerm.bytes, priorTerm.offset, priorTerm.offset + priorTerm.length,
|
||||
currentTerm.bytes, currentTerm.offset, currentTerm.offset + currentTerm.length);
|
||||
if (mismatch < 0) {
|
||||
throw new IllegalArgumentException("terms out of order: priorTerm=" + priorTerm + ",currentTerm=" + currentTerm);
|
||||
}
|
||||
return mismatch;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,15 +55,7 @@ public abstract class StringHelper {
|
|||
* This method assumes currentTerm comes after priorTerm.
|
||||
*/
|
||||
public static int sortKeyLength(final BytesRef priorTerm, final BytesRef currentTerm) {
|
||||
final int currentTermOffset = currentTerm.offset;
|
||||
final int priorTermOffset = priorTerm.offset;
|
||||
final int limit = Math.min(priorTerm.length, currentTerm.length);
|
||||
for (int i = 0; i < limit; i++) {
|
||||
if (priorTerm.bytes[priorTermOffset+i] != currentTerm.bytes[currentTermOffset+i]) {
|
||||
return i+1;
|
||||
}
|
||||
}
|
||||
return Math.min(1+priorTerm.length, currentTerm.length);
|
||||
return bytesDifference(priorTerm, currentTerm) + 1;
|
||||
}
|
||||
|
||||
private StringHelper() {
|
||||
|
@ -83,17 +73,12 @@ public abstract class StringHelper {
|
|||
* Otherwise <code>false</code>.
|
||||
*/
|
||||
public static boolean startsWith(byte[] ref, BytesRef prefix) {
|
||||
// not long enough to start with the prefix
|
||||
if (ref.length < prefix.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i=0;i<prefix.length;i++) {
|
||||
if (ref[i] != prefix.bytes[prefix.offset+i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return FutureArrays.equals(ref, 0, prefix.length,
|
||||
prefix.bytes, prefix.offset, prefix.offset + prefix.length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -108,7 +93,12 @@ public abstract class StringHelper {
|
|||
* Otherwise <code>false</code>.
|
||||
*/
|
||||
public static boolean startsWith(BytesRef ref, BytesRef prefix) {
|
||||
return sliceEquals(ref, prefix, 0);
|
||||
// not long enough to start with the prefix
|
||||
if (ref.length < prefix.length) {
|
||||
return false;
|
||||
}
|
||||
return FutureArrays.equals(ref.bytes, ref.offset, ref.offset + prefix.length,
|
||||
prefix.bytes, prefix.offset, prefix.offset + prefix.length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -123,24 +113,13 @@ public abstract class StringHelper {
|
|||
* Otherwise <code>false</code>.
|
||||
*/
|
||||
public static boolean endsWith(BytesRef ref, BytesRef suffix) {
|
||||
return sliceEquals(ref, suffix, ref.length - suffix.length);
|
||||
}
|
||||
|
||||
private static boolean sliceEquals(BytesRef sliceToTest, BytesRef other, int pos) {
|
||||
if (pos < 0 || sliceToTest.length - pos < other.length) {
|
||||
int startAt = ref.length - suffix.length;
|
||||
// not long enough to start with the suffix
|
||||
if (startAt < 0) {
|
||||
return false;
|
||||
}
|
||||
int i = sliceToTest.offset + pos;
|
||||
int j = other.offset;
|
||||
final int k = other.offset + other.length;
|
||||
|
||||
while (j < k) {
|
||||
if (sliceToTest.bytes[i++] != other.bytes[j++]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return FutureArrays.equals(ref.bytes, ref.offset + startAt, ref.offset + startAt + suffix.length,
|
||||
suffix.bytes, suffix.offset, suffix.offset + suffix.length);
|
||||
}
|
||||
|
||||
/** Pass this as the seed to {@link #murmurhash3_x86_32}. */
|
||||
|
@ -375,16 +354,12 @@ public abstract class StringHelper {
|
|||
|
||||
/** Compares a fixed length slice of two byte arrays interpreted as
|
||||
* big-endian unsigned values. Returns positive int if a > b,
|
||||
* negative int if a < b and 0 if a == b */
|
||||
* negative int if a < b and 0 if a == b
|
||||
*
|
||||
* @deprecated Use FutureArrays.compareUnsigned instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static int compare(int count, byte[] a, int aOffset, byte[] b, int bOffset) {
|
||||
// TODO: dedup this w/ BytesRef.compareTo?
|
||||
for(int i=0;i<count;i++) {
|
||||
int cmp = (a[aOffset+i]&0xff) - (b[bOffset+i]&0xff);
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return FutureArrays.compareUnsigned(a, aOffset, aOffset + count, b, bOffset, bOffset + count);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.Set;
|
|||
|
||||
import org.apache.lucene.util.Accountable;
|
||||
import org.apache.lucene.util.ArrayUtil;
|
||||
import org.apache.lucene.util.FutureObjects;
|
||||
import org.apache.lucene.util.InPlaceMergeSorter;
|
||||
import org.apache.lucene.util.RamUsageEstimator;
|
||||
import org.apache.lucene.util.Sorter;
|
||||
|
@ -114,14 +115,8 @@ public class Automaton implements Accountable {
|
|||
|
||||
/** Set or clear this state as an accept state. */
|
||||
public void setAccept(int state, boolean accept) {
|
||||
if (state >= getNumStates()) {
|
||||
throw new IllegalArgumentException("state=" + state + " is out of bounds (numStates=" + getNumStates() + ")");
|
||||
}
|
||||
if (accept) {
|
||||
isAccept.set(state);
|
||||
} else {
|
||||
isAccept.clear(state);
|
||||
}
|
||||
FutureObjects.checkIndex(state, getNumStates());
|
||||
isAccept.set(state, accept);
|
||||
}
|
||||
|
||||
/** Sugar to get all transitions for all states. This is
|
||||
|
@ -161,12 +156,9 @@ public class Automaton implements Accountable {
|
|||
public void addTransition(int source, int dest, int min, int max) {
|
||||
assert nextTransition%3 == 0;
|
||||
|
||||
if (source >= nextState/2) {
|
||||
throw new IllegalArgumentException("source=" + source + " is out of bounds (maxState is " + (nextState/2-1) + ")");
|
||||
}
|
||||
if (dest >= nextState/2) {
|
||||
throw new IllegalArgumentException("dest=" + dest + " is out of bounds (max state is " + (nextState/2-1) + ")");
|
||||
}
|
||||
int bounds = nextState/2;
|
||||
FutureObjects.checkIndex(source, bounds);
|
||||
FutureObjects.checkIndex(dest, bounds);
|
||||
|
||||
growTransitions();
|
||||
if (curState != source) {
|
||||
|
@ -842,10 +834,7 @@ public class Automaton implements Accountable {
|
|||
|
||||
/** Set or clear this state as an accept state. */
|
||||
public void setAccept(int state, boolean accept) {
|
||||
if (state >= getNumStates()) {
|
||||
throw new IllegalArgumentException("state=" + state + " is out of bounds (numStates=" + getNumStates() + ")");
|
||||
}
|
||||
|
||||
FutureObjects.checkIndex(state, getNumStates());
|
||||
this.isAccept.set(state, accept);
|
||||
}
|
||||
|
||||
|
|
|
@ -46,10 +46,9 @@ public class TestCharTermAttributeImpl extends LuceneTestCase {
|
|||
CharTermAttributeImpl t = new CharTermAttributeImpl();
|
||||
char[] content = "hello".toCharArray();
|
||||
t.copyBuffer(content, 0, content.length);
|
||||
IllegalArgumentException expected = expectThrows(IllegalArgumentException.class, () -> {
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
t.setLength(-1);
|
||||
});
|
||||
assertTrue(expected.getMessage().contains("must not be negative"));
|
||||
}
|
||||
|
||||
public void testGrow() {
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
*/
|
||||
package org.apache.lucene.util;
|
||||
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
@ -107,20 +105,6 @@ public class TestArrayUtil extends LuceneTestCase {
|
|||
test = ArrayUtil.parseInt("foo 1923 bar".toCharArray(), 4, 4);
|
||||
assertTrue(test + " does not equal: " + 1923, test == 1923);
|
||||
}
|
||||
|
||||
public void testSliceEquals() {
|
||||
String left = "this is equal";
|
||||
String right = left;
|
||||
byte[] leftChars = left.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] rightChars = right.getBytes(StandardCharsets.UTF_8);
|
||||
assertTrue(left + " does not equal: " + right, ArrayUtil.equals(leftChars, 0, rightChars, 0, left.length()));
|
||||
|
||||
assertFalse(left + " does not equal: " + right, ArrayUtil.equals(leftChars, 1, rightChars, 0, left.length()));
|
||||
assertFalse(left + " does not equal: " + right, ArrayUtil.equals(leftChars, 1, rightChars, 2, left.length()));
|
||||
|
||||
assertFalse(left + " does not equal: " + right, ArrayUtil.equals(leftChars, 25, rightChars, 0, left.length()));
|
||||
assertFalse(left + " does not equal: " + right, ArrayUtil.equals(leftChars, 12, rightChars, 0, left.length()));
|
||||
}
|
||||
|
||||
private Integer[] createRandomArray(int maxSize) {
|
||||
final Random rnd = random();
|
||||
|
|
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
* 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.nio.charset.StandardCharsets;
|
||||
|
||||
/** Test java 8-compatible implementations of {@code java.util.Arrays} methods */
|
||||
public class TestFutureArrays extends LuceneTestCase {
|
||||
|
||||
public void testByteMismatch() {
|
||||
assertEquals(1, FutureArrays.mismatch(bytes("ab"), 0, 2, bytes("ac"), 0, 2));
|
||||
assertEquals(0, FutureArrays.mismatch(bytes("ab"), 0, 2, bytes("b"), 0, 1));
|
||||
assertEquals(-1, FutureArrays.mismatch(bytes("ab"), 0, 2, bytes("ab"), 0, 2));
|
||||
assertEquals(1, FutureArrays.mismatch(bytes("ab"), 0, 2, bytes("a"), 0, 1));
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.mismatch(bytes("ab"), 2, 1, bytes("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.mismatch(bytes("ab"), 2, 1, bytes("a"), 1, 0);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.mismatch(null, 0, 2, bytes("a"), 0, 1);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.mismatch(bytes("ab"), 0, 2, null, 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.mismatch(bytes("ab"), 0, 3, bytes("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.mismatch(bytes("ab"), 0, 2, bytes("a"), 0, 2);
|
||||
});
|
||||
}
|
||||
|
||||
public void testCharMismatch() {
|
||||
assertEquals(1, FutureArrays.mismatch(chars("ab"), 0, 2, chars("ac"), 0, 2));
|
||||
assertEquals(0, FutureArrays.mismatch(chars("ab"), 0, 2, chars("b"), 0, 1));
|
||||
assertEquals(-1, FutureArrays.mismatch(chars("ab"), 0, 2, chars("ab"), 0, 2));
|
||||
assertEquals(1, FutureArrays.mismatch(chars("ab"), 0, 2, chars("a"), 0, 1));
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.mismatch(chars("ab"), 2, 1, chars("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.mismatch(chars("ab"), 2, 1, chars("a"), 1, 0);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.mismatch(null, 0, 2, chars("a"), 0, 1);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.mismatch(chars("ab"), 0, 2, null, 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.mismatch(chars("ab"), 0, 3, chars("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.mismatch(chars("ab"), 0, 2, chars("a"), 0, 2);
|
||||
});
|
||||
}
|
||||
|
||||
public void testByteCompareUnsigned() {
|
||||
assertEquals(1, Integer.signum(FutureArrays.compareUnsigned(bytes("ab"), 0, 2, bytes("a"), 0, 1)));
|
||||
assertEquals(1, Integer.signum(FutureArrays.compareUnsigned(bytes("ab"), 0, 2, bytes("aa"), 0, 2)));
|
||||
assertEquals(0, Integer.signum(FutureArrays.compareUnsigned(bytes("ab"), 0, 2, bytes("ab"), 0, 2)));
|
||||
assertEquals(-1, Integer.signum(FutureArrays.compareUnsigned(bytes("a"), 0, 1, bytes("ab"), 0, 2)));
|
||||
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.compareUnsigned(bytes("ab"), 2, 1, bytes("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.compareUnsigned(bytes("ab"), 2, 1, bytes("a"), 1, 0);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.compareUnsigned(null, 0, 2, bytes("a"), 0, 1);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.compareUnsigned(bytes("ab"), 0, 2, null, 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.compareUnsigned(bytes("ab"), 0, 3, bytes("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.compareUnsigned(bytes("ab"), 0, 2, bytes("a"), 0, 2);
|
||||
});
|
||||
}
|
||||
|
||||
public void testCharCompare() {
|
||||
assertEquals(1, Integer.signum(FutureArrays.compare(chars("ab"), 0, 2, chars("a"), 0, 1)));
|
||||
assertEquals(1, Integer.signum(FutureArrays.compare(chars("ab"), 0, 2, chars("aa"), 0, 2)));
|
||||
assertEquals(0, Integer.signum(FutureArrays.compare(chars("ab"), 0, 2, chars("ab"), 0, 2)));
|
||||
assertEquals(-1, Integer.signum(FutureArrays.compare(chars("a"), 0, 1, chars("ab"), 0, 2)));
|
||||
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.compare(chars("ab"), 2, 1, chars("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.compare(chars("ab"), 2, 1, chars("a"), 1, 0);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.compare(null, 0, 2, chars("a"), 0, 1);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.compare(chars("ab"), 0, 2, null, 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.compare(chars("ab"), 0, 3, chars("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.compare(chars("ab"), 0, 2, chars("a"), 0, 2);
|
||||
});
|
||||
}
|
||||
|
||||
public void testIntCompare() {
|
||||
assertEquals(1, Integer.signum(FutureArrays.compare(ints("ab"), 0, 2, ints("a"), 0, 1)));
|
||||
assertEquals(1, Integer.signum(FutureArrays.compare(ints("ab"), 0, 2, ints("aa"), 0, 2)));
|
||||
assertEquals(0, Integer.signum(FutureArrays.compare(ints("ab"), 0, 2, ints("ab"), 0, 2)));
|
||||
assertEquals(-1, Integer.signum(FutureArrays.compare(ints("a"), 0, 1, ints("ab"), 0, 2)));
|
||||
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.compare(ints("ab"), 2, 1, ints("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.compare(ints("ab"), 2, 1, ints("a"), 1, 0);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.compare(null, 0, 2, ints("a"), 0, 1);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.compare(ints("ab"), 0, 2, null, 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.compare(ints("ab"), 0, 3, ints("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.compare(ints("ab"), 0, 2, ints("a"), 0, 2);
|
||||
});
|
||||
}
|
||||
|
||||
public void testLongCompare() {
|
||||
assertEquals(1, Integer.signum(FutureArrays.compare(longs("ab"), 0, 2, longs("a"), 0, 1)));
|
||||
assertEquals(1, Integer.signum(FutureArrays.compare(longs("ab"), 0, 2, longs("aa"), 0, 2)));
|
||||
assertEquals(0, Integer.signum(FutureArrays.compare(longs("ab"), 0, 2, longs("ab"), 0, 2)));
|
||||
assertEquals(-1, Integer.signum(FutureArrays.compare(longs("a"), 0, 1, longs("ab"), 0, 2)));
|
||||
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.compare(longs("ab"), 2, 1, longs("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.compare(longs("ab"), 2, 1, longs("a"), 1, 0);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.compare(null, 0, 2, longs("a"), 0, 1);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.compare(longs("ab"), 0, 2, null, 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.compare(longs("ab"), 0, 3, longs("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.compare(longs("ab"), 0, 2, longs("a"), 0, 2);
|
||||
});
|
||||
}
|
||||
|
||||
public void testByteEquals() {
|
||||
assertFalse(FutureArrays.equals(bytes("ab"), 0, 2, bytes("a"), 0, 1));
|
||||
assertFalse(FutureArrays.equals(bytes("ab"), 0, 2, bytes("aa"), 0, 2));
|
||||
assertTrue(FutureArrays.equals(bytes("ab"), 0, 2, bytes("ab"), 0, 2));
|
||||
assertFalse(FutureArrays.equals(bytes("a"), 0, 1, bytes("ab"), 0, 2));
|
||||
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.equals(bytes("ab"), 2, 1, bytes("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.equals(bytes("ab"), 2, 1, bytes("a"), 1, 0);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.equals(null, 0, 2, bytes("a"), 0, 1);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.equals(bytes("ab"), 0, 2, null, 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.equals(bytes("ab"), 0, 3, bytes("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.equals(bytes("ab"), 0, 2, bytes("a"), 0, 2);
|
||||
});
|
||||
}
|
||||
|
||||
public void testCharEquals() {
|
||||
assertFalse(FutureArrays.equals(chars("ab"), 0, 2, chars("a"), 0, 1));
|
||||
assertFalse(FutureArrays.equals(chars("ab"), 0, 2, chars("aa"), 0, 2));
|
||||
assertTrue(FutureArrays.equals(chars("ab"), 0, 2, chars("ab"), 0, 2));
|
||||
assertFalse(FutureArrays.equals(chars("a"), 0, 1, chars("ab"), 0, 2));
|
||||
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.equals(chars("ab"), 2, 1, chars("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.equals(chars("ab"), 2, 1, chars("a"), 1, 0);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.equals(null, 0, 2, chars("a"), 0, 1);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.equals(chars("ab"), 0, 2, null, 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.equals(chars("ab"), 0, 3, chars("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.equals(chars("ab"), 0, 2, chars("a"), 0, 2);
|
||||
});
|
||||
}
|
||||
|
||||
public void testIntEquals() {
|
||||
assertFalse(FutureArrays.equals(ints("ab"), 0, 2, ints("a"), 0, 1));
|
||||
assertFalse(FutureArrays.equals(ints("ab"), 0, 2, ints("aa"), 0, 2));
|
||||
assertTrue(FutureArrays.equals(ints("ab"), 0, 2, ints("ab"), 0, 2));
|
||||
assertFalse(FutureArrays.equals(ints("a"), 0, 1, ints("ab"), 0, 2));
|
||||
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.equals(ints("ab"), 2, 1, ints("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.equals(ints("ab"), 2, 1, ints("a"), 1, 0);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.equals(null, 0, 2, ints("a"), 0, 1);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.equals(ints("ab"), 0, 2, null, 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.equals(ints("ab"), 0, 3, ints("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.equals(ints("ab"), 0, 2, ints("a"), 0, 2);
|
||||
});
|
||||
}
|
||||
|
||||
public void testLongEquals() {
|
||||
assertFalse(FutureArrays.equals(longs("ab"), 0, 2, longs("a"), 0, 1));
|
||||
assertFalse(FutureArrays.equals(longs("ab"), 0, 2, longs("aa"), 0, 2));
|
||||
assertTrue(FutureArrays.equals(longs("ab"), 0, 2, longs("ab"), 0, 2));
|
||||
assertFalse(FutureArrays.equals(longs("a"), 0, 1, longs("ab"), 0, 2));
|
||||
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.equals(longs("ab"), 2, 1, longs("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
FutureArrays.equals(longs("ab"), 2, 1, longs("a"), 1, 0);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.equals(null, 0, 2, longs("a"), 0, 1);
|
||||
});
|
||||
expectThrows(NullPointerException.class, () -> {
|
||||
FutureArrays.equals(longs("ab"), 0, 2, null, 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.equals(longs("ab"), 0, 3, longs("a"), 0, 1);
|
||||
});
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureArrays.equals(longs("ab"), 0, 2, longs("a"), 0, 2);
|
||||
});
|
||||
}
|
||||
|
||||
private byte[] bytes(String s) {
|
||||
return s.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private char[] chars(String s) {
|
||||
return s.toCharArray();
|
||||
}
|
||||
|
||||
private int[] ints(String s) {
|
||||
int ints[] = new int[s.length()];
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
ints[i] = s.charAt(i);
|
||||
}
|
||||
return ints;
|
||||
}
|
||||
|
||||
private long[] longs(String s) {
|
||||
long longs[] = new long[s.length()];
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
longs[i] = s.charAt(i);
|
||||
}
|
||||
return longs;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/** Test java 8-compatible implementations of {@code java.util.Objects} methods */
|
||||
public class TestFutureObjects extends LuceneTestCase {
|
||||
|
||||
public void testCheckIndex() {
|
||||
assertEquals(0, FutureObjects.checkIndex(0, 1));
|
||||
assertEquals(1, FutureObjects.checkIndex(1, 2));
|
||||
|
||||
Exception e = expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureObjects.checkIndex(-1, 0);
|
||||
});
|
||||
assertEquals("Index -1 out-of-bounds for length 0", e.getMessage());
|
||||
|
||||
e = expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureObjects.checkIndex(0, 0);
|
||||
});
|
||||
assertEquals("Index 0 out-of-bounds for length 0", e.getMessage());
|
||||
|
||||
e = expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureObjects.checkIndex(1, 0);
|
||||
});
|
||||
assertEquals("Index 1 out-of-bounds for length 0", e.getMessage());
|
||||
|
||||
e = expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureObjects.checkIndex(0, -1);
|
||||
});
|
||||
assertEquals("Index 0 out-of-bounds for length -1", e.getMessage());
|
||||
}
|
||||
|
||||
public void testCheckFromToIndex() {
|
||||
assertEquals(0, FutureObjects.checkFromToIndex(0, 0, 0));
|
||||
assertEquals(1, FutureObjects.checkFromToIndex(1, 2, 2));
|
||||
|
||||
Exception e = expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureObjects.checkFromToIndex(-1, 0, 0);
|
||||
});
|
||||
assertEquals("Range [-1, 0) out-of-bounds for length 0", e.getMessage());
|
||||
|
||||
e = expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureObjects.checkFromToIndex(1, 0, 2);
|
||||
});
|
||||
assertEquals("Range [1, 0) out-of-bounds for length 2", e.getMessage());
|
||||
|
||||
e = expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureObjects.checkFromToIndex(1, 3, 2);
|
||||
});
|
||||
assertEquals("Range [1, 3) out-of-bounds for length 2", e.getMessage());
|
||||
|
||||
e = expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureObjects.checkFromToIndex(0, 0, -1);
|
||||
});
|
||||
assertEquals("Range [0, 0) out-of-bounds for length -1", e.getMessage());
|
||||
}
|
||||
|
||||
public void testCheckFromIndexSize() {
|
||||
assertEquals(0, FutureObjects.checkFromIndexSize(0, 0, 0));
|
||||
assertEquals(1, FutureObjects.checkFromIndexSize(1, 2, 3));
|
||||
|
||||
Exception e = expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureObjects.checkFromIndexSize(-1, 0, 1);
|
||||
});
|
||||
assertEquals("Range [-1, -1 + 0) out-of-bounds for length 1", e.getMessage());
|
||||
|
||||
e = expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureObjects.checkFromIndexSize(0, -1, 1);
|
||||
});
|
||||
assertEquals("Range [0, 0 + -1) out-of-bounds for length 1", e.getMessage());
|
||||
|
||||
e = expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureObjects.checkFromIndexSize(0, 2, 1);
|
||||
});
|
||||
assertEquals("Range [0, 0 + 2) out-of-bounds for length 1", e.getMessage());
|
||||
|
||||
e = expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureObjects.checkFromIndexSize(1, Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
});
|
||||
assertEquals("Range [1, 1 + 2147483647) out-of-bounds for length 2147483647", e.getMessage());
|
||||
|
||||
e = expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
FutureObjects.checkFromIndexSize(0, 0, -1);
|
||||
});
|
||||
assertEquals("Range [0, 0 + 0) out-of-bounds for length -1", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
|
@ -23,6 +23,15 @@ public class TestStringHelper extends LuceneTestCase {
|
|||
BytesRef left = new BytesRef("foobar");
|
||||
BytesRef right = new BytesRef("foozo");
|
||||
assertEquals(3, StringHelper.bytesDifference(left, right));
|
||||
assertEquals(2, StringHelper.bytesDifference(new BytesRef("foo"), new BytesRef("for")));
|
||||
assertEquals(2, StringHelper.bytesDifference(new BytesRef("foo1234"), new BytesRef("for1234")));
|
||||
assertEquals(1, StringHelper.bytesDifference(new BytesRef("foo"), new BytesRef("fz")));
|
||||
assertEquals(0, StringHelper.bytesDifference(new BytesRef("foo"), new BytesRef("g")));
|
||||
assertEquals(3, StringHelper.bytesDifference(new BytesRef("foo"), new BytesRef("food")));
|
||||
// we can detect terms are out of order if we see a duplicate
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
StringHelper.bytesDifference(new BytesRef("ab"), new BytesRef("ab"));
|
||||
});
|
||||
}
|
||||
|
||||
public void testStartsWith() {
|
||||
|
@ -63,5 +72,9 @@ public class TestStringHelper extends LuceneTestCase {
|
|||
assertEquals(2, StringHelper.sortKeyLength(new BytesRef("foo"), new BytesRef("fz")));
|
||||
assertEquals(1, StringHelper.sortKeyLength(new BytesRef("foo"), new BytesRef("g")));
|
||||
assertEquals(4, StringHelper.sortKeyLength(new BytesRef("foo"), new BytesRef("food")));
|
||||
// we can detect terms are out of order if we see a duplicate
|
||||
expectThrows(IllegalArgumentException.class, () -> {
|
||||
StringHelper.sortKeyLength(new BytesRef("ab"), new BytesRef("ab"));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
*/
|
||||
package org.apache.lucene.util;
|
||||
|
||||
|
||||
/*
|
||||
* Some of this code came from the excellent Unicode
|
||||
* conversion examples from:
|
||||
|
@ -143,7 +142,7 @@ public class TestUnicodeUtil extends LuceneTestCase {
|
|||
final int utf32Len = UnicodeUtil.UTF8toUTF32(new BytesRef(utf8, 0, utf8Len), utf32);
|
||||
|
||||
int[] codePoints = s.codePoints().toArray();
|
||||
if (!ArrayUtil.equals(codePoints, 0, utf32, 0, codePoints.length)) {
|
||||
if (!FutureArrays.equals(codePoints, 0, codePoints.length, utf32, 0, codePoints.length)) {
|
||||
System.out.println("FAILED");
|
||||
for(int j=0;j<s.length();j++) {
|
||||
System.out.println(" char[" + j + "]=" + Integer.toHexString(s.charAt(j)));
|
||||
|
|
|
@ -79,7 +79,7 @@ public interface TaxonomyWriter extends Closeable, TwoPhaseCommit {
|
|||
* If the given ordinal is the ROOT_ORDINAL, an INVALID_ORDINAL is returned.
|
||||
* If the given ordinal is a top-level category, the ROOT_ORDINAL is returned.
|
||||
* If an invalid ordinal is given (negative or beyond the last available
|
||||
* ordinal), an ArrayIndexOutOfBoundsException is thrown. However, it is
|
||||
* ordinal), an IndexOutOfBoundsException is thrown. However, it is
|
||||
* expected that getParent will only be called for ordinals which are
|
||||
* already known to be in the taxonomy.
|
||||
* TODO (Facet): instead of a getParent(ordinal) method, consider having a
|
||||
|
|
|
@ -61,6 +61,7 @@ import org.apache.lucene.store.AlreadyClosedException;
|
|||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.store.LockObtainFailedException;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.FutureObjects;
|
||||
|
||||
/**
|
||||
* {@link TaxonomyWriter} which uses a {@link Directory} to store the taxonomy
|
||||
|
@ -763,9 +764,7 @@ public class DirectoryTaxonomyWriter implements TaxonomyWriter {
|
|||
// Note: the following if() just enforces that a user can never ask
|
||||
// for the parent of a nonexistant category - even if the parent array
|
||||
// was allocated bigger than it really needs to be.
|
||||
if (ordinal >= nextID) {
|
||||
throw new ArrayIndexOutOfBoundsException("requested ordinal is bigger than the largest ordinal in the taxonomy");
|
||||
}
|
||||
FutureObjects.checkIndex(ordinal, nextID);
|
||||
|
||||
int[] parents = getTaxoArrays().parents();
|
||||
assert ordinal < parents.length : "requested ordinal (" + ordinal + "); parents.length (" + parents.length + ") !";
|
||||
|
|
|
@ -490,13 +490,13 @@ public class TestTaxonomyCombined extends FacetTestCase {
|
|||
}
|
||||
|
||||
// check parent of of invalid ordinals:
|
||||
expectThrows(ArrayIndexOutOfBoundsException.class, () -> {
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
tw.getParent(-1);
|
||||
});
|
||||
expectThrows(ArrayIndexOutOfBoundsException.class, () -> {
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
tw.getParent(TaxonomyReader.INVALID_ORDINAL);
|
||||
});
|
||||
expectThrows(ArrayIndexOutOfBoundsException.class, () -> {
|
||||
expectThrows(IndexOutOfBoundsException.class, () -> {
|
||||
tw.getParent(tr.getSize());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -34,11 +34,20 @@
|
|||
<!-- default classpath refid, can be overridden by contrib's build.xml (use the above base.classpath as basis): -->
|
||||
<path id="classpath" refid="base.classpath"/>
|
||||
|
||||
<!-- if we run with Java 9+, we refer to the java9 classes directory and insert this before the main classpath (to "emulate" a MR-JAR): -->
|
||||
<condition property="-test.classpath.java9.addon" value="${build.dir}/classes/java9" else="${build.dir}/classes/java">
|
||||
<and>
|
||||
<not><equals arg1="${build.java.runtime}" arg2="1.8"/></not>
|
||||
<istrue value="${tests.withJava9Patches}"/>
|
||||
</and>
|
||||
</condition>
|
||||
|
||||
<path id="test.base.classpath">
|
||||
<pathelement location="${common.dir}/build/test-framework/classes/java"/>
|
||||
<pathelement location="${common.dir}/build/codecs/classes/java"/>
|
||||
<path refid="classpath"/>
|
||||
<path refid="junit-path"/>
|
||||
<pathelement location="${-test.classpath.java9.addon}"/><!-- if it's a duplicate it gets removed by Ant! -->
|
||||
<pathelement location="${build.dir}/classes/java"/>
|
||||
</path>
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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.tools.ant.Project;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.commons.ClassRemapper;
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
|
||||
def mappings = [
|
||||
'org/apache/lucene/util/FutureObjects': 'java/util/Objects',
|
||||
'org/apache/lucene/util/FutureArrays': 'java/util/Arrays',
|
||||
];
|
||||
|
||||
File inputDir = new File(properties['build.dir'], 'classes/java');
|
||||
File outputDir = new File(properties['build.dir'], 'classes/java9');
|
||||
|
||||
outputDir.mkdirs();
|
||||
|
||||
def scanner = ant.fileScanner {
|
||||
fileset(dir:inputDir) {
|
||||
include(name:"**/*.class")
|
||||
}
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (f in scanner) {
|
||||
ClassReader reader = new ClassReader(f.getBytes());
|
||||
if (mappings.containsKey(reader.className)) {
|
||||
// we do not remap our replacements! :-)
|
||||
continue;
|
||||
}
|
||||
|
||||
ClassWriter writer = new ClassWriter(0 /* no recalculations needed */);
|
||||
boolean remapped = false;
|
||||
ClassRemapper remapper = new ClassRemapper(writer, new Remapper() {
|
||||
@Override
|
||||
public String map(String typeName) {
|
||||
if (mappings.containsKey(typeName)) {
|
||||
remapped = true;
|
||||
return mappings.get(typeName);
|
||||
}
|
||||
return typeName;
|
||||
}
|
||||
});
|
||||
|
||||
reader.accept(remapper, 0 /* keep everything as-is*/);
|
||||
|
||||
if (remapped) {
|
||||
task.log("Remapped: "+reader.className, Project.MSG_INFO);
|
||||
File output = new File(outputDir, reader.className + '.class');
|
||||
output.parentFile.mkdirs();
|
||||
output.setBytes(writer.toByteArray());
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
task.log("Remapped $count class files for Java 9 to: $outputDir", Project.MSG_INFO);
|
|
@ -555,4 +555,7 @@
|
|||
<target name="test" unless="tests.disable-solr">
|
||||
<antcall target="common.test" inheritrefs="true" inheritall="true"/>
|
||||
</target>
|
||||
|
||||
<!-- In Solr we do not generate MR-JARs yet; disable completely so we do not accidentally patch -->
|
||||
<target name="patch-mrjar-classes"/>
|
||||
</project>
|
||||
|
|
Loading…
Reference in New Issue