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

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: ...and clean up 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<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 // 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 // void OnFoo(const Foo& foo) {
erikwright (departed) 2013/09/09 19:56:18 nit: put this in private.
Cait (Slow) 2013/09/09 20:33:03 Done.
58 // // Do something.
59 // }
60 //
61 // private:
62 // scoped_ptr<CallbackRegistry<Foo>::Subscription> foo_subscription_;
63 // };
64
65 namespace base {
66
67 namespace internal {
erikwright (departed) 2013/09/09 19:56:18 blank line between namespace and the implementatio
Cait (Slow) 2013/09/09 20:33:03 Done.
68 // Holds the methods shared by all specializations of CallbackRegistry to avoid
erikwright (departed) 2013/09/09 19:56:18 I'm of the opinion that this comment is unnecessar
awong 2013/09/09 20:04:54 Yeah, you're right. Let's remove it too.
Cait (Slow) 2013/09/09 20:33:03 Done.
69 // code duplication.
70 template <typename CallbackType>
71 class CallbackRegistryBase {
72 public:
73 typedef std::list<CallbackType> ListType;
awong 2013/09/09 19:30:20 Put this typedef in Subscription?
Cait (Slow) 2013/09/09 19:40:31 Done.
74
75 class Subscription {
76 public:
77 Subscription(CallbackRegistryBase<CallbackType>* list,
78 typename ListType::iterator iter)
awong 2013/09/09 19:30:20 nit: indent
Cait (Slow) 2013/09/09 19:40:31 Done.
79 : list_(list),
80 iter_(iter) {}
81
82 ~Subscription() {
83 if (list_->active_iterator_count_)
84 (*iter_).Reset();
85 else
86 list_->callbacks_.erase(iter_);
87 }
88
89 private:
90 CallbackRegistryBase<CallbackType>* list_;
91 typename ListType::iterator iter_;
92
93 DISALLOW_COPY_AND_ASSIGN(Subscription);
94 };
95
96 // Add a callback to the list. The callback will remain registered until the
97 // returned Subscription is destroyed, which must occur before the
98 // CallbackRegistry is destroyed.
99 scoped_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT {
100 DCHECK(!cb.is_null());
101 typename ListType::iterator it = callbacks_.insert(callbacks_.end(), cb);
102 return scoped_ptr<Subscription>(new Subscription(this, it));
103 }
104
105 protected:
106 // An iterator class that can be used to access the list of callbacks.
107 class Iterator {
108 public:
109 explicit Iterator(CallbackRegistryBase<CallbackType>* list)
110 : list_(list),
111 list_iter_(list_->callbacks_.begin()) {
112 ++list_->active_iterator_count_;
113 }
114
115 Iterator(const Iterator& iter)
116 : list_(iter.list_),
117 list_iter_(iter.list_iter_) {
118 ++list_->active_iterator_count_;
119 }
120
121 ~Iterator() {
122 if (list_ && --list_->active_iterator_count_ == 0) {
123 list_->Compact();
124 }
125 }
126
127 CallbackType* GetNext() {
128 while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null())
129 list_iter_++;
erikwright (departed) 2013/09/09 19:56:18 ++list_iter_; ?
Cait (Slow) 2013/09/09 20:33:03 Done.
130
131 CallbackType* cb =
132 list_iter_ != list_->callbacks_.end() ? &(*list_iter_) : NULL;
133 list_iter_++;
erikwright (departed) 2013/09/09 19:56:18 ditto?
Cait (Slow) 2013/09/09 20:33:03 Done.
134 return cb;
135 }
136
137 private:
138 CallbackRegistryBase<CallbackType>* list_;
139 typename ListType::iterator list_iter_;
140 };
141
142 CallbackRegistryBase()
143 : active_iterator_count_(0) {}
144
145 ~CallbackRegistryBase() {
146 DCHECK(active_iterator_count_ == 0);
147 DCHECK(callbacks_.size() == 0);
148 }
149
150 // Returns an instance of a CallbackRegistryBase::Iterator which can be used
151 // to run callbacks.
152 Iterator GetIterator() {
153 return Iterator(this);
154 }
155
156 // Compact the list: remove any entries which were NULLed out during
157 // iteration.
158 void Compact() {
159 typename ListType::iterator it = callbacks_.begin();
160 while (it != callbacks_.end()) {
161 if ((*it).is_null())
162 it = callbacks_.erase(it);
163 else
164 ++it;
165 }
166 }
167
168 private:
169
erikwright (departed) 2013/09/09 19:56:18 remove blank
Cait (Slow) 2013/09/09 20:33:03 Done.
170 ListType callbacks_;
171 int active_iterator_count_;
172
173 DISALLOW_COPY_AND_ASSIGN(CallbackRegistryBase);
174 };
175
176 } // namespace internal
177
178 template <typename Details>
179 class CallbackRegistry
180 : public base::internal::CallbackRegistryBase<
awong 2013/09/09 19:30:20 The base:: still seems to be here.
Cait (Slow) 2013/09/09 19:40:31 Done.
181 Callback<void(const Details&)> > {
182 public:
183 typedef typename base::internal::CallbackRegistryBase<
184 base::Callback<void(const Details&)> >::Iterator Iterator;
awong 2013/09/09 19:30:20 Move the iterator typedef into Notify or just dire
Cait (Slow) 2013/09/09 19:40:31 Done.
185 typedef typename base::internal::CallbackRegistryBase<
186 base::Callback<void(const Details&)> >::Subscription Subscription;
187 CallbackRegistry() {}
188
189 // Execute all active callbacks with |details| parameter.
190 void Notify(const Details& details) {
191 Iterator it = this->GetIterator();
192 base::Callback<void(const Details&)>* cb;
193 while((cb = it.GetNext()) != NULL) {
194 cb->Run(details);
195 }
196 }
197
198 private:
199 DISALLOW_COPY_AND_ASSIGN(CallbackRegistry);
200 };
201
202 template <> class CallbackRegistry<void>
203 : public base::internal::CallbackRegistryBase<Closure> {
204 public:
205 CallbackRegistry() {}
206
207 // Execute all active callbacks.
208 void Notify() {
209 Iterator it = this->GetIterator();
210 Closure* cb;
211 while((cb = it.GetNext()) != NULL) {
212 cb->Run();
213 }
214 }
215
216 private:
217 DISALLOW_COPY_AND_ASSIGN(CallbackRegistry);
218 };
219
220 } // namespace base
221
222 #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