equals()/hashCode() & tests for ByteArrays to avoid materializing a

full byte[].

Fixes #5435
This commit is contained in:
Holger Hoffstätte 2014-03-14 14:20:06 +01:00
parent 84b5b45644
commit 7b26e1fbf8
2 changed files with 99 additions and 0 deletions

View File

@ -382,6 +382,39 @@ public class BigArrays extends AbstractComponent {
return resize(array, newSize);
}
/** @see Arrays.hashCode(byte[]) */
public int hashCode(ByteArray array) {
if (array == null) {
return 0;
}
int hash = 1;
for (long i = 0; i < array.size(); i++) {
hash = 31 * hash + array.get(i);
}
return hash;
}
/** @see Arrays.equals(byte[], byte[]) */
public boolean equals(ByteArray array, ByteArray other) {
if (array == other) {
return true;
}
if (array.size() != other.size()) {
return false;
}
for (long i = 0; i < array.size(); i++) {
if (array.get(i) != other.get(i)) {
return false;
}
}
return true;
}
/**
* Allocate a new {@link IntArray}.
* @param size the initial length of the array

View File

@ -260,4 +260,70 @@ public class BigArraysTests extends ElasticsearchTestCase {
array2.release();
}
public void testByteArrayEquals() {
final ByteArray empty1 = byteArrayWithBytes(BytesRef.EMPTY_BYTES);
final ByteArray empty2 = byteArrayWithBytes(BytesRef.EMPTY_BYTES);
// identity = equality
assertTrue(bigArrays.equals(empty1, empty1));
// equality: both empty
assertTrue(bigArrays.equals(empty1, empty2));
empty1.release();
empty2.release();
// not equal: contents differ
final ByteArray a1 = byteArrayWithBytes(new byte[]{0});
final ByteArray a2 = byteArrayWithBytes(new byte[]{1});
assertFalse(bigArrays.equals(a1, a2));
a1.release();
a2.release();
// not equal: contents differ
final ByteArray a3 = byteArrayWithBytes(new byte[]{1,2,3});
final ByteArray a4 = byteArrayWithBytes(new byte[]{1,1,3});
assertFalse(bigArrays.equals(a3, a4));
a3.release();
a4.release();
// not equal: contents differ
final ByteArray a5 = byteArrayWithBytes(new byte[]{1,2,3});
final ByteArray a6 = byteArrayWithBytes(new byte[]{1,2,4});
assertFalse(bigArrays.equals(a5, a6));
a5.release();
a6.release();
}
public void testByteArrayHashCode() {
// null arg has hashCode 0
assertEquals(0, bigArrays.hashCode(null));
// empty array should have equal hash
final int emptyHash = Arrays.hashCode(BytesRef.EMPTY_BYTES);
final ByteArray emptyByteArray = byteArrayWithBytes(BytesRef.EMPTY_BYTES);
final int emptyByteArrayHash = bigArrays.hashCode(emptyByteArray);
assertEquals(emptyHash, emptyByteArrayHash);
emptyByteArray.release();
// FUN FACT: Arrays.hashCode() and BytesReference.bytesHashCode() are inconsistent for empty byte[]
// final int emptyHash3 = new BytesArray(BytesRef.EMPTY_BYTES).hashCode();
// assertEquals(emptyHash1, emptyHash3); -> fail (1 vs. 0)
// large arrays should be different
final byte[] array1 = new byte[randomIntBetween(1, 4000000)];
getRandom().nextBytes(array1);
final int array1Hash = Arrays.hashCode(array1);
final ByteArray array2 = byteArrayWithBytes(array1);
final int array2Hash = bigArrays.hashCode(array2);
assertEquals(array1Hash, array2Hash);
array2.release();
}
private ByteArray byteArrayWithBytes(byte[] bytes) {
ByteArray bytearray = bigArrays.newByteArray(bytes.length);
for (int i = 0; i < bytes.length; ++i) {
bytearray.set(i, bytes[i]);
}
return bytearray;
}
}