/* * Copyright 2014 Higher Frequency Trading http://www.higherfrequencytrading.com * * Licensed 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 net.openhft.chronicle.hash.hashing; import net.openhft.chronicle.hash.serialization.BytesInterop; import net.openhft.lang.io.Bytes; import net.openhft.lang.io.NativeBytes; import org.jetbrains.annotations.NotNull; import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.ByteOrder; import static java.nio.ByteOrder.LITTLE_ENDIAN; import static java.nio.ByteOrder.nativeOrder; import static net.openhft.chronicle.hash.hashing.CharSequenceAccess.nativeCharSequenceAccess; import static net.openhft.chronicle.hash.hashing.UnsafeAccess.*; /** * Hash function producing {@code long}-valued result from byte sequences of any length and * a plenty of different sources which "feels like byte sequences". Except {@link * #hashBytes(byte[])}, {@link #hashBytes(ByteBuffer)} (with their "sliced" versions) and * {@link #hashMemory(long, long)} methods, which actually accept byte sequences, notion of byte * sequence is defined as follows: *
This method doesn't promise to throw a {@code RuntimeException} if {@code
* [off, off + len - 1]} subsequence exceeds the bounds of the bytes sequence, defined by {@code
* access} strategy for the given {@code input}, so use this method with caution.
*
* @param input the object to read bytes from
* @param access access which defines the abstraction of the given input
* as ordered byte sequence
* @param off offset to the first byte of the subsequence to hash
* @param len length of the subsequence to hash
* @param This method doesn't alter the state (mark, position, limit or order) of the given
* {@code ByteBuffer}.
*
* @param input the buffer to read bytes from
* @param off index of the first {@code byte} in the subsequence to hash
* @param len length of the subsequence to hash
* @return hash code for the specified subsequence
* @throws IndexOutOfBoundsException if {@code off < 0} or {@code off + len > input.capacity()}
* or {@code len < 0}
*/
public long hashBytes(@NotNull ByteBuffer input, int off, int len) {
checkArrayOffs(input.capacity(), off, len);
return hash(input, ByteBufferAccess.INSTANCE, off, len);
}
/**
* Shortcut for {@link #hashBytes(Bytes, long, long)
* hashBytes(input, input.position(), input.remaining())}.
*/
public long hashBytes(Bytes input) {
return hashBytes(input, input.position(), input.remaining());
}
/**
* Returns the hash code for the specified subsequence of the given {@code Bytes}.
*
* This method doesn't alter the state (position or limit) of the given {@code Bytes}.
*
* @param input the {@code Bytes} to read bytes from
* @param off index of the first {@code byte} in the subsequence to hash
* @param len length of the subsequence to hash
* @return hash code for the specified subsequence
* @throws IndexOutOfBoundsException if {@code off < 0} or {@code off + len > input.capacity()}
* or {@code len < 0}
*/
public long hashBytes(Bytes input, long off, long len) {
if (len < 0 || off < 0 || off + len > input.capacity() || off + len < 0)
throw new IndexOutOfBoundsException();
if (input instanceof NativeBytes) {
return hashMemory(input.address() + off, len);
} else {
return hash(input, toBytes(), off, len);
}
}
/**
* Returns the hash code of bytes of the wild memory from the given address. Use with caution.
*
* @param address the address of the first byte to hash
* @param len length of the byte sequence to hash
* @return hash code for the specified byte sequence
*/
public long hashMemory(long address, long len) {
return unsafeHash(null, address, len);
}
/**
* Shortcut for {@link #hashChars(char[], int, int) hashChars(input, 0, input.length)}.
*/
public long hashChars(@NotNull char[] input) {
return hashChars(input, 0, input.length);
}
/**
* Returns the hash code for bytes, as they lay in memory, of the specified subsequence
* of the given {@code char} array.
*
* @param input the array to read data from
* @param off index of the first {@code char} in the subsequence to hash
* @param len length of the subsequence to hash, in chars (i. e. the length of the bytes
* sequence to hash is {@code len * 2L})
* @return hash code for the specified subsequence
* @throws IndexOutOfBoundsException if {@code off < 0} or {@code off + len > input.length}
* or {@code len < 0}
*/
public long hashChars(@NotNull char[] input, int off, int len) {
checkArrayOffs(input.length, off, len);
return unsafeHash(input, CHAR_BASE + (off * 2L), len * 2L);
}
/**
* Shortcut for {@link #hashChars(String, int, int) hashChars(input, 0, input.length())}.*
*/
public long hashChars(@NotNull String input) {
return stringHash.longHash(input, this, 0, input.length());
}
/**
* Returns the hash code for bytes of the specified subsequence of the given {@code String}'s
* underlying {@code char} array.
*
* @param input the string which bytes to hash
* @param off index of the first {@code char} in the subsequence to hash
* @param len length of the subsequence to hash, in chars (i. e. the length of the bytes
* sequence to hash is {@code len * 2L})
* @return the hash code of the given {@code String}'s bytes
* @throws IndexOutOfBoundsException if {@code off < 0} or {@code off + len > input.length()}
* or {@code len < 0}
*/
public long hashChars(@NotNull String input, int off, int len) {
checkArrayOffs(input.length(), off, len);
return stringHash.longHash(input, this, off, len);
}
/**
* Shortcut for {@link #hashChars(StringBuilder, int, int) hashChars(input, 0, input.length())}.
*/
public long hashChars(@NotNull StringBuilder input) {
return hashNativeChars(input);
}
/**
* Returns the hash code for bytes of the specified subsequence of the given
* {@code StringBuilder}'s underlying {@code char} array.
*
* @param input the string builder which bytes to hash
* @param off index of the first {@code char} in the subsequence to hash
* @param len length of the subsequence to hash, in chars (i. e. the length of the bytes
* sequence to hash is {@code len * 2L})
* @return the hash code of the given {@code String}'s bytes
* @throws IndexOutOfBoundsException if {@code off < 0} or {@code off + len > input.length()}
* or {@code len < 0}
*/
public long hashChars(@NotNull StringBuilder input, int off, int len) {
return hashNativeChars(input, off, len);
}
long hashNativeChars(CharSequence input) {
return hashNativeChars(input, 0, input.length());
}
long hashNativeChars(CharSequence input, int off, int len) {
checkArrayOffs(input.length(), off, len);
return hash(input, nativeCharSequenceAccess(), off * 2L, len * 2L);
}
/**
* Shortcut for {@link #hashShorts(short[], int, int) hashShorts(input, 0, input.length)}.
*/
public long hashShorts(@NotNull short[] input) {
return hashShorts(input, 0, input.length);
}
/**
* Returns the hash code for bytes, as they lay in memory, of the specified subsequence
* of the given {@code short} array.
*
* @param input the array to read data from
* @param off index of the first {@code short} in the subsequence to hash
* @param len length of the subsequence to hash, in shorts (i. e. the length of the bytes
* sequence to hash is {@code len * 2L})
* @return hash code for the specified subsequence
* @throws IndexOutOfBoundsException if {@code off < 0} or {@code off + len > input.length}
* or {@code len < 0}
*/
public long hashShorts(@NotNull short[] input, int off, int len) {
checkArrayOffs(input.length, off, len);
return unsafeHash(input, SHORT_BASE + (off * 2L), len * 2L);
}
/**
* Shortcut for {@link #hashInts(int[], int, int) hashInts(input, 0, input.length)}.
*/
public long hashInts(@NotNull int[] input) {
return hashInts(input, 0, input.length);
}
/**
* Returns the hash code for bytes, as they lay in memory, of the specified subsequence
* of the given {@code int} array.
*
* @param input the array to read data from
* @param off index of the first {@code int} in the subsequence to hash
* @param len length of the subsequence to hash, in ints (i. e. the length of the bytes
* sequence to hash is {@code len * 4L})
* @return hash code for the specified subsequence
* @throws IndexOutOfBoundsException if {@code off < 0} or {@code off + len > input.length}
* or {@code len < 0}
*/
public long hashInts(@NotNull int[] input, int off, int len) {
checkArrayOffs(input.length, off, len);
return unsafeHash(input, INT_BASE + (off * 4L), len * 4L);
}
/**
* Shortcut for {@link #hashLongs(long[], int, int) hashLongs(input, 0, input.length)}.
*/
public long hashLongs(@NotNull long[] input) {
return hashLongs(input, 0, input.length);
}
/**
* Returns the hash code for bytes, as they lay in memory, of the specified subsequence
* of the given {@code long} array.
*
* @param input the array to read data from
* @param off index of the first {@code long} in the subsequence to hash
* @param len length of the subsequence to hash, in longs (i. e. the length of the bytes
* sequence to hash is {@code len * 8L})
* @return hash code for the specified subsequence
* @throws IndexOutOfBoundsException if {@code off < 0} or {@code off + len > input.length}
* or {@code len < 0}
*/
public long hashLongs(@NotNull long[] input, int off, int len) {
checkArrayOffs(input.length, off, len);
return unsafeHash(input, LONG_BASE + (off * 8L), len * 8L);
}
}