PageRenderTime 100ms CodeModel.GetById 12ms app.highlight 84ms RepoModel.GetById 1ms app.codeStats 0ms

/core/externals/google-toolbox-for-mac/Foundation/GTMNSEnumerator+Filter.m

http://macfuse.googlecode.com/
Objective C | 221 lines | 151 code | 22 blank | 48 comment | 5 complexity | 5509bba325587b220677502c62c1ec04 MD5 | raw file
  1//
  2//  GTMNSEnumerator+Filter.m
  3//
  4//  Copyright 2007-2009 Google Inc.
  5//
  6//  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  7//  use this file except in compliance with the License.  You may obtain a copy
  8//  of the License at
  9//
 10//  http://www.apache.org/licenses/LICENSE-2.0
 11//
 12//  Unless required by applicable law or agreed to in writing, software
 13//  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 14//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 15//  License for the specific language governing permissions and limitations under
 16//  the License.
 17//
 18
 19#import "GTMNSEnumerator+Filter.h"
 20#import "GTMDebugSelectorValidation.h"
 21#import "GTMDefines.h"
 22#if GTM_IPHONE_SDK
 23#import <objc/message.h>
 24#import <objc/runtime.h>
 25#else
 26#import <objc/objc-runtime.h>
 27#endif
 28
 29// a private subclass of NSEnumerator that does all the work.
 30// public interface just returns one of these.
 31// This top level class contains all the additional boilerplate. Specific
 32// behavior is in the subclasses.
 33@interface GTMEnumeratorPrivateBase : NSEnumerator {
 34 @protected
 35  NSEnumerator *base_;
 36  SEL operation_; // either a predicate or a transform depending on context.
 37  id target_;  // may be nil
 38  id object_;  // may be nil
 39}
 40@end
 41
 42@interface GTMEnumeratorPrivateBase (SubclassesMustProvide)
 43- (BOOL)filterObject:(id)obj returning:(id *)resultp;
 44@end
 45
 46@implementation GTMEnumeratorPrivateBase
 47- (id)initWithBase:(NSEnumerator *)base
 48               sel:(SEL)filter
 49            target:(id)optionalTarget
 50            object:(id)optionalOther {
 51  self = [super init];
 52  if (self) {
 53
 54    // someone would have to subclass or directly create an object of this
 55    // class, and this class is private to this impl.
 56    _GTMDevAssert(base, @"can't initWithBase: a nil base enumerator");
 57    base_ = [base retain];
 58    operation_ = filter;
 59    target_ = [optionalTarget retain];
 60    object_ = [optionalOther retain];
 61  }
 62  return self;
 63}
 64
 65// we don't provide an init because this base class is private to this
 66// impl, and no one would be able to create it (if they do, they get whatever
 67// they happens...).
 68
 69- (void)dealloc {
 70  [base_ release];
 71  [target_ release];
 72  [object_ release];
 73  [super dealloc];
 74}
 75
 76- (id)nextObject {
 77  for (id obj = [base_ nextObject]; obj; obj = [base_ nextObject]) {
 78    id result = nil;
 79    if ([self filterObject:obj returning:&result]) {
 80      return result;
 81    }
 82  }
 83  return nil;
 84}
 85@end
 86
 87// a transformer, for each item in the enumerator, returns a f(item).
 88@interface GTMEnumeratorTransformer : GTMEnumeratorPrivateBase
 89@end
 90@implementation GTMEnumeratorTransformer
 91- (BOOL)filterObject:(id)obj returning:(id *)resultp {
 92  *resultp = [obj performSelector:operation_ withObject:object_];
 93  return nil != *resultp;
 94}
 95@end
 96
 97// a transformer, for each item in the enumerator, returns a f(item).
 98// a target transformer swaps the target and the argument.
 99@interface GTMEnumeratorTargetTransformer : GTMEnumeratorPrivateBase
