testData =
55 | TEST_DATA_LONG.get(ThreadLocalRandom.current().nextInt(NUM_TEST_DATA_SETS));
56 | long hash = Hashing.murmur3_128().hashToLong(testData, LIST_LONG_FUNNEL);
57 | blackhole.consume(hash);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/jmh/java/com/dynatrace/hash4j/hashing/WyhashFinal3PerformanceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.hashing;
17 |
18 | public class WyhashFinal3PerformanceTest extends AbstactHasher64PerformanceTest {
19 |
20 | private static final Hasher64 HASHER_INSTANCE = Hashing.wyhashFinal3();
21 |
22 | @Override
23 | protected Hasher64 getHasherInstance() {
24 | return HASHER_INSTANCE;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/jmh/java/com/dynatrace/hash4j/hashing/WyhashFinal4PerformanceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.hashing;
17 |
18 | public class WyhashFinal4PerformanceTest extends AbstactHasher64PerformanceTest {
19 |
20 | private static final Hasher64 HASHER_INSTANCE = Hashing.wyhashFinal4();
21 |
22 | @Override
23 | protected Hasher64 getHasherInstance() {
24 | return HASHER_INSTANCE;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/jmh/java/com/dynatrace/hash4j/hashing/XXH3_128PerformanceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.hashing;
17 |
18 | public class XXH3_128PerformanceTest extends AbstactHasher128PerformanceTest {
19 |
20 | private static final Hasher128 HASHER_INSTANCE = Hashing.xxh3_128();
21 |
22 | @Override
23 | protected Hasher128 getHasherInstance() {
24 | return HASHER_INSTANCE;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/jmh/java/com/dynatrace/hash4j/hashing/XXH3_128ZeroAllocationHashingPerformanceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.hashing;
17 |
18 | import net.openhft.hashing.LongTupleHashFunction;
19 |
20 | public class XXH3_128ZeroAllocationHashingPerformanceTest
21 | extends AbstractZeroAllocationHashing128BitPerformanceTest {
22 |
23 | private static final LongTupleHashFunction HASH_FUNCTION = LongTupleHashFunction.xx128();
24 |
25 | @Override
26 | protected LongTupleHashFunction createHashFunction() {
27 | return HASH_FUNCTION;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/jmh/java/com/dynatrace/hash4j/hashing/XXH3_64PerformanceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2024 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.hashing;
17 |
18 | public class XXH3_64PerformanceTest extends AbstactHasher64PerformanceTest {
19 |
20 | private static final Hasher64 HASHER_INSTANCE = Hashing.xxh3_64();
21 |
22 | @Override
23 | protected Hasher64 getHasherInstance() {
24 | return HASHER_INSTANCE;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/jmh/java/com/dynatrace/hash4j/hashing/XXH3_64ZeroAllocationHashingPerformanceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.hashing;
17 |
18 | import net.openhft.hashing.LongHashFunction;
19 |
20 | public class XXH3_64ZeroAllocationHashingPerformanceTest
21 | extends AbstractZeroAllocationHashing64BitPerformanceTest {
22 |
23 | private static final LongHashFunction HASH_FUNCTION = LongHashFunction.xx3();
24 |
25 | @Override
26 | protected LongHashFunction createHashFunction() {
27 | return HASH_FUNCTION;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/jmh/java/com/dynatrace/hash4j/hashing/package-info.java:
--------------------------------------------------------------------------------
1 | /** Hash algorithms */
2 | package com.dynatrace.hash4j.hashing;
3 |
--------------------------------------------------------------------------------
/src/jmh/java/com/dynatrace/hash4j/random/RandomPerformanceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.random;
17 |
18 | import org.openjdk.jmh.annotations.*;
19 | import org.openjdk.jmh.infra.Blackhole;
20 |
21 | public class RandomPerformanceTest {
22 | @State(Scope.Thread)
23 | public static class RandomGeneratorState {
24 | public final PseudoRandomGenerator prng =
25 | PseudoRandomGeneratorProvider.splitMix64_V1().create();
26 | }
27 |
28 | @Benchmark
29 | @BenchmarkMode(Mode.AverageTime)
30 | public void randomLong(RandomGeneratorState randomGeneratorState, Blackhole blackhole) {
31 | blackhole.consume(randomGeneratorState.prng.nextLong());
32 | }
33 |
34 | @Benchmark
35 | @BenchmarkMode(Mode.AverageTime)
36 | public void randomInt(RandomGeneratorState randomGeneratorState, Blackhole blackhole) {
37 | blackhole.consume(randomGeneratorState.prng.nextInt());
38 | }
39 |
40 | @Benchmark
41 | @BenchmarkMode(Mode.AverageTime)
42 | public void randomExponential(RandomGeneratorState randomGeneratorState, Blackhole blackhole) {
43 | blackhole.consume(randomGeneratorState.prng.nextExponential());
44 | }
45 |
46 | @Benchmark
47 | @BenchmarkMode(Mode.AverageTime)
48 | public void randomDouble(RandomGeneratorState randomGeneratorState, Blackhole blackhole) {
49 | blackhole.consume(randomGeneratorState.prng.nextDouble());
50 | }
51 |
52 | @Benchmark
53 | @BenchmarkMode(Mode.AverageTime)
54 | public void randomExponentialAlternative(
55 | RandomGeneratorState randomGeneratorState, Blackhole blackhole) {
56 | blackhole.consume(StrictMath.log1p(-randomGeneratorState.prng.nextDouble()));
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/jmh/java/com/dynatrace/hash4j/similarity/SimilarityHashingPerformanceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.similarity;
17 |
18 | import com.dynatrace.hash4j.random.PseudoRandomGeneratorProvider;
19 | import java.util.SplittableRandom;
20 | import org.openjdk.jmh.annotations.*;
21 | import org.openjdk.jmh.infra.Blackhole;
22 |
23 | public class SimilarityHashingPerformanceTest {
24 |
25 | @State(Scope.Thread)
26 | public static class StateBase implements ElementHashProvider {
27 | public final SplittableRandom random = new SplittableRandom();
28 | public final SimilarityHasher similarityHasher;
29 |
30 | @Param({"1", "10", "100", "1000", "10000", "100000"})
31 | public int numElements;
32 |
33 | public StateBase(SimilarityHasher similarityHasher) {
34 | this.similarityHasher = similarityHasher;
35 | }
36 |
37 | public final long[] elementHashes = new long[100000]; // maximum number of elements
38 |
39 | @Override
40 | public long getElementHash(int elementIndex) {
41 | return elementHashes[elementIndex];
42 | }
43 |
44 | @Override
45 | public int getNumberOfElements() {
46 | return numElements;
47 | }
48 | }
49 |
50 | protected void testSimilarityHashing(StateBase state, Blackhole blackhole) {
51 | for (int i = 0; i < state.numElements; ++i) {
52 | state.elementHashes[i] = state.random.nextLong();
53 | }
54 | byte[] signature = state.similarityHasher.compute(state);
55 | blackhole.consume(signature);
56 | }
57 |
58 | protected static PseudoRandomGeneratorProvider getPseudoRandomGeneratorProvider() {
59 | return PseudoRandomGeneratorProvider.splitMix64_V1();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/consistent/ConsistentBucketHasher.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.consistent;
17 |
18 | /** A hash function that maps a given hash consistently to a bucket index of given range. */
19 | public interface ConsistentBucketHasher {
20 |
21 | /**
22 | * Returns a bucket index in the range {@code [0, numBuckets)} based on a 64-bit hash value of the
23 | * key.
24 | *
25 | * The returned bucket index is uniformly distributed. If {@code numBuckets} is changed,
26 | * remapping to other bucket indices is minimized.
27 | *
28 | *
This function is not thread-safe!
29 | *
30 | * @param hash a 64-bit hash value of the key
31 | * @param numBuckets the number of buckets, must be positive
32 | * @return the bucket index
33 | */
34 | int getBucket(long hash, int numBuckets);
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/consistent/ConsistentHashingUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.consistent;
17 |
18 | import static com.dynatrace.hash4j.internal.Preconditions.checkArgument;
19 |
20 | class ConsistentHashingUtil {
21 |
22 | private ConsistentHashingUtil() {}
23 |
24 | static void checkNumberOfBuckets(int numBuckets) {
25 | checkArgument(numBuckets > 0, "number of buckets must be positive");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/consistent/package-info.java:
--------------------------------------------------------------------------------
1 | /** Consistent hash algorithms for load balancing, sharding, task distribution, etc. */
2 | package com.dynatrace.hash4j.consistent;
3 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/distinctcount/StateChangeObserver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.distinctcount;
17 |
18 | /**
19 | * An observer of state changes of distinct counters such as {@link HyperLogLog} or {@link
20 | * UltraLogLog}.
21 | */
22 | @FunctionalInterface
23 | public interface StateChangeObserver {
24 |
25 | /**
26 | * This method is called whenever the internal state of the approximate distinct counter has
27 | * changed. After a state change, the probability of a next state change is usually smaller. The
28 | * positive decrement of this state change probability is passed as an argument.
29 | *
30 | * @param probabilityDecrement the positive probability decrement
31 | */
32 | void stateChanged(double probabilityDecrement);
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/distinctcount/package-info.java:
--------------------------------------------------------------------------------
1 | /** Algorithms and data structures for approximate distinct counting */
2 | package com.dynatrace.hash4j.distinctcount;
3 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/file/AbstractFileHasher128.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.file;
17 |
18 | import com.dynatrace.hash4j.hashing.HashValue128;
19 | import java.io.File;
20 | import java.io.IOException;
21 | import java.io.InputStream;
22 | import java.nio.file.Files;
23 | import java.nio.file.Path;
24 | import java.nio.file.StandardOpenOption;
25 |
26 | abstract class AbstractFileHasher128 implements FileHasher128 {
27 | @Override
28 | public HashValue128 hashFileTo128Bits(File file) throws IOException {
29 | return hashFileTo128Bits(file.toPath());
30 | }
31 |
32 | @Override
33 | public HashValue128 hashFileTo128Bits(Path path) throws IOException {
34 | try (InputStream fileContent = Files.newInputStream(path, StandardOpenOption.READ)) {
35 | return hashInputStreamTo128Bits(fileContent, Files.size(path));
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/file/FileHasher128.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.file;
17 |
18 | import com.dynatrace.hash4j.hashing.HashValue128;
19 | import java.io.File;
20 | import java.io.IOException;
21 | import java.io.InputStream;
22 | import java.nio.file.Path;
23 |
24 | /** A 128-bit hash function for files and input streams. */
25 | public interface FileHasher128 {
26 |
27 | /**
28 | * Calculates a 128-bit hash value for the given file.
29 | *
30 | * @param file a file
31 | * @return the hash value
32 | * @throws IOException if an I/O error occurs
33 | */
34 | HashValue128 hashFileTo128Bits(File file) throws IOException;
35 |
36 | /**
37 | * Calculates a 128-bit hash value for the given path.
38 | *
39 | * @param path a path
40 | * @return the hash value
41 | * @throws IOException if an I/O error occurs
42 | */
43 | HashValue128 hashFileTo128Bits(Path path) throws IOException;
44 |
45 | /**
46 | * Calculates a 128-bit hash value for a given number of bytes of the given input stream.
47 | *
48 | * @param inputStream the input stream
49 | * @param length the length of the input stream
50 | * @return the hash value
51 | * @throws IOException if an I/O error occurs
52 | */
53 | HashValue128 hashInputStreamTo128Bits(InputStream inputStream, long length) throws IOException;
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/file/FileHashing.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.file;
17 |
18 | /** Various implementations of hash functions for files. */
19 | public interface FileHashing {
20 |
21 | /**
22 | * Returns a {@link FileHasher128} implementing version 1.0.2 of the Imohash algorithm using
23 | * default parameters.
24 | *
25 | *
This implementation is compatible with the Go reference implementation imohash.go.
27 | *
28 | *
For a description of the algorithm see here.
30 | *
31 | *
This algorithm does not return a uniformly distributed hash value.
32 | *
33 | * @return a file hasher instance
34 | */
35 | static FileHasher128 imohash1_0_2() {
36 | return Imohash1_0_2.create();
37 | }
38 |
39 | /**
40 | * Returns a {@link FileHasher128} implementing version 1.0.2 of the Imohash algorithm using
41 | * default parameters.
42 | *
43 | *
This implementation is compatible with the Go reference implementation imohash.go.
45 | *
46 | *
For a description of the algorithm and the parameters see here.
48 | *
49 | *
This algorithm does not return a uniformly distributed hash value.
50 | *
51 | * @param sampleSize the sample size
52 | * @param sampleThreshold the sample threshold
53 | * @return a file hasher instance
54 | */
55 | static FileHasher128 imohash1_0_2(int sampleSize, long sampleThreshold) {
56 | return Imohash1_0_2.create(sampleSize, sampleThreshold);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/file/package-info.java:
--------------------------------------------------------------------------------
1 | /** Algorithms for file hashing */
2 | package com.dynatrace.hash4j.file;
3 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/hashing/AbstractHasher128.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.hashing;
17 |
18 | interface AbstractHasher128 extends AbstractHasher64, Hasher128 {
19 |
20 | @Override
21 | default HashValue128 hashTo128Bits(T data, HashFunnel funnel) {
22 | return hashStream().put(data, funnel).get();
23 | }
24 |
25 | @Override
26 | default HashValue128 hashBytesTo128Bits(byte[] input) {
27 | return hashBytesTo128Bits(input, 0, input.length);
28 | }
29 |
30 | @Override
31 | default long hashBytesToLong(byte[] input, int off, int len) {
32 | return hashBytesTo128Bits(input, off, len).getAsLong();
33 | }
34 |
35 | @Override
36 | default long hashCharsToLong(CharSequence input) {
37 | return hashCharsTo128Bits(input).getAsLong();
38 | }
39 |
40 | @Override
41 | default int getHashBitSize() {
42 | return 128;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/hashing/AbstractHasher32.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.hashing;
17 |
18 | interface AbstractHasher32 extends Hasher32, Hasher {
19 |
20 | @Override
21 | default int hashToInt(T data, HashFunnel funnel) {
22 | return hashStream().put(data, funnel).getAsInt();
23 | }
24 |
25 | @Override
26 | default int hashBytesToInt(byte[] input) {
27 | return hashBytesToInt(input, 0, input.length);
28 | }
29 |
30 | @Override
31 | default int getHashBitSize() {
32 | return 32;
33 | }
34 |
35 | @Override
36 | default int hashLongLongToInt(long v1, long v2) {
37 | return hashStream().putLong(v1).putLong(v2).getAsInt();
38 | }
39 |
40 | @Override
41 | default int hashLongLongLongToInt(long v1, long v2, long v3) {
42 | return hashStream().putLong(v1).putLong(v2).putLong(v3).getAsInt();
43 | }
44 |
45 | @Override
46 | default int hashLongIntToInt(long v1, int v2) {
47 | return hashStream().putLong(v1).putInt(v2).getAsInt();
48 | }
49 |
50 | @Override
51 | default int hashIntLongToInt(int v1, long v2) {
52 | return hashStream().putInt(v1).putLong(v2).getAsInt();
53 | }
54 |
55 | @Override
56 | default int hashIntIntIntToInt(int v1, int v2, int v3) {
57 | return hashStream().putInt(v1).putInt(v2).putInt(v3).getAsInt();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/hashing/Hasher.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.hashing;
17 |
18 | /**
19 | * A hash function.
20 | *
21 | * Instances are immutable. Therefore, it is safe to use a single instance across multiple
22 | * threads and for multiple hash calculations.
23 | */
24 | interface Hasher {
25 |
26 | /**
27 | * Starts a hash stream.
28 | *
29 | * @return a new {@link HashStream} instance
30 | */
31 | HashStream hashStream();
32 |
33 | /**
34 | * The size of the hash value in bits.
35 | *
36 | * @return the size of the hash value in bits
37 | */
38 | int getHashBitSize();
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/hashing/WyhashFinal3.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.hashing;
17 |
18 | class WyhashFinal3 extends AbstractWyhashFinal {
19 |
20 | private WyhashFinal3(long seedForHash, long[] secret) {
21 | super(seedForHash ^ secret[0], secret[1], secret[2], secret[3]);
22 | }
23 |
24 | @Override
25 | protected long finish(long a, long b, long seed, long len) {
26 | return wymix(secret1 ^ len, wymix(a ^ secret1, b ^ seed));
27 | }
28 |
29 | static Hasher64 create() {
30 | return DEFAULT_HASHER_INSTANCE;
31 | }
32 |
33 | static Hasher64 create(long seedForHash) {
34 | return new WyhashFinal3(seedForHash, DEFAULT_SECRET);
35 | }
36 |
37 | static Hasher64 create(long seedForHash, long seedForSecret) {
38 | return new WyhashFinal3(seedForHash, makeSecret(seedForSecret));
39 | }
40 |
41 | private static final Hasher64 DEFAULT_HASHER_INSTANCE = create(0L);
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/hashing/WyhashFinal4.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.hashing;
17 |
18 | import static com.dynatrace.hash4j.internal.UnsignedMultiplyUtil.unsignedMultiplyHigh;
19 |
20 | class WyhashFinal4 extends AbstractWyhashFinal {
21 |
22 | private final long secret0;
23 |
24 | private WyhashFinal4(long seedForHash, long[] secret) {
25 | super(seedForHash ^ wymix(seedForHash ^ secret[0], secret[1]), secret[1], secret[2], secret[3]);
26 | this.secret0 = secret[0];
27 | }
28 |
29 | static Hasher64 create() {
30 | return DEFAULT_HASHER_INSTANCE;
31 | }
32 |
33 | static Hasher64 create(long seedForHash) {
34 | return new WyhashFinal4(seedForHash, DEFAULT_SECRET);
35 | }
36 |
37 | static Hasher64 create(long seedForHash, long seedForSecret) {
38 | return new WyhashFinal4(seedForHash, makeSecret(seedForSecret));
39 | }
40 |
41 | private static final Hasher64 DEFAULT_HASHER_INSTANCE = create(0L);
42 |
43 | @Override
44 | protected long finish(long a, long b, long seed, long len) {
45 | a ^= secret1;
46 | b ^= seed;
47 | return wymix((a * b) ^ secret0 ^ len, unsignedMultiplyHigh(a, b) ^ secret1);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/hashing/package-info.java:
--------------------------------------------------------------------------------
1 | /** Hash algorithms */
2 | package com.dynatrace.hash4j.hashing;
3 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/internal/EmptyArray.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.internal;
17 |
18 | /** Utility class defining empty arrays. */
19 | public final class EmptyArray {
20 |
21 | private EmptyArray() {}
22 |
23 | /** An empty byte array. */
24 | public static byte[] EMPTY_BYTE_ARRAY = {};
25 |
26 | /** An empty short array. */
27 | public static short[] EMPTY_SHORT_ARRAY = {};
28 |
29 | /** An empty int array. */
30 | public static int[] EMPTY_INT_ARRAY = {};
31 |
32 | /** An empty long array. */
33 | public static long[] EMPTY_LONG_ARRAY = {};
34 |
35 | /** An empty boolean array. */
36 | public static boolean[] EMPTY_BOOLEAN_ARRAY = {};
37 |
38 | /** An empty float array. */
39 | public static float[] EMPTY_FLOAT_ARRAY = {};
40 |
41 | /** An empty double array. */
42 | public static double[] EMPTY_DOUBLE_ARRAY = {};
43 |
44 | /** An empty char array. */
45 | public static char[] EMPTY_CHAR_ARRAY = {};
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/internal/UnsignedMultiplyUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.internal;
17 |
18 | /** Utility class for the unsigned multiplication of {@code long} values. */
19 | public final class UnsignedMultiplyUtil {
20 |
21 | private UnsignedMultiplyUtil() {}
22 |
23 | /**
24 | * Returns the most significant 64 bits of the unsigned 128-bit product of two unsigned 64-bit
25 | * factors as a long.
26 | *
27 | * @param x the first value
28 | * @param y the second value
29 | * @return the result
30 | */
31 | public static long unsignedMultiplyHigh(long x, long y) {
32 | return Math.multiplyHigh(x, y) + ((x >> 63) & y) + ((y >> 63) & x);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/internal/package-info.java:
--------------------------------------------------------------------------------
1 | /** Helper classes. */
2 | package com.dynatrace.hash4j.internal;
3 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/random/AbstractPseudoRandomGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.random;
17 |
18 | abstract class AbstractPseudoRandomGenerator implements PseudoRandomGenerator {
19 |
20 | @Override
21 | public int nextInt() {
22 | return (int) nextLong();
23 | }
24 |
25 | // see algorithm 5 with L=32 in Lemire, Daniel. "Fast random integer generation in an interval."
26 | // ACM Transactions on Modeling and Computer Simulation (TOMACS) 29.1 (2019): 1-12.
27 | @Override
28 | public int uniformInt(int exclusiveUpperBound) {
29 | long s = exclusiveUpperBound;
30 | long x = nextInt() & 0xFFFFFFFFL;
31 | long m = x * s; // is always positive as 0 <= s < 2^31 and 0 <= x < 2^32 => 0 <= m < 2^63
32 | long l = m & 0xFFFFFFFFL;
33 | if (l < s) {
34 | long t = 0x100000000L % s;
35 | while (l < t) {
36 | x = nextInt() & 0xFFFFFFFFL;
37 | m = x * s; // is always positive as 0 <= s < 2^31 and 0 <= x < 2^32 => 0 <= m < 2^63
38 | l = m & 0xFFFFFFFFL;
39 | }
40 | }
41 | return (int) (m >>> 32);
42 | }
43 |
44 | @Override
45 | public double nextDouble() {
46 | return (nextLong() >>> 11) * 0x1.0p-53;
47 | }
48 |
49 | @Override
50 | public double nextExponential() {
51 | return RandomExponentialUtil.exponential(this);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/random/PseudoRandomGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.random;
17 |
18 | /** A pseudo-random generator. */
19 | public interface PseudoRandomGenerator {
20 |
21 | /**
22 | * Returns a random uniformly distributed 64-bit {@code long} value.
23 | *
24 | * @return a random value
25 | */
26 | long nextLong();
27 |
28 | /**
29 | * Returns a random uniformly distributed 32-bit {@code int} value.
30 | *
31 | * @return a random value
32 | */
33 | int nextInt();
34 |
35 | /**
36 | * Returns a random uniformly distributed 32-bit {code int} value greater than or equal to 0 and
37 | * less than the given upper bound.
38 | *
39 | *
The behavior is undefined, if the given upper bound is non-positive.
40 | *
41 | * @param exclusiveBound the (exclusive) upper bound (must be positve)
42 | * @return a random value
43 | */
44 | int uniformInt(int exclusiveBound);
45 |
46 | /**
47 | * Resets the pseudo-random generator using the given 64-bit seed value.
48 | *
49 | * @param seed the seed value
50 | * @return this
51 | */
52 | PseudoRandomGenerator reset(long seed);
53 |
54 | /**
55 | * Returns a random uniformly distributed {@code double} value in the range [0, 1).
56 | *
57 | * @return a random value
58 | */
59 | double nextDouble();
60 |
61 | /**
62 | * Returns an exponentially distributed {@code double} value with mean 1.
63 | *
64 | * @return a random value
65 | */
66 | double nextExponential();
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/random/PseudoRandomGeneratorProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.random;
17 |
18 | /** A provider for pseudo-random generators. */
19 | public interface PseudoRandomGeneratorProvider {
20 |
21 | /**
22 | * Creates a new {@link PseudoRandomGenerator} instance.
23 | *
24 | * @return the new pseudo-random generator instance
25 | */
26 | PseudoRandomGenerator create();
27 |
28 | /**
29 | * Creates a new {@link PseudoRandomGenerator} instance and sets a seed.
30 | *
31 | * @param seed the seed value
32 | * @return the new pseudo-random generator instance
33 | */
34 | default PseudoRandomGenerator create(long seed) {
35 | return create().reset(seed);
36 | }
37 |
38 | /**
39 | * Returns a {@link PseudoRandomGeneratorProvider} based on the SplitMix64 algorithm.
40 | *
41 | * @return a {@link PseudoRandomGeneratorProvider}
42 | */
43 | static PseudoRandomGeneratorProvider splitMix64_V1() {
44 | return SplitMix64V1::new;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/random/SplitMix64V1.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | /*
18 | * The implementation in this file is based on the implementation published
19 | * at https://prng.di.unimi.it/splitmix64.c under the following license:
20 | *
21 | * Written in 2015 by Sebastiano Vigna (vigna@acm.org)
22 | *
23 | * To the extent possible under law, the author has dedicated all copyright
24 | * and related and neighboring rights to this software to the public domain
25 | * worldwide. This software is distributed without any warranty.
26 | *
27 | * See .
28 | */
29 | package com.dynatrace.hash4j.random;
30 |
31 | final class SplitMix64V1 extends AbstractPseudoRandomGenerator {
32 |
33 | private long state;
34 |
35 | SplitMix64V1() {}
36 |
37 | @Override
38 | public long nextLong() {
39 | state += 0x9e3779b97f4a7c15L;
40 | long z = state;
41 | z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L;
42 | z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL;
43 | return z ^ (z >>> 31);
44 | }
45 |
46 | @Override
47 | public SplitMix64V1 reset(long seed) {
48 | this.state = seed;
49 | return this;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/random/package-info.java:
--------------------------------------------------------------------------------
1 | /** Algorithms for pseudo-random number generation */
2 | package com.dynatrace.hash4j.random;
3 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/similarity/FastSimHashVersion.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.similarity;
17 |
18 | import com.dynatrace.hash4j.random.PseudoRandomGeneratorProvider;
19 |
20 | /** Versions of FastSimHash implementations. */
21 | public enum FastSimHashVersion {
22 | /**
23 | * Default version.
24 | *
25 | *
Not stable! Use concrete version if compatibility is important, if for example hash
26 | * signatures are persisted.
27 | */
28 | DEFAULT {
29 | @Override
30 | SimilarityHashPolicy create(int numberOfComponents) {
31 | return new FastSimHashPolicy_v1(
32 | numberOfComponents, PseudoRandomGeneratorProvider.splitMix64_V1());
33 | }
34 | },
35 | /** Version 1. */
36 | V1 {
37 | @Override
38 | SimilarityHashPolicy create(int numberOfComponents) {
39 | return new FastSimHashPolicy_v1(
40 | numberOfComponents, PseudoRandomGeneratorProvider.splitMix64_V1());
41 | }
42 | };
43 |
44 | abstract SimilarityHashPolicy create(int numberOfComponents);
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/similarity/MinHashVersion.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.similarity;
17 |
18 | import com.dynatrace.hash4j.random.PseudoRandomGeneratorProvider;
19 |
20 | /** Versions of MinHash implementations. */
21 | public enum MinHashVersion {
22 | /**
23 | * Default version.
24 | *
25 | *
Not stable! Use concrete version if compatibility is important, if for example hash
26 | * signatures are persisted.
27 | */
28 | DEFAULT {
29 | @Override
30 | SimilarityHashPolicy create(int numberOfComponents, int bitsPerComponent) {
31 | return new MinHashPolicy_v1(
32 | numberOfComponents, bitsPerComponent, PseudoRandomGeneratorProvider.splitMix64_V1());
33 | }
34 | },
35 | /** Version 1. */
36 | V1 {
37 | @Override
38 | SimilarityHashPolicy create(int numberOfComponents, int bitsPerComponent) {
39 | return new MinHashPolicy_v1(
40 | numberOfComponents, bitsPerComponent, PseudoRandomGeneratorProvider.splitMix64_V1());
41 | }
42 | };
43 |
44 | abstract SimilarityHashPolicy create(int numberOfComponents, int bitsPerComponent);
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/similarity/SimHashVersion.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.similarity;
17 |
18 | import com.dynatrace.hash4j.random.PseudoRandomGeneratorProvider;
19 |
20 | /** Versions of FastSimHash implementations. */
21 | public enum SimHashVersion {
22 | /**
23 | * Default version.
24 | *
25 | *
Not stable! Use concrete version if compatibility is important, if for example hash
26 | * signatures are persisted.
27 | */
28 | DEFAULT {
29 | @Override
30 | SimilarityHashPolicy create(int numberOfComponents) {
31 | return new SimHashPolicy_v1(
32 | numberOfComponents, PseudoRandomGeneratorProvider.splitMix64_V1());
33 | }
34 | },
35 | /** Version 1. */
36 | V1 {
37 | @Override
38 | SimilarityHashPolicy create(int numberOfComponents) {
39 | return new SimHashPolicy_v1(
40 | numberOfComponents, PseudoRandomGeneratorProvider.splitMix64_V1());
41 | }
42 | };
43 |
44 | abstract SimilarityHashPolicy create(int numberOfComponents);
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/similarity/SimilarityHasher.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.similarity;
17 |
18 | /**
19 | * A hasher that is able to compute hash signatures which can be used for similarity estimations.
20 | */
21 | public interface SimilarityHasher {
22 |
23 | /**
24 | * Computes a hash signature for a given collection of 64-bit element hash values provided by the
25 | * given element hash provider.
26 | *
27 | * @param elementHashProvider the element hash provider
28 | * @return the hash signature
29 | */
30 | byte[] compute(ElementHashProvider elementHashProvider);
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/similarity/SuperMinHashVersion.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.similarity;
17 |
18 | import com.dynatrace.hash4j.random.PseudoRandomGeneratorProvider;
19 |
20 | /** Versions of SuperMinHash implementations. */
21 | public enum SuperMinHashVersion {
22 | /**
23 | * Default version.
24 | *
25 | *
Not stable! Use concrete version if compatibility is important, if for example hash
26 | * signatures are persisted.
27 | */
28 | DEFAULT {
29 | @Override
30 | SimilarityHashPolicy create(int numberOfComponents, int bitsPerComponent) {
31 | return new SuperMinHashPolicy_v1(
32 | numberOfComponents, bitsPerComponent, PseudoRandomGeneratorProvider.splitMix64_V1());
33 | }
34 | },
35 | /** Version 1. */
36 | V1 {
37 | @Override
38 | SimilarityHashPolicy create(int numberOfComponents, int bitsPerComponent) {
39 | return new SuperMinHashPolicy_v1(
40 | numberOfComponents, bitsPerComponent, PseudoRandomGeneratorProvider.splitMix64_V1());
41 | }
42 | };
43 |
44 | abstract SimilarityHashPolicy create(int numberOfComponents, int bitsPerComponent);
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/similarity/package-info.java:
--------------------------------------------------------------------------------
1 | /** Algorithms for similarity hashing */
2 | package com.dynatrace.hash4j.similarity;
3 |
--------------------------------------------------------------------------------
/src/main/java/com/dynatrace/hash4j/util/package-info.java:
--------------------------------------------------------------------------------
1 | /** Utilities */
2 | package com.dynatrace.hash4j.util;
3 |
--------------------------------------------------------------------------------
/src/main/java/module-info.java:
--------------------------------------------------------------------------------
1 | /** Hash4j */
2 | module hash4j {
3 | exports com.dynatrace.hash4j.consistent;
4 | exports com.dynatrace.hash4j.distinctcount;
5 | exports com.dynatrace.hash4j.file;
6 | exports com.dynatrace.hash4j.hashing;
7 | exports com.dynatrace.hash4j.random;
8 | exports com.dynatrace.hash4j.similarity;
9 | exports com.dynatrace.hash4j.util;
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java21/com/dynatrace/hash4j/internal/UnsignedMultiplyUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.internal;
17 |
18 | /** Utility class for the unsigned multiplication of {@code long} values. */
19 | public final class UnsignedMultiplyUtil {
20 |
21 | private UnsignedMultiplyUtil() {}
22 |
23 | /**
24 | * Returns the most significant 64 bits of the unsigned 128-bit product of two unsigned 64-bit
25 | * factors as a long.
26 | *
27 | * @param x the first value
28 | * @param y the second value
29 | * @return the result
30 | */
31 | public static long unsignedMultiplyHigh(long x, long y) {
32 | return Math.unsignedMultiplyHigh(x, y);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/consistent/ConsistentHashingUtilTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.consistent;
17 |
18 | import static com.dynatrace.hash4j.consistent.ConsistentHashingUtil.checkNumberOfBuckets;
19 | import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
20 | import static org.assertj.core.api.Assertions.assertThatNoException;
21 |
22 | import org.junit.jupiter.api.Test;
23 |
24 | class ConsistentHashingUtilTest {
25 |
26 | @Test
27 | void testCheckNumberOfBuckets() {
28 | assertThatIllegalArgumentException().isThrownBy(() -> checkNumberOfBuckets(0));
29 | assertThatIllegalArgumentException().isThrownBy(() -> checkNumberOfBuckets(-1));
30 | assertThatIllegalArgumentException().isThrownBy(() -> checkNumberOfBuckets(Integer.MIN_VALUE));
31 | assertThatNoException().isThrownBy(() -> checkNumberOfBuckets(1));
32 | assertThatNoException().isThrownBy(() -> checkNumberOfBuckets(2));
33 | assertThatNoException().isThrownBy(() -> checkNumberOfBuckets(Integer.MAX_VALUE));
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/consistent/ConsistentJumpBackBucketHasherTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023-2024 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.consistent;
17 |
18 | import com.dynatrace.hash4j.random.PseudoRandomGeneratorProvider;
19 |
20 | class ConsistentJumpBackBucketHasherTest extends AbstractConsistentBucketHasherTest {
21 |
22 | @Override
23 | protected ConsistentBucketHasher getConsistentBucketHasher(
24 | PseudoRandomGeneratorProvider pseudoRandomGeneratorProvider) {
25 | return ConsistentHashing.jumpBackHash(pseudoRandomGeneratorProvider);
26 | }
27 |
28 | @Override
29 | protected long getCheckSum() {
30 | return 0x23d7a0d288cd67e7L;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/consistent/ConsistentJumpBucketHasherTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.consistent;
17 |
18 | import static org.assertj.core.api.Assertions.*;
19 |
20 | import com.dynatrace.hash4j.random.PseudoRandomGeneratorProvider;
21 |
22 | class ConsistentJumpBucketHasherTest extends AbstractConsistentBucketHasherTest {
23 |
24 | @Override
25 | protected ConsistentBucketHasher getConsistentBucketHasher(
26 | PseudoRandomGeneratorProvider pseudoRandomGeneratorProvider) {
27 | return ConsistentHashing.jumpHash(pseudoRandomGeneratorProvider);
28 | }
29 |
30 | @Override
31 | protected long getCheckSum() {
32 | return 0xfd5390c955b998f7L;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/distinctcount/BigIntTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.distinctcount;
17 |
18 | import static org.assertj.core.api.Assertions.assertThat;
19 |
20 | import java.math.BigInteger;
21 | import org.junit.jupiter.api.Test;
22 |
23 | class BigIntTest {
24 |
25 | @Test
26 | void testBigIntFloor() {
27 | assertThat(BigInt.floor(1.2)).hasToString("1");
28 | assertThat(BigInt.floor(1e20)).hasToString("100000000000000000000");
29 | assertThat(BigInt.floor(1e30)).hasToString("1000000000000000019884624838656");
30 | }
31 |
32 | @Test
33 | void testBigIntCeil() {
34 | assertThat(BigInt.ceil(1.2)).hasToString("2");
35 | assertThat(BigInt.ceil(1e20)).hasToString("100000000000000000000");
36 | assertThat(BigInt.ceil(1e30)).hasToString("1000000000000000019884624838656");
37 | }
38 |
39 | @Test
40 | void testIncrement() {
41 | BigInt i = BigInt.ceil(1);
42 | i.increment();
43 | assertThat(i).hasToString("2");
44 | }
45 |
46 | @Test
47 | void testDecrement() {
48 | BigInt i = BigInt.ceil(Math.pow(2, 63));
49 | i.decrement();
50 | assertThat(i).hasToString(Long.toString(Long.MAX_VALUE));
51 | }
52 |
53 | @Test
54 | void testAdd() {
55 | BigInt i1 = BigInt.fromBigInt(new BigInteger("10000500000000005"));
56 | BigInt i2 = BigInt.fromBigInt(new BigInteger("10000900000000006"));
57 | i1.add(i2);
58 | assertThat(i1).hasToString("20001400000000011");
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/distinctcount/ConversionDemo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.distinctcount;
17 |
18 | import static org.assertj.core.api.Assertions.assertThat;
19 |
20 | import com.dynatrace.hash4j.hashing.Hasher64;
21 | import com.dynatrace.hash4j.hashing.Hashing;
22 | import org.junit.jupiter.api.Test;
23 |
24 | class ConversionDemo {
25 |
26 | @Test
27 | void demoUltraLogLogToHyperLogLogConversion() {
28 |
29 | Hasher64 hasher = Hashing.komihash5_0();
30 |
31 | HyperLogLog hllSketch = HyperLogLog.create(12);
32 | UltraLogLog ullSketch = UltraLogLog.create(12);
33 |
34 | hllSketch.add(hasher.hashCharsToLong("foo"));
35 | hllSketch.add(hasher.hashCharsToLong("bar"));
36 | hllSketch.add(hasher.hashCharsToLong("foo"));
37 |
38 | ullSketch.add(hasher.hashCharsToLong("foo"));
39 | ullSketch.add(hasher.hashCharsToLong("bar"));
40 | ullSketch.add(hasher.hashCharsToLong("foo"));
41 |
42 | HyperLogLog hllSketchConvertedFromUllSketch = HyperLogLog.create(ullSketch);
43 |
44 | assertThat(hllSketchConvertedFromUllSketch.getState()).isEqualTo(hllSketch.getState());
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/distinctcount/TestUtilsTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.distinctcount;
17 |
18 | import static org.assertj.core.api.Assertions.assertThat;
19 |
20 | import java.util.List;
21 | import java.util.stream.Collectors;
22 | import java.util.stream.IntStream;
23 | import org.junit.jupiter.api.Test;
24 |
25 | class TestUtilsTest {
26 |
27 | @Test
28 | void testGetDistinctCountValues() {
29 | List list = TestUtils.getDistinctCountValues(1e3, 0.5);
30 | List actual = list.stream().map(BigInt::toString).collect(Collectors.toList());
31 | List expected =
32 | IntStream.of(1, 2, 3, 4, 6, 8, 12, 18, 27, 40, 59, 88, 132, 198, 297, 445, 667, 1000)
33 | .mapToObj(Integer::toString)
34 | .collect(Collectors.toList());
35 | assertThat(actual).isEqualTo(expected);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/file/FileHashingDemo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023-2024 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.file;
17 |
18 | import static org.assertj.core.api.Assertions.assertThat;
19 |
20 | import com.dynatrace.hash4j.hashing.HashValue128;
21 | import java.io.File;
22 | import java.io.FileWriter;
23 | import java.io.IOException;
24 | import java.nio.charset.StandardCharsets;
25 | import java.nio.file.Path;
26 | import org.junit.jupiter.api.Test;
27 | import org.junit.jupiter.api.io.TempDir;
28 |
29 | class FileHashingDemo {
30 |
31 | @Test
32 | void demoImohash(@TempDir Path path) throws IOException {
33 |
34 | // create some file in the given path
35 | File file = path.resolve("test.txt").toFile();
36 | try (FileWriter fileWriter = new FileWriter(file, StandardCharsets.UTF_8)) {
37 | fileWriter.write("this is the file content");
38 | }
39 |
40 | // use ImoHash to hash that file
41 | HashValue128 hash = FileHashing.imohash1_0_2().hashFileTo128Bits(file);
42 | // returns 0xd317f2dad6ea7ae56ff7fdb517e33918
43 |
44 | assertThat(hash).hasToString("0xd317f2dad6ea7ae56ff7fdb517e33918");
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/hashing/AbstractHashStreamCompatibilityTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.hashing;
17 |
18 | import static org.assertj.core.api.Assertions.assertThat;
19 |
20 | import org.junit.jupiter.api.Test;
21 |
22 | class AbstractHashStreamCompatibilityTest {
23 |
24 | @Test
25 | void testHashCompatibility() {
26 |
27 | HashValue128 hash128 = new HashValue128(0x4cdfea92fccec3ffL, 0x85e6a3b83eb8873aL);
28 | AbstractHashStream128 calculator =
29 | new AbstractHashStream128() {
30 |
31 | @Override
32 | public HashStream128 putByte(byte v) {
33 | return this;
34 | }
35 |
36 | @Override
37 | public HashStream128 reset() {
38 | return this;
39 | }
40 |
41 | @Override
42 | public HashStream128 copy() {
43 | throw new UnsupportedOperationException();
44 | }
45 |
46 | @Override
47 | public Hasher128 getHasher() {
48 | throw new UnsupportedOperationException();
49 | }
50 |
51 | @Override
52 | public int getHashBitSize() {
53 | return 128;
54 | }
55 |
56 | @Override
57 | public HashValue128 get() {
58 | return hash128;
59 | }
60 | };
61 |
62 | assertThat(calculator.getAsInt()).isEqualTo(hash128.getAsInt());
63 | assertThat(calculator.getAsLong()).isEqualTo(hash128.getAsLong());
64 | assertThat(calculator.get()).isEqualTo(hash128);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/hashing/HashValuesTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.hashing;
17 |
18 | import static org.assertj.core.api.Assertions.assertThat;
19 |
20 | import org.junit.jupiter.api.Test;
21 |
22 | class HashValuesTest {
23 |
24 | @Test
25 | void testToHexStringAndToByteArray() {
26 |
27 | HashValue128 hashValue128 = new HashValue128(0xf0e1d2c3b4a59687L, 0x78695a4b3c2d1e0fL);
28 | long hashValue64 = 0x78695a4b3c2d1e0fL;
29 | int hashValue32 = 0x3c2d1e0f;
30 |
31 | assertThat(hashValue128.getAsLong()).isEqualTo(hashValue64);
32 | assertThat(hashValue128.getAsInt()).isEqualTo(hashValue32);
33 | assertThat((int) hashValue64).isEqualTo(hashValue32);
34 |
35 | assertThat(HashValues.toHexString(hashValue128)).isEqualTo("f0e1d2c3b4a5968778695a4b3c2d1e0f");
36 | assertThat(HashValues.toHexString(hashValue64)).isEqualTo("78695a4b3c2d1e0f");
37 | assertThat(HashValues.toHexString(hashValue32)).isEqualTo("3c2d1e0f");
38 |
39 | assertThat(Long.toHexString(hashValue64)).isEqualTo("78695a4b3c2d1e0f");
40 | assertThat(Long.toHexString(hashValue32)).isEqualTo("3c2d1e0f");
41 |
42 | assertThat(HashValues.toByteArray(hashValue128))
43 | .containsExactly(
44 | 0x0f, 0x1e, 0x2d, 0x3c, 0x4b, 0x5a, 0x69, 0x78, 0x87, 0x96, 0xa5, 0xb4, 0xc3, 0xd2,
45 | 0xe1, 0xf0);
46 | assertThat(HashValues.toByteArray(hashValue64))
47 | .containsExactly(0x0f, 0x1e, 0x2d, 0x3c, 0x4b, 0x5a, 0x69, 0x78);
48 | assertThat(HashValues.toByteArray(hashValue32)).containsExactly(0x0f, 0x1e, 0x2d, 0x3c);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/hashing/TestHashStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.hashing;
17 |
18 | import java.util.Arrays;
19 | import java.util.Objects;
20 |
21 | class TestHashStream implements AbstractHashStream {
22 | private int size = 0;
23 | private byte[] data = new byte[1];
24 |
25 | @Override
26 | public HashStream putByte(byte v) {
27 | if (size == data.length) {
28 | data = Arrays.copyOf(data, data.length * 2);
29 | }
30 | data[size] = v;
31 | size += 1;
32 | return this;
33 | }
34 |
35 | @Override
36 | public HashStream reset() {
37 | size = 0;
38 | return this;
39 | }
40 |
41 | @Override
42 | public TestHashStream copy() {
43 | final TestHashStream hashStream = new TestHashStream();
44 | hashStream.size = size;
45 | System.arraycopy(data, 0, hashStream.data, 0, data.length);
46 | return hashStream;
47 | }
48 |
49 | @Override
50 | public Hasher getHasher() {
51 | throw new UnsupportedOperationException();
52 | }
53 |
54 | @Override
55 | public int getHashBitSize() {
56 | throw new UnsupportedOperationException();
57 | }
58 |
59 | @Override
60 | public boolean equals(Object o) {
61 | if (this == o) return true;
62 | if (!(o instanceof TestHashStream)) return false;
63 | TestHashStream that = (TestHashStream) o;
64 | return size == that.size && Arrays.equals(data, that.data);
65 | }
66 |
67 | public byte[] getData() {
68 | return Arrays.copyOf(data, size);
69 | }
70 |
71 | @Override
72 | public int hashCode() {
73 | int result = Objects.hash(size);
74 | result = 31 * result + Arrays.hashCode(data);
75 | return result;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/internal/PreconditionsTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.internal;
17 |
18 | import static com.dynatrace.hash4j.internal.Preconditions.checkArgument;
19 | import static com.dynatrace.hash4j.internal.Preconditions.checkState;
20 | import static org.assertj.core.api.Assertions.*;
21 |
22 | import org.junit.jupiter.api.Test;
23 |
24 | class PreconditionsTest {
25 |
26 | @Test
27 | void testCheckArgument() {
28 | assertThatNoException().isThrownBy(() -> checkArgument(true));
29 | assertThatIllegalArgumentException().isThrownBy(() -> checkArgument(false));
30 | }
31 |
32 | @Test
33 | void testCheckArgumentWithErrorMessage() {
34 | String msg = "msg";
35 | assertThatNoException().isThrownBy(() -> checkArgument(true, msg));
36 | assertThatIllegalArgumentException()
37 | .isThrownBy(() -> checkArgument(false, msg))
38 | .withMessage(msg);
39 | }
40 |
41 | @Test
42 | void testCheckArgumentWithErrorMessageAndLongValue() {
43 | long value = 123;
44 | String msgPrefix = "abc";
45 | String msgPostfix = "xyz";
46 | String msgFormatString = msgPrefix + "%d" + msgPostfix;
47 | String expectedMsg = msgPrefix + value + msgPostfix;
48 | assertThatNoException().isThrownBy(() -> checkArgument(true, msgFormatString, value));
49 | assertThatIllegalArgumentException()
50 | .isThrownBy(() -> checkArgument(false, msgFormatString, value))
51 | .withMessage(expectedMsg);
52 | }
53 |
54 | @Test
55 | void testCheckState() {
56 | assertThatNoException().isThrownBy(() -> checkState(true));
57 | assertThatIllegalStateException().isThrownBy(() -> checkState(false));
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/internal/UnsignedMultiplyUtilTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.internal;
17 |
18 | import static org.assertj.core.api.Assertions.assertThat;
19 |
20 | import java.util.SplittableRandom;
21 | import org.junit.jupiter.api.Test;
22 |
23 | class UnsignedMultiplyUtilTest {
24 |
25 | @Test
26 | void testUnsignedMultiply() {
27 | SplittableRandom random = new SplittableRandom(0L);
28 | int n = 10000;
29 | long checkSum = 0;
30 | for (int i = 0; i < n; ++i) {
31 | checkSum += UnsignedMultiplyUtil.unsignedMultiplyHigh(random.nextLong(), random.nextLong());
32 | }
33 | assertThat(checkSum).isEqualTo(0xab0a08649b745db7L);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/random/AbstractPseudoRandomGeneratorProviderTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.random;
17 |
18 | import org.assertj.core.api.Assertions;
19 | import org.junit.jupiter.api.Test;
20 |
21 | public abstract class AbstractPseudoRandomGeneratorProviderTest {
22 |
23 | protected abstract PseudoRandomGeneratorProvider getPseudoRandomGeneratorProvider();
24 |
25 | @Test
26 | void testCreateWithSeed() {
27 | long seed = 0x668914708c9e7635L;
28 | Assertions.assertThat(getPseudoRandomGeneratorProvider().create(seed).nextLong())
29 | .isEqualTo(getPseudoRandomGeneratorProvider().create().reset(seed).nextLong());
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/random/SplitMix64_v1ProviderTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.random;
17 |
18 | public class SplitMix64_v1ProviderTest extends AbstractPseudoRandomGeneratorProviderTest {
19 | @Override
20 | protected PseudoRandomGeneratorProvider getPseudoRandomGeneratorProvider() {
21 | return PseudoRandomGeneratorProvider.splitMix64_V1();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/random/SplitMix64_v1Test.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.random;
17 |
18 | import static org.assertj.core.api.Assertions.assertThat;
19 |
20 | import java.util.SplittableRandom;
21 | import org.hipparchus.random.RandomGenerator;
22 | import org.hipparchus.random.Well1024a;
23 | import org.junit.jupiter.api.Test;
24 |
25 | class SplitMix64_v1Test extends AbstractPseudoRandomGeneratorTest {
26 |
27 | @Test
28 | void testConsistency() {
29 |
30 | RandomGenerator rng = new Well1024a(0x321f290dee3d921dL);
31 |
32 | int numIterations = 100;
33 | int numValuesPerIterations = 10;
34 |
35 | for (int i = 0; i < numIterations; ++i) {
36 | long seed = rng.nextLong();
37 |
38 | SplittableRandom splittableRandom = new SplittableRandom(seed);
39 | PseudoRandomGenerator pseudoRandomGenerator = createPseudoRandomGenerator();
40 | pseudoRandomGenerator.reset(seed);
41 |
42 | for (int j = 0; j < numValuesPerIterations; ++j) {
43 | long actual = pseudoRandomGenerator.nextLong();
44 | long expected = splittableRandom.nextLong();
45 | assertThat(actual).isEqualTo(expected);
46 | }
47 | }
48 | }
49 |
50 | @Override
51 | protected PseudoRandomGenerator createPseudoRandomGenerator() {
52 | return new SplitMix64V1();
53 | }
54 |
55 | @Override
56 | protected long getExpectedStabilityCheckSum() {
57 | return 0x8d81600546698168L;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/similarity/AbstractMinHashPolicyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.similarity;
17 |
18 | import static org.assertj.core.api.Assertions.assertThat;
19 | import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
20 |
21 | import org.junit.jupiter.api.Test;
22 |
23 | abstract class AbstractMinHashPolicyTest extends AbstractSimilarityHasherPolicyTest {
24 |
25 | @Override
26 | protected final SimilarityHashPolicy getSimilarityHashPolicy(int numberOfComponents) {
27 | return getSimilarityHashPolicy(numberOfComponents, 1);
28 | }
29 |
30 | protected abstract SimilarityHashPolicy getSimilarityHashPolicy(
31 | int numberOfComponents, int bitsPerComponent);
32 |
33 | @Test
34 | void testInvalidBitsPerComponent() {
35 | assertThatIllegalArgumentException().isThrownBy(() -> getSimilarityHashPolicy(5, -1));
36 | assertThatIllegalArgumentException().isThrownBy(() -> getSimilarityHashPolicy(5, 0));
37 | assertThatIllegalArgumentException().isThrownBy(() -> getSimilarityHashPolicy(5, 65));
38 | }
39 |
40 | @Test
41 | void testGetComponentSizeInBits() {
42 | for (int bitsPerComponent = 1; bitsPerComponent <= 64; ++bitsPerComponent) {
43 | SimilarityHashPolicy policy = getSimilarityHashPolicy(3, bitsPerComponent);
44 | assertThat(policy.getComponentSizeInBits()).isEqualTo(bitsPerComponent);
45 | }
46 | }
47 |
48 | @Override
49 | protected double calculateExpectedMatchProbability(
50 | long intersectionSize, long difference1Size, long difference2Size) {
51 | long unionSize = intersectionSize + difference1Size + difference2Size;
52 | double expectedJaccardSimilarity = intersectionSize / (double) unionSize;
53 | return (1. + expectedJaccardSimilarity) * 0.5;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/similarity/ElementHashProviderTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022-2023 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.similarity;
17 |
18 | import static org.assertj.core.api.Assertions.*;
19 |
20 | import java.util.Collections;
21 | import org.junit.jupiter.api.Test;
22 |
23 | class ElementHashProviderTest {
24 |
25 | @Test
26 | void testNullArray() {
27 | assertThatNullPointerException().isThrownBy(() -> ElementHashProvider.ofValues(null));
28 | }
29 |
30 | @Test
31 | void testEmpty() {
32 | assertThatIllegalArgumentException().isThrownBy(() -> ElementHashProvider.ofValues());
33 | assertThatIllegalArgumentException()
34 | .isThrownBy(() -> ElementHashProvider.ofCollection(Collections.emptySet(), x -> 0));
35 | }
36 |
37 | @Test
38 | void testNullFunction() {
39 | assertThatNullPointerException().isThrownBy(() -> ElementHashProvider.ofFunction(null, 5));
40 | assertThatNullPointerException()
41 | .isThrownBy(() -> ElementHashProvider.ofCollection(null, x -> 0));
42 | assertThatNullPointerException()
43 | .isThrownBy(() -> ElementHashProvider.ofCollection(Collections.emptySet(), null));
44 | }
45 |
46 | @Test
47 | void testFunctionWithInvalidNumberOfElements() {
48 | assertThatIllegalArgumentException()
49 | .isThrownBy(() -> ElementHashProvider.ofFunction(i -> i, 0));
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/similarity/MinHashVersionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.similarity;
17 |
18 | import static org.assertj.core.api.Assertions.assertThat;
19 |
20 | import org.junit.jupiter.api.Test;
21 |
22 | class MinHashVersionTest {
23 |
24 | @Test
25 | void testConstants() {
26 | assertThat(MinHashVersion.DEFAULT.create(3, 5)).isInstanceOf(MinHashPolicy_v1.class);
27 | assertThat(MinHashVersion.V1.create(3, 5)).isInstanceOf(MinHashPolicy_v1.class);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/similarity/SuperMinHashPolicy_v1aTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.similarity;
17 |
18 | import com.dynatrace.hash4j.random.PseudoRandomGeneratorProvider;
19 |
20 | public class SuperMinHashPolicy_v1aTest extends AbstractSuperMinHashPolicyTest {
21 |
22 | @Override
23 | protected SimilarityHashPolicy getSimilarityHashPolicy(
24 | int numberOfComponents, int bitsPerComponent) {
25 | return new SuperMinHashPolicy_v1a(
26 | numberOfComponents, bitsPerComponent, PseudoRandomGeneratorProvider.splitMix64_V1());
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/similarity/SuperMinHashPolicy_v1bTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.similarity;
17 |
18 | import static org.assertj.core.api.Assertions.assertThat;
19 |
20 | import com.dynatrace.hash4j.random.PseudoRandomGeneratorProvider;
21 | import org.junit.jupiter.api.Test;
22 |
23 | class SuperMinHashPolicy_v1bTest extends AbstractSuperMinHashPolicyTest {
24 |
25 | @Override
26 | protected SimilarityHashPolicy getSimilarityHashPolicy(
27 | int numberOfComponents, int bitsPerComponent) {
28 | return new SuperMinHashPolicy_v1b(
29 | numberOfComponents, bitsPerComponent, PseudoRandomGeneratorProvider.splitMix64_V1());
30 | }
31 |
32 | @Test
33 | void testCycleLimitEstimation() {
34 |
35 | int numberOfComponents = 10;
36 | SuperMinHashPolicy_v1b policy =
37 | new SuperMinHashPolicy_v1b(
38 | numberOfComponents, 3, PseudoRandomGeneratorProvider.splitMix64_V1());
39 | assertThat(policy.estimateCycleLimit(1)).isEqualTo(10);
40 | assertThat(policy.estimateCycleLimit(2)).isEqualTo(10);
41 | assertThat(policy.estimateCycleLimit(3)).isEqualTo(9);
42 | assertThat(policy.estimateCycleLimit(4)).isEqualTo(9);
43 | assertThat(policy.estimateCycleLimit(5)).isEqualTo(8);
44 | assertThat(policy.estimateCycleLimit(1000)).isEqualTo(1);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/test/java/com/dynatrace/hash4j/similarity/SuperMinHashVersionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.similarity;
17 |
18 | import static org.assertj.core.api.Assertions.assertThat;
19 |
20 | import org.junit.jupiter.api.Test;
21 |
22 | class SuperMinHashVersionTest {
23 |
24 | @Test
25 | void testConstants() {
26 | assertThat(SuperMinHashVersion.DEFAULT.create(3, 5)).isInstanceOf(SuperMinHashPolicy_v1.class);
27 | assertThat(SuperMinHashVersion.V1.create(3, 5)).isInstanceOf(SuperMinHashPolicy_v1.class);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/test/java21/com/dynatrace/hash4j/internal/UnsignedMultiplyUtilReferenceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2025 Dynatrace LLC
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.dynatrace.hash4j.internal;
17 |
18 | import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
19 |
20 | import java.util.SplittableRandom;
21 | import org.junit.jupiter.api.Test;
22 |
23 | public class UnsignedMultiplyUtilReferenceTest {
24 |
25 | @Test
26 | public void testAgainstJava() {
27 |
28 | SplittableRandom random = new SplittableRandom(0x75ec0a7f2d98ba4fL);
29 | int numIterations = 50;
30 | for (int i = 0; i < numIterations; ++i) {
31 | long a = random.nextLong();
32 | long b = random.nextLong();
33 | assertThat(UnsignedMultiplyUtil.unsignedMultiplyHigh(a, b))
34 | .isEqualTo(Math.unsignedMultiplyHigh(a, b));
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/test/resources/junit-platform.properties:
--------------------------------------------------------------------------------
1 | junit.jupiter.execution.parallel.enabled = true
2 | junit.jupiter.execution.parallel.mode.default = concurrent
--------------------------------------------------------------------------------
/test-results/hyperloglog-estimation-error-p03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/hyperloglog-estimation-error-p03.png
--------------------------------------------------------------------------------
/test-results/hyperloglog-estimation-error-p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/hyperloglog-estimation-error-p04.png
--------------------------------------------------------------------------------
/test-results/hyperloglog-estimation-error-p05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/hyperloglog-estimation-error-p05.png
--------------------------------------------------------------------------------
/test-results/hyperloglog-estimation-error-p06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/hyperloglog-estimation-error-p06.png
--------------------------------------------------------------------------------
/test-results/hyperloglog-estimation-error-p07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/hyperloglog-estimation-error-p07.png
--------------------------------------------------------------------------------
/test-results/hyperloglog-estimation-error-p08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/hyperloglog-estimation-error-p08.png
--------------------------------------------------------------------------------
/test-results/hyperloglog-estimation-error-p09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/hyperloglog-estimation-error-p09.png
--------------------------------------------------------------------------------
/test-results/hyperloglog-estimation-error-p10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/hyperloglog-estimation-error-p10.png
--------------------------------------------------------------------------------
/test-results/hyperloglog-estimation-error-p11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/hyperloglog-estimation-error-p11.png
--------------------------------------------------------------------------------
/test-results/hyperloglog-estimation-error-p12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/hyperloglog-estimation-error-p12.png
--------------------------------------------------------------------------------
/test-results/hyperloglog-estimation-error-p13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/hyperloglog-estimation-error-p13.png
--------------------------------------------------------------------------------
/test-results/hyperloglog-estimation-error-p14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/hyperloglog-estimation-error-p14.png
--------------------------------------------------------------------------------
/test-results/hyperloglog-estimation-error-p15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/hyperloglog-estimation-error-p15.png
--------------------------------------------------------------------------------
/test-results/hyperloglog-estimation-error-p16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/hyperloglog-estimation-error-p16.png
--------------------------------------------------------------------------------
/test-results/ultraloglog-estimation-error-p03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/ultraloglog-estimation-error-p03.png
--------------------------------------------------------------------------------
/test-results/ultraloglog-estimation-error-p04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/ultraloglog-estimation-error-p04.png
--------------------------------------------------------------------------------
/test-results/ultraloglog-estimation-error-p05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/ultraloglog-estimation-error-p05.png
--------------------------------------------------------------------------------
/test-results/ultraloglog-estimation-error-p06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/ultraloglog-estimation-error-p06.png
--------------------------------------------------------------------------------
/test-results/ultraloglog-estimation-error-p07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/ultraloglog-estimation-error-p07.png
--------------------------------------------------------------------------------
/test-results/ultraloglog-estimation-error-p08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/ultraloglog-estimation-error-p08.png
--------------------------------------------------------------------------------
/test-results/ultraloglog-estimation-error-p09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/ultraloglog-estimation-error-p09.png
--------------------------------------------------------------------------------
/test-results/ultraloglog-estimation-error-p10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/ultraloglog-estimation-error-p10.png
--------------------------------------------------------------------------------
/test-results/ultraloglog-estimation-error-p11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/ultraloglog-estimation-error-p11.png
--------------------------------------------------------------------------------
/test-results/ultraloglog-estimation-error-p12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/ultraloglog-estimation-error-p12.png
--------------------------------------------------------------------------------
/test-results/ultraloglog-estimation-error-p13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/ultraloglog-estimation-error-p13.png
--------------------------------------------------------------------------------
/test-results/ultraloglog-estimation-error-p14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/ultraloglog-estimation-error-p14.png
--------------------------------------------------------------------------------
/test-results/ultraloglog-estimation-error-p15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/ultraloglog-estimation-error-p15.png
--------------------------------------------------------------------------------
/test-results/ultraloglog-estimation-error-p16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dynatrace-oss/hash4j/b16da7afce68fcd629a634975338c65f893db34e/test-results/ultraloglog-estimation-error-p16.png
--------------------------------------------------------------------------------