Skip to content
This repository was archived by the owner on Dec 2, 2025. It is now read-only.

Commit f65a4b7

Browse files
committed
support bytebuffer updates on streaming hashes
In some cases ByteBuffers do not provide access to an underlying byte array without incurring copies, this is notably the case for off-heap direct bytebuffers. This patch provides a way to call update on streaming XXHASH instances against a ByteBuffer, which avoids the extra copy needed into a byte array.
1 parent a9c1b3a commit f65a4b7

File tree

8 files changed

+110
-2
lines changed

8 files changed

+110
-2
lines changed

src/build/source_templates/xxhash32_streaming.template

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import static net.jpountz.xxhash.XXHashConstants.*;
66
import static net.jpountz.util.${type}Utils.*;
77
import static net.jpountz.util.SafeUtils.checkRange;
88
import static java.lang.Integer.rotateLeft;
9+
import java.nio.ByteBuffer;
910

1011
/**
1112
* Streaming xxhash.
@@ -60,6 +61,11 @@ final class StreamingXXHash32Java${type} extends AbstractStreamingXXHash32Java {
6061
return h32;
6162
}
6263

64+
@Override
65+
public void update(ByteBuffer buf, int off, int len) {
66+
throw new RuntimeException("unimplemented");
67+
}
68+
6369
@Override
6470
public void update(byte[] buf, int off, int len) {
6571
checkRange(buf, off, len);
@@ -139,4 +145,3 @@ final class StreamingXXHash32Java${type} extends AbstractStreamingXXHash32Java {
139145
}
140146

141147
}
142-

src/build/source_templates/xxhash64_streaming.template

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import static net.jpountz.xxhash.XXHashConstants.*;
66
import static net.jpountz.util.${type}Utils.*;
77
import static net.jpountz.util.SafeUtils.checkRange;
88
import static java.lang.Long.rotateLeft;
9+
import java.nio.ByteBuffer;
910

1011
/**
1112
* Streaming xxhash.
@@ -84,6 +85,11 @@ final class StreamingXXHash64Java${type} extends AbstractStreamingXXHash64Java {
8485
return h64;
8586
}
8687

88+
@Override
89+
public void update(ByteBuffer buf, int off, int len) {
90+
throw new RuntimeException("unimplemented");
91+
}
92+
8793
@Override
8894
public void update(byte[] buf, int off, int len) {
8995
checkRange(buf, off, len);
@@ -163,4 +169,3 @@ final class StreamingXXHash64Java${type} extends AbstractStreamingXXHash64Java {
163169
}
164170

165171
}
166-

src/java/net/jpountz/xxhash/StreamingXXHash32.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.zip.Checksum;
44
import java.io.Closeable;
5+
import java.nio.ByteBuffer;
56

67
/*
78
* Copyright 2020 Adrien Grand and the lz4-java contributors.
@@ -71,6 +72,15 @@ interface Factory {
7172
*/
7273
public abstract void update(byte[] buf, int off, int len);
7374

75+
/**
76+
* Updates the value of the hash with buf[off:off+len].
77+
*
78+
* @param buf the input data
79+
* @param off the start offset in buf
80+
* @param len the number of bytes to hash
81+
*/
82+
public abstract void update(ByteBuffer buf, int off, int len);
83+
7484
/**
7585
* Resets this instance to the state it had right after instantiation. The
7686
* seed remains unchanged.

src/java/net/jpountz/xxhash/StreamingXXHash32JNI.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package net.jpountz.xxhash;
22

3+
import static net.jpountz.util.ByteBufferUtils.checkRange;
4+
import static net.jpountz.util.SafeUtils.checkRange;
5+
import java.nio.ByteBuffer;
6+
37
/*
48
* Copyright 2020 Adrien Grand and the lz4-java contributors.
59
*
@@ -69,6 +73,20 @@ public synchronized void update(byte[] bytes, int off, int len) {
6973
XXHashJNI.XXH32_update(state, bytes, off, len);
7074
}
7175

76+
public synchronized void update(ByteBuffer buf, int off, int len) {
77+
checkState();
78+
if (buf.isDirect()) {
79+
checkRange(buf, off, len);
80+
XXHashJNI.XXH32BB_update(state, buf, off, len);
81+
} else if (buf.hasArray()) {
82+
XXHashJNI.XXH32_update(state, buf.array(), off + buf.arrayOffset(), len);
83+
} else {
84+
// XXX: What to do here?
85+
throw new RuntimeException("unsupported");
86+
}
87+
88+
}
89+
7290
@Override
7391
public synchronized void close() {
7492
if (state != 0) {

src/java/net/jpountz/xxhash/StreamingXXHash64.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package net.jpountz.xxhash;
22

33
import java.util.zip.Checksum;
4+
import java.nio.ByteBuffer;
45
import java.io.Closeable;
56

67
/*
@@ -71,6 +72,15 @@ interface Factory {
7172
*/
7273
public abstract void update(byte[] buf, int off, int len);
7374

