]> git.wincent.com - WOTest.git/blob - WOEnumerate.h
Fix object-to-pointer comparisons on Leopard
[WOTest.git] / WOEnumerate.h
1 //
2 //  WOEnumerate.h
3 //  WOTest (imported from WODebug 28 January 2006)
4 //
5 //  Created by Wincent Colaiuta on 12 October 2004.
6 //
7 //  Copyright 2004-2006 Wincent Colaiuta.
8 //  This program is distributed in the hope that it will be useful, but WITHOUT
9 //  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 //  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11 //  in the accompanying file, "LICENSE.txt", for more details.
12 //
13
14 //! \file WOEnumerate.h
15
16 // don't attempt to redefine macro (for example, may already be defined by WOCommon)
17 #ifndef WO_ENUMERATE
18
19 /*! WO_ENUMERATE is a convenience macro for expressing the Objective-C enumerator idiom in more compact form. Instead of the standard, longer form:
20
21 <pre>NSEnumerator *enumerator = [collection objectEnumerator];
22 id object = nil;
23 while ((object = [enumerator nextObject]))
24 NSLog(@"Object: %@", object);</pre>
25
26 The following, shorter form can be used:
27
28 <pre>WO_ENUMERATE(collection, object)
29 NSLog(@"Object: %@", object);</pre>
30
31 Or for those that prefer a Perl-like syntax:
32
33 <pre>foreach (object, collection)
34 NSLog(@"Object: %@", object);</pre>
35
36 The WO_ENUMERATE macro is also considerably faster than the standard form because is uses a cached IMP (implementation pointer) and selector to speed up repeated invocations of the <tt>nextObject</tt> selector. In informal testing (enumerating over a 10,000,000-item array ten times) the macro performed 49% faster than the standard idiom (averaging 3.6 million objects per second compared with 2.4 million per second).
37
38 If passed a nil pointer instead of a valid collection, no iterations are performed. If passed an object which does not respond to the objectEnumerator selector then an exception is raised. Both of these behaviours match the pattern of the standard idiom.
39
40 Note that the compiler C dialect must be set to C99 or GNU99 in order to use this macro because of the initialization of variables inside the for expression.
41
42 \see  http://mjtsai.com/blog/2003/12/08/cocoa_enumeration and http://rentzsch.com/papers/improvingCocoaObjCEnumeration
43
44 */
45 #define WO_ENUMERATE(collection, object)                                                                                        \
46 for (id WOMacroEnumerator_ ## object    = [collection objectEnumerator],                                                        \
47      WOMacroSelector_ ## object         = (id)@selector(nextObject),                                                            \
48      WOMacroMethod_ ## object           = (id)[WOMacroEnumerator_ ## object methodForSelector:(SEL)WOMacroSelector_ ## object], \
49      object                             = WOMacroEnumerator_ ## object ?                                                        \
50      ((IMP)WOMacroMethod_ ## object)(WOMacroEnumerator_ ## object, (SEL)WOMacroSelector_ ## object) : nil;                   \
51      object != nil;                                                                                                             \
52      object = ((IMP)WOMacroMethod_ ## object)(WOMacroEnumerator_ ## object, (SEL)WOMacroSelector_ ## object))
53
54 /*! Perl-like syntax for WO_ENUMERATE. */
55 #define foreach(object, collection) WO_ENUMERATE(collection, object)
56
57 #endif /* WO_ENUMERATE */
58
59 #ifndef WO_REVERSE_ENUMERATE
60
61 #define WO_REVERSE_ENUMERATE(collection, object)                                                                                \
62 for (id WOMacroEnumerator_ ## object    = [collection reverseObjectEnumerator],                                                 \
63      WOMacroSelector_ ## object         = (id)@selector(nextObject),                                                            \
64      WOMacroMethod_ ## object           = (id)[WOMacroEnumerator_ ## object methodForSelector:(SEL)WOMacroSelector_ ## object], \
65      object = WOMacroEnumerator_ ## object ?                                                                                    \
66      ((IMP)WOMacroMethod_ ## object)(WOMacroEnumerator_ ## object,(SEL)WOMacroSelector_ ## object) : nil;                    \
67      object != nil;                                                                                                             \
68      object = ((IMP)WOMacroMethod_ ## object)(WOMacroEnumerator_ ## object, (SEL)WOMacroSelector_ ## object))
69
70 #endif /* WO_REVERSE_ENUMERATE */
71
72 #ifndef WO_KEY_ENUMERATE
73
74 #define WO_KEY_ENUMERATE(collection, key)                                                                               \
75 for (id WOMacroEnumerator_ ## key   = [collection keyEnumerator],                                                       \
76      WOMacroSelector_ ## key        = (id)@selector(nextObject),                                                        \
77      WOMacroMethod_ ## key          = (id)[WOMacroEnumerator_ ## key methodForSelector:(SEL)WOMacroSelector_ ## key],   \
78      key = WOMacroEnumerator_ ## key ?                                                                                  \
79      ((IMP)WOMacroMethod_ ## key)(WOMacroEnumerator_ ## key, (SEL)WOMacroSelector_ ## key) : nil;                    \
80      key != nil;                                                                                                        \
81      key = ((IMP)WOMacroMethod_ ## key)(WOMacroEnumerator_ ## key, (SEL)WOMacroSelector_ ## key))
82
83 /*! Perl-like syntax for WO_KEY_ENUMERATE. */
84 #define foreachkey(key, collection) WO_KEY_ENUMERATE(collection, key)
85
86 #endif /* WO_KEY_ENUMERATE */