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

Side by Side Diff: base/callback_registry.h

Issue 22877038: Add a CallbackRegistry class to base/ to manage callbacks (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase + nits Created 7 years, 3 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 | « base/base.gypi ('k') | base/callback_registry_unittest.cc » ('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 #ifndef BASE_CALLBACK_REGISTRY_H_
6 #define BASE_CALLBACK_REGISTRY_H_
7
8 #include <list>
9
10 #include "base/basictypes.h"
11 #include "base/callback.h"
12 #include "base/compiler_specific.h"
13 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h"
15
16 // OVERVIEW:
17 //
18 // A container for a list of callbacks. Unlike a normal STL vector or list,
19 // this container can be modified during iteration without invalidating the
20 // iterator. It safely handles the case of a callback removing itself
21 // or another callback from the list while callbacks are being run.
22 //
23 // TYPICAL USAGE:
24 //
25 // class MyWidget {
26 // public:
27 // ...
28 //
29 // typedef base::Callback<void(const Foo&)> OnFooCallback;
30 //
31 // scoped_ptr<base::CallbackRegistry<Foo>::Subscription> RegisterCallback(
32 // const OnFooCallback& cb) {
33 // return callback_registry_.Add(cb);
34 // }
35 //
36 // private:
37 // void NotifyFoo(const Foo& foo) {
38 // callback_registry_.Notify(foo);
39 // }
40 //
41 // base::CallbackRegistry<Foo> callback_registry_;
42 // };
43 //
44 //
45 // class MyWidgetListener {
46 // public:
47 // MyWidgetListener::MyWidgetListener() {
48 // foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback(
49 // base::Bind(&MyWidgetListener::OnFoo, this)));
50 // }
51 //
52 // MyWidgetListener::~MyWidgetListener() {
53 // // Subscription gets deleted automatically and will deregister
54 // // the callback in the process.
55 // }
56 //
57 // private:
58 // void OnFoo(const Foo& foo) {
59 // // Do something.
60 // }
61 //
62 // scoped_ptr<base::CallbackRegistry<Foo>::Subscription> foo_subscription_;
63 // };
64
65 namespace base {
66
67 namespace internal {
68
69 template <typename CallbackType>
70 class CallbackRegistryBase {
71 public:
72 class Subscription {
73 public:
74 Subscription(CallbackRegistryBase<CallbackType>* list,
75 typename std::list<CallbackType>::iterator iter)
76 : list_(list),
77 iter_(iter) {}
78
79 ~Subscription() {
80 if (list_->active_iterator_count_)
81 (*iter_).Reset();
82 else
83 list_->callbacks_.erase(iter_);
84 }
85
86 private:
87 CallbackRegistryBase<CallbackType>* list_;
88 typename std::list<CallbackType>::iterator iter_;
89
90 DISALLOW_COPY_AND_ASSIGN(Subscription);
91 };
92
93 // Add a callback to the list. The callback will remain registered until the
94 // returned Subscription is destroyed, which must occur before the
95 // CallbackRegistry is destroyed.
96 scoped_ptr<Subscription> Add(const CallbackType& cb) {
97 DCHECK(!cb.is_null());
98 return scoped_ptr<Subscription>(
99 new Subscription(this, callbacks_.insert(callbacks_.end(), cb)));
100 }
101
102 protected:
103 // An iterator class that can be used to access the list of callbacks.
104 class Iterator {
105 public:
106 explicit Iterator(CallbackRegistryBase<CallbackType>* list)
107 : list_(list),
108 list_iter_(list_->callbacks_.begin()) {
109 ++list_->active_iterator_count_;
110 }
111
112 Iterator(const Iterator& iter)
113 : list_(iter.list_),
114 list_iter_(iter.list_iter_) {
115 ++list_->active_iterator_count_;
116 }
117
118 ~Iterator() {
119 if (list_ && --list_->active_iterator_count_ == 0) {
120 list_->Compact();
121 }
122 }
123
124 CallbackType* GetNext() {
125 while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null())
126 ++list_iter_;
127
128 CallbackType* cb =
129 list_iter_ != list_->callbacks_.end() ? &(*list_iter_) : NULL;
130 ++list_iter_;
131 return cb;
132 }
133
134 private:
135 CallbackRegistryBase<CallbackType>* list_;
136 typename std::list<CallbackType>::iterator list_iter_;
137 };
138
139 CallbackRegistryBase()
140 : active_iterator_count_(0) {}
141
142 ~CallbackRegistryBase() {
143 DCHECK_EQ(0, active_iterator_count_);
144 DCHECK_EQ(0U, callbacks_.size());
145 }
146
147 // Returns an instance of a CallbackRegistryBase::Iterator which can be used
148 // to run callbacks.
149 Iterator GetIterator() {
150 return Iterator(this);
151 }
152
153 // Compact the list: remove any entries which were NULLed out during
154 // iteration.
155 void Compact() {
156 typename std::list<CallbackType>::iterator it = callbacks_.begin();
157 while (it != callbacks_.end()) {
158 if ((*it).is_null())
159 it = callbacks_.erase(it);
160 else
161 ++it;
162 }
163 }
164
165 private:
166 std::list<CallbackType> callbacks_;
167 int active_iterator_count_;
168
169 DISALLOW_COPY_AND_ASSIGN(CallbackRegistryBase);
170 };
171
172 } // namespace internal
173
174 template <typename Details>
175 class CallbackRegistry
176 : public internal::CallbackRegistryBase<Callback<void(const Details&)> > {
177 public:
178 CallbackRegistry() {}
179
180 // Execute all active callbacks with |details| parameter.
181 void Notify(const Details& details) {
182 typename internal::CallbackRegistryBase<
183 Callback<void(const Details&)> >::Iterator it = this->GetIterator();
184 Callback<void(const Details&)>* cb;
185 while((cb = it.GetNext()) != NULL) {
186 cb->Run(details);
187 }
188 }
189
190 private:
191 DISALLOW_COPY_AND_ASSIGN(CallbackRegistry);
192 };
193
194 template <> class CallbackRegistry<void>
195 : public internal::CallbackRegistryBase<Closure> {
196 public:
197 CallbackRegistry() {}
198
199 // Execute all active callbacks.
200 void Notify() {
201 Iterator it = this->GetIterator();
202 Closure* cb;
203 while((cb = it.GetNext()) != NULL) {
204 cb->Run();
205 }
206 }
207
208 private:
209 DISALLOW_COPY_AND_ASSIGN(CallbackRegistry);
210 };
211
212 } // namespace base
213
214 #endif // BASE_CALLBACK_REGISTRY_H_
OLDNEW
« no previous file with comments | « base/base.gypi ('k') | base/callback_registry_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698