Index: base/android/java/src/org/chromium/base/BaseObserverList.java |
diff --git a/base/android/java/src/org/chromium/base/ObserverList.java b/base/android/java/src/org/chromium/base/BaseObserverList.java |
similarity index 74% |
copy from base/android/java/src/org/chromium/base/ObserverList.java |
copy to base/android/java/src/org/chromium/base/BaseObserverList.java |
index e812b0de4341e0ac21fed05c71b1a268abb18c0d..6410422fc1c6ca97fae3564aba5dde5720b4d64b 100644 |
--- a/base/android/java/src/org/chromium/base/ObserverList.java |
+++ b/base/android/java/src/org/chromium/base/BaseObserverList.java |
@@ -1,4 +1,4 @@ |
-// Copyright 2013 The Chromium Authors. All rights reserved. |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
@@ -12,7 +12,7 @@ import java.util.NoSuchElementException; |
import javax.annotation.concurrent.NotThreadSafe; |
/** |
- * A container for a list of observers. |
+ * A container for a list of (optionally wrapped) observers. |
* <p/> |
* This container can be modified during iteration without invalidating the iterator. |
* So, it safely handles the case of an observer removing itself or other observers from the list |
@@ -27,27 +27,31 @@ import javax.annotation.concurrent.NotThreadSafe; |
* thread this is created. |
* |
* @param <E> The type of observers that this list should hold. |
+ * @param <Wrapper> The wrapper type for each added observer, useful when the storage of an |
+ * observer instance should be different than the observer type itself, |
+ * e.g., for storing WeakReferences to the underlying observer). For most |
+ * cases this will be identical to the observer type E. |
*/ |
@NotThreadSafe |
-public class ObserverList<E> implements Iterable<E> { |
- /** |
- * Extended iterator interface that provides rewind functionality. |
- */ |
- public interface RewindableIterator<E> extends Iterator<E> { |
- /** |
- * Rewind the iterator back to the beginning. |
- * |
- * If we need to iterate multiple times, we can avoid iterator object reallocation by using |
- * this method. |
- */ |
- public void rewind(); |
- } |
+abstract class BaseObserverList<E, Wrapper> implements Iterable<E> { |
- public final List<E> mObservers = new ArrayList<E>(); |
+ public final List<Wrapper> mObservers = new ArrayList<Wrapper>(); |
private int mIterationDepth = 0; |
private int mCount = 0; |
- public ObserverList() {} |
+ /** |
+ * Override to provide translation from the externally visible Observer |
+ * type to the underlying storage type. |
+ */ |
+ abstract Wrapper wrap(E obs); |
+ |
+ /** |
+ * Override to provide translation from the underlying storage type to the |
+ * externally visible observer type. |
+ */ |
+ abstract E unwrap(Wrapper wrapper); |
+ |
+ public BaseObserverList() {} |
/** |
* Add an observer to the list. |
@@ -59,13 +63,13 @@ public class ObserverList<E> implements Iterable<E> { |
*/ |
public boolean addObserver(E obs) { |
// Avoid adding null elements to the list as they may be removed on a compaction. |
- if (obs == null || mObservers.contains(obs)) { |
+ if (obs == null || hasObserver(obs)) { |
return false; |
} |
// Structurally modifying the underlying list here. This means we |
// cannot use the underlying list's iterator to iterate over the list. |
- boolean result = mObservers.add(obs); |
+ boolean result = mObservers.add(wrap(obs)); |
assert result; |
++mCount; |
@@ -82,7 +86,7 @@ public class ObserverList<E> implements Iterable<E> { |
return false; |
} |
- int index = mObservers.indexOf(obs); |
+ int index = indexOf(obs); |
if (index == -1) { |
return false; |
} |
@@ -100,7 +104,7 @@ public class ObserverList<E> implements Iterable<E> { |
} |
public boolean hasObserver(E obs) { |
- return mObservers.contains(obs); |
+ return indexOf(obs) != -1; |
} |
public void clear() { |
@@ -154,12 +158,21 @@ public class ObserverList<E> implements Iterable<E> { |
private void compact() { |
assert mIterationDepth == 0; |
for (int i = mObservers.size() - 1; i >= 0; i--) { |
- if (mObservers.get(i) == null) { |
+ if (getObserverAt(i) == null) { |
mObservers.remove(i); |
} |
} |
} |
+ private int indexOf(E obs) { |
+ for (int i = 0; i < mObservers.size(); ++i) { |
+ if (getObserverAt(i) == obs) { |
+ return i; |
+ } |
+ } |
+ return -1; |
+ } |
+ |
private void incrementIterationDepth() { |
mIterationDepth++; |
} |
@@ -179,7 +192,7 @@ public class ObserverList<E> implements Iterable<E> { |
} |
private E getObserverAt(int index) { |
- return mObservers.get(index); |
+ return unwrap(mObservers.get(index)); |
} |
private class ObserverListIterator implements RewindableIterator<E> { |
@@ -188,15 +201,15 @@ public class ObserverList<E> implements Iterable<E> { |
private boolean mIsExhausted = false; |
private ObserverListIterator() { |
- ObserverList.this.incrementIterationDepth(); |
- mListEndMarker = ObserverList.this.capacity(); |
+ BaseObserverList.this.incrementIterationDepth(); |
+ mListEndMarker = BaseObserverList.this.capacity(); |
} |
@Override |
public void rewind() { |
compactListIfNeeded(); |
- ObserverList.this.incrementIterationDepth(); |
- mListEndMarker = ObserverList.this.capacity(); |
+ BaseObserverList.this.incrementIterationDepth(); |
+ mListEndMarker = BaseObserverList.this.capacity(); |
mIsExhausted = false; |
mIndex = 0; |
} |
@@ -205,7 +218,7 @@ public class ObserverList<E> implements Iterable<E> { |
public boolean hasNext() { |
int lookupIndex = mIndex; |
while (lookupIndex < mListEndMarker |
- && ObserverList.this.getObserverAt(lookupIndex) == null) { |
+ && BaseObserverList.this.getObserverAt(lookupIndex) == null) { |
lookupIndex++; |
} |
if (lookupIndex < mListEndMarker) return true; |
@@ -218,10 +231,10 @@ public class ObserverList<E> implements Iterable<E> { |
@Override |
public E next() { |
// Advance if the current element is null. |
- while (mIndex < mListEndMarker && ObserverList.this.getObserverAt(mIndex) == null) { |
+ while (mIndex < mListEndMarker && BaseObserverList.this.getObserverAt(mIndex) == null) { |
mIndex++; |
} |
- if (mIndex < mListEndMarker) return ObserverList.this.getObserverAt(mIndex++); |
+ if (mIndex < mListEndMarker) return BaseObserverList.this.getObserverAt(mIndex++); |
// We have reached the end of the list, allow for compaction. |
compactListIfNeeded(); |
@@ -236,7 +249,7 @@ public class ObserverList<E> implements Iterable<E> { |
private void compactListIfNeeded() { |
if (!mIsExhausted) { |
mIsExhausted = true; |
- ObserverList.this.decrementIterationDepthAndCompactIfNeeded(); |
+ BaseObserverList.this.decrementIterationDepthAndCompactIfNeeded(); |
} |
} |
} |