From 16920f7f48294b8aac2ee603cd5d9158be5e85c6 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Thu, 11 Sep 2025 17:24:20 +0200 Subject: [PATCH] [util] UnmodifiableHashMap.entrySet.contains; withAll optimization GitOrigin-RevId: e77dff68010e3cd402ddce63ba2b8701a0627a20 --- .../util/containers/UnmodifiableHashMap.java | 49 ++++++++++++++----- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/platform/util/src/com/intellij/util/containers/UnmodifiableHashMap.java b/platform/util/src/com/intellij/util/containers/UnmodifiableHashMap.java index a582b681144a..e927608a80e9 100644 --- a/platform/util/src/com/intellij/util/containers/UnmodifiableHashMap.java +++ b/platform/util/src/com/intellij/util/containers/UnmodifiableHashMap.java @@ -249,6 +249,7 @@ public final @Unmodifiable class UnmodifiableHashMap implements Map<@NotNu * of the resulting map is the same as the strategy of this map. */ public @NotNull UnmodifiableHashMap withAll(@NotNull Map map) { + if (map == this) return this; if (isEmpty()) { return fromMap(strategy, map); } @@ -261,20 +262,31 @@ public final @Unmodifiable class UnmodifiableHashMap implements Map<@NotNu Entry entry = map.entrySet().iterator().next(); return with(entry.getKey(), entry.getValue()); } + Iterator> iterator = map.entrySet().iterator(); + Set> myEntries = entrySet(); + while (iterator.hasNext()) { + Entry entry = iterator.next(); + if (!myEntries.contains(entry)) { + Map newMap; + if (strategy == HashingStrategy.canonical()) { + //noinspection SSBasedInspection + newMap = new Object2ObjectOpenHashMap<>(mapSize + size); + } + else { + // Could be optimized further for map.size() == 2 or 3. + newMap = new Object2ObjectOpenCustomHashMap<>(mapSize + size, getFastutilHashingStrategy(strategy)); + } - Map newMap; - if (strategy == HashingStrategy.canonical()) { - //noinspection SSBasedInspection - newMap = new Object2ObjectOpenHashMap<>(mapSize + size); + newMap.putAll(this); + newMap.put(entry.getKey(), entry.getValue()); + while (iterator.hasNext()) { + entry = iterator.next(); + newMap.put(entry.getKey(), entry.getValue()); + } + return fromMap(strategy, newMap); + } } - else { - // Could be optimized further for map.size() == 2 or 3. - newMap = new Object2ObjectOpenCustomHashMap<>(mapSize + size, getFastutilHashingStrategy(strategy)); - } - - newMap.putAll(this); - newMap.putAll(map); - return fromMap(strategy, newMap); + return this; } private static @NotNull Hash.Strategy getFastutilHashingStrategy(@NotNull HashingStrategy strategy) { @@ -668,6 +680,19 @@ public final @Unmodifiable class UnmodifiableHashMap implements Map<@NotNu @Override public @NotNull Set> entrySet() { return new AbstractSet>() { + @Override + public boolean contains(Object o) { + if (!(o instanceof Entry)) return false; + Entry entry = (Entry)o; + Object key = entry.getKey(); + if (key == null) return false; + V value = get(key); + if (value == null) { + return entry.getValue() == null && containsKey(key); + } + return value.equals(entry.getValue()); + } + @Override public @NotNull Iterator> iterator() { return new MyIterator>() {