diff --git a/CHANGES.txt b/CHANGES.txt index 5fdd7257..d0d91ad6 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,6 +4,6 @@ Version 1.0 =========== First release. - Java ports and bindings of LZ4 and xxHash. + Java ports and bindings of LZ4 and xxhash. LZ4 r85 - xxhash r4 + xxhash r5 diff --git a/src/java/net/jpountz/util/UnsafeUtils.java b/src/java/net/jpountz/util/UnsafeUtils.java index fabb3720..48b77835 100644 --- a/src/java/net/jpountz/util/UnsafeUtils.java +++ b/src/java/net/jpountz/util/UnsafeUtils.java @@ -17,7 +17,11 @@ * limitations under the License. */ +import static java.lang.Integer.reverseBytes; +import static net.jpountz.util.Utils.NATIVE_BYTE_ORDER; + import java.lang.reflect.Field; +import java.nio.ByteOrder; import sun.misc.Unsafe; @@ -76,6 +80,14 @@ public static int readInt(byte[] src, int srcOff) { return UNSAFE.getInt(src, BYTE_ARRAY_OFFSET + srcOff); } + public static int readIntLE(byte[] src, int srcOff) { + int i = readInt(src, srcOff); + if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) { + i = reverseBytes(i); + } + return i; + } + public static void writeInt(byte[] dest, int destOff, int value) { UNSAFE.putInt(dest, BYTE_ARRAY_OFFSET + destOff, value); } diff --git a/src/java/net/jpountz/xxhash/StreamingXXHash32JNI.java b/src/java/net/jpountz/xxhash/StreamingXXHash32JNI.java index 0b4533cf..3fef54f3 100644 --- a/src/java/net/jpountz/xxhash/StreamingXXHash32JNI.java +++ b/src/java/net/jpountz/xxhash/StreamingXXHash32JNI.java @@ -24,33 +24,31 @@ final class StreamingXXHash32JNI extends StreamingXXHash32 { StreamingXXHash32JNI(int seed) { super(seed); - reset(); + state = XXHashJNI.XXH32_init(seed); + } + + private void checkState() { + if (state == 0) { + throw new AssertionError("Already finalized"); + } } @Override public void reset() { - if (state != 0) { - XXHashJNI.XXH32_result(state); - state = 0; - } + checkState(); + XXHashJNI.XXH32_result(state); state = XXHashJNI.XXH32_init(seed); } @Override public int getValue() { - if (state == 0) { - throw new IllegalStateException("getValue has already been called"); - } - final int result = XXHashJNI.XXH32_result(state); - state = 0; - return result; + checkState(); + return XXHashJNI.XXH32_getIntermediateResult(state); } @Override public void update(byte[] bytes, int off, int len) { - if (state == 0) { - throw new IllegalStateException("getValue has already been called"); - } + checkState(); XXHashJNI.XXH32_feed(state, bytes, off, len); } @@ -59,9 +57,9 @@ protected void finalize() throws Throwable { super.finalize(); // free memory if (state != 0) { - getValue(); + XXHashJNI.XXH32_result(state); + state = 0; } - assert state == 0; } } diff --git a/src/java/net/jpountz/xxhash/StreamingXXHash32JavaSafe.java b/src/java/net/jpountz/xxhash/StreamingXXHash32JavaSafe.java index ec60ff50..ca1bd038 100644 --- a/src/java/net/jpountz/xxhash/StreamingXXHash32JavaSafe.java +++ b/src/java/net/jpountz/xxhash/StreamingXXHash32JavaSafe.java @@ -19,7 +19,7 @@ import static java.lang.Integer.rotateLeft; import static net.jpountz.util.Utils.checkRange; -import static net.jpountz.util.Utils.readInt; +import static net.jpountz.util.Utils.readIntLE; import static net.jpountz.xxhash.XXHashUtils.PRIME1; import static net.jpountz.xxhash.XXHashUtils.PRIME2; import static net.jpountz.xxhash.XXHashUtils.PRIME3; @@ -41,11 +41,11 @@ public int getValue() { h32 = seed + PRIME5; } - h32 += (int) totalLen; + h32 += totalLen; int off = 0; while (off <= memSize - 4) { - h32 += readInt(memory, off) * PRIME3; + h32 += readIntLE(memory, off) * PRIME3; h32 = rotateLeft(h32, 17) * PRIME4; off += 4; } @@ -82,19 +82,19 @@ public void update(byte[] buf, int off, int len) { if (memSize > 0) { // data left from previous update System.arraycopy(buf, off, memory, memSize, 16 - memSize); - v1 += readInt(memory, 0) * PRIME2; + v1 += readIntLE(memory, 0) * PRIME2; v1 = rotateLeft(v1, 13); v1 *= PRIME1; - v2 += readInt(memory, 4) * PRIME2; + v2 += readIntLE(memory, 4) * PRIME2; v2 = rotateLeft(v2, 13); v2 *= PRIME1; - v3 += readInt(memory, 8) * PRIME2; + v3 += readIntLE(memory, 8) * PRIME2; v3 = rotateLeft(v3, 13); v3 *= PRIME1; - v4 += readInt(memory, 12) * PRIME2; + v4 += readIntLE(memory, 12) * PRIME2; v4 = rotateLeft(v4, 13); v4 *= PRIME1; @@ -110,22 +110,22 @@ public void update(byte[] buf, int off, int len) { int v4 = this.v4; while (off <= limit) { - v1 += readInt(buf, off) * PRIME2; + v1 += readIntLE(buf, off) * PRIME2; v1 = rotateLeft(v1, 13); v1 *= PRIME1; off += 4; - v2 += readInt(buf, off) * PRIME2; + v2 += readIntLE(buf, off) * PRIME2; v2 = rotateLeft(v2, 13); v2 *= PRIME1; off += 4; - v3 += readInt(buf, off) * PRIME2; + v3 += readIntLE(buf, off) * PRIME2; v3 = rotateLeft(v3, 13); v3 *= PRIME1; off += 4; - v4 += readInt(buf, off) * PRIME2; + v4 += readIntLE(buf, off) * PRIME2; v4 = rotateLeft(v4, 13); v4 *= PRIME1; off += 4; diff --git a/src/java/net/jpountz/xxhash/StreamingXXHash32JavaUnsafe.java b/src/java/net/jpountz/xxhash/StreamingXXHash32JavaUnsafe.java index aa293468..c6b55796 100644 --- a/src/java/net/jpountz/xxhash/StreamingXXHash32JavaUnsafe.java +++ b/src/java/net/jpountz/xxhash/StreamingXXHash32JavaUnsafe.java @@ -19,7 +19,7 @@ import static java.lang.Integer.rotateLeft; import static net.jpountz.util.UnsafeUtils.readByte; -import static net.jpountz.util.UnsafeUtils.readInt; +import static net.jpountz.util.UnsafeUtils.readIntLE; import static net.jpountz.util.Utils.checkRange; import static net.jpountz.xxhash.XXHashUtils.PRIME1; import static net.jpountz.xxhash.XXHashUtils.PRIME2; @@ -42,11 +42,11 @@ public int getValue() { h32 = seed + PRIME5; } - h32 += (int) totalLen; + h32 += totalLen; int off = 0; while (off <= memSize - 4) { - h32 += readInt(memory, off) * PRIME3; + h32 += readIntLE(memory, off) * PRIME3; h32 = rotateLeft(h32, 17) * PRIME4; off += 4; } @@ -83,19 +83,19 @@ public void update(byte[] buf, int off, int len) { if (memSize > 0) { // data left from previous update System.arraycopy(buf, off, memory, memSize, 16 - memSize); - v1 += readInt(memory, 0) * PRIME2; + v1 += readIntLE(memory, 0) * PRIME2; v1 = rotateLeft(v1, 13); v1 *= PRIME1; - v2 += readInt(memory, 4) * PRIME2; + v2 += readIntLE(memory, 4) * PRIME2; v2 = rotateLeft(v2, 13); v2 *= PRIME1; - v3 += readInt(memory, 8) * PRIME2; + v3 += readIntLE(memory, 8) * PRIME2; v3 = rotateLeft(v3, 13); v3 *= PRIME1; - v4 += readInt(memory, 12) * PRIME2; + v4 += readIntLE(memory, 12) * PRIME2; v4 = rotateLeft(v4, 13); v4 *= PRIME1; @@ -111,22 +111,22 @@ public void update(byte[] buf, int off, int len) { int v4 = this.v4; while (off <= limit) { - v1 += readInt(buf, off) * PRIME2; + v1 += readIntLE(buf, off) * PRIME2; v1 = rotateLeft(v1, 13); v1 *= PRIME1; off += 4; - v2 += readInt(buf, off) * PRIME2; + v2 += readIntLE(buf, off) * PRIME2; v2 = rotateLeft(v2, 13); v2 *= PRIME1; off += 4; - v3 += readInt(buf, off) * PRIME2; + v3 += readIntLE(buf, off) * PRIME2; v3 = rotateLeft(v3, 13); v3 *= PRIME1; off += 4; - v4 += readInt(buf, off) * PRIME2; + v4 += readIntLE(buf, off) * PRIME2; v4 = rotateLeft(v4, 13); v4 *= PRIME1; off += 4; diff --git a/src/java/net/jpountz/xxhash/XXHash32JavaSafe.java b/src/java/net/jpountz/xxhash/XXHash32JavaSafe.java index 086a3827..3e896cb5 100644 --- a/src/java/net/jpountz/xxhash/XXHash32JavaSafe.java +++ b/src/java/net/jpountz/xxhash/XXHash32JavaSafe.java @@ -19,7 +19,7 @@ import static java.lang.Integer.rotateLeft; import static net.jpountz.util.Utils.checkRange; -import static net.jpountz.util.Utils.readInt; +import static net.jpountz.util.Utils.readIntLE; import static net.jpountz.xxhash.XXHashUtils.PRIME1; import static net.jpountz.xxhash.XXHashUtils.PRIME2; import static net.jpountz.xxhash.XXHashUtils.PRIME3; @@ -47,22 +47,22 @@ public int hash(byte[] buf, int off, int len, int seed) { int v3 = seed + 0; int v4 = seed - PRIME1; do { - v1 += readInt(buf, off) * PRIME2; + v1 += readIntLE(buf, off) * PRIME2; v1 = rotateLeft(v1, 13); v1 *= PRIME1; off += 4; - v2 += readInt(buf, off) * PRIME2; + v2 += readIntLE(buf, off) * PRIME2; v2 = rotateLeft(v2, 13); v2 *= PRIME1; off += 4; - v3 += readInt(buf, off) * PRIME2; + v3 += readIntLE(buf, off) * PRIME2; v3 = rotateLeft(v3, 13); v3 *= PRIME1; off += 4; - v4 += readInt(buf, off) * PRIME2; + v4 += readIntLE(buf, off) * PRIME2; v4 = rotateLeft(v4, 13); v4 *= PRIME1; off += 4; @@ -76,7 +76,7 @@ public int hash(byte[] buf, int off, int len, int seed) { h32 += len; while (off <= end - 4) { - h32 += readInt(buf, off) * PRIME3; + h32 += readIntLE(buf, off) * PRIME3; h32 = rotateLeft(h32, 17) * PRIME4; off += 4; } diff --git a/src/java/net/jpountz/xxhash/XXHash32JavaUnsafe.java b/src/java/net/jpountz/xxhash/XXHash32JavaUnsafe.java index 1688b918..a6119c98 100644 --- a/src/java/net/jpountz/xxhash/XXHash32JavaUnsafe.java +++ b/src/java/net/jpountz/xxhash/XXHash32JavaUnsafe.java @@ -19,7 +19,7 @@ import static java.lang.Integer.rotateLeft; import static net.jpountz.util.UnsafeUtils.readByte; -import static net.jpountz.util.UnsafeUtils.readInt; +import static net.jpountz.util.UnsafeUtils.readIntLE; import static net.jpountz.util.Utils.checkRange; import static net.jpountz.xxhash.XXHashUtils.PRIME1; import static net.jpountz.xxhash.XXHashUtils.PRIME2; @@ -48,22 +48,22 @@ public int hash(byte[] buf, int off, int len, int seed) { int v3 = seed + 0; int v4 = seed - PRIME1; do { - v1 += readInt(buf, off) * PRIME2; + v1 += readIntLE(buf, off) * PRIME2; v1 = rotateLeft(v1, 13); v1 *= PRIME1; off += 4; - v2 += readInt(buf, off) * PRIME2; + v2 += readIntLE(buf, off) * PRIME2; v2 = rotateLeft(v2, 13); v2 *= PRIME1; off += 4; - v3 += readInt(buf, off) * PRIME2; + v3 += readIntLE(buf, off) * PRIME2; v3 = rotateLeft(v3, 13); v3 *= PRIME1; off += 4; - v4 += readInt(buf, off) * PRIME2; + v4 += readIntLE(buf, off) * PRIME2; v4 = rotateLeft(v4, 13); v4 *= PRIME1; off += 4; @@ -77,7 +77,7 @@ public int hash(byte[] buf, int off, int len, int seed) { h32 += len; while (off <= end - 4) { - h32 += readInt(buf, off) * PRIME3; + h32 += readIntLE(buf, off) * PRIME3; h32 = rotateLeft(h32, 17) * PRIME4; off += 4; } diff --git a/src/java/net/jpountz/xxhash/XXHashJNI.java b/src/java/net/jpountz/xxhash/XXHashJNI.java index ed4b609c..0341c04c 100644 --- a/src/java/net/jpountz/xxhash/XXHashJNI.java +++ b/src/java/net/jpountz/xxhash/XXHashJNI.java @@ -31,6 +31,7 @@ enum XXHashJNI { static native int XXH32(byte[] input, int offset, int len, int seed); static native long XXH32_init(int seed); static native void XXH32_feed(long state, byte[] input, int offset, int len); + static native int XXH32_getIntermediateResult(long state); static native int XXH32_result(long state); } diff --git a/src/jni/net_jpountz_xxhash_XXHashJNI.c b/src/jni/net_jpountz_xxhash_XXHashJNI.c index b9062520..5a59fd77 100644 --- a/src/jni/net_jpountz_xxhash_XXHashJNI.c +++ b/src/jni/net_jpountz_xxhash_XXHashJNI.c @@ -87,6 +87,18 @@ JNIEXPORT void JNICALL Java_net_jpountz_xxhash_XXHashJNI_XXH32_1feed } +/* + * Class: net_jpountz_xxhash_XXHashJNI + * Method: XXH32_getIntermediateResult + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_net_jpountz_xxhash_XXHashJNI_XXH32_1getIntermediateResult + (JNIEnv *env, jclass cls, jlong state) { + + return XXH32_getIntermediateResult((void*) state); + +} + /* * Class: net_jpountz_xxhash_XXHashJNI * Method: XXH32_result @@ -98,3 +110,4 @@ JNIEXPORT jint JNICALL Java_net_jpountz_xxhash_XXHashJNI_XXH32_1result return XXH32_result((void*) state); } + diff --git a/src/test/net/jpountz/xxhash/XXHashTest.java b/src/test/net/jpountz/xxhash/XXHashTest.java index ffc96cf1..17f99ac8 100644 --- a/src/test/net/jpountz/xxhash/XXHashTest.java +++ b/src/test/net/jpountz/xxhash/XXHashTest.java @@ -32,6 +32,9 @@ public int hash(byte[] buf, int off, int len, int seed) { --remainingPasses; off = originalOff; } + if (randomBoolean()) { + h.getValue(); + } } return h.getValue(); } @@ -108,4 +111,27 @@ public void testInstances() { } } + @Test + public void test4GB() { + byte[] bytes = new byte[randomIntBetween(1 << 22, 1 << 26)]; + for (int i = 0; i < bytes.length; ++i) { + bytes[i] = randomByte(); + } + final int off = randomInt(5); + final int len = randomIntBetween(bytes.length - off - 1024, bytes.length - off); + long totalLen = 0; + final int seed = randomInt(); + StreamingXXHash32 hash1 = XXHashFactory.nativeInstance().newStreamingHash32(seed); + StreamingXXHash32 hash2 = XXHashFactory.unsafeInstance().newStreamingHash32(seed); + StreamingXXHash32 hash3 = XXHashFactory.safeInstance().newStreamingHash32(seed); + while (totalLen < (1L << 33)) { + hash1.update(bytes, off, len); + hash2.update(bytes, off, len); + hash3.update(bytes, off, len); + assertEquals(hash2.toString() + " " + totalLen, hash1.getValue(), hash2.getValue()); + assertEquals(hash3.toString() + " " + totalLen, hash1.getValue(), hash3.getValue()); + totalLen += len; + } + } + } diff --git a/src/xxhash/xxhash.c b/src/xxhash/xxhash.c index 7e4adc93..1d4d3a36 100644 --- a/src/xxhash/xxhash.c +++ b/src/xxhash/xxhash.c @@ -32,6 +32,20 @@ +//************************************** +// Tuning parameters +//************************************** +// FORCE_NATIVE_FORMAT : +// By default, xxHash library provides endian-independant Hash values. +// Results are therefore identical for big-endian and little-endian CPU. +// This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format. +// Should endian-independance be of no importance to your application, you may uncomment the #define below +// It will improve speed for Big-endian CPU. +// This option has no impact on Little_Endian CPU. +//#define FORCE_NATIVE_FORMAT 1 + + + //************************************** // Includes //************************************** @@ -42,13 +56,57 @@ //************************************** -// Compiler Options +// CPU Feature Detection //************************************** -// Note : under GCC, it may, sometimes, be faster to let the macro definition, instead of using win32 intrinsic +// Little Endian or Big Endian ? +// You can overwrite the #define below if you know your architecture endianess +#if defined(FORCE_NATIVE_FORMAT) && (FORCE_NATIVE_FORMAT==1) +// Force native format. The result will be endian dependant. +# define XXH_BIG_ENDIAN 0 +#elif defined (__GLIBC__) +# include +# if (__BYTE_ORDER == __BIG_ENDIAN) +# define XXH_BIG_ENDIAN 1 +# endif +#elif (defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN)) && !(defined(__LITTLE_ENDIAN__) || defined(__LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN)) +# define XXH_BIG_ENDIAN 1 +#elif defined(__sparc) || defined(__sparc__) \ + || defined(__ppc__) || defined(_POWER) || defined(__powerpc__) || defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC) || defined(PPC) || defined(__powerpc__) || defined(__powerpc) || defined(powerpc) \ + || defined(__hpux) || defined(__hppa) \ + || defined(_MIPSEB) || defined(__s390__) +# define XXH_BIG_ENDIAN 1 +#endif + +#if !defined(XXH_BIG_ENDIAN) +// Little Endian assumed. PDP Endian and other very rare endian format are unsupported. +# define XXH_BIG_ENDIAN 0 +#endif + + + +//************************************** +// Compiler-specific Options & Functions +//************************************** +#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) + +// Note : under GCC, it may sometimes be faster to enable the (2nd) macro definition, instead of using win32 intrinsic #if defined(_WIN32) -# define XXH_rotl32(x,r) _rotl(x,r) +# define XXH_rotl32(x,r) _rotl(x,r) +#else +# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r))) +#endif + +#if defined(_MSC_VER) // Visual Studio +# define XXH_swap32 _byteswap_ulong +#elif GCC_VERSION >= 430 +# define XXH_swap32 __builtin_bswap32 #else -# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r))) +static inline unsigned int XXH_swap32 (unsigned int x) { + return ((x << 24) & 0xff000000 ) | + ((x << 8) & 0x00ff0000 ) | + ((x >> 8) & 0x0000ff00 ) | + ((x >> 24) & 0x000000ff ); + } #endif @@ -64,6 +122,13 @@ +//************************************** +// Macros +//************************************** +#define XXH_LE32(p) (XXH_BIG_ENDIAN ? XXH_swap32(*(unsigned int*)(p)) : *(unsigned int*)(p)) + + + //**************************** // Simple Hash Functions //**************************** @@ -74,7 +139,7 @@ unsigned int XXH32(const void* input, int len, unsigned int seed) // Simple version, good for code maintenance, but unfortunately slow for small inputs void* state = XXH32_init(seed); XXH32_feed(state, input, len); - return XXH32_result32(state); + return XXH32_result(state); #else const unsigned char* p = (const unsigned char*)input; @@ -91,10 +156,10 @@ unsigned int XXH32(const void* input, int len, unsigned int seed) do { - v1 += (*(unsigned int*)p) * PRIME32_2; v1 = XXH_rotl32(v1, 13); v1 *= PRIME32_1; p+=4; - v2 += (*(unsigned int*)p) * PRIME32_2; v2 = XXH_rotl32(v2, 13); v2 *= PRIME32_1; p+=4; - v3 += (*(unsigned int*)p) * PRIME32_2; v3 = XXH_rotl32(v3, 13); v3 *= PRIME32_1; p+=4; - v4 += (*(unsigned int*)p) * PRIME32_2; v4 = XXH_rotl32(v4, 13); v4 *= PRIME32_1; p+=4; + v1 += XXH_LE32(p) * PRIME32_2; v1 = XXH_rotl32(v1, 13); v1 *= PRIME32_1; p+=4; + v2 += XXH_LE32(p) * PRIME32_2; v2 = XXH_rotl32(v2, 13); v2 *= PRIME32_1; p+=4; + v3 += XXH_LE32(p) * PRIME32_2; v3 = XXH_rotl32(v3, 13); v3 *= PRIME32_1; p+=4; + v4 += XXH_LE32(p) * PRIME32_2; v4 = XXH_rotl32(v4, 13); v4 *= PRIME32_1; p+=4; } while (p<=limit) ; h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); @@ -108,7 +173,7 @@ unsigned int XXH32(const void* input, int len, unsigned int seed) while (p<=bEnd-4) { - h32 += (*(unsigned int*)p) * PRIME32_3; + h32 += XXH_LE32(p) * PRIME32_3; h32 = XXH_rotl32(h32, 17) * PRIME32_4 ; p+=4; } @@ -143,7 +208,7 @@ struct XXH_state32_t unsigned int v2; unsigned int v3; unsigned int v4; - unsigned long long total_len; + unsigned int total_len; char memory[16]; int memsize; }; @@ -184,10 +249,10 @@ int XXH32_feed (void* state_in, const void* input, int len) memcpy(state->memory + state->memsize, input, 16-state->memsize); { const unsigned int* p32 = (const unsigned int*)state->memory; - state->v1 += (*p32) * PRIME32_2; state->v1 = XXH_rotl32(state->v1, 13); state->v1 *= PRIME32_1; p32++; - state->v2 += (*p32) * PRIME32_2; state->v2 = XXH_rotl32(state->v2, 13); state->v2 *= PRIME32_1; p32++; - state->v3 += (*p32) * PRIME32_2; state->v3 = XXH_rotl32(state->v3, 13); state->v3 *= PRIME32_1; p32++; - state->v4 += (*p32) * PRIME32_2; state->v4 = XXH_rotl32(state->v4, 13); state->v4 *= PRIME32_1; p32++; + state->v1 += XXH_LE32(p32) * PRIME32_2; state->v1 = XXH_rotl32(state->v1, 13); state->v1 *= PRIME32_1; p32++; + state->v2 += XXH_LE32(p32) * PRIME32_2; state->v2 = XXH_rotl32(state->v2, 13); state->v2 *= PRIME32_1; p32++; + state->v3 += XXH_LE32(p32) * PRIME32_2; state->v3 = XXH_rotl32(state->v3, 13); state->v3 *= PRIME32_1; p32++; + state->v4 += XXH_LE32(p32) * PRIME32_2; state->v4 = XXH_rotl32(state->v4, 13); state->v4 *= PRIME32_1; p32++; } p += 16-state->memsize; state->memsize = 0; @@ -202,10 +267,10 @@ int XXH32_feed (void* state_in, const void* input, int len) while (p<=limit) { - v1 += (*(unsigned int*)p) * PRIME32_2; v1 = XXH_rotl32(v1, 13); v1 *= PRIME32_1; p+=4; - v2 += (*(unsigned int*)p) * PRIME32_2; v2 = XXH_rotl32(v2, 13); v2 *= PRIME32_1; p+=4; - v3 += (*(unsigned int*)p) * PRIME32_2; v3 = XXH_rotl32(v3, 13); v3 *= PRIME32_1; p+=4; - v4 += (*(unsigned int*)p) * PRIME32_2; v4 = XXH_rotl32(v4, 13); v4 *= PRIME32_1; p+=4; + v1 += XXH_LE32(p) * PRIME32_2; v1 = XXH_rotl32(v1, 13); v1 *= PRIME32_1; p+=4; + v2 += XXH_LE32(p) * PRIME32_2; v2 = XXH_rotl32(v2, 13); v2 *= PRIME32_1; p+=4; + v3 += XXH_LE32(p) * PRIME32_2; v3 = XXH_rotl32(v3, 13); v3 *= PRIME32_1; p+=4; + v4 += XXH_LE32(p) * PRIME32_2; v4 = XXH_rotl32(v4, 13); v4 *= PRIME32_1; p+=4; } state->v1 = v1; @@ -224,7 +289,7 @@ int XXH32_feed (void* state_in, const void* input, int len) } -unsigned int XXH32_result (void* state_in) +unsigned int XXH32_getIntermediateResult (void* state_in) { struct XXH_state32_t * state = state_in; unsigned char * p = (unsigned char*)state->memory; @@ -245,7 +310,7 @@ unsigned int XXH32_result (void* state_in) while (p<=bEnd-4) { - h32 += (*(unsigned int*)p) * PRIME32_3; + h32 += XXH_LE32(p) * PRIME32_3; h32 = XXH_rotl32(h32, 17) * PRIME32_4 ; p+=4; } @@ -263,6 +328,14 @@ unsigned int XXH32_result (void* state_in) h32 *= PRIME32_3; h32 ^= h32 >> 16; + return h32; +} + + +unsigned int XXH32_result (void* state_in) +{ + unsigned int h32 = XXH32_getIntermediateResult(state_in); + free(state_in); return h32; diff --git a/src/xxhash/xxhash.h b/src/xxhash/xxhash.h index 105e0a7e..be2b9710 100644 --- a/src/xxhash/xxhash.h +++ b/src/xxhash/xxhash.h @@ -104,7 +104,15 @@ This function returns the final 32-bits hash. You must provide the same "void* state" parameter created by XXH32_init(). Memory will be freed by XXH32_result(). +*/ + +unsigned int XXH32_getIntermediateResult (void* state); +/* +This function does the same as XXH32_result(), generating a 32-bit hash, +but preserve memory context. +This way, it becomes possible to generate an intermediate hash, and then continue feeding data with XXH32_feed(). +To free memory context, use XXH32_result(). */