From 9ab3397a2f69334f17e54d61764e740468505e38 Mon Sep 17 00:00:00 2001 From: Looly Date: Mon, 13 Mar 2023 11:15:47 +0800 Subject: [PATCH] fix code --- .../cn/hutool/core/codec/hash/CityHash.java | 117 ++++++++---------- .../cn/hutool/core/codec/hash/MurmurHash.java | 3 + .../codec/hash/metro/AbstractMetroHash.java | 30 +++-- .../core/codec/hash/metro/MetroHash.java | 7 +- .../core/codec/hash/metro/MetroHash128.java | 90 ++++++-------- .../core/codec/hash/metro/MetroHash64.java | 58 ++++----- .../hash/metro/MetroHashInternalUtil.java | 51 -------- .../java/cn/hutool/core/math/NumberUtil.java | 1 - .../java/cn/hutool/core/tree/BeanTree.java | 15 ++- .../codec/hash/metro/MetroHash128Test.java | 4 +- .../cn/hutool/core/util/NumberUtilTest.java | 12 +- 11 files changed, 163 insertions(+), 225 deletions(-) delete mode 100644 hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/MetroHashInternalUtil.java diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/hash/CityHash.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/CityHash.java index bd34700c4..cebc5f715 100644 --- a/hutool-core/src/main/java/cn/hutool/core/codec/hash/CityHash.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/hash/CityHash.java @@ -17,6 +17,9 @@ import java.util.Arrays; * @since 5.2.5 */ public class CityHash implements Hash32, Hash64, Hash128{ + /** + * 单例 + */ public static CityHash INSTANCE = new CityHash(); // Some primes between 2^63 and 2^64 for various uses. @@ -50,46 +53,46 @@ public class CityHash implements Hash32, Hash64, Hash128 // len > 24 int h = len, g = c1 * len, f = g; - int a0 = rotate32(fetch32(data, len - 4) * c1, 17) * c2; - int a1 = rotate32(fetch32(data, len - 8) * c1, 17) * c2; - int a2 = rotate32(fetch32(data, len - 16) * c1, 17) * c2; - int a3 = rotate32(fetch32(data, len - 12) * c1, 17) * c2; - int a4 = rotate32(fetch32(data, len - 20) * c1, 17) * c2; + int a0 = Integer.rotateRight(fetch32(data, len - 4) * c1, 17) * c2; + int a1 = Integer.rotateRight(fetch32(data, len - 8) * c1, 17) * c2; + int a2 = Integer.rotateRight(fetch32(data, len - 16) * c1, 17) * c2; + int a3 = Integer.rotateRight(fetch32(data, len - 12) * c1, 17) * c2; + int a4 = Integer.rotateRight(fetch32(data, len - 20) * c1, 17) * c2; h ^= a0; - h = rotate32(h, 19); + h = Integer.rotateRight(h, 19); h = h * 5 + 0xe6546b64; h ^= a2; - h = rotate32(h, 19); + h = Integer.rotateRight(h, 19); h = h * 5 + 0xe6546b64; g ^= a1; - g = rotate32(g, 19); + g = Integer.rotateRight(g, 19); g = g * 5 + 0xe6546b64; g ^= a3; - g = rotate32(g, 19); + g = Integer.rotateRight(g, 19); g = g * 5 + 0xe6546b64; f += a4; - f = rotate32(f, 19); + f = Integer.rotateRight(f, 19); f = f * 5 + 0xe6546b64; int iters = (len - 1) / 20; int pos = 0; do { - a0 = rotate32(fetch32(data, pos) * c1, 17) * c2; + a0 = Integer.rotateRight(fetch32(data, pos) * c1, 17) * c2; a1 = fetch32(data, pos + 4); - a2 = rotate32(fetch32(data, pos + 8) * c1, 17) * c2; - a3 = rotate32(fetch32(data, pos + 12) * c1, 17) * c2; + a2 = Integer.rotateRight(fetch32(data, pos + 8) * c1, 17) * c2; + a3 = Integer.rotateRight(fetch32(data, pos + 12) * c1, 17) * c2; a4 = fetch32(data, pos + 16); h ^= a0; - h = rotate32(h, 18); + h = Integer.rotateRight(h, 18); h = h * 5 + 0xe6546b64; f += a1; - f = rotate32(f, 19); + f = Integer.rotateRight(f, 19); f = f * c1; g += a2; - g = rotate32(g, 18); + g = Integer.rotateRight(g, 18); g = g * 5 + 0xe6546b64; h ^= a3 + a1; - h = rotate32(h, 19); + h = Integer.rotateRight(h, 19); h = h * 5 + 0xe6546b64; g ^= a4; g = Integer.reverseBytes(g) * 5; @@ -104,16 +107,16 @@ public class CityHash implements Hash32, Hash64, Hash128 pos += 20; } while (--iters != 0); - g = rotate32(g, 11) * c1; - g = rotate32(g, 17) * c1; - f = rotate32(f, 11) * c1; - f = rotate32(f, 17) * c1; - h = rotate32(h + g, 19); + g = Integer.rotateRight(g, 11) * c1; + g = Integer.rotateRight(g, 17) * c1; + f = Integer.rotateRight(f, 11) * c1; + f = Integer.rotateRight(f, 17) * c1; + h = Integer.rotateRight(h + g, 19); h = h * 5 + 0xe6546b64; - h = rotate32(h, 17) * c1; - h = rotate32(h + f, 19); + h = Integer.rotateRight(h, 17) * c1; + h = Integer.rotateRight(h + f, 19); h = h * 5 + 0xe6546b64; - h = rotate32(h, 17) * c1; + h = Integer.rotateRight(h, 17) * c1; return h; } @@ -149,11 +152,11 @@ public class CityHash implements Hash32, Hash64, Hash128 len = (len - 1) & ~63; int pos = 0; do { - x = rotate64(x + y + v.getLowValue() + fetch64(data, pos + 8), 37) * k1; - y = rotate64(y + v.getHighValue() + fetch64(data, pos + 48), 42) * k1; + x = Long.rotateRight(x + y + v.getLowValue() + fetch64(data, pos + 8), 37) * k1; + y = Long.rotateRight(y + v.getHighValue() + fetch64(data, pos + 48), 42) * k1; x ^= w.getHighValue(); y += v.getLowValue() + fetch64(data, pos + 40); - z = rotate64(z + w.getLowValue(), 33) * k1; + z = Long.rotateRight(z + w.getLowValue(), 33) * k1; v = weakHashLen32WithSeeds(data, pos, v.getHighValue() * k1, x + w.getLowValue()); w = weakHashLen32WithSeeds(data, pos + 32, z + w.getHighValue(), y + fetch64(data, pos + 16)); // swap z,x value @@ -231,19 +234,19 @@ public class CityHash implements Hash32, Hash64, Hash128 long x = seed.getLowValue(); long y = seed.getHighValue(); long z = len * k1; - v.setLowValue(rotate64(y ^ k1, 49) * k1 + fetch64(byteArray, start)); - v.setHighValue(rotate64(v.getLowValue(), 42) * k1 + fetch64(byteArray, start + 8)); - w.setLowValue(rotate64(y + z, 35) * k1 + x); - w.setHighValue(rotate64(x + fetch64(byteArray, start + 88), 53) * k1); + v.setLowValue(Long.rotateRight(y ^ k1, 49) * k1 + fetch64(byteArray, start)); + v.setHighValue(Long.rotateRight(v.getLowValue(), 42) * k1 + fetch64(byteArray, start + 8)); + w.setLowValue(Long.rotateRight(y + z, 35) * k1 + x); + w.setHighValue(Long.rotateRight(x + fetch64(byteArray, start + 88), 53) * k1); // This is the same inner loop as CityHash64(), manually unrolled. int pos = start; do { - x = rotate64(x + y + v.getLowValue() + fetch64(byteArray, pos + 8), 37) * k1; - y = rotate64(y + v.getHighValue() + fetch64(byteArray, pos + 48), 42) * k1; + x = Long.rotateRight(x + y + v.getLowValue() + fetch64(byteArray, pos + 8), 37) * k1; + y = Long.rotateRight(y + v.getHighValue() + fetch64(byteArray, pos + 48), 42) * k1; x ^= w.getHighValue(); y += v.getLowValue() + fetch64(byteArray, pos + 40); - z = rotate64(z + w.getLowValue(), 33) * k1; + z = Long.rotateRight(z + w.getLowValue(), 33) * k1; v = weakHashLen32WithSeeds(byteArray, pos, v.getHighValue() * k1, x + w.getLowValue()); w = weakHashLen32WithSeeds(byteArray, pos + 32, z + w.getHighValue(), y + fetch64(byteArray, pos + 16)); @@ -251,11 +254,11 @@ public class CityHash implements Hash32, Hash64, Hash128 x = z; z = swapValue; pos += 64; - x = rotate64(x + y + v.getLowValue() + fetch64(byteArray, pos + 8), 37) * k1; - y = rotate64(y + v.getHighValue() + fetch64(byteArray, pos + 48), 42) * k1; + x = Long.rotateRight(x + y + v.getLowValue() + fetch64(byteArray, pos + 8), 37) * k1; + y = Long.rotateRight(y + v.getHighValue() + fetch64(byteArray, pos + 48), 42) * k1; x ^= w.getHighValue(); y += v.getLowValue() + fetch64(byteArray, pos + 40); - z = rotate64(z + w.getLowValue(), 33) * k1; + z = Long.rotateRight(z + w.getLowValue(), 33) * k1; v = weakHashLen32WithSeeds(byteArray, pos, v.getHighValue() * k1, x + w.getLowValue()); w = weakHashLen32WithSeeds(byteArray, pos + 32, z + w.getHighValue(), y + fetch64(byteArray, pos + 16)); swapValue = x; @@ -264,16 +267,16 @@ public class CityHash implements Hash32, Hash64, Hash128 pos += 64; len -= 128; } while (len >= 128); - x += rotate64(v.getLowValue() + z, 49) * k0; - y = y * k0 + rotate64(w.getHighValue(), 37); - z = z * k0 + rotate64(w.getLowValue(), 27); + x += Long.rotateRight(v.getLowValue() + z, 49) * k0; + y = y * k0 + Long.rotateRight(w.getHighValue(), 37); + z = z * k0 + Long.rotateRight(w.getLowValue(), 27); w.setLowValue(w.getLowValue() * 9); v.setLowValue(v.getLowValue() * k0); // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s. for (int tail_done = 0; tail_done < len; ) { tail_done += 32; - y = rotate64(x + y, 42) * k0 + v.getHighValue(); + y = Long.rotateRight(x + y, 42) * k0 + v.getHighValue(); w.setLowValue(w.getLowValue() + fetch64(byteArray, pos + len - tail_done + 16)); x = x * k0 + w.getLowValue(); z += w.getHighValue() + fetch64(byteArray, pos + len - tail_done); @@ -333,8 +336,8 @@ public class CityHash implements Hash32, Hash64, Hash128 final long mul = k2 + len * 2L; final long a = fetch64(byteArray, 0) + k2; final long b = fetch64(byteArray, len - 8); - final long c = rotate64(b, 37) * mul + a; - final long d = (rotate64(a, 25) + b) * mul; + final long c = Long.rotateRight(b, 37) * mul + a; + final long d = (Long.rotateRight(a, 25) + b) * mul; return hashLen16(c, d, mul); } if (len >= 4) { @@ -361,8 +364,8 @@ public class CityHash implements Hash32, Hash64, Hash128 final long b = fetch64(byteArray, 8); final long c = fetch64(byteArray, len - 8) * mul; final long d = fetch64(byteArray, len - 16) * k2; - return hashLen16(rotate64(a + b, 43) + rotate64(c, 30) + d, - a + rotate64(b + k2, 18) + c, mul); + return hashLen16(Long.rotateRight(a + b, 43) + Long.rotateRight(c, 30) + d, + a + Long.rotateRight(b + k2, 18) + c, mul); } private long hashLen33to64(final byte[] byteArray) { @@ -376,10 +379,10 @@ public class CityHash implements Hash32, Hash64, Hash128 final long f = fetch64(byteArray, 24) * 9; final long g = fetch64(byteArray, len - 8); final long h = fetch64(byteArray, len - 16) * mul; - final long u = rotate64(a + g, 43) + (rotate64(b, 30) + c) * 9; + final long u = Long.rotateRight(a + g, 43) + (Long.rotateRight(b, 30) + c) * 9; final long v = ((a + g) ^ d) + f + 1; final long w = Long.reverseBytes((u + v) * mul) + h; - final long x = rotate64(e + f, 42) + c; + final long x = Long.rotateRight(e + f, 42) + c; final long y = (Long.reverseBytes((v + w) * mul) + g) * mul; final long z = e + f + c; a = Long.reverseBytes((x + z) * mul + y) + b; @@ -395,16 +398,6 @@ public class CityHash implements Hash32, Hash64, Hash128 return ByteUtil.bytesToInt(byteArray, start, ByteUtil.CPU_ENDIAN); } - private static long rotate64(final long val, final int shift) { - // Avoid shifting by 64: doing so yields an undefined result. - return shift == 0 ? val : ((val >>> shift) | (val << (64 - shift))); - } - - private static int rotate32(final int val, final int shift) { - // Avoid shifting by 32: doing so yields an undefined result. - return shift == 0 ? val : ((val >>> shift) | (val << (32 - shift))); - } - private static long hashLen16(final long u, final long v, final long mul) { // Murmur-inspired hashing. long a = (u ^ v) * mul; @@ -446,21 +439,21 @@ public class CityHash implements Hash32, Hash64, Hash128 private int mur(int a, int h) { // Helper from Murmur3 for combining two 32-bit values. a *= c1; - a = rotate32(a, 17); + a = Integer.rotateRight(a, 17); a *= c2; h ^= a; - h = rotate32(h, 19); + h = Integer.rotateRight(h, 19); return h * 5 + 0xe6546b64; } private static Number128 weakHashLen32WithSeeds( final long w, final long x, final long y, final long z, long a, long b) { a += w; - b = rotate64(b + a + z, 21); + b = Long.rotateRight(b + a + z, 21); final long c = a; a += x; a += y; - b += rotate64(a, 44); + b += Long.rotateRight(a, 44); return new Number128(a + z, b + c); } diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/hash/MurmurHash.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/MurmurHash.java index 0f3065973..e5d69616c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/codec/hash/MurmurHash.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/hash/MurmurHash.java @@ -21,6 +21,9 @@ import java.nio.charset.Charset; * @since 4.3.3 */ public class MurmurHash implements Hash32, Hash64, Hash128{ + /** + * 单例 + */ public static final MurmurHash INSTANCE = new MurmurHash(); // Constants for 32 bit variant diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/AbstractMetroHash.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/AbstractMetroHash.java index 240f060f0..ac736d053 100644 --- a/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/AbstractMetroHash.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/AbstractMetroHash.java @@ -30,13 +30,7 @@ public abstract class AbstractMetroHash> implemen reset(); } - /** - * Applies the instance's Metro hash function to the bytes in the given buffer. - * This updates this instance's hashing state. - * - * @param input 内容 - * @return this - */ + @Override public R apply(final ByteBuffer input) { reset(); while (input.remaining() >= 32) { @@ -46,18 +40,32 @@ public abstract class AbstractMetroHash> implemen } /** - * Consumes a 32-byte chunk from the byte buffer and updates the hashing state. + * 从byteBuffer中计算32-byte块并更新hash状态 * - * @param partialInput byte buffer with at least 32 bytes remaining. + * @param partialInput byte buffer,至少有32byte的数据 * @return this */ abstract R partialApply32ByteChunk(ByteBuffer partialInput); /** - * Consumes the remaining bytes from the byte buffer and updates the hashing state. + * 从byteBuffer中计算剩余bytes并更新hash状态 * - * @param partialInput byte buffer with less than 32 bytes remaining. + * @param partialInput byte buffer,少于32byte的数据 * @return this */ abstract R partialApplyRemaining(ByteBuffer partialInput); + + static long grab(final ByteBuffer bb, final int length) { + long result = bb.get() & 0xFFL; + for (int i = 1; i < length; i++) { + result |= (bb.get() & 0xFFL) << (i << 3); + } + return result; + } + + static void writeLittleEndian(final long hash, final ByteBuffer output) { + for (int i = 0; i < 8; i++) { + output.put((byte) (hash >>> (i*8))); + } + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/MetroHash.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/MetroHash.java index 940e2e9fc..ba461a8a5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/MetroHash.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/MetroHash.java @@ -29,8 +29,8 @@ public interface MetroHash> { } /** - * Applies the instance's Metro hash function to the bytes in the given buffer. - * This updates this instance's hashing state. + * 将给定的{@link ByteBuffer}中的数据追加计算hash值
+ * 此方法会更新hash值状态 * * @param input 内容 * @return this @@ -38,8 +38,7 @@ public interface MetroHash> { R apply(final ByteBuffer input); /** - * Writes the current hash to the given byte buffer in big-endian order. - * 将结果hash值写出到{@link ByteBuffer}中 + * 将结果hash值写出到{@link ByteBuffer}中,可选端序 * * @param output 输出 * @param byteOrder 端序 diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/MetroHash128.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/MetroHash128.java index 5a905f696..045bd4d5a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/MetroHash128.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/MetroHash128.java @@ -52,24 +52,6 @@ public class MetroHash128 extends AbstractMetroHash implements Has return this; } - /** - * 获取高64位结果hash值 - * - * @return hash值 - */ - public long getHigh() { - return v0; - } - - /** - * 获取低64位结果hash值 - * - * @return hash值 - */ - public long getLow() { - return v1; - } - /** * 获取结果hash值 * @@ -87,8 +69,8 @@ public class MetroHash128 extends AbstractMetroHash implements Has @Override public MetroHash128 write(final ByteBuffer output, final ByteOrder byteOrder) { if (ByteOrder.LITTLE_ENDIAN == byteOrder) { - MetroHashInternalUtil.writeLittleEndian(v0, output); - MetroHashInternalUtil.writeLittleEndian(v1, output); + writeLittleEndian(v0, output); + writeLittleEndian(v1, output); } else { output.asLongBuffer().put(v1).put(v0); } @@ -98,14 +80,14 @@ public class MetroHash128 extends AbstractMetroHash implements Has @Override MetroHash128 partialApply32ByteChunk(final ByteBuffer partialInput) { assert partialInput.remaining() >= 32; - v0 += MetroHashInternalUtil.grab8(partialInput) * K0; - v0 = MetroHashInternalUtil.rotateRight64(v0, 29) + v2; - v1 += MetroHashInternalUtil.grab8(partialInput) * K1; - v1 = MetroHashInternalUtil.rotateRight64(v1, 29) + v3; - v2 += MetroHashInternalUtil.grab8(partialInput) * K2; - v2 = MetroHashInternalUtil.rotateRight64(v2, 29) + v0; - v3 += MetroHashInternalUtil.grab8(partialInput) * K3; - v3 = MetroHashInternalUtil.rotateRight64(v3, 29) + v1; + v0 += grab(partialInput, 8) * K0; + v0 = Long.rotateRight(v0, 29) + v2; + v1 += grab(partialInput, 8) * K1; + v1 = Long.rotateRight(v1, 29) + v3; + v2 += grab(partialInput, 8) * K2; + v2 = Long.rotateRight(v2, 29) + v0; + v3 += grab(partialInput, 8) * K3; + v3 = Long.rotateRight(v3, 29) + v1; ++nChunks; return this; } @@ -131,52 +113,52 @@ public class MetroHash128 extends AbstractMetroHash implements Has if (partialInput.remaining() >= 1) { metroHash128_1(partialInput); } - v0 += MetroHashInternalUtil.rotateRight64(v0 * K0 + v1, 13); - v1 += MetroHashInternalUtil.rotateRight64(v1 * K1 + v0, 37); - v0 += MetroHashInternalUtil.rotateRight64(v0 * K2 + v1, 13); - v1 += MetroHashInternalUtil.rotateRight64(v1 * K3 + v0, 37); + v0 += Long.rotateRight(v0 * K0 + v1, 13); + v1 += Long.rotateRight(v1 * K1 + v0, 37); + v0 += Long.rotateRight(v0 * K2 + v1, 13); + v1 += Long.rotateRight(v1 * K3 + v0, 37); return this; } // region ----- private methods private void metroHash128_32() { - v2 ^= MetroHashInternalUtil.rotateRight64((v0 + v3) * K0 + v1, 21) * K1; - v3 ^= MetroHashInternalUtil.rotateRight64((v1 + v2) * K1 + v0, 21) * K0; - v0 ^= MetroHashInternalUtil.rotateRight64((v0 + v2) * K0 + v3, 21) * K1; - v1 ^= MetroHashInternalUtil.rotateRight64((v1 + v3) * K1 + v2, 21) * K0; + v2 ^= Long.rotateRight((v0 + v3) * K0 + v1, 21) * K1; + v3 ^= Long.rotateRight((v1 + v2) * K1 + v0, 21) * K0; + v0 ^= Long.rotateRight((v0 + v2) * K0 + v3, 21) * K1; + v1 ^= Long.rotateRight((v1 + v3) * K1 + v2, 21) * K0; } private void metroHash128_16(final ByteBuffer bb) { - v0 += MetroHashInternalUtil.grab8(bb) * K2; - v0 = MetroHashInternalUtil.rotateRight64(v0, 33) * K3; - v1 += MetroHashInternalUtil.grab8(bb) * K2; - v1 = MetroHashInternalUtil.rotateRight64(v1, 33) * K3; - v0 ^= MetroHashInternalUtil.rotateRight64(v0 * K2 + v1, 45) * K1; - v1 ^= MetroHashInternalUtil.rotateRight64(v1 * K3 + v0, 45) * K0; + v0 += grab(bb, 8) * K2; + v0 = Long.rotateRight(v0, 33) * K3; + v1 += grab(bb, 8) * K2; + v1 = Long.rotateRight(v1, 33) * K3; + v0 ^= Long.rotateRight(v0 * K2 + v1, 45) * K1; + v1 ^= Long.rotateRight(v1 * K3 + v0, 45) * K0; } private void metroHash128_8(final ByteBuffer bb) { - v0 += MetroHashInternalUtil.grab8(bb) * K2; - v0 = MetroHashInternalUtil.rotateRight64(v0, 33) * K3; - v0 ^= MetroHashInternalUtil.rotateRight64(v0 * K2 + v1, 27) * K1; + v0 += grab(bb, 8) * K2; + v0 = Long.rotateRight(v0, 33) * K3; + v0 ^= Long.rotateRight(v0 * K2 + v1, 27) * K1; } private void metroHash128_4(final ByteBuffer bb) { - v1 += MetroHashInternalUtil.grab4(bb) * K2; - v1 = MetroHashInternalUtil.rotateRight64(v1, 33) * K3; - v1 ^= MetroHashInternalUtil.rotateRight64(v1 * K3 + v0, 46) * K0; + v1 += grab(bb, 4) * K2; + v1 = Long.rotateRight(v1, 33) * K3; + v1 ^= Long.rotateRight(v1 * K3 + v0, 46) * K0; } private void metroHash128_2(final ByteBuffer bb) { - v0 += MetroHashInternalUtil.grab2(bb) * K2; - v0 = MetroHashInternalUtil.rotateRight64(v0, 33) * K3; - v0 ^= MetroHashInternalUtil.rotateRight64(v0 * K2 + v1, 22) * K1; + v0 += grab(bb, 2) * K2; + v0 = Long.rotateRight(v0, 33) * K3; + v0 ^= Long.rotateRight(v0 * K2 + v1, 22) * K1; } private void metroHash128_1(final ByteBuffer bb) { - v1 += MetroHashInternalUtil.grab1(bb) * K2; - v1 = MetroHashInternalUtil.rotateRight64(v1, 33) * K3; - v1 ^= MetroHashInternalUtil.rotateRight64(v1 * K3 + v0, 58) * K0; + v1 += grab(bb, 1) * K2; + v1 = Long.rotateRight(v1, 33) * K3; + v1 ^= Long.rotateRight(v1 * K3 + v0, 58) * K0; } // endregion } diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/MetroHash64.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/MetroHash64.java index 8f9a78514..9a2e38703 100644 --- a/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/MetroHash64.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/MetroHash64.java @@ -67,7 +67,7 @@ public class MetroHash64 extends AbstractMetroHash implements Hash6 @Override public MetroHash64 write(final ByteBuffer output, final ByteOrder byteOrder) { if(ByteOrder.LITTLE_ENDIAN == byteOrder){ - MetroHashInternalUtil.writeLittleEndian(hash, output); + writeLittleEndian(hash, output); } else{ output.asLongBuffer().put(hash); } @@ -77,14 +77,14 @@ public class MetroHash64 extends AbstractMetroHash implements Hash6 @Override MetroHash64 partialApply32ByteChunk(final ByteBuffer partialInput) { assert partialInput.remaining() >= 32; - v0 += MetroHashInternalUtil.grab8(partialInput) * K0; - v0 = MetroHashInternalUtil.rotateRight64(v0, 29) + v2; - v1 += MetroHashInternalUtil.grab8(partialInput) * K1; - v1 = MetroHashInternalUtil.rotateRight64(v1, 29) + v3; - v2 += MetroHashInternalUtil.grab8(partialInput) * K2; - v2 = MetroHashInternalUtil.rotateRight64(v2, 29) + v0; - v3 += MetroHashInternalUtil.grab8(partialInput) * K3; - v3 = MetroHashInternalUtil.rotateRight64(v3, 29) + v1; + v0 += grab(partialInput, 8) * K0; + v0 = Long.rotateRight(v0, 29) + v2; + v1 += grab(partialInput, 8) * K1; + v1 = Long.rotateRight(v1, 29) + v3; + v2 += grab(partialInput, 8) * K2; + v2 = Long.rotateRight(v2, 29) + v0; + v3 += grab(partialInput, 8) * K3; + v3 = Long.rotateRight(v3, 29) + v1; ++nChunks; return this; } @@ -110,49 +110,49 @@ public class MetroHash64 extends AbstractMetroHash implements Hash6 if (partialInput.remaining() >= 1) { metroHash64_1(partialInput); } - hash ^= MetroHashInternalUtil.rotateRight64(hash, 28); + hash ^= Long.rotateRight(hash, 28); hash *= K0; - hash ^= MetroHashInternalUtil.rotateRight64(hash, 29); + hash ^= Long.rotateRight(hash, 29); return this; } // region ----- private methods private void metroHash64_32() { - v2 ^= MetroHashInternalUtil.rotateRight64(((v0 + v3) * K0) + v1, 37) * K1; - v3 ^= MetroHashInternalUtil.rotateRight64(((v1 + v2) * K1) + v0, 37) * K0; - v0 ^= MetroHashInternalUtil.rotateRight64(((v0 + v2) * K0) + v3, 37) * K1; - v1 ^= MetroHashInternalUtil.rotateRight64(((v1 + v3) * K1) + v2, 37) * K0; + v2 ^= Long.rotateRight(((v0 + v3) * K0) + v1, 37) * K1; + v3 ^= Long.rotateRight(((v1 + v2) * K1) + v0, 37) * K0; + v0 ^= Long.rotateRight(((v0 + v2) * K0) + v3, 37) * K1; + v1 ^= Long.rotateRight(((v1 + v3) * K1) + v2, 37) * K0; hash += v0 ^ v1; } private void metroHash64_16(final ByteBuffer bb) { - v0 = hash + MetroHashInternalUtil.grab8(bb) * K2; - v0 = MetroHashInternalUtil.rotateRight64(v0, 29) * K3; - v1 = hash + MetroHashInternalUtil.grab8(bb) * K2; - v1 = MetroHashInternalUtil.rotateRight64(v1, 29) * K3; - v0 ^= MetroHashInternalUtil.rotateRight64(v0 * K0, 21) + v1; - v1 ^= MetroHashInternalUtil.rotateRight64(v1 * K3, 21) + v0; + v0 = hash + grab(bb, 8) * K2; + v0 = Long.rotateRight(v0, 29) * K3; + v1 = hash + grab(bb, 8) * K2; + v1 = Long.rotateRight(v1, 29) * K3; + v0 ^= Long.rotateRight(v0 * K0, 21) + v1; + v1 ^= Long.rotateRight(v1 * K3, 21) + v0; hash += v1; } private void metroHash64_8(final ByteBuffer bb) { - hash += MetroHashInternalUtil.grab8(bb) * K3; - hash ^= MetroHashInternalUtil.rotateRight64(hash, 55) * K1; + hash += grab(bb, 8) * K3; + hash ^= Long.rotateRight(hash, 55) * K1; } private void metroHash64_4(final ByteBuffer bb) { - hash += MetroHashInternalUtil.grab4(bb) * K3; - hash ^= MetroHashInternalUtil.rotateRight64(hash, 26) * K1; + hash += grab(bb, 4) * K3; + hash ^= Long.rotateRight(hash, 26) * K1; } private void metroHash64_2(final ByteBuffer bb) { - hash += MetroHashInternalUtil.grab2(bb) * K3; - hash ^= MetroHashInternalUtil.rotateRight64(hash, 48) * K1; + hash += grab(bb, 2) * K3; + hash ^= Long.rotateRight(hash, 48) * K1; } private void metroHash64_1(final ByteBuffer bb) { - hash += MetroHashInternalUtil.grab1(bb) * K3; - hash ^= MetroHashInternalUtil.rotateRight64(hash, 37) * K1; + hash += grab(bb, 1) * K3; + hash ^= Long.rotateRight(hash, 37) * K1; } // endregion } diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/MetroHashInternalUtil.java b/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/MetroHashInternalUtil.java deleted file mode 100644 index 2a4e49713..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/codec/hash/metro/MetroHashInternalUtil.java +++ /dev/null @@ -1,51 +0,0 @@ -package cn.hutool.core.codec.hash.metro; - -import java.nio.ByteBuffer; - -class MetroHashInternalUtil { - - static void writeLittleEndian(final long hash, final ByteBuffer output) { - output.put((byte) hash); - output.put((byte) (hash >>> 8)); - output.put((byte) (hash >>> 16)); - output.put((byte) (hash >>> 24)); - output.put((byte) (hash >>> 32)); - output.put((byte) (hash >>> 40)); - output.put((byte) (hash >>> 48)); - output.put((byte) (hash >>> 56)); - } - - static long rotateRight64(final long x, final int r) { - return (x >>> r) | (x << (64 - r)); - } - - static long grab1(final ByteBuffer bb) { - return ((long) bb.get() & 0xFFL); - } - - static long grab2(final ByteBuffer bb) { - final long v0 = bb.get(); - final long v1 = bb.get(); - return (v0 & 0xFFL) | (v1 & 0xFFL) << 8; - } - - static long grab4(final ByteBuffer bb) { - final long v0 = bb.get(); - final long v1 = bb.get(); - final long v2 = bb.get(); - final long v3 = bb.get(); - return (v0 & 0xFFL) | (v1 & 0xFFL) << 8 | (v2 & 0xFFL) << 16 | (v3 & 0xFFL) << 24; - } - - static long grab8(final ByteBuffer bb) { - final long v0 = bb.get(); - final long v1 = bb.get(); - final long v2 = bb.get(); - final long v3 = bb.get(); - final long v4 = bb.get(); - final long v5 = bb.get(); - final long v6 = bb.get(); - final long v7 = bb.get(); - return (v0 & 0xFFL) | (v1 & 0xFFL) << 8 | (v2 & 0xFFL) << 16 | (v3 & 0xFFL) << 24 | (v4 & 0xFFL) << 32 | (v5 & 0xFFL) << 40 | (v6 & 0xFFL) << 48 | (v7 & 0xFFL) << 56; - } -} diff --git a/hutool-core/src/main/java/cn/hutool/core/math/NumberUtil.java b/hutool-core/src/main/java/cn/hutool/core/math/NumberUtil.java index 365fdcaf0..f40ae04af 100644 --- a/hutool-core/src/main/java/cn/hutool/core/math/NumberUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/math/NumberUtil.java @@ -1761,5 +1761,4 @@ public class NumberUtil { public static boolean isEven(final int num) { return false == isOdd(num); } - } diff --git a/hutool-core/src/main/java/cn/hutool/core/tree/BeanTree.java b/hutool-core/src/main/java/cn/hutool/core/tree/BeanTree.java index aa0cf12df..38e9eb05f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/tree/BeanTree.java +++ b/hutool-core/src/main/java/cn/hutool/core/tree/BeanTree.java @@ -30,10 +30,13 @@ import java.util.function.Predicate; * 也可以将已有的树转换为集合,例如: *
{@code final List javaBeanList = beanTree.flat(originJavaBeanTree);}
* + *

最后,引用一句电影经典台词: 无处安放的双手,以及无处安放的灵魂。——《Hello!树先生》

+ * + * @param Bean类型 + * @param 主键、外键类型 * @author VampireAchao * @author emptypoint * @author CreateSequence - * 最后,引用一句电影经典台词: 无处安放的双手,以及无处安放的灵魂。——《Hello!树先生》 */ public class BeanTree> { @@ -126,10 +129,10 @@ public class BeanTree> { if (CollUtil.isEmpty(list)) { return ListUtil.zero(); } - if (Objects.isNull(parentPredicate)) { - final Map> pIdValuesMap = EasyStream.of(list) - .peek(e -> Objects.requireNonNull(idGetter.apply(e), () -> "The id of tree node must not be null " + e)) - .group(pidGetter); + if (Objects.isNull(parentPredicate)) { + final Map> pIdValuesMap = EasyStream.of(list) + .peek(e -> Objects.requireNonNull(idGetter.apply(e), () -> "The id of tree node must not be null " + e)) + .group(pidGetter); final List parents = pIdValuesMap.getOrDefault(pidValue, new ArrayList<>()); findChildren(list, pIdValuesMap); return parents; @@ -206,7 +209,7 @@ public class BeanTree> { * @param pIdValuesMap 父id与子集的映射 */ private void findChildren(final List list, final Map> pIdValuesMap) { - for (T node : list) { + for (final T node : list) { final List children = pIdValuesMap.get(idGetter.apply(node)); if (children != null) { childrenSetter.accept(node, children); diff --git a/hutool-core/src/test/java/cn/hutool/core/codec/hash/metro/MetroHash128Test.java b/hutool-core/src/test/java/cn/hutool/core/codec/hash/metro/MetroHash128Test.java index 0f2da98b7..b15f4359a 100644 --- a/hutool-core/src/test/java/cn/hutool/core/codec/hash/metro/MetroHash128Test.java +++ b/hutool-core/src/test/java/cn/hutool/core/codec/hash/metro/MetroHash128Test.java @@ -1,6 +1,7 @@ package cn.hutool.core.codec.hash.metro; import cn.hutool.core.codec.HexUtil; +import cn.hutool.core.codec.Number128; import cn.hutool.core.text.StrUtil; import org.junit.Assert; import org.junit.Test; @@ -106,7 +107,8 @@ public class MetroHash128Test { static String h128(final String input) { final MetroHash128 mh = MetroHash128.of(0).apply(ByteBuffer.wrap(StrUtil.utf8Bytes(input))); - return hex(mh.getHigh()) + hex(mh.getLow()); + final Number128 hash = mh.get(); + return hex(hash.getHighValue()) + hex(hash.getLowValue()); } private static String hex(final long value){ diff --git a/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java index 7e2af1963..aa76ecd97 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java @@ -82,13 +82,13 @@ public class NumberUtilTest { @Test public void isIntegerTest() { - String[] validNumArr = {"0", "-0", "+0", "12", "+12", "1234567890", "2147483647", "-2147483648", + final String[] validNumArr = {"0", "-0", "+0", "12", "+12", "1234567890", "2147483647", "-2147483648", "0x012345678", "0X012345678", "0xabcdef", "-0xabcdef", "0x12abcdef", "0x7FFFFFFF", "-0x80000000", "01234567", "017777777777", "-020000000000" }; privateIsIntegerTest(validNumArr, true); - String[] invalidNumArr = {null, "", " ", "+", "+1.", ".1", "99L", "99D", "99F", "12.3", "123e1", "-12.3", "1.2.3", + final String[] invalidNumArr = {null, "", " ", "+", "+1.", ".1", "99L", "99D", "99F", "12.3", "123e1", "-12.3", "1.2.3", "2147483648", "0x80000000", "020000000000", "-2147483649", "-0x80000001", "-020000000001", "-020000000001", "a", "+a", "123abc", "09" }; @@ -96,14 +96,14 @@ public class NumberUtilTest { } private void privateIsIntegerTest(final String[] numStrArr, final boolean expected) { - for (String numStr : numStrArr) { + for (final String numStr : numStrArr) { Assert.assertEquals("未通过的数字为: " + numStr, expected, NumberUtil.isInteger(numStr)); } } @Test public void isLongTest() { - String[] validNumArr = { + final String[] validNumArr = { "0", "0L", "-0L", "+0L", "12", "+12", "1234567890123456789", "99L", "2147483648", "0x80000000", "020000000000", "-2147483649", "-0x80000001", "-020000000001", "-020000000001", "9223372036854775807", "-9223372036854775808", @@ -113,7 +113,7 @@ public class NumberUtilTest { }; privateIsLongTest(validNumArr, true); - String[] invalidNumArr = {null, "", " ", "+", "+1.", ".1", "99D", "99F", "12.3", "123e1", "-12.3", "1.2.3", + final String[] invalidNumArr = {null, "", " ", "+", "+1.", ".1", "99D", "99F", "12.3", "123e1", "-12.3", "1.2.3", "a", "+a", "123abc", "09", "9223372036854775808", "-9223372036854775809", "0x8000000000000000", "-0x8000000000000001", @@ -123,7 +123,7 @@ public class NumberUtilTest { } private void privateIsLongTest(final String[] numStrArr, final boolean expected) { - for (String numStr : numStrArr) { + for (final String numStr : numStrArr) { Assert.assertEquals("未通过的数字为: " + numStr, expected, NumberUtil.isLong(numStr)); } }