Skip to content

Commit

Permalink
Merge pull request #337 from mhansen/mergeDouble
Browse files Browse the repository at this point in the history
OpenHashMaps.mergePRIMITIVE: Avoid double-hashing key
  • Loading branch information
vigna authored Nov 26, 2024
2 parents 355d8eb + 87bb74c commit fcac58f
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 0 deletions.
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);
}
}

0 comments on commit fcac58f

Please sign in to comment.