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

Add ofEntries static method to Map interfaces #330

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
35 changes: 35 additions & 0 deletions drv/Map.drv
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,41 @@ public interface MAP KEY_VALUE_GENERIC extends FUNCTION KEY_VALUE_GENERIC, Map<K

#endif

/** Returns an unmodifiable, type-specific map with the specified entries.
* See {@link java.util.Map#ofEntries(Map.Entry[])} */
#if !KEYS_PRIMITIVE || !VALUES_PRIMITIVE
@SafeVarargs
@SuppressWarnings({"varargs", "unchecked"})
#else
@SuppressWarnings("varargs")
#endif
static KEY_VALUE_GENERIC MAP KEY_VALUE_GENERIC ofEntries(MAP.Entry KEY_VALUE_GENERIC ... entries) {
if (entries.length == 0) return MAPS.EMPTY_MAP;
if (entries.length == 1) return MAPS.singleton(entries[0].ENTRY_GET_KEY(), entries[0].ENTRY_GET_VALUE());

KEY_GENERIC_TYPE[] keys = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[entries.length];
VALUE_GENERIC_TYPE[] vals = VALUE_GENERIC_ARRAY_CAST new VALUE_TYPE[entries.length];

for (int i = 0; i < entries.length; ++i) {
MAP.Entry KEY_VALUE_GENERIC entry = entries[i];
keys[i] = entry.ENTRY_GET_KEY();
// Prevent duplicate keys
for (int j = 0; j < i; ++j) if (KEY_EQUALS(keys[j], keys[i])) throw new IllegalArgumentException("duplicate key: " + keys[i]);
vals[i] = entry.ENTRY_GET_VALUE();
}
if (entries.length <= 8) {
return MAPS.unmodifiable(new ARRAY_MAP KEY_VALUE_GENERIC_DIAMOND(keys, vals, entries.length));
} else {
return MAPS.unmodifiable(new OPEN_HASH_MAP KEY_VALUE_GENERIC_DIAMOND(keys, vals, 0.75f));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this creates the keys / values array unnecessarily. I think the code should be like

if (number of entries is small)
  create keys and vals as above (with duplicate checking)
  return array map with keys and vales
else
  create appropriately sized hash map
  for each entry:
    if map.put(entry.key, entry.value) != null then throw exception
  return hash map

}
}

/** Returns an unmodifiable, type-specific entry.
* See {@link java.util.Map#entry(Object, Object)} */
static KEY_VALUE_GENERIC Entry KEY_VALUE_GENERIC entry(KEY_GENERIC_TYPE key, VALUE_GENERIC_TYPE value) {
return new ABSTRACT_MAP.BasicEntry KEY_VALUE_GENERIC_DIAMOND(key, value);
}

/** A type-specific {@link java.util.Map.Entry}; provides some additional methods
* that use polymorphism to avoid (un)boxing.
*
Expand Down
27 changes: 27 additions & 0 deletions test/it/unimi/dsi/fastutil/objects/Object2ObjectMapTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package it.unimi.dsi.fastutil.objects;

import org.junit.Test;

import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;

public class Object2ObjectMapTest {

@Test
public void testSmallMaps() {
assertTrue(Object2ObjectMap.ofEntries() instanceof Object2ObjectMaps.EmptyMap);
assertTrue(Object2ObjectMap.ofEntries(Object2ObjectMap.entry(new Object(), new Object())) instanceof Object2ObjectMaps.Singleton);
}

@Test
public void testThrowOnDuplicate() {
assertThrows(IllegalArgumentException.class, () -> Object2ObjectMap.ofEntries(
Object2ObjectMap.entry("dupe", "foo"),
Object2ObjectMap.entry("not a dupe", "bar"),
Object2ObjectMap.entry("dupe", "exception")
)
);
}


}