blob: d34e8385101e834c16e8e0cc327921802b82c45e [file] [log] [blame]
license.botf003cfe2008-08-24 09:55:55 +09001// Copyright (c) 2006-2008 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.
initial.commit3f4a7322008-07-27 06:49:38 +09004
5#ifndef BASE_OBSERVER_LIST_H__
6#define BASE_OBSERVER_LIST_H__
7
8#include <vector>
9#include <algorithm>
10
11#include "base/basictypes.h"
12#include "base/logging.h"
13
14///////////////////////////////////////////////////////////////////////////////
15//
16// OVERVIEW:
17//
18// A container for a list of observers. Unlike a normal STL vector or list,
19// this container can be modified during iteration without invalidating the
20// iterator. So, it safely handles the case of an observer removing itself
21// or other observers from the list while observers are being notified.
22//
23// TYPICAL USAGE:
24//
25// class MyWidget {
26// public:
27// ...
28//
29// class Observer {
30// public:
31// virtual void OnFoo(MyWidget* w) = 0;
32// virtual void OnBar(MyWidget* w, int x, int y) = 0;
33// };
34//
35// void AddObserver(Observer* obs) {
36// observer_list_.AddObserver(obs);
37// }
38//
39// void RemoveObserver(Observer* obs) {
40// observer_list_.RemoveObserver(obs);
41// }
42//
43// void NotifyFoo() {
44// FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this));
45// }
46//
47// void NotifyBar(int x, int y) {
48// FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y));
49// }
50//
51// private:
52// ObserverList<Observer> observer_list_;
53// };
54//
55///////////////////////////////////////////////////////////////////////////////
56
57template <class ObserverType, bool check_empty = false>
58class ObserverList {
59 public:
60 ObserverList() : notify_depth_(0) {}
61 ~ObserverList() {
62 // When check_empty is true, assert that the list is empty on destruction.
63 if (check_empty) {
64 Compact();
darin@google.comf3272802008-08-15 05:27:29 +090065 DCHECK_EQ(observers_.size(), 0U);
initial.commit3f4a7322008-07-27 06:49:38 +090066 }
67 }
68
69 // Add an observer to the list.
70 void AddObserver(ObserverType* obs) {
71 DCHECK(find(observers_.begin(), observers_.end(), obs) == observers_.end())
72 << "Observers can only be added once!";
73 observers_.push_back(obs);
74 }
75
76 // Remove an observer from the list.
77 void RemoveObserver(ObserverType* obs) {
pinkerton@google.com94a9d912008-08-05 02:40:42 +090078 typename ListType::iterator it =
79 std::find(observers_.begin(), observers_.end(), obs);
initial.commit3f4a7322008-07-27 06:49:38 +090080 if (it != observers_.end()) {
81 if (notify_depth_) {
82 *it = 0;
83 } else {
84 observers_.erase(it);
85 }
86 }
87 }
88
89 // An iterator class that can be used to access the list of observers. See
90 // also the FOREACH_OBSERVER macro defined below.
91 class Iterator {
92 public:
93 Iterator(const ObserverList<ObserverType>& list) : list_(list), index_(0) {
94 ++list_.notify_depth_;
95 }
96
97 ~Iterator() {
98 if (--list_.notify_depth_ == 0)
99 list_.Compact();
100 }
101
102 ObserverType* GetNext() {
103 ListType& observers = list_.observers_;
104 // Advance if the current element is null
105 while (index_ < observers.size() && !observers[index_])
106 ++index_;
107 return index_ < observers.size() ? observers[index_++] : NULL;
108 }
109
110 private:
111 const ObserverList<ObserverType>& list_;
112 size_t index_;
113 };
114
115 private:
116 typedef std::vector<ObserverType*> ListType;
117
118 void Compact() const {
pinkerton@google.com94a9d912008-08-05 02:40:42 +0900119 typename ListType::iterator it = observers_.begin();
initial.commit3f4a7322008-07-27 06:49:38 +0900120 while (it != observers_.end()) {
121 if (*it) {
122 ++it;
123 } else {
124 it = observers_.erase(it);
125 }
126 }
127 }
128
129 // These are marked mutable to facilitate having NotifyAll be const.
130 mutable ListType observers_;
131 mutable int notify_depth_;
132
133 friend class ObserverList::Iterator;
134
135 DISALLOW_EVIL_CONSTRUCTORS(ObserverList);
136};
137
138#define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \
139 do { \
140 ObserverList<ObserverType>::Iterator it(observer_list); \
141 ObserverType* obs; \
darin@google.comf3272802008-08-15 05:27:29 +0900142 while ((obs = it.GetNext()) != NULL) \
initial.commit3f4a7322008-07-27 06:49:38 +0900143 obs->func; \
144 } while (0)
145
146#endif // BASE_OBSERVER_LIST_H__
license.botf003cfe2008-08-24 09:55:55 +0900147