
org.mapdb20.DataIO Maven / Gradle / Ivy
package org.mapdb20;
import java.io.*;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import static java.lang.Long.rotateLeft;
/**
* Various IO classes and utilities..
*/
public final class DataIO {
private DataIO(){}
/**
* Unpack int value from the input stream.
*
* @param is The input stream.
* @return The long value.
*
* @throws java.io.IOException in case of IO error
*/
static public int unpackInt(DataInput is) throws IOException {
int ret = 0;
byte v;
do{
v = is.readByte();
ret = (ret<<7 ) | (v & 0x7F);
}while(v<0);
return ret;
}
/**
* Unpack long value from the input stream.
*
* @param in The input stream.
* @return The long value.
*
* @throws java.io.IOException in case of IO error
*/
static public long unpackLong(DataInput in) throws IOException {
long ret = 0;
byte v;
do{
v = in.readByte();
ret = (ret<<7 ) | (v & 0x7F);
}while(v<0);
return ret;
}
/**
* Unpack long value from the input stream.
*
* @param in The input stream.
* @return The long value.
*
* @throws java.io.IOException in case of IO error
*/
static public long unpackLong(InputStream in) throws IOException {
long ret = 0;
int v;
do{
v = in.read();
if(v==-1)
throw new EOFException();
ret = (ret<<7 ) | (v & 0x7F);
}while((v&0x80)!=0);
return ret;
}
/**
* Pack long into output.
* It will occupy 1-10 bytes depending on value (lower values occupy smaller space)
*
* @param out DataOutput to put value into
* @param value to be serialized, must be non-negative
*
* @throws java.io.IOException in case of IO error
*/
static public void packLong(DataOutput out, long value) throws IOException {
//$DELAY$
int shift = 63-Long.numberOfLeadingZeros(value);
shift -= shift%7; // round down to nearest multiple of 7
while(shift!=0){
out.writeByte((byte) (((value>>>shift) & 0x7F) | 0x80));
//$DELAY$
shift-=7;
}
out.writeByte((byte) (value & 0x7F));
}
/**
* Pack long into output.
* It will occupy 1-10 bytes depending on value (lower values occupy smaller space)
*
* @param out OutputStream to put value into
* @param value to be serialized, must be non-negative
*
* @throws java.io.IOException in case of IO error
*/
static public void packLong(OutputStream out, long value) throws IOException {
//$DELAY$
int shift = 63-Long.numberOfLeadingZeros(value);
shift -= shift%7; // round down to nearest multiple of 7
while(shift!=0){
out.write((int) (((value>>>shift) & 0x7F) | 0x80));
//$DELAY$
shift-=7;
}
out.write((int) (value & 0x7F));
}
/**
* Calculate how much bytes packed long consumes.
*
* @param value to calculate
* @return number of bytes used in packed form
*/
public static int packLongSize(long value) {
int shift = 63-Long.numberOfLeadingZeros(value);
shift -= shift%7; // round down to nearest multiple of 7
int ret = 1;
while(shift!=0){
//TODO remove cycle, just count zeroes
shift-=7;
ret++;
}
return ret;
}
/**
* Unpack RECID value from the input stream with 3 bit checksum.
*
* @param in The input stream.
* @return The long value.
* @throws java.io.IOException in case of IO error
*/
static public long unpackRecid(DataInput in) throws IOException {
long val = unpackLong(in);
val = DataIO.parity3Get(val);
return val >>> 3;
}
/**
* Pack RECID into output stream with 3 bit checksum.
* It will occupy 1-10 bytes depending on value (lower values occupy smaller space)
*
* @param out DataOutput to put value into
* @param value to be serialized, must be non-negative
* @throws java.io.IOException in case of IO error
*/
static public void packRecid(DataOutput out, long value) throws IOException {
value = DataIO.parity3Set(value<<3);
packLong(out,value);
}
/**
* Pack int into an output stream.
* It will occupy 1-5 bytes depending on value (lower values occupy smaller space)
*
* @param out DataOutput to put value into
* @param value to be serialized, must be non-negative
* @throws java.io.IOException in case of IO error
*/
static public void packInt(DataOutput out, int value) throws IOException {
// Optimize for the common case where value is small. This is particular important where our caller
// is SerializerBase.SER_STRING.serialize because most chars will be ASCII characters and hence in this range.
// credit Max Bolingbroke https://github.com/jankotek/MapDB/pull/489
int shift = (value & ~0x7F); //reuse variable
if (shift != 0) {
//$DELAY$
shift = 31-Integer.numberOfLeadingZeros(value);
shift -= shift%7; // round down to nearest multiple of 7
while(shift!=0){
out.writeByte((byte) (((value>>>shift) & 0x7F) | 0x80));
//$DELAY$
shift-=7;
}
}
//$DELAY$
out.writeByte((byte) (value & 0x7F));
}
/**
* Pack int into an output stream.
* It will occupy 1-5 bytes depending on value (lower values occupy smaller space)
*
* This method is same as {@link #packInt(DataOutput, int)},
* but is optimized for values larger than 127. Usually it is recids.
*
* @param out DataOutput to put value into
* @param value to be serialized, must be non-negative
* @throws java.io.IOException in case of IO error
*/
static public void packIntBigger(DataOutput out, int value) throws IOException {
//$DELAY$
int shift = 31-Integer.numberOfLeadingZeros(value);
shift -= shift%7; // round down to nearest multiple of 7
while(shift!=0){
out.writeByte((byte) (((value>>>shift) & 0x7F) | 0x80));
//$DELAY$
shift-=7;
}
//$DELAY$
out.writeByte((byte) (value & 0x7F));
}
public static int longHash(long h) {
//$DELAY$
h = h * -7046029254386353131L;
h ^= h >> 32;
return (int)(h ^ h >> 16);
}
public static int intHash(int h) {
//$DELAY$
h = h * -1640531527;
return h ^ h >> 16;
}
public static final long PACK_LONG_RESULT_MASK = 0xFFFFFFFFFFFFFFFL;
public static int packLongBidi(DataOutput out, long value) throws IOException {
out.write((((int) value & 0x7F)) | 0x80);
value >>>= 7;
int counter = 2;
//$DELAY$
while ((value & ~0x7FL) != 0) {
out.write((((int) value & 0x7F)));
value >>>= 7;
//$DELAY$
counter++;
}
//$DELAY$
out.write((byte) value| 0x80);
return counter;
}
public static int packLongBidi(byte[] buf, int pos, long value) {
buf[pos++] = (byte) ((((int) value & 0x7F))| 0x80);
value >>>= 7;
int counter = 2;
//$DELAY$
while ((value & ~0x7FL) != 0) {
buf[pos++] = (byte) (((int) value & 0x7F));
value >>>= 7;
//$DELAY$
counter++;
}
//$DELAY$
buf[pos++] = (byte) ((byte) value| 0x80);
return counter;
}
public static long unpackLongBidi(byte[] bb, int pos){
//$DELAY$
long b = bb[pos++];
if(CC.ASSERT && (b&0x80)==0)
throw new DBException.DataCorruption("long pack bidi wrong header");
long result = (b & 0x7F) ;
int offset = 7;
do {
//$DELAY$
b = bb[pos++];
result |= (b & 0x7F) << offset;
if(CC.ASSERT && offset>64)
throw new DBException.DataCorruption("long pack bidi too long");
offset += 7;
}while((b & 0x80) == 0);
//$DELAY$
return (((long)(offset/7))<<60) | result;
}
public static long unpackLongBidiReverse(byte[] bb, int pos){
//$DELAY$
long b = bb[--pos];
if(CC.ASSERT && (b&0x80)==0)
throw new DBException.DataCorruption("long pack bidi wrong header");
long result = (b & 0x7F) ;
int counter = 1;
do {
//$DELAY$
b = bb[--pos];
result = (b & 0x7F) | (result<<7);
if(CC.ASSERT && counter>8)
throw new DBException.DataCorruption("long pack bidi too long");
counter++;
}while((b & 0x80) == 0);
//$DELAY$
return (((long)counter)<<60) | result;
}
public static long getLong(byte[] buf, int pos) {
return
((((long)buf[pos++]) << 56) |
(((long)buf[pos++] & 0xFF) << 48) |
(((long)buf[pos++] & 0xFF) << 40) |
(((long)buf[pos++] & 0xFF) << 32) |
(((long)buf[pos++] & 0xFF) << 24) |
(((long)buf[pos++] & 0xFF) << 16) |
(((long)buf[pos++] & 0xFF) << 8) |
(((long)buf[pos] & 0xFF)));
}
public static void putLong(byte[] buf, int pos,long v) {
buf[pos++] = (byte) (0xff & (v >> 56));
buf[pos++] = (byte) (0xff & (v >> 48));
buf[pos++] = (byte) (0xff & (v >> 40));
buf[pos++] = (byte) (0xff & (v >> 32));
buf[pos++] = (byte) (0xff & (v >> 24));
buf[pos++] = (byte) (0xff & (v >> 16));
buf[pos++] = (byte) (0xff & (v >> 8));
buf[pos] = (byte) (0xff & (v));
}
public static long getSixLong(byte[] buf, int pos) {
return
((long) (buf[pos++] & 0xff) << 40) |
((long) (buf[pos++] & 0xff) << 32) |
((long) (buf[pos++] & 0xff) << 24) |
((long) (buf[pos++] & 0xff) << 16) |
((long) (buf[pos++] & 0xff) << 8) |
((long) (buf[pos] & 0xff));
}
public static void putSixLong(byte[] buf, int pos, long value) {
if(CC.ASSERT && (value>>>48!=0))
throw new AssertionError();
buf[pos++] = (byte) (0xff & (value >> 40));
buf[pos++] = (byte) (0xff & (value >> 32));
buf[pos++] = (byte) (0xff & (value >> 24));
buf[pos++] = (byte) (0xff & (value >> 16));
buf[pos++] = (byte) (0xff & (value >> 8));
buf[pos] = (byte) (0xff & (value));
}
public static long nextPowTwo(final long a)
{
return 1L << (64 - Long.numberOfLeadingZeros(a - 1L));
}
public static int nextPowTwo(final int a)
{
return 1 << (32 - Integer.numberOfLeadingZeros(a - 1));
}
public static void readFully(InputStream in, byte[] data) throws IOException {
int len = data.length;
for(int read=0; read 0);
}
/**
* Give access to internal byte[] or ByteBuffer in DataInput2..
* Should not be used unless you are writing MapDB extension and needs some performance bonus
*/
public interface DataInputInternal extends DataInput,Closeable {
int getPos();
void setPos(int pos);
/** @return underlying {@code byte[]} or null if it does not exist*/
byte[] internalByteArray();
/** @return underlying {@code ByteBuffer} or null if it does not exist*/
ByteBuffer internalByteBuffer();
void close();
long unpackLong() throws IOException;
int unpackInt() throws IOException;
long[] unpackLongArrayDeltaCompression(int size) throws IOException;
void unpackLongArray(long[] ret, int i, int len);
void unpackIntArray(int[] ret, int i, int len);
}
/** DataInput on top of {@code byte[]} */
static public final class DataInputByteArray implements DataInput, DataInputInternal {
protected final byte[] buf;
protected int pos;
public DataInputByteArray(byte[] b) {
this(b, 0);
}
public DataInputByteArray(byte[] bb, int pos) {
//$DELAY$
buf = bb;
this.pos = pos;
}
@Override
public void readFully(byte[] b) throws IOException {
readFully(b, 0, b.length);
}
@Override
public void readFully(byte[] b, int off, int len) throws IOException {
System.arraycopy(buf, pos, b, off, len);
//$DELAY$
pos += len;
}
@Override
public int skipBytes(final int n) throws IOException {
pos += n;
//$DELAY$
return n;
}
@Override
public boolean readBoolean() throws IOException {
//$DELAY$
return buf[pos++] == 1;
}
@Override
public byte readByte() throws IOException {
//$DELAY$
return buf[pos++];
}
@Override
public int readUnsignedByte() throws IOException {
//$DELAY$
return buf[pos++] & 0xff;
}
@Override
public short readShort() throws IOException {
//$DELAY$
return (short)((buf[pos++] << 8) | (buf[pos++] & 0xff));
}
@Override
public int readUnsignedShort() throws IOException {
//$DELAY$
return readChar();
}
@Override
public char readChar() throws IOException {
//$DELAY$
return (char) (
((buf[pos++] & 0xff) << 8) |
(buf[pos++] & 0xff));
}
@Override
public int readInt() throws IOException {
int p = pos;
final byte[] b = buf;
final int ret =
((((int)b[p++]) << 24) |
(((int)b[p++] & 0xFF) << 16) |
(((int)b[p++] & 0xFF) << 8) |
(((int)b[p++] & 0xFF)));
pos = p;
return ret;
}
@Override
public long readLong() throws IOException {
int p = pos;
final byte[] b = buf;
final long ret =
((((long)b[p++]) << 56) |
(((long)b[p++] & 0xFF) << 48) |
(((long)b[p++] & 0xFF) << 40) |
(((long)b[p++] & 0xFF) << 32) |
(((long)b[p++] & 0xFF) << 24) |
(((long)b[p++] & 0xFF) << 16) |
(((long)b[p++] & 0xFF) << 8) |
(((long)b[p++] & 0xFF)));
pos = p;
return ret;
}
@Override
public float readFloat() throws IOException {
return Float.intBitsToFloat(readInt());
}
@Override
public double readDouble() throws IOException {
return Double.longBitsToDouble(readLong());
}
@Override
public String readLine() throws IOException {
return readUTF();
}
@Override
public String readUTF() throws IOException {
final int len = unpackInt();
char[] b = new char[len];
for (int i = 0; i < len; i++)
//$DELAY$
b[i] = (char) unpackInt();
return new String(b);
}
@Override
public int getPos() {
return pos;
}
@Override
public void setPos(int pos) {
this.pos = pos;
}
@Override
public byte[] internalByteArray() {
return buf;
}
@Override
public ByteBuffer internalByteBuffer() {
return null;
}
@Override
public void close() {
}
@Override
public long unpackLong() throws IOException {
byte[] b = buf;
int p = pos;
long ret = 0;
byte v;
do{
//$DELAY$
v = b[p++];
ret = (ret<<7 ) | (v & 0x7F);
}while(v<0);
pos = p;
return ret;
}
@Override
public int unpackInt() throws IOException {
byte[] b = buf;
int p = pos;
int ret = 0;
byte v;
do{
//$DELAY$
v = b[p++];
ret = (ret<<7 ) | (v & 0x7F);
}while(v<0);
pos = p;
return ret;
}
@Override
public long[] unpackLongArrayDeltaCompression(final int size) throws IOException {
long[] ret = new long[size];
int pos2 = pos;
byte[] buf2 = buf;
long prev =0;
byte v;
for(int i=0;i> 8));
//$DELAY$
buf[pos++] = (byte) (0xff & (v));
}
@Override
public void writeChar(final int v) throws IOException {
ensureAvail(2);
buf[pos++] = (byte) (v>>>8);
buf[pos++] = (byte) (v);
}
@Override
public void writeInt(final int v) throws IOException {
ensureAvail(4);
buf[pos++] = (byte) (0xff & (v >> 24));
//$DELAY$
buf[pos++] = (byte) (0xff & (v >> 16));
buf[pos++] = (byte) (0xff & (v >> 8));
//$DELAY$
buf[pos++] = (byte) (0xff & (v));
}
@Override
public void writeLong(final long v) throws IOException {
ensureAvail(8);
buf[pos++] = (byte) (0xff & (v >> 56));
buf[pos++] = (byte) (0xff & (v >> 48));
//$DELAY$
buf[pos++] = (byte) (0xff & (v >> 40));
buf[pos++] = (byte) (0xff & (v >> 32));
buf[pos++] = (byte) (0xff & (v >> 24));
//$DELAY$
buf[pos++] = (byte) (0xff & (v >> 16));
buf[pos++] = (byte) (0xff & (v >> 8));
buf[pos++] = (byte) (0xff & (v));
//$DELAY$
}
@Override
public void writeFloat(final float v) throws IOException {
writeInt(Float.floatToIntBits(v));
}
@Override
public void writeDouble(final double v) throws IOException {
writeLong(Double.doubleToLongBits(v));
}
@Override
public void writeBytes(final String s) throws IOException {
writeUTF(s);
}
@Override
public void writeChars(final String s) throws IOException {
writeUTF(s);
}
@Override
public void writeUTF(final String s) throws IOException {
final int len = s.length();
packInt(len);
for (int i = 0; i < len; i++) {
//$DELAY$
int c = (int) s.charAt(i);
packInt(c);
}
}
public void packInt(int value) throws IOException {
ensureAvail(5); //ensure worst case bytes
// Optimize for the common case where value is small. This is particular important where our caller
// is SerializerBase.SER_STRING.serialize because most chars will be ASCII characters and hence in this range.
// credit Max Bolingbroke https://github.com/jankotek/MapDB/pull/489
int shift = (value & ~0x7F); //reuse variable
if (shift != 0) {
shift = 31 - Integer.numberOfLeadingZeros(value);
shift -= shift % 7; // round down to nearest multiple of 7
while (shift != 0) {
buf[pos++] = (byte) (((value >>> shift) & 0x7F) | 0x80);
shift -= 7;
}
}
buf[pos++] = (byte) (value & 0x7F);
}
public void packIntBigger(int value) throws IOException {
ensureAvail(5); //ensure worst case bytes
int shift = 31-Integer.numberOfLeadingZeros(value);
shift -= shift%7; // round down to nearest multiple of 7
while(shift!=0){
buf[pos++] = (byte) (((value>>>shift) & 0x7F) | 0x80);
shift-=7;
}
buf[pos++] = (byte) (value & 0x7F);
}
public void packLong(long value) {
ensureAvail(10); //ensure worst case bytes
int shift = 63-Long.numberOfLeadingZeros(value);
shift -= shift%7; // round down to nearest multiple of 7
while(shift!=0){
buf[pos++] = (byte) (((value>>>shift) & 0x7F) | 0x80);
shift-=7;
}
buf[pos++] = (byte) (value & 0x7F);
}
}
public static long parity1Set(long i) {
if(CC.ASSERT && (i&1)!=0)
throw new DBException.PointerChecksumBroken();
return i | ((Long.bitCount(i)+1)%2);
}
public static long parity1Get(long i) {
if(Long.bitCount(i)%2!=1){
throw new DBException.PointerChecksumBroken();
}
return i&0xFFFFFFFFFFFFFFFEL;
}
public static long parity3Set(long i) {
if(CC.ASSERT && (i&0x7)!=0)
throw new DBException.PointerChecksumBroken();
return i | ((Long.bitCount(i)+1)%8);
}
public static long parity3Get(long i) {
long ret = i&0xFFFFFFFFFFFFFFF8L;
if((Long.bitCount(ret)+1)%8!=(i&0x7)){
throw new DBException.PointerChecksumBroken();
}
return ret;
}
public static long parity4Set(long i) {
if(CC.ASSERT && (i&0xF)!=0)
throw new DBException.PointerChecksumBroken();
return i | ((Long.bitCount(i)+1)%16);
}
public static long parity4Get(long i) {
long ret = i&0xFFFFFFFFFFFFFFF0L;
if((Long.bitCount(ret)+1)%16!=(i&0xF)){
throw new DBException.PointerChecksumBroken();
}
return ret;
}
public static long parity16Set(long i) {
if(CC.ASSERT && (i&0xFFFF)!=0)
throw new DBException.PointerChecksumBroken();
return i | (DataIO.longHash(i)&0xFFFFL);
}
public static long parity16Get(long i) {
long ret = i&0xFFFFFFFFFFFF0000L;
if((DataIO.longHash(ret)&0xFFFFL) != (i&0xFFFFL)){
throw new DBException.PointerChecksumBroken();
}
return ret;
}
/**
* Converts binary array into its hexadecimal representation.
*
* @param bb binary data
* @return hexadecimal string
*/
public static String toHexa( byte [] bb ) {
char[] HEXA_CHARS = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char[] ret = new char[bb.length*2];
for(int i=0;i> 4)];
ret[i*2+1] = HEXA_CHARS[((bb[i] & 0x0F))];
}
return new String(ret);
}
/**
* Converts hexadecimal string into binary data
* @param s hexadecimal string
* @return binary data
* @throws NumberFormatException in case of string format error
*/
public static byte[] fromHexa(String s ) {
byte[] ret = new byte[s.length()/2];
for(int i=0;i TIME_GRANULARITY) {
return;
}
sleep(SLEEP_GAP);
}
throw new DBException.FileLocked("Lock file recently modified");
}
public synchronized void lock(){
if (locked) {
throw new DBException.FileLocked("Already locked, cannot call lock() twice");
}
try {
// TODO is this needed?: FileUtils.createDirectories(FileUtils.getParent(fileName));
if (!file.createNewFile()) {
waitUntilOld();
save();
sleep(10 * sleep);
if (load() != id) {
throw new DBException.FileLocked("Locked by another process");
}
delete();
if (!file.createNewFile()) {
throw new DBException.FileLocked("Another process was faster");
}
}
save();
sleep(SLEEP_GAP);
if (load() != id) {
file = null;
throw new DBException.FileLocked("Concurrent update");
}
//TODO use MapDB Executor Service if available
watchdog = new Thread(runnable,
"MapDB File Lock Watchdog " + file.getAbsolutePath());
watchdog.setDaemon(true);
try {
watchdog.setPriority(Thread.MAX_PRIORITY - 1);
}catch(Exception e){
LOG.log(Level.FINE,"Could not set thread priority",e);
}
watchdog.start();
}catch(IOException e){
throw new DBException.FileLocked("Could not lock file: " + file, e);
}
locked = true;
}
/**
* Unlock the file. The watchdog thread is stopped. This method does nothing
* if the file is already unlocked.
*/
public synchronized void unlock() {
if (!locked) {
return;
}
locked = false;
try {
if (watchdog != null) {
watchdog.interrupt();
}
} catch (Exception e) {
LOG.log(Level.FINE, "unlock interrupt", e);
}
try {
if (file != null) {
if (load() == id) {
delete();
}
}
} catch (Exception e) {
LOG.log(Level.FINE, "unlock", e);
} finally {
file = null;
}
try {
if (watchdog != null) {
watchdog.join();
}
} catch (Exception e) {
LOG.log(Level.FINE, "unlock", e);
} finally {
watchdog = null;
}
}
private void save() throws IOException {
//save file
RandomAccessFile raf = new RandomAccessFile(file,"rw");
raf.seek(0);
raf.writeLong(id);
raf.getFD().sync(); //TODO is raf synced on close? In that case this is redundant, it applies to Volumes etc
raf.close();
lastWrite = file.lastModified();
}
private long load() throws IOException{
//load file
RandomAccessFile raf = new RandomAccessFile(file,"r");
raf.seek(0);
long ret = raf.readLong();
raf.close();
return ret;
}
private static void sleep(int delay){
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
throw new DBException.Interrupted(e);
}
}
protected void delete() {
for (int i = 0; i < CC.FILE_RETRY; i++) { //TODO use delete/retry mapdb wide, in compaction!
boolean ok = file.delete();
if (ok || !file.exists()) {
return;
}
wait(i);
}
throw new DBException.FileDeleteFailed(file);
}
//TODO h2 code, check context and errors. what it is ????
private static void wait(int i) {
if (i == 8) {
System.gc();
}
try {
// sleep at most 256 ms
long sleep = Math.min(256, i * i);
Thread.sleep(sleep);
} catch (InterruptedException e) {
// ignore
}
}
public boolean isLocked() {
return locked;
}
public File getFile() {
return file;
}
}
static final long PRIME64_1 = -7046029288634856825L; //11400714785074694791
static final long PRIME64_2 = -4417276706812531889L; //14029467366897019727
static final long PRIME64_3 = 1609587929392839161L;
static final long PRIME64_4 = -8796714831421723037L; //9650029242287828579
static final long PRIME64_5 = 2870177450012600261L;
/**
*
* Calculates XXHash64 from given {@code byte[]} buffer.
*
* This code comes from LZ4-Java created
* by Adrien Grand.
*
*
* @param buf to calculate hash from
* @param off offset to start calculation from
* @param len length of data to calculate hash
* @param seed hash seed
* @return XXHash.
*/
public static long hash(byte[] buf, int off, int len, long seed) {
if (len < 0) {
throw new IllegalArgumentException("lengths must be >= 0");
}
if(off<0 || off>buf.length || off+len<0 || off+len>buf.length){
throw new IndexOutOfBoundsException();
}
final int end = off + len;
long h64;
if (len >= 32) {
final int limit = end - 32;
long v1 = seed + PRIME64_1 + PRIME64_2;
long v2 = seed + PRIME64_2;
long v3 = seed + 0;
long v4 = seed - PRIME64_1;
do {
v1 += readLongLE(buf, off) * PRIME64_2;
v1 = rotateLeft(v1, 31);
v1 *= PRIME64_1;
off += 8;
v2 += readLongLE(buf, off) * PRIME64_2;
v2 = rotateLeft(v2, 31);
v2 *= PRIME64_1;
off += 8;
v3 += readLongLE(buf, off) * PRIME64_2;
v3 = rotateLeft(v3, 31);
v3 *= PRIME64_1;
off += 8;
v4 += readLongLE(buf, off) * PRIME64_2;
v4 = rotateLeft(v4, 31);
v4 *= PRIME64_1;
off += 8;
} while (off <= limit);
h64 = rotateLeft(v1, 1) + rotateLeft(v2, 7) + rotateLeft(v3, 12) + rotateLeft(v4, 18);
v1 *= PRIME64_2; v1 = rotateLeft(v1, 31); v1 *= PRIME64_1; h64 ^= v1;
h64 = h64 * PRIME64_1 + PRIME64_4;
v2 *= PRIME64_2; v2 = rotateLeft(v2, 31); v2 *= PRIME64_1; h64 ^= v2;
h64 = h64 * PRIME64_1 + PRIME64_4;
v3 *= PRIME64_2; v3 = rotateLeft(v3, 31); v3 *= PRIME64_1; h64 ^= v3;
h64 = h64 * PRIME64_1 + PRIME64_4;
v4 *= PRIME64_2; v4 = rotateLeft(v4, 31); v4 *= PRIME64_1; h64 ^= v4;
h64 = h64 * PRIME64_1 + PRIME64_4;
} else {
h64 = seed + PRIME64_5;
}
h64 += len;
while (off <= end - 8) {
long k1 = readLongLE(buf, off);
k1 *= PRIME64_2; k1 = rotateLeft(k1, 31); k1 *= PRIME64_1; h64 ^= k1;
h64 = rotateLeft(h64, 27) * PRIME64_1 + PRIME64_4;
off += 8;
}
if (off <= end - 4) {
h64 ^= (readIntLE(buf, off) & 0xFFFFFFFFL) * PRIME64_1;
h64 = rotateLeft(h64, 23) * PRIME64_2 + PRIME64_3;
off += 4;
}
while (off < end) {
h64 ^= (buf[off] & 0xFF) * PRIME64_5;
h64 = rotateLeft(h64, 11) * PRIME64_1;
++off;
}
h64 ^= h64 >>> 33;
h64 *= PRIME64_2;
h64 ^= h64 >>> 29;
h64 *= PRIME64_3;
h64 ^= h64 >>> 32;
return h64;
}
static long readLongLE(byte[] buf, int i) {
return (buf[i] & 0xFFL) | ((buf[i+1] & 0xFFL) << 8) | ((buf[i+2] & 0xFFL) << 16) | ((buf[i+3] & 0xFFL) << 24)
| ((buf[i+4] & 0xFFL) << 32) | ((buf[i+5] & 0xFFL) << 40) | ((buf[i+6] & 0xFFL) << 48) | ((buf[i+7] & 0xFFL) << 56);
}
static int readIntLE(byte[] buf, int i) {
return (buf[i] & 0xFF) | ((buf[i+1] & 0xFF) << 8) | ((buf[i+2] & 0xFF) << 16) | ((buf[i+3] & 0xFF) << 24);
}
/**
*
* Calculates XXHash64 from given {@code char[]} buffer.
*
* This code comes from LZ4-Java created
* by Adrien Grand.
*
*
* @param buf to calculate hash from
* @param off offset to start calculation from
* @param len length of data to calculate hash
* @param seed hash seed
* @return XXHash.
*/
public static long hash(char[] buf, int off, int len, long seed) {
if (len < 0) {
throw new IllegalArgumentException("lengths must be >= 0");
}
if(off<0 || off>buf.length || off+len<0 || off+len>buf.length){
throw new IndexOutOfBoundsException();
}
final int end = off + len;
long h64;
if (len >= 16) {
final int limit = end - 16;
long v1 = seed + PRIME64_1 + PRIME64_2;
long v2 = seed + PRIME64_2;
long v3 = seed + 0;
long v4 = seed - PRIME64_1;
do {
v1 += readLongLE(buf, off) * PRIME64_2;
v1 = rotateLeft(v1, 31);
v1 *= PRIME64_1;
off += 4;
v2 += readLongLE(buf, off) * PRIME64_2;
v2 = rotateLeft(v2, 31);
v2 *= PRIME64_1;
off += 4;
v3 += readLongLE(buf, off) * PRIME64_2;
v3 = rotateLeft(v3, 31);
v3 *= PRIME64_1;
off += 4;
v4 += readLongLE(buf, off) * PRIME64_2;
v4 = rotateLeft(v4, 31);
v4 *= PRIME64_1;
off += 4;
} while (off <= limit);
h64 = rotateLeft(v1, 1) + rotateLeft(v2, 7) + rotateLeft(v3, 12) + rotateLeft(v4, 18);
v1 *= PRIME64_2; v1 = rotateLeft(v1, 31); v1 *= PRIME64_1; h64 ^= v1;
h64 = h64 * PRIME64_1 + PRIME64_4;
v2 *= PRIME64_2; v2 = rotateLeft(v2, 31); v2 *= PRIME64_1; h64 ^= v2;
h64 = h64 * PRIME64_1 + PRIME64_4;
v3 *= PRIME64_2; v3 = rotateLeft(v3, 31); v3 *= PRIME64_1; h64 ^= v3;
h64 = h64 * PRIME64_1 + PRIME64_4;
v4 *= PRIME64_2; v4 = rotateLeft(v4, 31); v4 *= PRIME64_1; h64 ^= v4;
h64 = h64 * PRIME64_1 + PRIME64_4;
} else {
h64 = seed + PRIME64_5;
}
h64 += len;
while (off <= end - 4) {
long k1 = readLongLE(buf, off);
k1 *= PRIME64_2; k1 = rotateLeft(k1, 31); k1 *= PRIME64_1; h64 ^= k1;
h64 = rotateLeft(h64, 27) * PRIME64_1 + PRIME64_4;
off += 4;
}
if (off <= end - 2) {
h64 ^= (readIntLE(buf, off) & 0xFFFFFFFFL) * PRIME64_1;
h64 = rotateLeft(h64, 23) * PRIME64_2 + PRIME64_3;
off += 2;
}
while (off < end) {
h64 ^= (readCharLE(buf,off) & 0xFFFF) * PRIME64_5;
h64 = rotateLeft(h64, 11) * PRIME64_1;
++off;
}
h64 ^= h64 >>> 33;
h64 *= PRIME64_2;
h64 ^= h64 >>> 29;
h64 *= PRIME64_3;
h64 ^= h64 >>> 32;
return h64;
}
static long readLongLE(char[] buf, int i) {
return (buf[i] & 0xFFFFL) |
((buf[i+1] & 0xFFFFL) << 16) |
((buf[i+2] & 0xFFFFL) << 32) |
((buf[i+3] & 0xFFFFL) << 48);
}
static int readIntLE(char[] buf, int i) {
return (buf[i] & 0xFFFF) |
((buf[i+1] & 0xFFFF) << 16);
}
static int readCharLE(char[] buf, int i) {
return buf[i];
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy