Skip to content

Commit 6d85784

Browse files
committed
better hash for long and Long
1 parent 144fc57 commit 6d85784

File tree

2 files changed

+59
-28
lines changed

2 files changed

+59
-28
lines changed

src/main/java/com/trivago/fastutilconcurrentwrapper/util/CFUtil.java

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,29 +21,58 @@
2121
public final class CFUtil {
2222
public static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
2323

24-
/** @see it.unimi.dsi.fastutil.HashCommon#murmurHash3 */
25-
public static int hash (int hash) {
26-
return HashCommon.murmurHash3(hash);
24+
/// re-hash
25+
/// 👀 hash4j
26+
///
27+
/// @see it.unimi.dsi.fastutil.HashCommon#murmurHash3
28+
/// @see org.springframework.util.ConcurrentReferenceHashMap#getHash(Object)
29+
/// @see org.jsr166.ConcurrentLinkedHashMap#hash(int)
30+
/// @see jdk.internal.classfile.impl.AbstractPoolEntry#phiMix
31+
/// @see io.vertx.core.json.jackson.HybridJacksonPool.XorShiftThreadProbe#probe
32+
/// @see com.google.common.util.concurrent.Striped#smear
33+
/// @see java.util.concurrent.ThreadLocalRandom#PROBE_INCREMENT
34+
/// @see java.util.concurrent.ThreadLocalRandom#advanceProbe
35+
/// @see #bucket
36+
/// @see #hash
37+
public static int hash (int hashOrKey) {
38+
return HashCommon.murmurHash3(hashOrKey);
2739
}
2840

41+
public static int hash (long hashOrKey) {
42+
return hashOrKey < Integer.MIN_VALUE || hashOrKey > Integer.MAX_VALUE
43+
? Long.hashCode(HashCommon.murmurHash3(hashOrKey))
44+
: HashCommon.murmurHash3((int) hashOrKey);// if long uses low 32bit only
45+
}
46+
47+
public static int hash (@Nullable Long hashOrKey) {
48+
if (hashOrKey == null)
49+
return 0;
50+
return hashOrKey < Integer.MIN_VALUE || hashOrKey > Integer.MAX_VALUE
51+
? Long.hashCode(HashCommon.murmurHash3(hashOrKey))
52+
: HashCommon.murmurHash3(hashOrKey.intValue());// if long uses low 32bit only
53+
}
54+
55+
public static int hash (@Nullable Object object4hashCode) {
56+
if (object4hashCode == null)
57+
return 0;
58+
else if (object4hashCode instanceof Long n)
59+
return n < Integer.MIN_VALUE || n > Integer.MAX_VALUE
60+
? Long.hashCode(HashCommon.murmurHash3(n))
61+
: HashCommon.murmurHash3(n.intValue());// if long uses low 32bit only
62+
else
63+
return HashCommon.murmurHash3(object4hashCode.hashCode());
64+
}
65+
66+
2967
/** @see #bucket */
3068
public static @PositiveOrZero int bucket (int hashOrKey, @Positive int bucketSize) {
31-
int goodHash = HashCommon.murmurHash3(hashOrKey);
32-
return Math.abs(goodHash % bucketSize);
69+
return Math.abs(hash(hashOrKey) % bucketSize);
3370
}
3471

35-
/**
36-
@see #bucket
37-
@see java.util.Objects#hashCode(Object)
38-
*/
72+
/// @see #bucket
73+
/// @see java.util.Objects#hashCode(Object)
3974
public static @PositiveOrZero int bucket (@Nullable Object object4hashCode, @Positive int bucketSize) {
40-
if (object4hashCode == null){
41-
return 0;
42-
} else if (object4hashCode instanceof Long n){
43-
return bucket(n.longValue(), bucketSize);
44-
} else {
45-
return bucket(object4hashCode.hashCode(), bucketSize);
46-
}
75+
return Math.abs(hash(object4hashCode) % bucketSize);
4776
}
4877

4978
/**
@@ -59,11 +88,13 @@ Fast. Safe for negative keys (including Long.MIN_VALUE, Integer.MIN_VALUE)
5988
@see Long#hashCode(long)
6089
*/
6190
public static @PositiveOrZero int bucket (long hashOrKey, @Positive int bucketSize) {
62-
return hashOrKey > Integer.MAX_VALUE || hashOrKey < Integer.MIN_VALUE
63-
? bucket(Long.hashCode(hashOrKey), bucketSize)
64-
: bucket((int) hashOrKey, bucketSize);// long uses low 32bit only
91+
return Math.abs(hash(hashOrKey) % bucketSize);
92+
}
93+
public static @PositiveOrZero int bucket (@Nullable Long hashOrKey, @Positive int bucketSize) {
94+
return Math.abs(hash(hashOrKey) % bucketSize);
6595
}
6696

97+
6798
/**
6899
* Combined two 32-bit keys into a 64-bit compound.
69100

src/test/java/com/trivago/fastutilconcurrentwrapper/intkey/PrimitiveConcurrentMapTest.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,19 @@ void _hashInt () {
2929

3030
@Test
3131
void _hashLong () {
32-
assertEquals(74720, CFUtil.bucket(Long.MIN_VALUE, 100_000));
33-
assertEquals(79862, CFUtil.bucket(Long.MIN_VALUE+1, 100_000));
34-
assertEquals(74720, CFUtil.bucket(Integer.MIN_VALUE & 0xFFFFFFFFL, 100_000));
32+
assertEquals(99203, CFUtil.bucket(Long.MIN_VALUE, 100_000));
33+
assertEquals(66441, CFUtil.bucket(Long.MIN_VALUE+1, 100_000));
34+
assertEquals(59481, CFUtil.bucket(Integer.MIN_VALUE & 0xFFFFFFFFL, 100_000));
3535
assertEquals(74720, CFUtil.bucket((long) Integer.MIN_VALUE, 100_000));
36-
assertEquals(79862, CFUtil.bucket(-Integer.MAX_VALUE & 0xFFFFFFFFL, 100_000));
36+
assertEquals(57855, CFUtil.bucket(-Integer.MAX_VALUE & 0xFFFFFFFFL, 100_000));
3737
assertEquals(79862, CFUtil.bucket((long) -Integer.MAX_VALUE, 100_000));
3838
assertEquals(3539, CFUtil.bucket(-100_000L, 100_000));
3939
assertEquals(83783, CFUtil.bucket(-1L, 100_000));
4040
assertEquals(0, CFUtil.bucket(0L, 100_000));
4141
assertEquals(76727, CFUtil.bucket(1L, 100_000));
4242
assertEquals(55934, CFUtil.bucket(100_000L, 100_000));
4343
assertEquals(67416, CFUtil.bucket((long) Integer.MAX_VALUE, 100_000));
44-
assertEquals(74720, CFUtil.bucket(Long.MAX_VALUE, 100_000));
44+
assertEquals(86138, CFUtil.bucket(Long.MAX_VALUE, 100_000));
4545
}
4646

4747
@Test @Disabled
@@ -92,11 +92,11 @@ void longsAreSame () {
9292
void _hashObj () {
9393
assertEquals(0, CFUtil.bucket(null, 100_000));
9494

95-
assertEquals(74720, CFUtil.bucket(Long.valueOf(Long.MIN_VALUE), 100_000));
96-
assertEquals(74720, CFUtil.bucket(Long.valueOf(Integer.MIN_VALUE & 0xFFFFFFFFL), 100_000));
95+
assertEquals(99203, CFUtil.bucket(Long.valueOf(Long.MIN_VALUE), 100_000));
96+
assertEquals(59481, CFUtil.bucket(Long.valueOf(Integer.MIN_VALUE & 0xFFFFFFFFL), 100_000));
9797
assertEquals(74720, CFUtil.bucket(Long.valueOf(Integer.MIN_VALUE), 100_000));
9898

99-
assertEquals(79862, CFUtil.bucket(Long.valueOf(-Integer.MAX_VALUE & 0xFFFFFFFFL), 100_000));
99+
assertEquals(57855, CFUtil.bucket(Long.valueOf(-Integer.MAX_VALUE & 0xFFFFFFFFL), 100_000));
100100
assertEquals(79862, CFUtil.bucket(Long.valueOf(-Integer.MAX_VALUE), 100_000));
101101
assertEquals(3539, CFUtil.bucket(Long.valueOf(-100_000L), 100_000));
102102
assertEquals(57924, CFUtil.bucket(Long.valueOf(-2L), 100_000));
@@ -108,7 +108,7 @@ void _hashObj () {
108108
assertEquals(47078, CFUtil.bucket(Integer.valueOf(2), 100_000));
109109
assertEquals(55934, CFUtil.bucket(Long.valueOf(100_000L), 100_000));
110110
assertEquals(67416, CFUtil.bucket(Long.valueOf(Integer.MAX_VALUE), 100_000));
111-
assertEquals(74720, CFUtil.bucket(Long.valueOf(Long.MAX_VALUE), 100_000));
111+
assertEquals(86138, CFUtil.bucket(Long.valueOf(Long.MAX_VALUE), 100_000));
112112
}
113113

114114
@Test

0 commit comments

Comments
 (0)