/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. #import "GTMNSEnumerator+Filter.h"
  19. #import "GTMDebugSelectorValidation.h"
  20. #import "GTMDefines.h"
  21. #if GTM_IPHONE_SDK
  22. #import <objc/message.h>
  23. #import <objc/runtime.h>
  24. #else
  25. #import <objc/objc-runtime.h>
  26. #endif
  27. // a private subclass of NSEnumerator that does all the work.
  28. // public interface just returns one of these.
  29. // This top level class contains all the additional boilerplate. Specific
  30. // behavior is in the subclasses.
  31. @interface GTMEnumeratorPrivateBase : NSEnumerator {
  32. @protected
  33. NSEnumerator *base_;
  34. SEL operation_; // either a predicate or a transform depending on context.
  35. id target_; // may be nil
  36. id object_; // may be nil
  37. }
  38. @end
  39. @interface GTMEnumeratorPrivateBase (SubclassesMustProvide)
  40. - (BOOL)filterObject:(id)obj returning:(id *)resultp;
  41. @end
  42. @implementation GTMEnumeratorPrivateBase
  43. - (id)initWithBase:(NSEnumerator *)base
  44. sel:(SEL)filter
  45. target:(id)optionalTarget
  46. object:(id)optionalOther {
  47. self = [super init];
  48. if (self) {
  49. // someone would have to subclass or directly create an object of this
  50. // class, and this class is private to this impl.
  51. _GTMDevAssert(base, @"can't initWithBase: a nil base enumerator");
  52. base_ = [base retain];
  53. operation_ = filter;
  54. target_ = [optionalTarget retain];
  55. object_ = [optionalOther retain];
  56. }
  57. return self;
  58. }
  59. // we don't provide an init because this base class is private to this
  60. // impl, and no one would be able to create it (if they do, they get whatever
  61. // they happens...).
  62. - (void)dealloc {
  63. [base_ release];
  64. [target_ release];
  65. [object_ release];
  66. [super dealloc];
  67. }
  68. - (id)nextObject {
  69. for (id obj = [base_ nextObject]; obj; obj = [base_ nextObject]) {
  70. id result = nil;
  71. if ([self filterObject:obj returning:&result]) {
  72. return result;
  73. }
  74. }
  75. return nil;
  76. }
  77. @end
  78. // a transformer, for each item in the enumerator, returns a f(item).
  79. @interface GTMEnumeratorTransformer : GTMEnumeratorPrivateBase
  80. @end
  81. @implementation GTMEnumeratorTransformer
  82. - (BOOL)filterObject:(id)obj returning:(id *)resultp {
  83. *resultp = [obj performSelector:operation_ withObject:object_];
  84. return nil != *resultp;
  85. }
  86. @end
  87. // a transformer, for each item in the enumerator, returns a f(item).
  88. // a target transformer swaps the target and the argument.
  89. @interface GTMEnumeratorTargetTransformer : GTMEnumeratorPrivateBase
  90. @end
  91. @implementation GTMEnumeratorTargetTransformer
  92. - (BOOL)filterObject:(id)obj returning:(id *)resultp {
  93. *resultp = [target_ performSelector:operation_
  94. withObject:obj
  95. withObject:object_];
  96. return nil != *resultp;
  97. }
  98. @end
  99. // a filter, for each item in the enumerator, if(f(item)) { returns item. }
  100. @interface GTMEnumeratorFilter : GTMEnumeratorPrivateBase
  101. @end
  102. @implementation GTMEnumeratorFilter
  103. // We must take care here, since Intel leaves junk in high bytes of return
  104. // register for predicates that return BOOL.
  105. // For details see:
  106. // 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
  107. // and
  108. // http://www.red-sweater.com/blog/320/abusing-objective-c-with-class#comment-83187
  109. - (BOOL)filterObject:(id)obj returning:(id *)resultp {
  110. *resultp = obj;
  111. return ((BOOL (*)(id, SEL, id))objc_msgSend)(obj, operation_, object_);
  112. }
  113. @end
  114. // a target filter, for each item in the enumerator, if(f(item)) { returns item. }
  115. // a target transformer swaps the target and the argument.
  116. @interface GTMEnumeratorTargetFilter : GTMEnumeratorPrivateBase
  117. @end
  118. @implementation GTMEnumeratorTargetFilter
  119. // We must take care here, since Intel leaves junk in high bytes of return
  120. // register for predicates that return BOOL.
  121. // For details see:
  122. // 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
  123. // and
  124. // http://www.red-sweater.com/blog/320/abusing-objective-c-with-class#comment-83187
  125. - (BOOL)filterObject:(id)obj returning:(id *)resultp {
  126. *resultp = obj;
  127. return ((BOOL (*)(id, SEL, id, id))objc_msgSend)(target_, operation_, obj, object_);
  128. }
  129. @end
  130. @implementation NSEnumerator (GTMEnumeratorFilterAdditions)
  131. - (NSEnumerator *)gtm_filteredEnumeratorByMakingEachObjectPerformSelector:(SEL)selector
  132. withObject:(id)argument {
  133. return [[[GTMEnumeratorFilter alloc] initWithBase:self
  134. sel:selector
  135. target:nil
  136. object:argument] autorelease];
  137. }
  138. - (NSEnumerator *)gtm_enumeratorByMakingEachObjectPerformSelector:(SEL)selector
  139. withObject:(id)argument {
  140. return [[[GTMEnumeratorTransformer alloc] initWithBase:self
  141. sel:selector
  142. target:nil
  143. object:argument] autorelease];
  144. }
  145. - (NSEnumerator *)gtm_filteredEnumeratorByTarget:(id)target
  146. performOnEachSelector:(SEL)predicate {
  147. // make sure the object impls this selector taking an object as an arg.
  148. GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(target, predicate,
  149. @encode(BOOL),
  150. @encode(id),
  151. NULL);
  152. return [[[GTMEnumeratorTargetFilter alloc] initWithBase:self
  153. sel:predicate
  154. target:target
  155. object:nil] autorelease];
  156. }
  157. - (NSEnumerator *)gtm_filteredEnumeratorByTarget:(id)target
  158. performOnEachSelector:(SEL)predicate
  159. withObject:(id)object {
  160. // make sure the object impls this selector taking an object as an arg.
  161. GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(target, predicate,
  162. @encode(BOOL),
  163. @encode(id),
  164. @encode(id),
  165. NULL);
  166. return [[[GTMEnumeratorTargetFilter alloc] initWithBase:self
  167. sel:predicate
  168. target:target
  169. object:object] autorelease];
  170. }
  171. - (NSEnumerator *)gtm_enumeratorByTarget:(id)target
  172. performOnEachSelector:(SEL)selector {
  173. // make sure the object impls this selector taking an object as an arg.
  174. GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(target, selector,
  175. @encode(id),
  176. @encode(id),
  177. NULL);
  178. return [[[GTMEnumeratorTargetTransformer alloc] initWithBase:self
  179. sel:selector
  180. target:target
  181. object:nil]
  182. autorelease];
  183. }
  184. - (NSEnumerator *)gtm_enumeratorByTarget:(id)target
  185. performOnEachSelector:(SEL)selector
  186. withObject:(id)object {
  187. // make sure the object impls this selector taking an object as an arg.
  188. GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(target, selector,
  189. @encode(id),
  190. @encode(id),
  191. @encode(id),
  192. NULL);
  193. return [[[GTMEnumeratorTargetTransformer alloc] initWithBase:self
  194. sel:selector
  195. target:target
  196. object:object]
  197. autorelease];
  198. }
  199. @end