mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
don't like these Ref<>
This commit is contained in:
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package com.intellij.openapi.editor.event;
|
||||
|
||||
import com.intellij.util.ArrayFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
/**
|
||||
@@ -27,6 +30,14 @@ import java.util.EventListener;
|
||||
@SuppressWarnings("JavadocReference")
|
||||
public interface DocumentListener extends EventListener{
|
||||
DocumentListener[] EMPTY_ARRAY = new DocumentListener[0];
|
||||
ArrayFactory<DocumentListener> ARRAY_FACTORY = new ArrayFactory<DocumentListener>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public DocumentListener[] create(int count) {
|
||||
return count == 0 ? EMPTY_ARRAY : new DocumentListener[count];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called before the text of the document is changed.
|
||||
*
|
||||
|
||||
@@ -60,8 +60,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.DocumentImpl");
|
||||
|
||||
private final Ref<DocumentListener[]> myCachedDocumentListeners = Ref.create(null);
|
||||
private final List<DocumentListener> myDocumentListeners = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
private final LockFreeCOWSortedArray<DocumentListener> myDocumentListeners = new LockFreeCOWSortedArray<DocumentListener>(PrioritizedDocumentListener.COMPARATOR, DocumentListener.ARRAY_FACTORY);
|
||||
private final List<DocumentBulkUpdateListener> myBulkDocumentInternalListeners = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
private final RangeMarkerTree<RangeMarkerEx> myRangeMarkers = new RangeMarkerTree<RangeMarkerEx>(this);
|
||||
private final RangeMarkerTree<RangeMarkerEx> myPersistentRangeMarkers = new RangeMarkerTree<RangeMarkerEx>(this);
|
||||
@@ -461,7 +460,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
|
||||
|
||||
@Override
|
||||
public int getListenersCount() {
|
||||
return myDocumentListeners.size();
|
||||
return getListeners().length;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -533,7 +532,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
|
||||
}
|
||||
|
||||
private void fireMoveText(int start, int end, int newBase) {
|
||||
for (DocumentListener listener : getCachedListeners()) {
|
||||
for (DocumentListener listener : getListeners()) {
|
||||
if (listener instanceof PrioritizedInternalDocumentListener) {
|
||||
((PrioritizedInternalDocumentListener)listener).moveTextHappened(start, end, newBase);
|
||||
}
|
||||
@@ -722,7 +721,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
|
||||
myChangeInProgress = true;
|
||||
try {
|
||||
DocumentEvent event = new DocumentEventImpl(this, offset, oldString, newString, myModificationStamp, wholeTextReplaced, initialStartOffset, initialOldLength);
|
||||
doBeforeChangedUpdate(event);
|
||||
beforeChangedUpdate(event);
|
||||
myTextString = null;
|
||||
ImmutableCharSequence prevText = myText;
|
||||
myText = newText;
|
||||
@@ -739,7 +738,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
|
||||
return sequence.get();
|
||||
}
|
||||
|
||||
private void doBeforeChangedUpdate(DocumentEvent event) {
|
||||
private void beforeChangedUpdate(DocumentEvent event) {
|
||||
Application app = ApplicationManager.getApplication();
|
||||
if (app != null) {
|
||||
FileDocumentManager manager = FileDocumentManager.getInstance();
|
||||
@@ -753,7 +752,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
|
||||
getLineSet(); // initialize line set to track changed lines
|
||||
|
||||
if (!ShutDownTracker.isShutdownHookRunning()) {
|
||||
DocumentListener[] listeners = getCachedListeners();
|
||||
DocumentListener[] listeners = getListeners();
|
||||
for (int i = listeners.length - 1; i >= 0; i--) {
|
||||
try {
|
||||
listeners[i].beforeDocumentChange(event);
|
||||
@@ -791,7 +790,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
|
||||
setModificationStamp(newModificationStamp);
|
||||
|
||||
if (!ShutDownTracker.isShutdownHookRunning()) {
|
||||
DocumentListener[] listeners = getCachedListeners();
|
||||
DocumentListener[] listeners = getListeners();
|
||||
for (DocumentListener listener : listeners) {
|
||||
try {
|
||||
listener.documentChanged(event);
|
||||
@@ -865,43 +864,29 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
|
||||
|
||||
@Override
|
||||
public void addDocumentListener(@NotNull DocumentListener listener) {
|
||||
myCachedDocumentListeners.set(null);
|
||||
|
||||
if (myDocumentListeners.contains(listener)) {
|
||||
if (ArrayUtil.contains(listener, getListeners())) {
|
||||
LOG.error("Already registered: " + listener);
|
||||
}
|
||||
boolean added = myDocumentListeners.add(listener);
|
||||
LOG.assertTrue(added, listener);
|
||||
myDocumentListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDocumentListener(@NotNull final DocumentListener listener, @NotNull Disposable parentDisposable) {
|
||||
addDocumentListener(listener);
|
||||
Disposer.register(parentDisposable, new DocumentListenerDisposable(listener, myCachedDocumentListeners, myDocumentListeners));
|
||||
}
|
||||
|
||||
private static class DocumentListenerDisposable implements Disposable {
|
||||
private final DocumentListener myListener;
|
||||
private final Ref<DocumentListener[]> myCachedDocumentListenersRef;
|
||||
private final List<DocumentListener> myDocumentListeners;
|
||||
|
||||
private DocumentListenerDisposable(@NotNull DocumentListener listener,
|
||||
@NotNull Ref<DocumentListener[]> cachedDocumentListenersRef,
|
||||
@NotNull List<DocumentListener> documentListeners) {
|
||||
myListener = listener;
|
||||
myCachedDocumentListenersRef = cachedDocumentListenersRef;
|
||||
myDocumentListeners = documentListeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
doRemoveDocumentListener(myListener, myCachedDocumentListenersRef, myDocumentListeners);
|
||||
}
|
||||
Disposer.register(parentDisposable, new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
removeDocumentListener(listener);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDocumentListener(@NotNull DocumentListener listener) {
|
||||
doRemoveDocumentListener(listener, myCachedDocumentListeners, myDocumentListeners);
|
||||
boolean success = myDocumentListeners.remove(listener);
|
||||
if (!success) {
|
||||
LOG.error("Can't remove document listener (" + listener + "). Registered listeners: " + Arrays.toString(getListeners()));
|
||||
}
|
||||
}
|
||||
|
||||
void addInternalBulkModeListener(@NotNull DocumentBulkUpdateListener listener) {
|
||||
@@ -912,16 +897,6 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
|
||||
myBulkDocumentInternalListeners.remove(listener);
|
||||
}
|
||||
|
||||
private static void doRemoveDocumentListener(@NotNull DocumentListener listener,
|
||||
@NotNull Ref<DocumentListener[]> cachedDocumentListenersRef,
|
||||
@NotNull List<DocumentListener> documentListeners) {
|
||||
cachedDocumentListenersRef.set(null);
|
||||
boolean success = documentListeners.remove(listener);
|
||||
if (!success) {
|
||||
LOG.error("Can't remove document listener (" + listener + "). Registered listeners: " + documentListeners);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLineNumber(final int offset) {
|
||||
return getLineSet().findLineIndex(offset);
|
||||
@@ -962,16 +937,8 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private DocumentListener[] getCachedListeners() {
|
||||
DocumentListener[] cachedListeners = myCachedDocumentListeners.get();
|
||||
if (cachedListeners == null) {
|
||||
DocumentListener[] listeners = ArrayUtil.stripTrailingNulls(myDocumentListeners.toArray(new DocumentListener[myDocumentListeners.size()]));
|
||||
Arrays.sort(listeners, PrioritizedDocumentListener.COMPARATOR);
|
||||
cachedListeners = listeners;
|
||||
myCachedDocumentListeners.set(cachedListeners);
|
||||
}
|
||||
|
||||
return cachedListeners;
|
||||
private DocumentListener[] getListeners() {
|
||||
return myDocumentListeners.getArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.editor.impl;
|
||||
|
||||
import com.intellij.util.ArrayFactory;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.concurrency.AtomicFieldUpdater;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Maintains an atomic immutable array of listeners of type {@code T} in sorted order according to {@link #comparator}
|
||||
* N.B. internal array is exposed for faster iterating listeners in to- and reverse order, so care should be taken for not mutating it by clients
|
||||
*/
|
||||
class LockFreeCOWSortedArray<T> {
|
||||
@NotNull private final Comparator<? super T> comparator;
|
||||
private final ArrayFactory<T> arrayFactory;
|
||||
/** changed by {@link #UPDATER} only */
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
@NotNull private volatile T[] listeners;
|
||||
private static final AtomicFieldUpdater<LockFreeCOWSortedArray, Object[]> UPDATER = AtomicFieldUpdater.forFieldOfType(LockFreeCOWSortedArray.class, Object[].class);
|
||||
|
||||
LockFreeCOWSortedArray(@NotNull Comparator<? super T> comparator, @NotNull ArrayFactory<T> arrayFactory) {
|
||||
this.comparator = comparator;
|
||||
this.arrayFactory = arrayFactory;
|
||||
listeners = arrayFactory.create(0);
|
||||
}
|
||||
|
||||
// returns true if changed
|
||||
void add(@NotNull T listener) {
|
||||
while (true) {
|
||||
T[] oldListeners = listeners;
|
||||
int i = insertionIndex(oldListeners, listener);
|
||||
T[] newListeners = ArrayUtil.insert(oldListeners, i, listener);
|
||||
if (UPDATER.compareAndSet(this, oldListeners, newListeners)) break;
|
||||
}
|
||||
}
|
||||
|
||||
boolean remove(@NotNull T listener) {
|
||||
while (true) {
|
||||
T[] oldListeners = listeners;
|
||||
T[] newListeners = ArrayUtil.remove(oldListeners, listener, arrayFactory);
|
||||
//noinspection ArrayEquality
|
||||
if (oldListeners == newListeners) return false;
|
||||
if (UPDATER.compareAndSet(this, oldListeners, newListeners)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private int insertionIndex(@NotNull T[] elements, @NotNull T e) {
|
||||
for (int i=0; i<elements.length; i++) {
|
||||
T element = elements[i];
|
||||
if (comparator.compare(e, element) < 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return elements.length;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
T[] getArray() {
|
||||
return listeners;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user