Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenHashMaps.mergePRIMITIVE: Avoid double-hashing key #337

Merged
merged 2 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions drv/OpenHashMap.drv
Original file line number Diff line number Diff line change
Expand Up @@ -1253,6 +1253,25 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
return value[pos] = newVal;
}

#if VALUES_PRIMITIVE && ! VALUE_CLASS_Boolean
/** {@inheritDoc} */
@Override
public VALUE_GENERIC_TYPE MERGE_VALUE(final KEY_GENERIC_TYPE k, final VALUE_GENERIC_TYPE v, METHOD_ARG_VALUE_BINARY_OPERATOR remappingFunction) {
java.util.Objects.requireNonNull(remappingFunction);
REQUIRE_VALUE_NON_NULL(v)

final int pos = find(k);
if (pos < 0) {
insert(-pos - 1, k, v);
return v;
}

final VALUE_GENERIC_TYPE newValue = remappingFunction.VALUE_OPERATOR_APPLY(value[pos], v);

return value[pos] = newValue;
}
#endif

/** {@inheritDoc} */
@Override
public VALUE_GENERIC_TYPE merge(final KEY_GENERIC_TYPE k, final VALUE_GENERIC_TYPE v, final java.util.function.BiFunction<? super VALUE_GENERIC_CLASS, ? super VALUE_GENERIC_CLASS, ? extends VALUE_GENERIC_CLASS> remappingFunction) {
Expand Down
20 changes: 20 additions & 0 deletions test/it/unimi/dsi/fastutil/objects/Object2IntOpenHashMapTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package it.unimi.dsi.fastutil.objects;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

Expand Down Expand Up @@ -215,5 +216,24 @@ public void test1000() throws IOException, ClassNotFoundException {
public void testLegacyMainMethodTests() throws Exception {
MainRunner.callMainIfExists(Object2IntOpenHashMap.class, "test", /*num=*/"500", /*loadFactor=*/"0.75", /*seed=*/"383454");
}

/** Counts times hashCode() is called, so we can test double-hashing. */
private static final class HashCounter {
int hashCount = 0;
@Override
public int hashCode() {
hashCount++;
return super.hashCode();
}
}

// Regression test for https://github.com/vigna/fastutil/pull/337.
@Test
public void testMergeIntHashesKeyOnce() {
Object2IntOpenHashMap m = new Object2IntOpenHashMap(Hash.DEFAULT_INITIAL_SIZE);
HashCounter hc = new HashCounter();
m.mergeInt(hc, 0, Math::max);
assertEquals(1, hc.hashCount);
}
}