diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/encoding/EncodingManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/encoding/EncodingManagerImpl.java index 2c33fccf9e7d..22e23f7c88a9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/encoding/EncodingManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/encoding/EncodingManagerImpl.java @@ -47,6 +47,7 @@ import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Alarm; import com.intellij.util.Processor; +import gnu.trove.Equality; import gnu.trove.THashSet; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -69,6 +70,12 @@ import java.util.Set; } ) public class EncodingManagerImpl extends EncodingManager implements PersistentStateComponent, Disposable { + public static final Equality> REFERENCE_EQUALITY = new Equality>() { + @Override + public boolean equals(Reference o1, Reference o2) { + return o1.get() == o2.get(); + } + }; private final PropertyChangeSupport myPropertyChangeSupport = new PropertyChangeSupport(this); private String myDefaultEncoding = CharsetToolkit.UTF8; private Charset myCachedCharset = null; @@ -129,7 +136,7 @@ public class EncodingManagerImpl extends EncodingManager implements PersistentSt } public void queueUpdateEncodingFromContent(@NotNull Document document) { - myChangedDocuments.offer(new WeakReference(document)); + myChangedDocuments.offerIfAbsent(new WeakReference(document), REFERENCE_EQUALITY); } @Override diff --git a/platform/util/src/com/intellij/util/containers/Queue.java b/platform/util/src/com/intellij/util/containers/Queue.java index a4c634254132..1dbe2e36756c 100644 --- a/platform/util/src/com/intellij/util/containers/Queue.java +++ b/platform/util/src/com/intellij/util/containers/Queue.java @@ -16,6 +16,8 @@ package com.intellij.util.containers; import com.intellij.util.ArrayUtil; +import com.intellij.util.Processor; +import org.jetbrains.annotations.NotNull; import java.util.Arrays; import java.util.List; @@ -66,7 +68,7 @@ public class Queue { } public T pullFirst() { - T result = (T)myArray[myFirst]; + T result = peekFirst(); myArray[myFirst] = null; myFirst++; if (myFirst == myArray.length) { @@ -77,6 +79,9 @@ public class Queue { } public T peekFirst() { + if (isEmpty()) { + throw new IndexOutOfBoundsException("queue is empty"); + } return (T)myArray[myFirst]; } @@ -99,10 +104,27 @@ public class Queue { } public void clear() { - for (int i = 0; i < myArray.length; i++) { - myArray[i] = null; - } - isWrapped = false; + Arrays.fill(myArray, null); myFirst = myLast = 0; } + + public boolean process(@NotNull Processor processor) { + if (isWrapped) { + for (int i = myFirst; i < myArray.length; i++) { + T t = (T)myArray[i]; + if (!processor.process(t)) return false; + } + for (int i = 0; i < myLast; i++) { + T t = (T)myArray[i]; + if (!processor.process(t)) return false; + } + } + else { + for (int i = myFirst; i < myLast; i++) { + T t = (T)myArray[i]; + if (!processor.process(t)) return false; + } + } + return true; + } } diff --git a/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java b/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java index 2d83017b15e3..e0326f65cdac 100644 --- a/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java +++ b/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java @@ -17,12 +17,11 @@ package com.intellij.util.containers; import com.intellij.openapi.util.Condition; import com.intellij.util.Processor; +import gnu.trove.Equality; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import javax.swing.*; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -38,7 +37,7 @@ public class TransferToEDTQueue { private final Condition myShutUpCondition; private final int myMaxUnitOfWorkThresholdMs; //-1 means indefinite - private final Queue myQueue = new ConcurrentLinkedQueue(); + private final Queue myQueue = new Queue(10); private final AtomicBoolean invokeLaterScheduled = new AtomicBoolean(); private final Runnable myUpdateRunnable = new Runnable() { @Override @@ -61,14 +60,23 @@ public class TransferToEDTQueue { long finish = System.currentTimeMillis(); if (myMaxUnitOfWorkThresholdMs != -1 && finish - start > myMaxUnitOfWorkThresholdMs) break; } - if (!myQueue.isEmpty()) { + if (!isEmpty()) { scheduleUpdate(); } } }; + private boolean isEmpty() { + synchronized (myQueue) { + return myQueue.isEmpty(); + } + } + private boolean processNext() { - T thing = myQueue.poll(); + T thing; + synchronized (myQueue) { + thing = myQueue.isEmpty() ? null : myQueue.pullFirst(); + } if (thing == null) return false; if (!myProcessor.process(thing)) { stop(); @@ -84,9 +92,29 @@ public class TransferToEDTQueue { myMaxUnitOfWorkThresholdMs = maxUnitOfWorkThresholdMs; } - public void offer(@NotNull T thing) { - myQueue.offer(thing); + public boolean offer(@NotNull T thing) { + synchronized (myQueue) { + myQueue.addLast(thing); + } scheduleUpdate(); + return true; + } + + public boolean offerIfAbsent(@NotNull final T thing, @NotNull final Equality equality) { + boolean absent; + synchronized (myQueue) { + absent = myQueue.process(new Processor() { + @Override + public boolean process(T t) { + return !equality.equals(t, thing); + } + }); + if (absent) { + myQueue.addLast(thing); + scheduleUpdate(); + } + } + return absent; } private void scheduleUpdate() { @@ -101,7 +129,9 @@ public class TransferToEDTQueue { public void stop() { stopped = true; - myQueue.clear(); + synchronized (myQueue) { + myQueue.clear(); + } } // process all queue in current thread