1// Copyright (c) 2011 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#ifndef BASE_OBSERVER_LIST_H__
6#define BASE_OBSERVER_LIST_H__
7
8#include <algorithm>
9#include <limits>
10#include <vector>
11
12#include "base/basictypes.h"
13#include "base/logging.h"
14#include "base/memory/weak_ptr.h"
15
16///////////////////////////////////////////////////////////////////////////////
17//
18// OVERVIEW:
19//
20//   A container for a list of observers.  Unlike a normal STL vector or list,
21//   this container can be modified during iteration without invalidating the
22//   iterator.  So, it safely handles the case of an observer removing itself
23//   or other observers from the list while observers are being notified.
24//
25// TYPICAL USAGE:
26//
27//   class MyWidget {
28//    public:
29//     ...
30//
31//     class Observer {
32//      public:
33//       virtual void OnFoo(MyWidget* w) = 0;
34//       virtual void OnBar(MyWidget* w, int x, int y) = 0;
35//     };
36//
37//     void AddObserver(Observer* obs) {
38//       observer_list_.AddObserver(obs);
39//     }
40//
41//     void RemoveObserver(Observer* obs) {
42//       observer_list_.RemoveObserver(obs);
43//     }
44//
45//     void NotifyFoo() {
46//       FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this));
47//     }
48//
49//     void NotifyBar(int x, int y) {
50//       FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y));
51//     }
52//
53//    private:
54//     ObserverList<Observer> observer_list_;
55//   };
56//
57//
58///////////////////////////////////////////////////////////////////////////////
59
60template <typename ObserverType>
61class ObserverListThreadSafe;
62
63template <class ObserverType>
64class ObserverListBase
65    : public base::SupportsWeakPtr<ObserverListBase<ObserverType> > {
66 public:
67  // Enumeration of which observers are notified.
68  enum NotificationType {
69    // Specifies that any observers added during notification are notified.
70    // This is the default type if non type is provided to the constructor.
71    NOTIFY_ALL,
72
73    // Specifies that observers added while sending out notification are not
74    // notified.
75    NOTIFY_EXISTING_ONLY
76  };
77
78  // An iterator class that can be used to access the list of observers.  See
79  // also the FOR_EACH_OBSERVER macro defined below.
80  class Iterator {
81   public:
82    Iterator(ObserverListBase<ObserverType>& list);
83    ~Iterator();
84    ObserverType* GetNext();
85
86   private:
87    base::WeakPtr<ObserverListBase<ObserverType> > list_;
88    size_t index_;
89    size_t max_index_;
90  };
91
92  ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {}
93  explicit ObserverListBase(NotificationType type)
94      : notify_depth_(0), type_(type) {}
95
96  // Add an observer to the list.  An observer should not be added to
97  // the same list more than once.
98  void AddObserver(ObserverType* obs);
99
100  // Remove an observer from the list if it is in the list.
101  void RemoveObserver(ObserverType* obs);
102
103  bool HasObserver(ObserverType* observer) const;
104
105  void Clear();
106
107 protected:
108  size_t size() const { return observers_.size(); }
109
110  void Compact();
111
112 private:
113  friend class ObserverListThreadSafe<ObserverType>;
114
115  typedef std::vector<ObserverType*> ListType;
116
117  ListType observers_;
118  int notify_depth_;
119  NotificationType type_;
120
121  friend class ObserverListBase::Iterator;
122
123  DISALLOW_COPY_AND_ASSIGN(ObserverListBase);
124};
125
126template <class ObserverType>
127ObserverListBase<ObserverType>::Iterator::Iterator(
128  ObserverListBase<ObserverType>& list)
129    : list_(list.AsWeakPtr()),
130      index_(0),
131      max_index_(list.type_ == NOTIFY_ALL ?
132                 std::numeric_limits<size_t>::max() :
133                 list.observers_.size()) {
134  ++list_->notify_depth_;
135}
136
137template <class ObserverType>
138ObserverListBase<ObserverType>::Iterator::~Iterator() {
139  if (list_.get() && --list_->notify_depth_ == 0)
140    list_->Compact();
141}
142
143template <class ObserverType>
144ObserverType* ObserverListBase<ObserverType>::Iterator::GetNext() {
145  if (!list_.get())
146    return NULL;
147  ListType& observers = list_->observers_;
148  // Advance if the current element is null
149  size_t max_index = std::min(max_index_, observers.size());
150  while (index_ < max_index && !observers[index_])
151    ++index_;
152  return index_ < max_index ? observers[index_++] : NULL;
153}
154
155template <class ObserverType>
156void ObserverListBase<ObserverType>::AddObserver(ObserverType* obs) {
157  if (std::find(observers_.begin(), observers_.end(), obs)
158      != observers_.end()) {
159    NOTREACHED() << "Observers can only be added once!";
160    return;
161  }
162  observers_.push_back(obs);
163}
164
165template <class ObserverType>
166void ObserverListBase<ObserverType>::RemoveObserver(ObserverType* obs) {
167  typename ListType::iterator it =
168    std::find(observers_.begin(), observers_.end(), obs);
169  if (it != observers_.end()) {
170    if (notify_depth_) {
171      *it = 0;
172    } else {
173      observers_.erase(it);
174    }
175  }
176}
177
178template <class ObserverType>
179bool ObserverListBase<ObserverType>::HasObserver(ObserverType* observer) const {
180  for (size_t i = 0; i < observers_.size(); ++i) {
181    if (observers_[i] == observer)
182      return true;
183  }
184  return false;
185}
186
187template <class ObserverType>
188void ObserverListBase<ObserverType>::Clear() {
189  if (notify_depth_) {
190    for (typename ListType::iterator it = observers_.begin();
191      it != observers_.end(); ++it) {
192      *it = 0;
193    }
194  } else {
195    observers_.clear();
196  }
197}
198
199template <class ObserverType>
200void ObserverListBase<ObserverType>::Compact() {
201  observers_.erase(
202      std::remove(observers_.begin(), observers_.end(),
203                  static_cast<ObserverType*>(NULL)), observers_.end());
204}
205
206template <class ObserverType, bool check_empty = false>
207class ObserverList : public ObserverListBase<ObserverType> {
208 public:
209  typedef typename ObserverListBase<ObserverType>::NotificationType
210      NotificationType;
211
212  ObserverList() {}
213  explicit ObserverList(NotificationType type)
214      : ObserverListBase<ObserverType>(type) {}
215
216  ~ObserverList() {
217    // When check_empty is true, assert that the list is empty on destruction.
218    if (check_empty) {
219      ObserverListBase<ObserverType>::Compact();
220      DCHECK_EQ(ObserverListBase<ObserverType>::size(), 0U);
221    }
222  }
223
224  bool might_have_observers() const {
225    return ObserverListBase<ObserverType>::size() != 0;
226  }
227};
228
229#define FOR_EACH_OBSERVER(ObserverType, observer_list, func)               \
230  do {                                                                     \
231    if ((observer_list).might_have_observers()) {                          \
232      ObserverListBase<ObserverType>::Iterator                             \
233          it_inside_observer_macro(observer_list);                         \
234      ObserverType* obs;                                                   \
235      while ((obs = it_inside_observer_macro.GetNext()) != NULL)           \
236        obs->func;                                                         \
237    }                                                                      \
238  } while (0)
239
240#endif  // BASE_OBSERVER_LIST_H__
241