Removing two commented out lines.
[hom.git] / Source / DPCollectionEnumeration.h
blob3a25b1fe7be8829237f01dca986b82b0e2544c32
1 //
2 // DPCollectionEnumeration.h
3 // HigherOrderMessaging
4 //
5 // Created by Ofri Wolfus on 11/05/07.
6 // Copyright 2007 Ofri Wolfus. All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without modification,
9 // are permitted provided that the following conditions are met:
10 //
11 // 1. Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // 2. Redistributions in binary form must reproduce the above copyright
14 // notice, this list of conditions and the following disclaimer in the
15 // documentation and/or other materials provided with the distribution.
16 // 3. Neither the name of Ofri Wolfus nor the names of his contributors
17 // may be used to endorse or promote products derived from this software
18 // without specific prior written permission.
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #import <Foundation/Foundation.h>
33 #if defined(__HOM_FRAMEWORK__)
34 #import <HigherOrderMessaging/DPObjCRuntime.h>
35 #elif defined(__UITESTINGKIT__)
36 #import <UITestingKit/DPObjCRuntime.h>
37 #else
38 #import "DPObjCRuntime.h" // For DP_EXTERN
39 #endif
41 #if defined(__HOM_FRAMEWORK__)
42 #import <HigherOrderMessaging/DPMessage.h>
43 #else
44 #import "DPMessage.h"
45 #endif
48 typedef struct DPEnumerationState DPEnumerationState;
51 * A callback function invoked before an enumeration is completed.
52 * This function is responsible of releasing the info and items field,
53 * and perform any other needed cleanups.
55 typedef void (*DPEnumeratioStateReleaseCallBack) (DPEnumerationState *state);
57 struct DPEnumerationState {
58 // The state of the enumeration, usually an index.
59 // Each call to enumerateWithState:objects:count: should
60 // read the state and update it to the new one.
61 unsigned long state;
62 // A buffer to the items of the collection. By default,
63 // the buffer points to the same buffer passed by
64 // enumerateWithState:objects:count:. If the collection
65 // doesn't use that buffer, it is responsible for setting
66 // the items poiner to its own buffer. The buffer should
67 // be released by the release callback function.
68 id *items;
69 // A private info used by the collection. The collection
70 // free to do whatever it wants with it.
71 void *info;
72 // A release callback for the info field and the objects
73 // buffer if the collection created it. The first call (when
74 // state == 0) to enumerateWithState:objects:count: is
75 // responsible for setting the release callback if needed.
76 DPEnumeratioStateReleaseCallBack release;
79 /*!
80 * @abstract A protocol defining a collection-independent
81 * fast enumeration.
83 @protocol DPEnumeration
85 /*!
86 * @abstract Given a state and a buffer of objects, this method
87 * returns the next bunch of objects from the receiver.
89 * @discussion This method is repeatedly called during enumeration
90 * in order to get the next bunch of objects. The collection (the
91 * receiver) is responsible for updating the state of the enumeration.
93 * @param state A pointer to a state structure holding the info of
94 * the enumeration. See above for more info of its fields.
96 * @param buff A buffer for placing the objects from the collection in.
97 * A buffer will must always be provided with this method, but the
98 * collection may choose not to use it and use its own buffer. In this
99 * case the collection is responsible for setting the <code>items</code>
100 * field of the enmeration state to its own buffer.
102 * @param buffLen The amount of objects that fit in the buffer.
104 * @result The number of objects returned by the collection.
106 - (unsigned)enumerateWithState:(DPEnumerationState *)state
107 objects:(id *)buff
108 count:(unsigned)buffLen;
110 @end
114 * @abstract A special enumerator designed for the <code>each</code> method.
116 @interface DPEnumerator : NSObject {
117 void *_reserved;
121 * @abstract Returns an enumerator for a given objects buffer.
123 * @param objects A C array of objects.
124 * @param count The size of the objects array.
125 * @param flag A flag indicating whether the enumerator should
126 * free the objects array when deallocating or not.
128 + (id)enumeratorWithObjects:(id *)objects
129 count:(unsigned)count
130 freeWhenDone:(BOOL)flag;
133 * @abstract Returns a lightweight enumerator for a given array.
135 + (id)enumeratorForArray:(NSArray *)arr;
138 * @abstract Returns an enumerator for a given collection.
140 + (id)enumeratorForCollection:(id <DPEnumeration>)collection;
142 - (id)nextObject;
143 - (NSArray *)allObjects;
145 // The following methods are not supported at this time
146 - (BOOL)isValid;
147 - (unsigned)count;
148 - (void)reset;
150 @end
153 * @abstract A function that's repeatedly called during enumeration to append
154 * objects to the results collection.
156 * @param resultsCollection The collection to append the objects to.
157 * @param state The state of the enumeration.
158 * @param objects An array of objects to append to the collection.
159 * @param count The number of objects in the objects array.
161 typedef void (*DPEnumerationAppendResultsCallBack) (id resultsCollection,
162 DPEnumerationState *state,
163 id *objects,
164 unsigned count);
167 * Generic implementations of the collect:, select/rejectWhere:
168 * and findObjectWhere: methods. Use them only if you're adding
169 * support for a new collection.
171 DP_EXTERN void DPCollectObjects(id <DPEnumeration> collection,
172 id resultsCollection,
173 DPMessage *message,
174 DPEnumerationAppendResultsCallBack callback);
176 DP_EXTERN void DPSelectObjects(id <DPEnumeration> collection,
177 id resultsCollection,
178 DPMessage **messages,
179 unsigned messageCount,
180 BOOL returnValue,
181 DPEnumerationAppendResultsCallBack callback);
183 DP_EXTERN id DPFindObject(id <DPEnumeration> collection,
184 DPMessage **messages,
185 unsigned messageCount,
186 BOOL returnValue);
188 // Returns whether a given pointer is an enumerated argument or not.
189 // It does not involve any message sending or dereferencing the pointer,
190 // so it's safe for use with any "random" pointer.
191 DP_EXTERN_INLINE BOOL DPIsEnumeratedArgument(void *ptr);
195 * @abstract Defines the HOM based enumeration methods.
197 @protocol DPCollectionEnumeration <DPEnumeration>
200 * @abstract Sends the passed message to all objects of the
201 * receiver and returns the results.
203 * @discussion If an object doesn't return an object, or it
204 * returns <code>nil</code>, the result is undefined.
205 * This method supports enumerated arguments returned by the
206 * <code>each</code> method.
208 - (id)collect:(DPMessage *)argumentMessage;
211 * @abstract Returns all objects of the receiver that returned
212 * <code>YES</code> for the last message.
214 * @discussion The messages list must be NULL/nil terminated.
215 * This method supports enumerated arguments returned by the
216 * <code>each</code> method.
218 - (id)selectWhere:(DPMessage *)firstMessage, ...;
221 * @abstract Returns all objects of the receiver that returned
222 * <code>NO</code> for the last message.
224 * @discussion The messages list must be NULL/nil terminated.
225 * This method supports enumerated arguments returned by the
226 * <code>each</code> method.
228 - (id)rejectWhere:(DPMessage *)firstMessage, ...;
231 * @abstract Returns the first object of the receiver that returned
232 * <code>YES</code> for the last message.
234 * @discussion The messages list must be NULL/nil terminated.
235 * This method supports enumerated arguments returned by the
236 * <code>each</code> method.
238 - (id)findObjectWhere:(DPMessage *)firstMessage, ...;
241 * @abstract Returns an enumerated argument that can be passed
242 * to one of the above methods.
244 * @discussion It's also possible to message the returned object
245 * directly, in which case it'll forward the message to all of
246 * its objects.
247 * For more info, please refer to the HOM paper at
248 * http://www.metaobject.com/papers/Higher_Order_Messaging_OOPSLA_2005.pdf
250 - (id)each;
252 @end
254 @interface NSArray (DPCollectionEnumeration) <DPCollectionEnumeration>
255 @end
257 @interface NSSet (DPCollectionEnumeration) <DPCollectionEnumeration>
258 @end
260 @interface NSDictionary (DPCollectionEnumeration) <DPCollectionEnumeration>
261 @end
264 @interface NSObject (DPHOMGoodies)
267 * @abstract Makes the receiver receive the passed message.
268 * @discussion This method accepts enumerated arguments.
269 * This is the equivalent of the <code>do</code> method
270 * described in Marcel's HOM paper.
272 - (id)collect:(DPMessage *)msg;
275 * @abstract Makes the receiver receive the passed message.
276 * @discussion The receiver will receive the passed message,
277 * repeating as many times needed for enumerated arguments.
278 * Upon completion, returns the result of the message or the
279 * result of the last message sent if there were any enumerated
280 * arguments.
282 - (id)receive:(DPMessage *)msg;
285 * @abstract Makes the receiver receive the passed message
286 * only if it responds to it.
288 * @discussion Only object return values are supported.
289 * For other return types the behaviour is undefined.
290 * NOTE: This method does *NOT* support enumerated arguments.
292 - (id)ifResponds:(DPMessage *)msg;
294 @end
298 * And when HOM fails to do what you need, foreach() is always handy :)
299 * In ObjC 1 it'll just send a -objectEnumerator to the collection
300 * while in ObjC 2 it translates to the native for(in) syntax.
302 * Example: foreach (NSString *str, myArr) { [str doSomething]; }
304 #if !__OBJC2__
307 Code taken from CocoaDev. See http://www.cocoadev.com/index.pl?ForallMacro for more details.
308 Modified by Ofri Wolfus.
310 #define foreach(element, collection...) \
311 for(id __foreach_macro_element = nil, __foreach_macro_enumerator = [collection objectEnumerator]; \
312 __foreach_macro_element = !__foreach_macro_element ? [__foreach_macro_enumerator nextObject] : nil;) \
313 for (element = __foreach_macro_element; __foreach_macro_element; __foreach_macro_element = nil)
315 #else
317 // For ObjC 2 we just use the built in for (in) syntax
318 #define foreach(obj, collection...) for(obj in collection)
320 #endif