EMMA Coverage Report (generated Fri Aug 23 16:39:17 PDT 2013)
[all classes][org.chromium.base]

COVERAGE SUMMARY FOR SOURCE FILE [ObserverList.java]

nameclass, %method, %block, %line, %
ObserverList.java67%  (2/3)95%  (21/22)85%  (233/275)85%  (58/68)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ObserverList100% (1/1)94%  (15/16)76%  (133/175)77%  (33/43)
clear (): void 0%   (0/1)0%   (0/25)0%   (0/7)
addObserver (Object): void 100% (1/1)65%  (13/20)60%  (3/5)
<static initializer> 100% (1/1)75%  (6/8)75%  (0.8/1)
decrementIterationDepthAndCompactIfNeeded (): void 100% (1/1)81%  (17/21)95%  (4.7/5)
compact (): void 100% (1/1)84%  (21/25)94%  (7.6/8)
ObserverList (): void 100% (1/1)100% (11/11)100% (3/3)
access$100 (ObserverList): void 100% (1/1)100% (3/3)100% (1/1)
access$200 (ObserverList): int 100% (1/1)100% (3/3)100% (1/1)
access$300 (ObserverList, int): Object 100% (1/1)100% (4/4)100% (1/1)
access$400 (ObserverList): void 100% (1/1)100% (3/3)100% (1/1)
getObserverAt (int): Object 100% (1/1)100% (5/5)100% (1/1)
getSize (): int 100% (1/1)100% (4/4)100% (1/1)
hasObserver (Object): boolean 100% (1/1)100% (5/5)100% (1/1)
incrementIterationDepth (): void 100% (1/1)100% (7/7)100% (2/2)
iterator (): Iterator 100% (1/1)100% (6/6)100% (1/1)
removeObserver (Object): void 100% (1/1)100% (25/25)100% (7/7)
     
class ObserverList$10%   (0/1)100% (0/0)100% (0/0)100% (0/0)
     
class ObserverList$ObserverListIterator100% (1/1)100% (6/6)100% (100/100)100% (25/25)
ObserverList$ObserverListIterator (ObserverList): void 100% (1/1)100% (18/18)100% (6/6)
ObserverList$ObserverListIterator (ObserverList, ObserverList$1): void 100% (1/1)100% (4/4)100% (1/1)
compactListIfNeeded (): void 100% (1/1)100% (10/10)100% (4/4)
hasNext (): boolean 100% (1/1)100% (24/24)100% (7/7)
next (): Object 100% (1/1)100% (40/40)100% (6/6)
remove (): void 100% (1/1)100% (4/4)100% (1/1)

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 
5package org.chromium.base;
6 
7import java.lang.Iterable;
8import java.util.ArrayList;
9import java.util.Iterator;
10import java.util.List;
11import java.util.NoSuchElementException;
12 
13import 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 iterator.
19 * So, it safely handles the case of an observer removing itself or other observers from the list
20 * while observers are being notified.
21 * <p/>
22 * The implementation (and the interface) is heavily influenced by the C++ ObserverList.
23 * Notable differences:
24 *   - The iterator implements NOTIFY_EXISTING_ONLY.
25 *   - The FOR_EACH_OBSERVER closure is left to the clients to implement in terms of iterator().
26 * <p/>
27 * This class is not threadsafe. Observers MUST be added, removed and will be notified on the same
28 * thread this is created.
29 */
30@NotThreadSafe
31public 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 iteration 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 compaction.
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 else
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(mIndex) == 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}

[all classes][org.chromium.base]
EMMA 2.0.5312 (C) Vladimir Roubtsov