diff --git a/platform/util/src/com/intellij/util/keyFMap/DebugFMap.java b/platform/util/src/com/intellij/util/keyFMap/DebugFMap.java new file mode 100644 index 000000000000..a56c414d20a6 --- /dev/null +++ b/platform/util/src/com/intellij/util/keyFMap/DebugFMap.java @@ -0,0 +1,63 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.util.keyFMap; + +import com.intellij.openapi.util.Key; +import com.intellij.util.containers.UnmodifiableHashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class DebugFMap implements KeyFMap { + private final UnmodifiableHashMap, Object> myMap; + + DebugFMap(@NotNull UnmodifiableHashMap, Object> map) { + myMap = map; + } + + @Override + public @NotNull KeyFMap plus(@NotNull Key key, @NotNull V value) { + UnmodifiableHashMap, Object> newMap = myMap.with(key, value); + return newMap == myMap ? this : new DebugFMap(newMap); + } + + @Override + public @NotNull KeyFMap minus(@NotNull Key key) { + UnmodifiableHashMap, Object> newMap = myMap.without(key); + return newMap == myMap ? this : new DebugFMap(newMap); + } + + @Override + public @Nullable V get(@NotNull Key key) { + @SuppressWarnings("unchecked") V value = (V)myMap.get(key); + return value; + } + + @Override + public int size() { + return myMap.size(); + } + + @Override + public Key @NotNull [] getKeys() { + return myMap.keySet().toArray(new Key[0]); + } + + @Override + public boolean isEmpty() { + return myMap.isEmpty(); + } + + @Override + public int getValueIdentityHashCode() { + final int[] hash = {0}; + myMap.forEach((key, value) -> { + hash[0] = (hash[0] * 31 + key.hashCode()) * 31 + System.identityHashCode(value); + }); + return hash[0]; + } + + @Override + public boolean equalsByReference(KeyFMap other) { + if (this.size() != other.size()) return false; + return myMap.entrySet().stream().noneMatch(entry -> entry.getValue() != other.get(entry.getKey())); + } +} diff --git a/platform/util/src/com/intellij/util/keyFMap/EmptyFMap.java b/platform/util/src/com/intellij/util/keyFMap/EmptyFMap.java index d31661b27873..f8de371ec660 100644 --- a/platform/util/src/com/intellij/util/keyFMap/EmptyFMap.java +++ b/platform/util/src/com/intellij/util/keyFMap/EmptyFMap.java @@ -16,9 +16,11 @@ package com.intellij.util.keyFMap; import com.intellij.openapi.util.Key; +import com.intellij.util.containers.UnmodifiableHashMap; import org.jetbrains.annotations.NotNull; class EmptyFMap implements KeyFMap { + private static final boolean DEBUG_FMAP = Boolean.getBoolean("idea.keyfmap.debug.implementation"); private static final Key[] EMPTY_KEYS_ARRAY = {}; EmptyFMap() { @@ -75,4 +77,8 @@ class EmptyFMap implements KeyFMap { public int hashCode() { return 0; } + + static KeyFMap create() { + return DEBUG_FMAP ? new DebugFMap(UnmodifiableHashMap.empty()) : new EmptyFMap(); + } } diff --git a/platform/util/src/com/intellij/util/keyFMap/KeyFMap.java b/platform/util/src/com/intellij/util/keyFMap/KeyFMap.java index fe752dae9d3f..24b10a89805e 100644 --- a/platform/util/src/com/intellij/util/keyFMap/KeyFMap.java +++ b/platform/util/src/com/intellij/util/keyFMap/KeyFMap.java @@ -22,7 +22,7 @@ public interface KeyFMap { /** * An empty {@code KeyFMap}. No additional instances of empty {@code KeyFMap} should be created as they are indistinguishable. */ - KeyFMap EMPTY_MAP = new EmptyFMap(); + KeyFMap EMPTY_MAP = EmptyFMap.create(); /** * Returns a {@code KeyFMap} which consists of the same elements as this {@code KeyFMap}, but