75+
/**
76+
* Updates the value of the hash with buf[off:off+len].
77+
*
78+
* @param buf the input data
79+
* @param off the start offset in buf
80+
* @param len the number of bytes to hash
81+
*/
82+
public abstract void update(ByteBuffer buf, int off, int len);
83+
7484
/**
7585
* Resets this instance to the state it had right after instantiation. The
7686
* seed remains unchanged.

src/java/net/jpountz/xxhash/StreamingXXHash64JNI.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package net.jpountz.xxhash;
22

3+
import static net.jpountz.util.ByteBufferUtils.checkRange;
4+
import static net.jpountz.util.SafeUtils.checkRange;
5+
import java.nio.ByteBuffer;
6+
37
/*
48
* Copyright 2020 Linnaea Von Lavia and the lz4-java contributors.
59
*
@@ -70,6 +74,20 @@ public synchronized void update(byte[] bytes, int off, int len) {
7074
XXHashJNI.XXH64_update(state, bytes, off, len);
7175
}
7276

77+
@Override
78+
public synchronized void update(ByteBuffer buf, int off, int len) {
79+
checkState();
80+
if (buf.isDirect()) {
81+
checkRange(buf, off, len);
82+
XXHashJNI.XXH64BB_update(state, buf, off, len);
83+
} else if (buf.hasArray()) {
84+
XXHashJNI.XXH64_update(state, buf.array(), off + buf.arrayOffset(), len);
85+
} else {
86+
// XXX: What to do here?
87+
throw new RuntimeException("unsupported");
88+
}
89+
}
90+
7391
@Override
7492
public synchronized void close() {
7593
if (state != 0) {

src/java/net/jpountz/xxhash/XXHashJNI.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,15 @@ enum XXHashJNI {
3333
static native int XXH32BB(ByteBuffer input, int offset, int len, int seed);
3434
static native long XXH32_init(int seed);
3535
static native void XXH32_update(long state, byte[] input, int offset, int len);
36+
static native void XXH32BB_update(long state, ByteBuffer input, int offset, int len);
3637
static native int XXH32_digest(long state);
3738
static native void XXH32_free(long state);
3839

3940
static native long XXH64(byte[] input, int offset, int len, long seed);
4041
static native long XXH64BB(ByteBuffer input, int offset, int len, long seed);
4142
static native long XXH64_init(long seed);
4243
static native void XXH64_update(long state, byte[] input, int offset, int len);
44+
static native void XXH64BB_update(long state, ByteBuffer input, int offset, int len);
4345
static native long XXH64_digest(long state);
4446
static native void XXH64_free(long state);
4547
}

src/jni/net_jpountz_xxhash_XXHashJNI.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,26 @@ JNIEXPORT void JNICALL Java_net_jpountz_xxhash_XXHashJNI_XXH32_1update
120120

121121
}
122122

123+
/*
124+
* Class: net_jpountz_xxhash_XXHashJNI
125+
* Method: XXH32BB_update
126+
* Signature: (JLjava/nio/ByteBuffer;II)V
127+
*/
128+
JNIEXPORT void JNICALL Java_net_jpountz_xxhash_XXHashJNI_XXH32BB_1update
129+
(JNIEnv *env, jclass cls, jlong state, jobject src, jint off, jint len) {
130+
131+
char* in;
132+
jlong h64;
133+
134+
in = (char*) (*env)->GetDirectBufferAddress(env, src);
135+
if (in == NULL) {
136+
throw_OOM(env);
137+
return;
138+
}
139+
140+
XXH32_update((XXH32_state_t*) state, in + off, len);
141+
}
142+
123143
/*
124144
* Class: net_jpountz_xxhash_XXHashJNI
125145
* Method: XXH32_digest
@@ -230,6 +250,26 @@ JNIEXPORT void JNICALL Java_net_jpountz_xxhash_XXHashJNI_XXH64_1update
230250

231251
}
232252

253+
/*
254+
* Class: net_jpountz_xxhash_XXHashJNI
255+
* Method: XXH64BB_update
256+
* Signature: (JLjava/nio/ByteBuffer;II)V
257+
*/
258+
JNIEXPORT void JNICALL Java_net_jpountz_xxhash_XXHashJNI_XXH64BB_1update
259+
(JNIEnv *env, jclass cls, jlong state, jobject src, jint off, jint len) {
260+
261+
char* in;
262+
263+
in = (char*) (*env)->GetDirectBufferAddress(env, src);
264+
if (in == NULL) {
265+
printf("I AM NULLLLL?\n");
266+
throw_OOM(env);
267+
return;
268+
}
269+
270+
XXH64_update((XXH64_state_t*) state, in + off, len);
271+
}
272+
233273
/*
234274
* Class: net_jpountz_xxhash_XXHashJNI
235275
* Method: XXH64_digest

0 commit comments

Comments
 (0)