blob: a64808d8da12d4558249fabcbf4d65db4c51f6d3 [file] [log] [blame]
initial.commit3f4a7322008-07-27 06:49:38 +09001// Copyright 2008, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#ifndef BASE_OBSERVER_LIST_H__
31#define BASE_OBSERVER_LIST_H__
32
33#include <vector>
34#include <algorithm>
35
36#include "base/basictypes.h"
37#include "base/logging.h"
38
39///////////////////////////////////////////////////////////////////////////////
40//
41// OVERVIEW:
42//
43// A container for a list of observers. Unlike a normal STL vector or list,
44// this container can be modified during iteration without invalidating the
45// iterator. So, it safely handles the case of an observer removing itself
46// or other observers from the list while observers are being notified.
47//
48// TYPICAL USAGE:
49//
50// class MyWidget {
51// public:
52// ...
53//
54// class Observer {
55// public:
56// virtual void OnFoo(MyWidget* w) = 0;
57// virtual void OnBar(MyWidget* w, int x, int y) = 0;
58// };
59//
60// void AddObserver(Observer* obs) {
61// observer_list_.AddObserver(obs);
62// }
63//
64// void RemoveObserver(Observer* obs) {
65// observer_list_.RemoveObserver(obs);
66// }
67//
68// void NotifyFoo() {
69// FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this));
70// }
71//
72// void NotifyBar(int x, int y) {
73// FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y));
74// }
75//
76// private:
77// ObserverList<Observer> observer_list_;
78// };
79//
80///////////////////////////////////////////////////////////////////////////////
81
82template <class ObserverType, bool check_empty = false>
83class ObserverList {
84 public:
85 ObserverList() : notify_depth_(0) {}
86 ~ObserverList() {
87 // When check_empty is true, assert that the list is empty on destruction.
88 if (check_empty) {
89 Compact();
90 DCHECK_EQ(observers_.size(), 0);
91 }
92 }
93
94 // Add an observer to the list.
95 void AddObserver(ObserverType* obs) {
96 DCHECK(find(observers_.begin(), observers_.end(), obs) == observers_.end())
97 << "Observers can only be added once!";
98 observers_.push_back(obs);
99 }
100
101 // Remove an observer from the list.
102 void RemoveObserver(ObserverType* obs) {
103 ListType::iterator it = find(observers_.begin(), observers_.end(), obs);
104 if (it != observers_.end()) {
105 if (notify_depth_) {
106 *it = 0;
107 } else {
108 observers_.erase(it);
109 }
110 }
111 }
112
113 // An iterator class that can be used to access the list of observers. See
114 // also the FOREACH_OBSERVER macro defined below.
115 class Iterator {
116 public:
117 Iterator(const ObserverList<ObserverType>& list) : list_(list), index_(0) {
118 ++list_.notify_depth_;
119 }
120
121 ~Iterator() {
122 if (--list_.notify_depth_ == 0)
123 list_.Compact();
124 }
125
126 ObserverType* GetNext() {
127 ListType& observers = list_.observers_;
128 // Advance if the current element is null
129 while (index_ < observers.size() && !observers[index_])
130 ++index_;
131 return index_ < observers.size() ? observers[index_++] : NULL;
132 }
133
134 private:
135 const ObserverList<ObserverType>& list_;
136 size_t index_;
137 };
138
139 private:
140 typedef std::vector<ObserverType*> ListType;
141
142 void Compact() const {
143 ListType::iterator it = observers_.begin();
144 while (it != observers_.end()) {
145 if (*it) {
146 ++it;
147 } else {
148 it = observers_.erase(it);
149 }
150 }
151 }
152
153 // These are marked mutable to facilitate having NotifyAll be const.
154 mutable ListType observers_;
155 mutable int notify_depth_;
156
157 friend class ObserverList::Iterator;
158
159 DISALLOW_EVIL_CONSTRUCTORS(ObserverList);
160};
161
162#define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \
163 do { \
164 ObserverList<ObserverType>::Iterator it(observer_list); \
165 ObserverType* obs; \
166 while (obs = it.GetNext()) \
167 obs->func; \
168 } while (0)
169
170#endif // BASE_OBSERVER_LIST_H__