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

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: 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::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_();
awong 2013/09/06 23:49:30 nit: callback_registry_(); -> callback_registry_;
Cait (Slow) 2013/09/09 18:46:53 Done.
42 // };
43 //
44 //
45 // class MyWidgetListener {
46 // public:
47 // MyWidgetListener::MyWidgetListener() {
48 // foo_callback_handle_ = 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) {
58 // // Do something.
59 // }
60 //
61 // private:
62 // scoped_ptr<base::Subscription> foo_callback_handle_;
awong 2013/09/06 23:49:30 foo_callback_handle_ -> foo_subscription_
Cait (Slow) 2013/09/09 18:46:53 Done.
63 // };
64
65 namespace base {
66
67 class Subscription {
awong 2013/09/06 23:49:30 base::Subscription is too general a name but befor
erikwright (departed) 2013/09/09 16:24:34 Anyone managing more than one subscription will, i
awong 2013/09/09 17:19:28 If there's only one expected user, I am weary of a
68 public:
69 virtual ~Subscription() {}
70 protected:
71 Subscription() {}
72 };
73
74 namespace internal {
75 // Holds the methods shared by all specializations of CallbackRegistry to avoid
76 // code duplication.
77 //
78 // This class is meant as an implementation detail for CallbackRegistry. Do not
awong 2013/09/06 23:49:30 This sentence is implied by base::internal. Can be
Cait (Slow) 2013/09/09 18:46:53 Done.
79 // use it directly.
80 template <typename CallbackType>
81 class CallbackRegistryBase {
82 public:
83 // Add a callback to the list. The callback will remain registered until the
84 // returned Subscription is destroyed, which must occur before the
85 // CallbackRegistry is destroyed.
86 scoped_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT {
87 DCHECK(!cb.is_null());
88 typename ListType::iterator it = callbacks_.insert(callbacks_.end(), cb);
89 return scoped_ptr<Subscription>(new SubscriptionImpl(this, it));
90 }
91
92 protected:
93 typedef std::list<CallbackType> ListType;
94
95 // An iterator class that can be used to access the list of callbacks.
96 class Iterator {
97 public:
98 explicit Iterator(CallbackRegistryBase<CallbackType>* list)
99 : list_(list),
100 list_iter_(list_->callbacks_.begin()) {
101 ++list_->active_iterator_count_;
102 }
103
104 Iterator(const Iterator& iter)
105 : list_(iter.list_),
106 list_iter_(iter.list_iter_) {
107 ++list_->active_iterator_count_;
108 }
109
110 ~Iterator() {
111 if (list_ && --list_->active_iterator_count_ == 0) {
112 list_->Compact();
113 }
114 }
115
116 CallbackType* GetNext() {
117 while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null())
118 list_iter_++;
119
120 CallbackType* cb =
121 list_iter_ != list_->callbacks_.end() ? &(*list_iter_) : NULL;
122 list_iter_++;
123 return cb;
124 }
125
126 private:
127 CallbackRegistryBase<CallbackType>* list_;
128 typename ListType::iterator list_iter_;
129 };
130
131 CallbackRegistryBase()
132 : active_iterator_count_(0) {}
133
134 ~CallbackRegistryBase() {
135 DCHECK(active_iterator_count_ == 0);
136 DCHECK(callbacks_.size() == 0);
137 }
138
139 // Returns an instance of a CallbackRegistryBase::Iterator which can be used
140 // to run callbacks.
141 Iterator GetIterator() {
142 return Iterator(this);
143 }
144
145 // Compact the list: remove any entries which were NULLed out during
146 // iteration.
147 void Compact() {
148 typename ListType::iterator it = callbacks_.begin();
149 while (it != callbacks_.end()) {
150 if ((*it).is_null())
151 it = callbacks_.erase(it);
152 else
153 ++it;
154 }
155 }
156
157 private:
158 class SubscriptionImpl : public Subscription {
159 public:
160 SubscriptionImpl(
awong 2013/09/06 23:49:30 nit: The parameters should be able to align with t
Cait (Slow) 2013/09/09 18:46:53 Done.
161 CallbackRegistryBase<CallbackType>* list,
162 typename ListType::iterator iter)
163 : list_(list),
164 iter_(iter) {}
165
166 ~SubscriptionImpl() {
167 if (list_->active_iterator_count_)
168 (*iter_).Reset();
169 else
170 list_->callbacks_.erase(iter_);
171 }
172
173 private:
174 CallbackRegistryBase<CallbackType>* list_;
175 typename ListType::iterator iter_;
176
177 DISALLOW_COPY_AND_ASSIGN(SubscriptionImpl);
178 };
179
180 ListType callbacks_;
181 int active_iterator_count_;
182
183 DISALLOW_COPY_AND_ASSIGN(CallbackRegistryBase);
184 };
185
186 } // namespace internal
187
188 template <typename Details>
189 class CallbackRegistry
190 : public base::internal::CallbackRegistryBase<
awong 2013/09/09 17:19:28 base:: is overqualified here. We're already in ba
Cait (Slow) 2013/09/09 18:46:53 Done.
191 Callback<void(const Details&)> > {
awong 2013/09/06 23:49:30 nit: should indent 2 more spaces.
Cait (Slow) 2013/09/09 18:46:53 Done.
192 public:
193 typedef typename base::internal::CallbackRegistryBase<
194 base::Callback<void(const Details&)> >::Iterator Iterator;
awong 2013/09/06 23:49:30 If removing this doesn't compile, why does it work
awong 2013/09/06 23:49:30 You seemed to be able to remove this for CallbackR
erikwright (departed) 2013/09/09 16:18:01 That's because, here, the base class is dependent
awong 2013/09/09 17:19:28 Ah right...it's that stupid 2-phase dependant look
195 CallbackRegistry() {}
196
197 // Execute all active callbacks with |details| parameter.
198 void Notify(const Details& details) {
199 Iterator it = this->GetIterator();
awong 2013/09/09 17:19:28 There's only one use of the typedef here. At the
Cait (Slow) 2013/09/09 18:46:53 Done.
200 base::Callback<void(const Details&)>* cb;
201 while((cb = it.GetNext()) != NULL) {
202 cb->Run(details);
203 }
204 }
205
206 private:
207 DISALLOW_COPY_AND_ASSIGN(CallbackRegistry);
208 };
209
210 template <> class CallbackRegistry<void>
211 : public base::internal::CallbackRegistryBase<Closure> {
212 public:
213 CallbackRegistry() {}
214
215 // Execute all active callbacks.
216 void Notify() {
217 Iterator it = this->GetIterator();
218 Closure* cb;
219 while((cb = it.GetNext()) != NULL) {
220 cb->Run();
221 }
222 }
223
224 private:
225 DISALLOW_COPY_AND_ASSIGN(CallbackRegistry);
226 };
227
228 } // namespace base
229
230 #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