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

Side by Side Diff: base/ios/crb_protocol_observers.mm

Issue 1647803004: Move base to DEPS (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 4 years, 10 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
« no previous file with comments | « base/ios/crb_protocol_observers.h ('k') | base/ios/crb_protocol_observers_unittest.mm » ('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 2014 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 #import "base/ios/crb_protocol_observers.h"
6
7 #include <objc/runtime.h>
8 #include <algorithm>
9 #include <vector>
10
11 #include "base/logging.h"
12 #include "base/mac/scoped_nsobject.h"
13
14 @interface CRBProtocolObservers () {
15 base::scoped_nsobject<Protocol> _protocol;
16 // ivars declared here are private to the implementation but must be
17 // public for allowing the C++ |Iterator| class access to those ivars.
18 @public
19 // vector of weak pointers to observers.
20 std::vector<__unsafe_unretained id> _observers;
21 // The nested level of observer iteration.
22 // A depth of 0 means nobody is currently iterating on the list of observers.
23 int _invocationDepth;
24 }
25
26 // Removes nil observers from the list and is called when the
27 // |_invocationDepth| reaches 0.
28 - (void)compact;
29
30 @end
31
32 namespace {
33
34 class Iterator {
35 public:
36 explicit Iterator(CRBProtocolObservers* protocol_observers);
37 ~Iterator();
38 id GetNext();
39
40 private:
41 CRBProtocolObservers* protocol_observers_;
42 size_t index_;
43 size_t max_index_;
44 };
45
46 Iterator::Iterator(CRBProtocolObservers* protocol_observers)
47 : protocol_observers_(protocol_observers),
48 index_(0),
49 max_index_(protocol_observers->_observers.size()) {
50 DCHECK(protocol_observers_);
51 ++protocol_observers->_invocationDepth;
52 }
53
54 Iterator::~Iterator() {
55 if (protocol_observers_ && --protocol_observers_->_invocationDepth == 0)
56 [protocol_observers_ compact];
57 }
58
59 id Iterator::GetNext() {
60 if (!protocol_observers_)
61 return nil;
62 auto& observers = protocol_observers_->_observers;
63 // Skip nil elements.
64 size_t max_index = std::min(max_index_, observers.size());
65 while (index_ < max_index && !observers[index_])
66 ++index_;
67 return index_ < max_index ? observers[index_++] : nil;
68 }
69 }
70
71 @interface CRBProtocolObservers ()
72
73 // Designated initializer.
74 - (id)initWithProtocol:(Protocol*)protocol;
75
76 @end
77
78 @implementation CRBProtocolObservers
79
80 + (instancetype)observersWithProtocol:(Protocol*)protocol {
81 return [[[self alloc] initWithProtocol:protocol] autorelease];
82 }
83
84 - (id)init {
85 NOTREACHED();
86 return nil;
87 }
88
89 - (id)initWithProtocol:(Protocol*)protocol {
90 self = [super init];
91 if (self) {
92 _protocol.reset([protocol retain]);
93 }
94 return self;
95 }
96
97 - (Protocol*)protocol {
98 return _protocol.get();
99 }
100
101 - (void)addObserver:(id)observer {
102 DCHECK(observer);
103 DCHECK([observer conformsToProtocol:self.protocol]);
104
105 if (std::find(_observers.begin(), _observers.end(), observer) !=
106 _observers.end())
107 return;
108
109 _observers.push_back(observer);
110 }
111
112 - (void)removeObserver:(id)observer {
113 DCHECK(observer);
114 auto it = std::find(_observers.begin(), _observers.end(), observer);
115 if (it != _observers.end()) {
116 if (_invocationDepth)
117 *it = nil;
118 else
119 _observers.erase(it);
120 }
121 }
122
123 - (BOOL)empty {
124 int count = 0;
125 for (id observer : _observers) {
126 if (observer != nil)
127 ++count;
128 }
129 return count == 0;
130 }
131
132 #pragma mark - NSObject
133
134 - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector {
135 NSMethodSignature* signature = [super methodSignatureForSelector:selector];
136 if (signature)
137 return signature;
138
139 // Look for a required method in the protocol. protocol_getMethodDescription
140 // returns a struct whose fields are null if a method for the selector was
141 // not found.
142 struct objc_method_description description =
143 protocol_getMethodDescription(self.protocol, selector, YES, YES);
144 if (description.types)
145 return [NSMethodSignature signatureWithObjCTypes:description.types];
146
147 // Look for an optional method in the protocol.
148 description = protocol_getMethodDescription(self.protocol, selector, NO, YES);
149 if (description.types)
150 return [NSMethodSignature signatureWithObjCTypes:description.types];
151
152 // There is neither a required nor optional method with this selector in the
153 // protocol, so invoke -[NSObject doesNotRecognizeSelector:] to raise
154 // NSInvalidArgumentException.
155 [self doesNotRecognizeSelector:selector];
156 return nil;
157 }
158
159 - (void)forwardInvocation:(NSInvocation*)invocation {
160 DCHECK(invocation);
161 if (_observers.empty())
162 return;
163 SEL selector = [invocation selector];
164 Iterator it(self);
165 id observer;
166 while ((observer = it.GetNext()) != nil) {
167 if ([observer respondsToSelector:selector])
168 [invocation invokeWithTarget:observer];
169 }
170 }
171
172 - (void)executeOnObservers:(ExecutionWithObserverBlock)callback {
173 DCHECK(callback);
174 if (_observers.empty())
175 return;
176 Iterator it(self);
177 id observer;
178 while ((observer = it.GetNext()) != nil)
179 callback(observer);
180 }
181
182 #pragma mark - Private
183
184 - (void)compact {
185 DCHECK(!_invocationDepth);
186 _observers.erase(std::remove(_observers.begin(), _observers.end(), nil),
187 _observers.end());
188 }
189
190 @end
OLDNEW
« no previous file with comments | « base/ios/crb_protocol_observers.h ('k') | base/ios/crb_protocol_observers_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698