Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: base/android/java/src/org/chromium/base/ObserverList.java

Issue 12378004: Android: Add a java version of ObserverList. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added hasObserver call in the test. Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | base/android/javatests/src/org/chromium/base/ObserverListTest.java » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.base;
6
7 import java.lang.Iterable;
8 import java.util.ArrayList;
9 import java.util.Iterator;
10 import java.util.List;
11 import java.util.NoSuchElementException;
12
13 import javax.annotation.concurrent.NotThreadSafe;
14
15 /**
16 * A container for a list of observers.
17 * <p/>
18 * This container can be modified during iteration without invalidating the iter ator.
19 * So, it safely handles the case of an observer removing itself or other observ ers from the list
20 * while observers are being notified.
21 * <p/>
22 * The implementation (and the interface) is heavily influenced by the C++ Obser verList.
23 * Notable differences:
24 * - The iterator implements NOTIFY_EXISTING_ONLY.
25 * - The FOR_EACH_OBSERVER closure is left to the clients to implement in term s of iterator().
26 * <p/>
27 * This class is not threadsafe. Observers MUST be added, removed and will be no tified on the same
28 * thread this is created.
29 */
30 @NotThreadSafe
31 public class ObserverList<E> implements Iterable<E> {
32 public final List<E> mObservers = new ArrayList<E>();
33 private int mIterationDepth = 0;
34
35 public ObserverList() {}
36
37 /**
38 * Add an observer to the list.
39 * <p/>
40 * An observer should not be added to the same list more than once. If an it eration is already
41 * in progress, this observer will be not be visible during that iteration.
42 */
43 public void addObserver(E obs) {
44 // Avoid adding null elements to the list as they may be removed on a co mpaction.
45 if (obs == null || mObservers.contains(obs)) {
46 assert false;
47 return;
48 }
49
50 // Structurally modifying the underlying list here. This means we
51 // cannot use the underlying list's iterator to iterate over the list.
52 mObservers.add(obs);
53 }
54
55 /**
56 * Remove an observer from the list if it is in the list.
57 */
58 public void removeObserver(E obs) {
59 int index = mObservers.indexOf(obs);
60
61 if (index == -1)
62 return;
63
64 if (mIterationDepth == 0) {
65 // No one is iterating over the list.
66 mObservers.remove(obs);
67 } else {
68 mObservers.set(index, null);
69 }
70 }
71
72 public boolean hasObserver(E obs) {
73 return mObservers.contains(obs);
74 }
75
76 public void clear() {
77 if (mIterationDepth == 0) {
78 mObservers.clear();
79 return;
80 }
81
82 int size = mObservers.size();
83 for (int i = 0; i < size; i++)
84 mObservers.set(i, null);
85 }
86
87 @Override
88 public Iterator<E> iterator() {
89 return new ObserverListIterator();
90 }
91
92 /**
93 * Compact the underlying list be removing null elements.
94 * <p/>
95 * Should only be called when mIterationDepth is zero.
96 */
97 private void compact() {
98 assert mIterationDepth == 0;
99 // Safe to use the underlying list's iterator, as we know that no-one el se
100 // is iterating over the list.
101 Iterator<E> it = mObservers.iterator();
102 while (it.hasNext()) {
103 E el = it.next();
104 if (el == null)
105 it.remove();
106 }
107 }
108
109 private void incrementIterationDepth() {
110 mIterationDepth++;
111 }
112
113 private void decrementIterationDepthAndCompactIfNeeded() {
114 mIterationDepth--;
115 assert mIterationDepth >= 0;
116 if (mIterationDepth == 0)
117 compact();
118 }
119
120 private int getSize() {
121 return mObservers.size();
122 }
123
124 private E getObserverAt(int index) {
125 return mObservers.get(index);
126 }
127
128 private class ObserverListIterator implements Iterator<E> {
129 private final int mListEndMarker;
130 private int mIndex = 0;
131 private boolean mIsExhausted = false;
132
133 private ObserverListIterator() {
134 ObserverList.this.incrementIterationDepth();
135 mListEndMarker = ObserverList.this.getSize();
136 }
137
138 @Override
139 public boolean hasNext() {
140 int lookupIndex = mIndex;
141 while (lookupIndex < mListEndMarker &&
142 ObserverList.this.getObserverAt(lookupIndex) == null)
143 lookupIndex++;
144 if (lookupIndex < mListEndMarker)
145 return true;
146
147 // We have reached the end of the list, allow for compaction.
148 compactListIfNeeded();
149 return false;
150 }
151
152 @Override
153 public E next() {
154 // Advance if the current element is null.
155 while (mIndex < mListEndMarker && ObserverList.this.getObserverAt(mI ndex) == null)
156 mIndex++;
157 if (mIndex < mListEndMarker)
158 return ObserverList.this.getObserverAt(mIndex++);
159
160 // We have reached the end of the list, allow for compaction.
161 compactListIfNeeded();
162 throw new NoSuchElementException();
163 }
164
165 @Override
166 public void remove() {
167 throw new UnsupportedOperationException();
168 }
169
170 private void compactListIfNeeded() {
171 if (!mIsExhausted) {
172 mIsExhausted = true;
173 ObserverList.this.decrementIterationDepthAndCompactIfNeeded();
174 }
175 }
176 }
177 }
OLDNEW
« no previous file with comments | « no previous file | base/android/javatests/src/org/chromium/base/ObserverListTest.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698