100@end
101@implementation GTMEnumeratorTargetTransformer
102- (BOOL)filterObject:(id)obj returning:(id *)resultp {
103  *resultp = [target_ performSelector:operation_
104                           withObject:obj
105                           withObject:object_];
106  return nil != *resultp;
107}
108@end
109
110// a filter, for each item in the enumerator, if(f(item)) { returns item. }
111@interface GTMEnumeratorFilter : GTMEnumeratorPrivateBase
112@end
113@implementation GTMEnumeratorFilter
114// We must take care here, since Intel leaves junk in high bytes of return
115// register for predicates that return BOOL.
116// For details see:
117// http://developer.apple.com/legacy/mac/library/documentation/MacOSX/Conceptual/universal_binary/universal_binary_tips/universal_binary_tips.html#//apple_ref/doc/uid/TP40002217-CH239-280661
118// and
119// http://www.red-sweater.com/blog/320/abusing-objective-c-with-class#comment-83187
120- (BOOL)filterObject:(id)obj returning:(id *)resultp {
121  *resultp = obj;
122  return ((BOOL (*)(id, SEL, id))objc_msgSend)(obj, operation_, object_);
123}
124@end
125
126// a target filter, for each item in the enumerator, if(f(item)) { returns item. }
127// a target transformer swaps the target and the argument.
128@interface GTMEnumeratorTargetFilter : GTMEnumeratorPrivateBase
129@end
130@implementation GTMEnumeratorTargetFilter
131// We must take care here, since Intel leaves junk in high bytes of return
132// register for predicates that return BOOL.
133// For details see:
134// http://developer.apple.com/legacy/mac/library/documentation/MacOSX/Conceptual/universal_binary/universal_binary_tips/universal_binary_tips.html#//apple_ref/doc/uid/TP40002217-CH239-280661
135// and
136// http://www.red-sweater.com/blog/320/abusing-objective-c-with-class#comment-83187
137- (BOOL)filterObject:(id)obj returning:(id *)resultp {
138  *resultp = obj;
139  return ((BOOL (*)(id, SEL, id, id))objc_msgSend)(target_, operation_, obj, object_);
140}
141@end
142
143@implementation NSEnumerator (GTMEnumeratorFilterAdditions)
144
145- (NSEnumerator *)gtm_filteredEnumeratorByMakingEachObjectPerformSelector:(SEL)selector
146                                                               withObject:(id)argument {
147  return [[[GTMEnumeratorFilter alloc] initWithBase:self
148                                                sel:selector
149                                             target:nil
150                                             object:argument] autorelease];
151}
152
153- (NSEnumerator *)gtm_enumeratorByMakingEachObjectPerformSelector:(SEL)selector
154                                                       withObject:(id)argument {
155  return [[[GTMEnumeratorTransformer alloc] initWithBase:self
156                                                     sel:selector
157                                                  target:nil
158                                                  object:argument] autorelease];
159}
160
161
162- (NSEnumerator *)gtm_filteredEnumeratorByTarget:(id)target
163                           performOnEachSelector:(SEL)predicate {
164  // make sure the object impls this selector taking an object as an arg.
165  GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(target, predicate,
166                                                              @encode(BOOL),
167                                                              @encode(id),
168                                                              NULL);
169  return [[[GTMEnumeratorTargetFilter alloc] initWithBase:self
170                                                      sel:predicate
171                                                   target:target
172                                                   object:nil] autorelease];
173}
174
175- (NSEnumerator *)gtm_filteredEnumeratorByTarget:(id)target
176                           performOnEachSelector:(SEL)predicate
177                                      withObject:(id)object {
178  // make sure the object impls this selector taking an object as an arg.
179  GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(target, predicate,
180                                                              @encode(BOOL),
181                                                              @encode(id),
182                                                              @encode(id),
183                                                              NULL);
184  return [[[GTMEnumeratorTargetFilter alloc] initWithBase:self
185                                                      sel:predicate
186                                                   target:target
187                                                   object:object] autorelease];
188}
189
190- (NSEnumerator *)gtm_enumeratorByTarget:(id)target
191                   performOnEachSelector:(SEL)selector {
192  // make sure the object impls this selector taking an object as an arg.
193  GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(target, selector,
194                                                              @encode(id),
195                                                              @encode(id),
196                                                              NULL);
197  return [[[GTMEnumeratorTargetTransformer alloc] initWithBase:self
198                                                           sel:selector
199                                                        target:target
200                                                        object:nil]
201          autorelease];
202}
203
204- (NSEnumerator *)gtm_enumeratorByTarget:(id)target
205                   performOnEachSelector:(SEL)selector
206                              withObject:(id)object {
207  // make sure the object impls this selector taking an object as an arg.
208  GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(target, selector,
209                                                              @encode(id),
210                                                              @encode(id),
211                                                              @encode(id),
212                                                              NULL);
213  return [[[GTMEnumeratorTargetTransformer alloc] initWithBase:self
214                                                           sel:selector
215                                                        target:target
216                                                        object:object]
217          autorelease];
218}
219
220@end
221