diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfoUpdater.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfoUpdater.java index 4626a2ca0ddd..256cc492a47d 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfoUpdater.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfoUpdater.java @@ -56,7 +56,7 @@ final class HighlightInfoUpdater implements Disposable { } static class ToolHighlights { - final Map> elementHighlights = CollectionFactory.createConcurrentSoftMap(evicted -> removeEvicted(evicted)); + final Map> elementHighlights = CollectionFactory.createConcurrentSoftMap((m,evicted) -> removeEvicted(evicted)); @NotNull ToolLatencies latencies = new ToolLatencies(0,0,0); } @@ -117,7 +117,7 @@ final class HighlightInfoUpdater implements Disposable { private static @NotNull Map> getOrCreateHostMap(@NotNull Document hostDocument) { Map> map = hostDocument.getUserData(VISITED_PSI_ELEMENTS); if (map == null) { - map = ((UserDataHolderEx)hostDocument).putUserDataIfAbsent(VISITED_PSI_ELEMENTS, CollectionFactory.createConcurrentSoftMap(oldMap -> removeEvictedFile(oldMap))); + map = ((UserDataHolderEx)hostDocument).putUserDataIfAbsent(VISITED_PSI_ELEMENTS, CollectionFactory.createConcurrentSoftMap((m,oldMap) -> removeEvictedFile(oldMap))); } return map; } diff --git a/platform/platform-tests/testSrc/com/intellij/util/containers/ContainerUtilCollectionsTest.java b/platform/platform-tests/testSrc/com/intellij/util/containers/ContainerUtilCollectionsTest.java index 50209a289207..192de9f988e9 100644 --- a/platform/platform-tests/testSrc/com/intellij/util/containers/ContainerUtilCollectionsTest.java +++ b/platform/platform-tests/testSrc/com/intellij/util/containers/ContainerUtilCollectionsTest.java @@ -865,28 +865,32 @@ public class ContainerUtilCollectionsTest extends Assert { @Test public void testKeyEvictionListenerWorks() { AtomicReference evicted = new AtomicReference<>(); - Map map = CollectionFactory.createConcurrentSoftMap(value -> { + AtomicReference> map = new AtomicReference<>(); + map.set(CollectionFactory.createConcurrentSoftMap((thisMap,value) -> { assertTrue(evicted.compareAndSet(null, value)); - }); + assertSame(map.get(), thisMap); + })); Object value = new Object(); - map.put(new Object(), value); + map.get().put(new Object(), value); - GCUtil.tryGcSoftlyReachableObjects(() -> map.remove("") != null/*to call processQueue()*/ || map.isEmpty()); - map.remove(""); // to call processQueue() + GCUtil.tryGcSoftlyReachableObjects(() -> map.get().remove("") != null/*to call processQueue()*/ || map.get().isEmpty()); + map.get().remove(""); // to call processQueue() assertSame(value, evicted.get()); } @Test public void testValueEvictionListenerWorks() { AtomicReference evicted = new AtomicReference<>(); - Map map = CollectionFactory.createConcurrentSoftValueMap(key -> { + AtomicReference> map = new AtomicReference<>(); + map.set(CollectionFactory.createConcurrentSoftValueMap((thisMap,key) -> { assertTrue(evicted.compareAndSet(null, key)); - }); + assertSame(map.get(), thisMap); + })); Object key = new Object(); - map.put(key, new Object()); + map.get().put(key, new Object()); - GCUtil.tryGcSoftlyReachableObjects(() -> map.remove("") != null/*to call processQueue()*/ || map.isEmpty()); - map.remove(""); // to call processQueue() + GCUtil.tryGcSoftlyReachableObjects(() -> map.get().remove("") != null/*to call processQueue()*/ || map.get().isEmpty()); + map.get().remove(""); // to call processQueue() assertSame(key, evicted.get()); } } diff --git a/platform/util/base/src/com/intellij/util/containers/CollectionFactory.java b/platform/util/base/src/com/intellij/util/containers/CollectionFactory.java index 090986b33112..3f2028afa349 100644 --- a/platform/util/base/src/com/intellij/util/containers/CollectionFactory.java +++ b/platform/util/base/src/com/intellij/util/containers/CollectionFactory.java @@ -10,6 +10,7 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.ConcurrentMap; +import java.util.function.BiConsumer; import java.util.function.Consumer; // ContainerUtil requires trove in classpath @@ -39,15 +40,21 @@ public final class CollectionFactory { return new ConcurrentSoftValueHashMap<>(null); } + /** + * Create {@link ConcurrentMap} with hard-referenced keys and weak-referenced values. + * When the value get garbage-collected, the {@code evictionListener} is (eventually) invoked with this map and the corresponding key + */ @Contract(value = "_ -> new", pure = true) - public static @NotNull ConcurrentMap<@NotNull K, @NotNull V> createConcurrentWeakValueMap( - @NotNull Consumer evictionListener) { + public static @NotNull ConcurrentMap<@NotNull K, @NotNull V> createConcurrentWeakValueMap(@NotNull BiConsumer, ? super K> evictionListener) { return new ConcurrentWeakValueHashMap<>(evictionListener); } + /** + * Create {@link ConcurrentMap} with hard-referenced keys and soft-referenced values. + * When the value get garbage-collected, the {@code evictionListener} is (eventually) invoked with this map and the corresponding key + */ @Contract(value = "_ -> new", pure = true) - public static @NotNull ConcurrentMap<@NotNull K, @NotNull V> createConcurrentSoftValueMap( - @NotNull Consumer evictionListener) { + public static @NotNull ConcurrentMap<@NotNull K, @NotNull V> createConcurrentSoftValueMap(@NotNull BiConsumer, ? super K> evictionListener) { return new ConcurrentSoftValueHashMap<>(evictionListener); } @@ -363,8 +370,13 @@ public final class CollectionFactory { public static @NotNull ConcurrentMap<@NotNull K, @NotNull V> createConcurrentSoftMap() { return new ConcurrentSoftHashMap<>(null); } + + /** + * Create {@link ConcurrentMap} with soft-referenced keys and hard-referenced values. + * When the key get garbage-collected, the {@code evictionListener} is (eventually) invoked with this map and the corresponding value + */ @Contract(value = "_ -> new", pure = true) - public static @NotNull ConcurrentMap<@NotNull K, @NotNull V> createConcurrentSoftMap(@NotNull Consumer evictionListener) { + public static @NotNull ConcurrentMap<@NotNull K, @NotNull V> createConcurrentSoftMap(@NotNull BiConsumer, ? super V> evictionListener) { return new ConcurrentSoftHashMap<>(evictionListener); } diff --git a/platform/util/base/src/com/intellij/util/containers/ConcurrentRefHashMap.java b/platform/util/base/src/com/intellij/util/containers/ConcurrentRefHashMap.java index d07ec3bfa40d..b69f2dc13dab 100644 --- a/platform/util/base/src/com/intellij/util/containers/ConcurrentRefHashMap.java +++ b/platform/util/base/src/com/intellij/util/containers/ConcurrentRefHashMap.java @@ -8,7 +8,7 @@ import java.lang.ref.ReferenceQueue; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.function.Consumer; +import java.util.function.BiConsumer; /** * Base class for concurrent (soft/weak) key:K -> strong value:V map @@ -23,9 +23,9 @@ abstract class ConcurrentRefHashMap extends AbstractMap implements C static final float LOAD_FACTOR = 0.75f; static final int DEFAULT_CAPACITY = 16; static final int DEFAULT_CONCURRENCY_LEVEL = Math.min(Runtime.getRuntime().availableProcessors(), 4); - private final Consumer myEvictionListener; + private final BiConsumer, ? super V> myEvictionListener; - ConcurrentRefHashMap(@Nullable Consumer evictionListener) { + ConcurrentRefHashMap(@Nullable BiConsumer, ? super V> evictionListener) { myHashingStrategy = this; myMap = new ConcurrentHashMap<>(DEFAULT_CAPACITY, LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); myEvictionListener = evictionListener; @@ -66,7 +66,7 @@ abstract class ConcurrentRefHashMap extends AbstractMap implements C while ((wk = (KeyReference)myReferenceQueue.poll()) != null) { V v = myMap.remove(wk); if (myEvictionListener != null) { - myEvictionListener.accept(v); + myEvictionListener.accept(this, v); } processed = true; } diff --git a/platform/util/base/src/com/intellij/util/containers/ConcurrentRefValueHashMap.java b/platform/util/base/src/com/intellij/util/containers/ConcurrentRefValueHashMap.java index 3ec793a3e28a..a592194b3306 100644 --- a/platform/util/base/src/com/intellij/util/containers/ConcurrentRefValueHashMap.java +++ b/platform/util/base/src/com/intellij/util/containers/ConcurrentRefValueHashMap.java @@ -10,7 +10,7 @@ import java.lang.ref.ReferenceQueue; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.function.Consumer; +import java.util.function.BiConsumer; /** * Base class for concurrent strong key:K -> (soft/weak) value:V map @@ -20,10 +20,10 @@ import java.util.function.Consumer; abstract class ConcurrentRefValueHashMap implements ConcurrentMap { private final ConcurrentMap> myMap = new ConcurrentHashMap<>(); - private final Consumer myEvictionListener; + private final BiConsumer, ? super K> myEvictionListener; protected final ReferenceQueue myQueue = new ReferenceQueue<>(); - ConcurrentRefValueHashMap(@Nullable Consumer evictionListener) { + ConcurrentRefValueHashMap(@Nullable BiConsumer, ? super K> evictionListener) { myEvictionListener = evictionListener; } @@ -44,7 +44,7 @@ abstract class ConcurrentRefValueHashMap implements ConcurrentMap { if (ref == null) break; K key = ref.getKey(); if (myMap.remove(key, ref) && myEvictionListener != null) { - myEvictionListener.accept(key); + myEvictionListener.accept(this, key); } processed = true; } diff --git a/platform/util/base/src/com/intellij/util/containers/ConcurrentSoftHashMap.java b/platform/util/base/src/com/intellij/util/containers/ConcurrentSoftHashMap.java index 2fcd2eaf49f6..e4a9ea74a141 100644 --- a/platform/util/base/src/com/intellij/util/containers/ConcurrentSoftHashMap.java +++ b/platform/util/base/src/com/intellij/util/containers/ConcurrentSoftHashMap.java @@ -6,7 +6,8 @@ import org.jetbrains.annotations.Nullable; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; -import java.util.function.Consumer; +import java.util.concurrent.ConcurrentMap; +import java.util.function.BiConsumer; /** * Concurrent soft key:K -> strong value:V map @@ -15,7 +16,7 @@ import java.util.function.Consumer; * Use {@link ContainerUtil#createConcurrentSoftMap()} to create this */ final class ConcurrentSoftHashMap extends ConcurrentRefHashMap { - ConcurrentSoftHashMap(@Nullable Consumer evictionListener) { + ConcurrentSoftHashMap(@Nullable BiConsumer, ? super V> evictionListener) { super(evictionListener); } diff --git a/platform/util/base/src/com/intellij/util/containers/ConcurrentSoftValueHashMap.java b/platform/util/base/src/com/intellij/util/containers/ConcurrentSoftValueHashMap.java index ee4fd39e5f88..a2bed6eed04f 100644 --- a/platform/util/base/src/com/intellij/util/containers/ConcurrentSoftValueHashMap.java +++ b/platform/util/base/src/com/intellij/util/containers/ConcurrentSoftValueHashMap.java @@ -6,6 +6,8 @@ import org.jetbrains.annotations.Nullable; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; +import java.util.concurrent.ConcurrentMap; +import java.util.function.BiConsumer; import java.util.function.Consumer; /** @@ -16,7 +18,7 @@ import java.util.function.Consumer; */ final class ConcurrentSoftValueHashMap extends ConcurrentRefValueHashMap { - ConcurrentSoftValueHashMap(@Nullable Consumer evictionListener) { + ConcurrentSoftValueHashMap(@Nullable BiConsumer, ? super K> evictionListener) { super(evictionListener); } diff --git a/platform/util/base/src/com/intellij/util/containers/ConcurrentWeakValueHashMap.java b/platform/util/base/src/com/intellij/util/containers/ConcurrentWeakValueHashMap.java index 4ebe924f0522..2b9365ebcb12 100644 --- a/platform/util/base/src/com/intellij/util/containers/ConcurrentWeakValueHashMap.java +++ b/platform/util/base/src/com/intellij/util/containers/ConcurrentWeakValueHashMap.java @@ -7,6 +7,8 @@ import org.jetbrains.annotations.Nullable; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; +import java.util.concurrent.ConcurrentMap; +import java.util.function.BiConsumer; import java.util.function.Consumer; /** @@ -17,7 +19,7 @@ import java.util.function.Consumer; */ final class ConcurrentWeakValueHashMap extends ConcurrentRefValueHashMap { - ConcurrentWeakValueHashMap(@Nullable Consumer evictionListener) { + ConcurrentWeakValueHashMap(@Nullable BiConsumer, ? super K> evictionListener) { super(evictionListener); }