Hello all,

I had some time to spare over the last week or so and put together some
higher-order messaging stuff that seems to work suprisingly well. The
attached patch represents the results of my work, implementing
map, fold and filter for arbitrary collections, both with and without
blocks. Please note:

* While the code is quite generic (with some bits and pieces mostly
  handling the special requirements of NSDictionary and
  NS(Counted|Index)Set), I did tie it into the class hierarchy through
  categories on the specific ETCollection-adopting classes, meaning you
  get -mappedArray, -mappedDictionary, -mappedSet etc. where
  -mappedCollection would have been sufficient. This is somewhat clumsy
  and I think it should be possible to unify this by mixins/traits, but
  I have yet to grasp how to use them.
* The method variants using blocks are only enabled when compiling with
  clang. They seem to work, but I could not do extensive testing because
  I'm still working out some kinks with clang. [0] But if you're not
  using clang, everything should still build and work fine.
* In this implementation, fold works as suggested by David.
* Some (naive) unit tests are included for the forwardInvocation-using
  method variants.
* At least with the GNU runtime, you will have problems with
  ETGetSuperclass() unless you apply the patch I suggested on Thursday
  (or something similar).

As always, I'm soliciting comments, suggestions and criticisms on this,
especially since this is the first bigger chunk of code I'm putting out
for the whole world to see...

Cheers,


Niels
--
[0] E.g.: When compiling with clang I always get a segfault when
    -[NSArray arrayWithObject:] is called.
Index: Frameworks/EtoileFoundation/Source/TestHOM.m
===================================================================
--- Frameworks/EtoileFoundation/Source/TestHOM.m	(revision 0)
+++ Frameworks/EtoileFoundation/Source/TestHOM.m	(revision 0)
@@ -0,0 +1,208 @@
+#import <Foundation/Foundation.h>
+#import <UnitKit/UnitKit.h>
+#import "Macros.h"
+#import "ETCollection+map.h"
+#import "ETCollection+fold.h"
+#import "ETCollection+filter.h"
+
+#define	INPUTS NSArray *inputArray = A(@"foo",@"bar"); \
+	NSDictionary *inputDictionary = D(@"foo",@"one",@"bar",@"two"); \
+	NSSet *inputSet = [NSSet setWithArray: inputArray]; \
+	NSCountedSet *inputCountedSet = [[NSCountedSet alloc] init]; \
+	[inputCountedSet addObject: @"foo"]; \
+	[inputCountedSet addObject: @"bar"]; \
+	[inputCountedSet addObject: @"foo"]; \
+	[inputCountedSet autorelease]; \
+	NSRange r; \
+	r.location=0; \
+	r.length=5; \
+	NSIndexSet *inputIndexSet = [NSIndexSet indexSetWithIndexesInRange: r];
+
+#define MUTABLEINPUTS NSMutableArray *array; \
+	array = [NSMutableArray arrayWithObjects: @"foo",@"bar", nil]; \
+	NSMutableDictionary *dictionary = [NSMutableDictionary \
+	       dictionaryWithObjectsAndKeys: @"foo",@"one",@"bar",@"two",nil];\
+	NSMutableSet *set = [NSMutableSet setWithArray: array]; \
+	NSCountedSet *countedSet = [[NSCountedSet alloc] init]; \
+	[countedSet addObject: @"foo"]; \
+	[countedSet addObject: @"bar"]; \
+	[countedSet addObject: @"foo"]; \
+	[countedSet autorelease]; \
+	int countOfFoo = [countedSet countForObject: @"foo"]; \
+	int countOfBar = [countedSet countForObject: @"bar"]; \
+	NSRange r; \
+	r.location=0; \
+	r.length=5; \
+	NSMutableIndexSet *indexSet = [NSMutableIndexSet \
+	                                       indexSetWithIndexesInRange: r]; \
+	NSIndexSet *origIndexSet = [NSIndexSet indexSetWithIndexesInRange: r]; \
+
+...@interface NSNumber (ETTestHOM)
+...@end
+
+...@implementation NSNumber (ETTestHOM)
+-(NSNumber*)twice
+{
+	int out = [self intValue] * 2;
+	return [NSNumber numberWithInt: out];
+}
+-(NSNumber*)addNumber: (NSNumber*)aNumber
+{
+	int out = [self intValue] + [aNumber intValue];
+	return [NSNumber numberWithInt: out];
+}
+...@end
+
+...@interface NSString (ETTestHOM)
+...@end
+
+...@implementation NSString (ETTestHOM)
+-(id)getNil
+{
+	return nil;
+}
+...@end
+...@interface TestHOM: NSObject <UKTest>
+...@end
+
+...@implementation TestHOM
+
+- (void) testMappedCollection
+{
+	INPUTS
+	NSArray *mappedArray;
+	NSDictionary *mappedDictionary;
+	NSSet *mappedSet;
+	NSCountedSet *mappedCountedSet;
+	NSIndexSet *mappedIndexSet;
+	mappedArray = (NSArray*)[[inputArray mappedArray] uppercaseString];
+	mappedDictionary = (NSDictionary*)[[inputDictionary mappedDictionary]uppercaseString];
+	mappedSet = (NSSet*)[[inputSet mappedSet] uppercaseString];
+	mappedCountedSet = (NSCountedSet*)[[inputCountedSet mappedSet] uppercaseString];
+	mappedIndexSet = (NSIndexSet*)[[inputIndexSet mappedIndexSet] twice];
+	
+	UKTrue([mappedArray containsObject: @"FOO"]);
+	UKTrue([mappedArray containsObject: @"BAR"]);
+	UKFalse([mappedArray containsObject: @"foo"]);
+	UKFalse([mappedArray containsObject: @"bar"]);
+	UKTrue([mappedSet containsObject: @"FOO"]);
+	UKTrue([mappedSet containsObject: @"BAR"]);
+	UKFalse([mappedSet containsObject: @"foo"]);
+	UKFalse([mappedSet containsObject: @"bar"]);
+	UKTrue([mappedCountedSet containsObject: @"FOO"]);
+	UKTrue([mappedCountedSet containsObject: @"BAR"]);
+	UKFalse([mappedCountedSet containsObject: @"foo"]);	
+	UKFalse([mappedCountedSet containsObject: @"bar"]);
+	UKIntsEqual([inputCountedSet countForObject: @"foo"],
+	            [mappedCountedSet countForObject: @"FOO"]);
+	UKIntsEqual([inputCountedSet countForObject: @"bar"],
+	            [mappedCountedSet countForObject: @"BAR"]);
+	
+	NSEnumerator *indexEnumerator = [(NSArray*)inputIndexSet
+	                                      objectEnumerator];
+	FOREACHW(inputIndexSet,number,id,indexEnumerator)
+	{	
+		int input = [(NSNumber*)number intValue];
+		UKTrue([mappedIndexSet containsIndex: input*2]);
+	}
+	UKObjectsEqual([mappedDictionary objectForKey: @"one"],@"FOO");
+	UKObjectsEqual([mappedDictionary objectForKey: @"two"],@"BAR");
+
+	//Test nil substitution.
+	mappedArray = (NSArray*)[[inputArray mappedArray]getNil];
+	UKIntsEqual([inputArray count],[mappedArray count]);
+}
+
+-(void)testMap
+{
+	MUTABLEINPUTS
+	[[array map] uppercaseString];
+	[[dictionary map]uppercaseString];
+	[[set map] uppercaseString];
+	[[countedSet map] uppercaseString];
+	[[indexSet map] twice];
+	
+	UKTrue([array containsObject: @"FOO"]);
+	UKTrue([array containsObject: @"BAR"]);
+	UKFalse([array containsObject: @"foo"]);
+	UKFalse([array containsObject: @"bar"]);
+	UKTrue([set containsObject: @"FOO"]);
+	UKTrue([set containsObject: @"BAR"]);
+	UKFalse([set containsObject: @"foo"]);
+	UKFalse([set containsObject: @"bar"]);
+	UKTrue([countedSet containsObject: @"FOO"]);
+	UKTrue([countedSet containsObject: @"BAR"]);
+	UKFalse([countedSet containsObject: @"foo"]);	
+	UKFalse([countedSet containsObject: @"bar"]);
+	UKIntsEqual(countOfFoo,
+	            [countedSet countForObject: @"FOO"]);
+	UKIntsEqual(countOfBar,
+	            [countedSet countForObject: @"BAR"]);
+	
+	NSEnumerator *indexEnumerator = [(NSArray*)origIndexSet
+	                                      objectEnumerator];
+	FOREACHW(origIndexSet,number,id,indexEnumerator)
+	{	
+		int input = [(NSNumber*)number intValue];
+		UKTrue([indexSet containsIndex: input*2]);
+	}
+	UKObjectsEqual([dictionary objectForKey: @"one"],@"FOO");
+	UKObjectsEqual([dictionary objectForKey: @"two"],@"BAR");
+
+	//Test nil substitution.
+	[[array map]getNil];
+	UKIntsNotEqual(0,[array count]);
+
+}
+
+-(void)testFold;
+{
+	INPUTS;
+	UKObjectsEqual(@"letters: foobar",[[inputArray
+	  leftFold]stringByAppendingString: @"letters: "]);
+	UKObjectsEqual(@"foobar: letters",[[inputArray
+	 rightFold]stringByAppendingString: @": letters"]);
+
+	BOOL success = NO; 
+	NSString* folded;
+	folded = [[inputSet fold] stringByAppendingString: @""];
+	if([folded isEqualToString: @"foobar"] ||
+	   [folded isEqualToString: @"barfoo"])
+	{
+		success = YES;
+	}
+	UKTrue(success);
+	success = NO;
+	folded = [[inputCountedSet fold] stringByAppendingString: @""];
+	if([folded isEqualToString: @"foofoobar"] ||
+	   [folded isEqualToString: @"barfoofoo"] ||
+	   [folded isEqualToString: @"foobarfoo"])
+	{
+		success = YES;
+	}
+	UKTrue(success);
+	UKIntsEqual(10,[(NSNumber*)[[inputIndexSet fold]addNumber: 
+	                   [NSNumber numberWithInt: 0]]intValue]);
+}
+-(void)testFilter
+{
+	MUTABLEINPUTS
+	NSArray *someInputs = A(array,set,countedSet);
+	FOREACHI(someInputs, collection)
+	{
+		
+		[[(NSMutableArray*)collection filter]isEqualToString: @"foo"];
+		UKTrue([(NSMutableArray*)collection containsObject: @"foo"]);
+		UKFalse([(NSMutableArray*)collection containsObject: @"bar"]);
+	}
+	[[dictionary filter] isEqualToString: @"foo"];
+	UKObjectsEqual(@"foo",[dictionary objectForKey: @"one"]);
+	UKNil([dictionary objectForKey: @"two"]);
+	[[indexSet filter] isEqualToNumber: [NSNumber numberWithInt: 2]];
+	NSEnumerator *indexEnumerator = [(NSArray*)indexSet objectEnumerator];
+	FOREACHW(indexSet,anIndex,id,indexEnumerator)
+	{
+		UKIntsEqual(2,[(NSNumber*)anIndex intValue]);
+	}
+}
+...@end
Index: Frameworks/EtoileFoundation/Source/NSArray+map.m
===================================================================
--- Frameworks/EtoileFoundation/Source/NSArray+map.m	(revision 4786)
+++ Frameworks/EtoileFoundation/Source/NSArray+map.m	(working copy)
@@ -1,54 +0,0 @@
-#import "NSArray+map.h"
-#import "Macros.h"
-
-...@interface NSArrayMapProxy : NSObject {
-	NSArray * array;
-}
-- (id) initWithArray:(NSArray*)anArray;
-...@end
-
-...@implementation NSArrayMapProxy
-- (id) initWithArray:(NSArray*)anArray
-{
-	SELFINIT;
-	array = [anArray retain];
-	return self;
-}
-- (id) methodSignatureForSelector:(SEL)aSelector
-{
-	FOREACHI(array, object)
-	{
-		if([object respondsToSelector:aSelector])
-		{
-			return [object methodSignatureForSelector:aSelector];
-		}
-	}
-	return [super methodSignatureForSelector:aSelector];
-}
-- (void) forwardInvocation:(NSInvocation*)anInvocation
-{
-	SEL selector = [anInvocation selector];
-	NSMutableArray * mappedArray = [NSMutableArray array];
-	FOREACHI(array, object)
-	{
-		if([object respondsToSelector:selector])
-		{
-			[anInvocation invokeWithTarget:object];
-			id mapped;
-			[anInvocation getReturnValue:&mapped];
-			[mappedArray addObject:mapped];
-		}
-	}
-	[anInvocation setReturnValue:&mappedArray];
-}
-DEALLOC(
-	[array release];
-)
-...@end
-
-...@implementation NSArray (AllElements)
-- (id) map
-{
-	return [[[NSArrayMapProxy alloc] initWithArray:self] autorelease];
-}
-...@end
Index: Frameworks/EtoileFoundation/Source/ETCollectionHOMProxy.m
===================================================================
--- Frameworks/EtoileFoundation/Source/ETCollectionHOMProxy.m	(revision 0)
+++ Frameworks/EtoileFoundation/Source/ETCollectionHOMProxy.m	(revision 0)
@@ -0,0 +1,121 @@
+#import "ETCollectionHOMProxy.h"
+#import "ETCollection.h"
+#import "NSObject+Etoile.h"
+#import "Macros.h"
+
+...@implementation ETCollectionHOMProxy
+- (id) initWithCollection:(id<ETCollection,NSObject>) aCollection
+{
+	SELFINIT;
+	collection = [aCollection retain];
+	return self;
+}
+- (id) methodSignatureForSelector:(SEL)aSelector
+{
+	/*
+	 * The collection is cast to NSArray because even though all classes
+	 * adopting ETCollection provide -objectEnumerator this is not declared.
+	 * (See ETColection.h)
+	 */
+	NSEnumerator *collectionEnumerator;
+	collectionEnumerator = [(NSArray*)collection objectEnumerator];
+	FOREACHW(collection, object,id,collectionEnumerator)
+	{
+		if([object respondsToSelector:aSelector])
+		{
+			return [object methodSignatureForSelector:aSelector];
+		}
+	}
+	return [super methodSignatureForSelector:aSelector];
+}
+
+/*
+ * FIXME: It is not really organic to put this here since it pertains to
+ * collections in general.
+ */
+-(Class)mutableClassForCollection
+{
+	/* 
+	 * First, find the class that the ETCollection protocol was declared
+	 * upon. This is needed because NSArray and friends are class clusters
+	 * which are likely to return some private subclass. Classes conforming
+	 * to ETCollectionMutation can be reused.
+	 */
+	Class collectionClass = [collection class];
+	Class nextClass = [collectionClass superclass];
+	BOOL haveFirstAdoptingClass = NO;
+	while((NO == haveFirstAdoptingClass) && ([nextClass superclass]!= nil))
+	{
+		if(([collectionClass conformsToProtocol:
+		                             @protocol(ETCollectionMutation)])||
+		   ([collectionClass conformsToProtocol:
+		                             @protocol(ETCollection)] &&
+		   ![nextClass conformsToProtocol: @protocol(ETCollection)])
+		  )
+		{//in this case, we found the first superclass adopting
+			haveFirstAdoptingClass = YES;
+		}
+		else
+		{//try again with the next pair of classes
+			collectionClass = nextClass;
+			nextClass = [collectionClass superclass];
+		}
+	}
+
+	//Next, get the subclasses in hierarchical order.
+	NSArray *classes = [NSArray arrayWithObject: collectionClass];
+	NSMutableArray *nextClasses = [[NSMutableArray alloc] init];
+	Class mutableCollectionClass = nil;
+	[classes retain];
+	do //repeat the search for each level of subclasses.
+	{
+		FOREACHI(classes,class)
+		{
+			/*
+			 * It is needed to check for NSMutableArray explicitly
+			 * because it does not adopt the ETCollectionMutation
+			 * protocol correctly.
+			 */
+			if(([class conformsToProtocol:
+			                 @protocol(ETCollectionMutation)]
+		        || (class == [NSMutableArray class]) 
+		        ) &&
+			   (nil == mutableCollectionClass))
+			{
+				mutableCollectionClass = class;	
+			}
+		}
+		if(nil == mutableCollectionClass)
+		{
+			[nextClasses removeAllObjects];
+			FOREACHI(classes, class)
+			{
+				NSArray *subClasses;
+				subClasses = [class directSubclasses];
+				if([subClasses count] > 0)
+				{
+					[nextClasses addObjectsFromArray:
+					                       subClasses];
+				}
+			}
+		}
+	[classes autorelease];
+	classes = [NSArray arrayWithArray: nextClasses];
+	[classes retain];
+	}while((nil == mutableCollectionClass) && ([nextClasses count] > 0));
+	[classes release];
+	[nextClasses release];
+	return mutableCollectionClass;
+}
+DEALLOC(
+	[collection release];
+)
+...@end
+
+...@implementation ETCollectionMutationHOMProxy
+- (id)initWithCollection: (id<NSObject,ETCollection,ETCollectionMutation>) aCol
+{
+	self = [super initWithCollection: aCol];
+	return self;
+}
+...@end
Index: Frameworks/EtoileFoundation/Source/GNUmakefile
===================================================================
--- Frameworks/EtoileFoundation/Source/GNUmakefile	(revision 4786)
+++ Frameworks/EtoileFoundation/Source/GNUmakefile	(working copy)
@@ -13,12 +13,16 @@
 # Class files
 #
 libEtoileFoundation_OBJC_FILES = \
-	NSArray+map.m \
 	NSObject+Mixins.m \
 	NSObject+Prototypes.m \
 	NSFileManager+TempFile.m\
 	UKPluginsRegistry.m \
 	ETCollection.m \
+	ETCollectionHOMProxy.m \
+	ETCollection+map.m \
+	ETCollection+filter.m \
+	ETCollection+fold.m \
+	ETCollectionMutation+map.m \
 	ETFilter.m \
 	ETGetOptionsDictionary.m \
 	ETHistoryManager.m \
@@ -50,7 +54,7 @@
 endif
 
 ifeq ($(test), yes)
-libEtoileFoundation_OBJC_FILES += TestUUID.m TestUTI.m
+libEtoileFoundation_OBJC_FILES += TestUUID.m TestUTI.m TestHOM.m
 endif
 
 include $(GNUSTEP_MAKEFILES)/subproject.make
Index: Frameworks/EtoileFoundation/Source/ETCollection+map.m
===================================================================
--- Frameworks/EtoileFoundation/Source/ETCollection+map.m	(revision 0)
+++ Frameworks/EtoileFoundation/Source/ETCollection+map.m	(revision 0)
@@ -0,0 +1,180 @@
+#import "ETCollection+map.h"
+#import "ETCollection.h"
+#import "NSObject+Etoile.h"
+#import "ETCollectionHOMProxy.h"
+#import "Macros.h"
+
+...@interface ETCollectionMapProxy : ETCollectionHOMProxy 
+...@end
+
+...@implementation ETCollectionMapProxy
+- (id<ETCollection>)mapWith: (void*)blockOrInvocation asBlock: (BOOL)isBlock
+{
+	NSInvocation *anInvocation = nil;
+	SEL selector;
+	Class mutableCollectionClass = [self mutableClassForCollection];
+	id<ETCollectionMutation> mappedCollection;
+	mappedCollection = [[mutableCollectionClass alloc] init];
+
+	/*
+	 * For some collections (such as NSDictionary) the index of the object
+	 * needs to be tracked. 
+ 	 */
+	unsigned int objectIndex = 0;
+
+	/*
+	 * All classes adopting ETCollection provide -objectEnumerator methods.
+	 * This just isn't declared because the compiler does not check whether
+	 * the original classes provide the method when the protocol is adopted
+	 * by a category on those classes (see ETCollection.h). Therefore it is
+	 * safe to cast the collection to NSArray of which it is known that
+	 * there is an -objectEnumerator method.
+	 */
+	NSEnumerator *collectionEnumerator;
+	collectionEnumerator = [(NSArray*)collection objectEnumerator];
+	FOREACHW(collection, object,id,collectionEnumerator)
+	{
+		id mapped = nil;
+		if(NO == isBlock)
+		{
+			NSInvocation *anInvocation;
+			anInvocation = (NSInvocation*)blockOrInvocation;
+			SEL selector = [anInvocation selector];
+			if([object respondsToSelector:selector])
+			{
+				[anInvocation invokeWithTarget:object];
+				[anInvocation getReturnValue:&mapped];
+			}
+		}
+		#if defined (__clang__)
+		else
+		{
+			id(^theBlock)(id) = (id(^)(id))blockOrInvocation;
+			mapped = theBlock(object);
+		}
+		#endif
+		if (nil == mapped)
+		{
+			mapped = [NSNull null];
+		}
+		
+		//Special handling for basic ETCollection adopting subclasses.
+		if([[collection class] isSubclassOfClass: [NSDictionary class]])
+		{
+			/* 
+			 * FIXME: -identifierAtIndex: uses -allKeys which is not
+			 * guaranteed to return the keys in any particular
+			 * order.
+			 */
+			NSString *key = [(NSDictionary*)collection
+			                 identifierAtIndex:objectIndex];
+			[(NSMutableDictionary*)mappedCollection 
+			                  setObject: mapped forKey:key];
+		}
+		else if ([[collection class] isSubclassOfClass:
+		                                  [NSCountedSet class]])
+		{
+			NSUInteger count = [(NSCountedSet*)collection
+			                         countForObject:object];
+			int i;
+			for(i=0;i<count;i++)
+			{
+				[mappedCollection addObject:mapped];
+			}
+		}
+		else if ([[collection class] isSubclassOfClass:
+		                                  [NSIndexSet class]])
+		{
+			if([mapped respondsToSelector:
+			             @selector(unsignedIntegerValue)])
+			{
+				[(NSMutableIndexSet*)mappedCollection
+				addIndex: [mapped unsignedIntegerValue]];
+			}
+		}
+		else
+		{
+			[mappedCollection addObject:mapped];
+		}
+		objectIndex++;
+	}
+	return [(NSObject*)mappedCollection autorelease];
+
+
+}
+- (void) forwardInvocation:(NSInvocation*)anInvocation
+{
+
+	id<ETCollection> mappedCollection;
+	mappedCollection = [self mapWith: anInvocation asBlock: NO];
+	[anInvocation setReturnValue:&mappedCollection];
+}
+...@end
+
+...@implementation NSArray (ETCollectionMapElements)
+- (id) mappedArray
+{
+	return [[[ETCollectionMapProxy alloc] initWithCollection:self] 
+	                                                  autorelease];
+}
+#if defined (__clang__)
+- (id) mappedArray: (id(^)(id))aBlock
+{
+	ETCollectionMapProxy *myProxy;
+	myProxy = [[[ETCollectionMapProxy alloc] initWithCollection:self] 
+	                                                     autorelease];
+	return [myProxy mapWith: aBlock asBlock: YES];
+}
+#endif
+...@end
+...@implementation NSSet (ETCollectionMapElements)
+- (id) mappedSet
+{
+	return [[[ETCollectionMapProxy alloc] initWithCollection:self] 
+	                                                  autorelease];
+}
+#if defined (__clang__)
+- (id) mappedSet: (id(^)(id))aBlock
+{
+	ETCollectionMapProxy *myProxy;
+	myProxy = [[[ETCollectionMapProxy alloc] initWithCollection:self] 
+	                                                     autorelease];
+	return [myProxy mapWith: aBlock asBlock: YES];
+}
+#endif
+...@end
+
+...@implementation NSIndexSet (ETCollectionMapElements)
+- (id) mappedIndexSet
+{
+	return [[[ETCollectionMapProxy alloc] initWithCollection:self]
+	                                                  autorelease];
+
+}
+#if defined (__clang__)
+- (id) mappedIndexSet: (id(^)(id))aBlock
+{
+	ETCollectionMapProxy *myProxy;
+	myProxy = [[[ETCollectionMapProxy alloc] initWithCollection:self] 
+	                                                     autorelease];
+	return [myProxy mapWith: aBlock asBlock: YES];
+}
+#endif
+...@end
+
+...@implementation NSDictionary (ETCollectionMapElements)
+- (id) mappedDictionary
+{
+	return [[[ETCollectionMapProxy alloc] initWithCollection:self]
+	                                                  autorelease];
+}
+#if defined (__clang__)
+- (id) mappedDictionary: (id(^)(id))aBlock
+{
+	ETCollectionMapProxy *myProxy;
+	myProxy = [[[ETCollectionMapProxy alloc] initWithCollection:self]
+	                                                     autorelease];
+	return [myProxy mapWith: aBlock asBlock: YES];
+}
+#endif
+...@end
Index: Frameworks/EtoileFoundation/Source/ETCollection+fold.m
===================================================================
--- Frameworks/EtoileFoundation/Source/ETCollection+fold.m	(revision 0)
+++ Frameworks/EtoileFoundation/Source/ETCollection+fold.m	(revision 0)
@@ -0,0 +1,215 @@
+#import "ETCollection+fold.h"
+#import "ETCollection.h"
+#import "NSObject+Etoile.h"
+#import "ETCollectionHOMProxy.h"
+#import "Macros.h"
+
+...@interface ETCollectionFoldProxy : ETCollectionHOMProxy 
+{
+	BOOL inverse;
+}
+...@end
+
+...@implementation ETCollectionFoldProxy
+- (id)initWithCollection: (id<ETCollection,NSObject>)aCollection 
+              forInverse: (BOOL)shallInvert
+{
+	
+	self = [super initWithCollection: aCollection];
+	if (self != nil)
+	{
+		inverse = shallInvert;
+		return self;
+	}
+	return nil;
+}
+
+- (id)foldWith: (void*)blockOrInvocation asBlock: (BOOL)isBlock 
+                                 andInitialValue: (id)initialValue
+{
+	NSInvocation *anInvocation = nil;
+	SEL selector;
+	id accumulator = initialValue;
+
+	/*
+	 * For folding we can savely consider only the content as an array.
+	 */
+	NSArray *content = [collection contentArray];
+	[content retain];
+	NSEnumerator *contentEnumerator;
+	if(NO == inverse)
+	{
+		contentEnumerator = [content objectEnumerator];
+	}
+	else
+	{
+		contentEnumerator = [content reverseObjectEnumerator];
+	}
+
+	FOREACHW(content, element,id,contentEnumerator)
+	{
+		NSUInteger i, count;
+		count = 1;
+		if ([collection respondsToSelector: @selector(countForObject:)])
+		{
+			count = [(NSCountedSet*)collection countForObject:
+			                                               element];
+		}
+		//Repeat to get stuff like counted sets right.
+		for(i = 0;i < count;i++)
+		{
+			id target;
+			id argument;
+			if(inverse==NO)
+			{
+				target=accumulator;
+				argument=element;
+			}
+			else
+			{
+				target=element;
+				argument=accumulator;
+			}
+
+			if(NO == isBlock)
+			{
+				NSInvocation *anInvocation;
+				anInvocation = (NSInvocation*)blockOrInvocation;
+				SEL selector = [anInvocation selector];
+				if([target respondsToSelector:selector])
+				{
+					[anInvocation setArgument: &argument 
+					                  atIndex: 2];
+					[anInvocation invokeWithTarget:target];
+					[anInvocation getReturnValue:&accumulator];
+				}
+			}
+			#if defined (__clang__)
+			else
+			{
+				id(^theBlock)(id,id) = 
+				                    (id(^)(id,id))blockOrInvocation;
+				accumulator = theBlock(target,argument);
+			}
+			#endif
+		}
+	}
+	[content release];
+	return accumulator;
+
+
+}
+- (void) forwardInvocation:(NSInvocation*)anInvocation
+{
+
+	id foldedValue;
+	id initialValue;
+	[anInvocation getArgument: &initialValue atIndex: 2];
+	foldedValue = [self foldWith: anInvocation asBlock: NO
+	             andInitialValue: initialValue];
+	[anInvocation setReturnValue:&foldedValue];
+}
+...@end
+
+...@implementation NSArray (ETCollectionFoldElements)
+- (id) leftFold
+{
+	return [[[ETCollectionFoldProxy alloc] initWithCollection:self
+	                                               forInverse: NO]
+	                                                   autorelease];
+}
+
+- (id) rightFold
+{
+	return [[[ETCollectionFoldProxy alloc] initWithCollection:self
+	                                               forInverse: YES]
+	                                                    autorelease];
+}
+#if defined (__clang__)
+- (id) inject: (id)initialValue into: (id(^)(id,id))aBlock 
+    andInvert: (BOOL)shallInvert
+{
+	ETCollectionFoldProxy *myProxy;
+	myProxy = [[[ETCollectionFoldProxy alloc] initWithCollection:self
+	                                              forInverse: shallInvert]
+	                                                          autorelease];
+	return [myProxy foldWith: aBlock asBlock: YES 
+	         andInitialValue: initialValue];
+}
+- (id) inject: (id)initialValue into: (id(^)(id,id))aBlock
+{
+	return [self inject: initialValue into: aBlock andInvert: NO];
+}
+#endif
+...@end
+...@implementation NSSet (ETCollectionFoldElements)
+- (id) fold
+{
+	return [[[ETCollectionFoldProxy alloc] initWithCollection:self
+	                                               forInverse: NO]
+	                                                   autorelease];
+}
+#if defined (__clang__)
+- (id) inject: (id)initialValue into: (id(^)(id,id))aBlock 
+{
+	ETCollectionFoldProxy *myProxy;
+	myProxy = [[[ETCollectionFoldProxy alloc] initWithCollection:self
+	                                              forInverse: NO]
+	                                                          autorelease];
+	return [myProxy foldWith: aBlock asBlock: YES 
+	         andInitialValue: initialValue];
+}
+#endif
+...@end
+
+...@implementation NSIndexSet (ETCollectionFoldElements)
+- (id) fold
+{
+	return [[[ETCollectionFoldProxy alloc] initWithCollection:self
+	                                               forInverse: NO]
+	                                                   autorelease];
+}
+#if defined (__clang__)
+- (id) inject: (id)initialValue into: (id(^)(id,id))aBlock 
+{
+	ETCollectionFoldProxy *myProxy;
+	myProxy = [[[ETCollectionFoldProxy alloc] initWithCollection:self
+	                                              forInverse: NO]
+	                                                          autorelease];
+	return [myProxy foldWith: aBlock asBlock: YES 
+	         andInitialValue: initialValue];
+}
+#endif
+...@end
+
+...@implementation NSDictionary (ETCollectionFoldElements)
+- (id) leftFold
+{
+	return [[[ETCollectionFoldProxy alloc] initWithCollection:self
+	                                               forInverse: NO]
+	                                                   autorelease];
+}
+
+- (id) rightFold
+{
+	return [[[ETCollectionFoldProxy alloc] initWithCollection:self
+	                                               forInverse: YES]
+	                                                    autorelease];
+}
+#if defined (__clang__)
+- (id) inject: (id)initialValue into: (id(^)(id,id))aBlock 
+    andInvert: (BOOL)shallInvert
+{
+	ETCollectionFoldProxy *myProxy;
+	myProxy = [[[ETCollectionFoldProxy alloc] initWithCollection:self
+	                                              forInverse: shallInvert]
+	                                                          autorelease];
+	return [myProxy foldWith: aBlock asBlock: YES 
+	         andInitialValue: initialValue];
+}
+- (id) inject: (id)initialValue into: (id(^)(id,id))aBlock
+{
+	return [self inject: initialValue into: aBlock andInvert: NO];
+}
+#endif
+...@end
Index: Frameworks/EtoileFoundation/Source/ETCollection+filter.m
===================================================================
--- Frameworks/EtoileFoundation/Source/ETCollection+filter.m	(revision 0)
+++ Frameworks/EtoileFoundation/Source/ETCollection+filter.m	(revision 0)
@@ -0,0 +1,252 @@
+#import "ETCollection+filter.h"
+#import "ETCollection.h"
+#import "NSObject+Etoile.h"
+#import "ETCollectionHOMProxy.h"
+#import "Macros.h"
+
+...@interface ETCollectionFilterProxy : ETCollectionHOMProxy 
+...@end
+
+...@implementation ETCollectionFilterProxy
+- (void)filterWith: (void *)blockOrInvocation asBlock: (BOOL) isBlock 
+         andTarget: (id<ETCollectionMutation>*)target
+{
+	NSInvocation *anInvocation = nil;
+	SEL selector;
+
+
+	NSArray* content = [collection contentArray];
+	id<NSObject,ETCollection,ETCollectionMutation> theCollection,theTarget;
+	theCollection = (id<NSObject,ETCollection,ETCollectionMutation>)collection;
+	theTarget = (id<NSObject,ETCollection,ETCollectionMutation>)*target;
+	[content retain];
+	
+	/*
+	 * For NSDictionaries the index of the object needs to be tracked.
+	 * Additionally, if a NSMutableDictionary is being manipulated, a
+	 * snapshot of the keys is needed.
+	 */	
+	NSArray* keys;
+	unsigned int objectIndex = 0;
+	if([theCollection respondsToSelector: @selector(allKeys)])
+	{
+		/*
+		 * FIXME: -allKeys is not guaranteed to return the keys in the
+		 * correct order.
+		 */
+		keys = [(NSDictionary*)theCollection allKeys];
+	}
+	
+	FOREACHI(content, object)
+	{
+		int i, count;
+		count = 1;
+		
+		long long filterResult;
+		filterResult = (long long)NO;
+		if(NO == isBlock)
+		{
+			NSInvocation *theInvocation;
+			SEL theSelector;
+			theInvocation = (NSInvocation*)blockOrInvocation;
+			theSelector = [theInvocation selector];
+			if([object respondsToSelector: theSelector])
+			{
+				[theInvocation invokeWithTarget: object];
+				[theInvocation getReturnValue: &filterResult];
+			}
+		}
+		#if defined (__clang__)
+		else
+		{
+			BOOL(^theBlock)(id) = (BOOL(^)(id))blockOrInvocation;
+			filterResult = (long long)theBlock(object);
+		}
+		#endif
+		if ([theCollection respondsToSelector:
+		                                  @selector(countForObject:)])
+		{
+			count = [(NSCountedSet*)theCollection countForObject:
+			                                               object];
+		}
+		for(i=0;i<count;i++)
+		{
+			if([[theCollection class] isSubclassOfClass: 
+			                            [NSMutableDictionary class]])
+			{
+				NSString *key = [keys objectAtIndex:objectIndex];
+				if(theTarget==theCollection && NO == (BOOL)filterResult)
+				{
+				[(NSMutableDictionary*)theTarget 
+				                  removeObjectForKey:key];
+				}
+				else if (theTarget!=theCollection && YES == (BOOL)filterResult)
+				{
+				[(NSMutableDictionary*)theTarget
+				                  setObject: object forKey:key];
+				}
+			}
+			else
+			{
+				if(theTarget == theCollection && NO == (BOOL)filterResult)
+				{
+					[theTarget removeObject: object];
+				}
+				else if (theTarget!=theCollection && YES == (BOOL)filterResult)
+				{
+					[theTarget addObject: object];
+				}
+			}
+		}
+		objectIndex++;
+	}
+	[content release];
+}
+- (id)filteredCollectionWith: (void *)blockOrInvocation asBlock: (BOOL) isBlock
+{
+	Class mutableClass = [self mutableClassForCollection];
+	id<NSObject,ETCollectionMutation> mutableCollection;
+	mutableCollection = [[mutableClass alloc] init];
+	[self filterWith: blockOrInvocation asBlock: isBlock 
+	       andTarget: (id<ETCollectionMutation>*)&mutableCollection];
+	return [mutableCollection autorelease];
+}
+...@end
+
+...@interface ETCollectionMutationFilterProxy: ETCollectionFilterProxy
+{
+}
+...@end
+...@implementation ETCollectionMutationFilterProxy
+
+- (id)initWithCollection: (id<NSObject,ETCollection,ETCollectionMutation>) aCol
+{
+        self = [super initWithCollection: aCol];
+        return self;
+}
+
+- (void) forwardInvocation:(NSInvocation*)anInvocation
+{
+
+	[self filterWith: anInvocation asBlock: NO 
+	       andTarget: (id<ETCollectionMutation>*)&collection];
+	//Actually, we don't care for the return value.
+	[anInvocation setReturnValue:&collection];
+}
+
+...@end
+
+
+
+//TODO: These can all go into a Mixin. I just don't know how that works.
+...@implementation NSArray (ETCollectionFilterElements)
+#if defined (__clang__)
+- (id) filteredArray: (BOOL(^)(id))aBlock
+{
+	ETCollectionFilterProxy *myProxy;
+	myProxy = [[[ETCollectionFilterProxy alloc]initWithCollection: self]
+	                                                    autorelease];
+	return [myProxy filteredCollectionWith: aBlock asBlock: YES];
+}
+#endif
+...@end
+...@implementation NSMutableArray (ETCollectionMutationFilterElements)
+- (id) filter
+{
+	return [[[ETCollectionMutationFilterProxy alloc] initWithCollection:self]
+	                                                         autorelease];
+}
+#if defined (__clang__)
+- (void) filter: (BOOL(^)(id))aBlock
+{
+	ETCollectionMutationFilterProxy *myProxy;
+	myProxy = [[[ETCollectionMutationFilterProxy alloc] initWithCollection:self]
+	                                                            autorelease];
+	return [myProxy filterWith: aBlock asBlock: YES andTarget: &self];
+}
+#endif
+...@end
+...@implementation NSSet (ETCollectionFilterElements)
+#if defined (__clang__)
+- (id) filteredSet: (BOOL(^)(id))aBlock
+{
+	ETCollectionFilterProxy *myProxy;
+	myProxy = [[[ETCollectionFilterProxy alloc]initWithCollection: self]
+	                                                      autorelease];
+	return [myProxy filteredCollectionWith: aBlock asBlock: YES];
+}
+#endif
+...@end
+...@implementation NSMutableSet (ETCollectionMutationFilterElements)
+- (id) filter
+{
+	return [[[ETCollectionMutationFilterProxy alloc] initWithCollection:self]
+	                                                         autorelease];
+}
+#if defined (__clang__)
+- (void) filter: (BOOL(^)(id))aBlock
+{
+	ETCollectionMutationFilterProxy *myProxy;
+	myProxy = [[[ETCollectionMutationFilterProxy alloc] initWithCollection:self]
+	                                                            autorelease];
+	return [myProxy filterWith: aBlock asBlock: YES andTarget: &self];
+}
+#endif
+...@end
+
+...@implementation NSIndexSet (ETCollectionFilterElements)
+#if defined (__clang__)
+- (id) filteredIndexSet: (BOOL(^)(id))aBlock
+{
+	ETCollectionFilterProxy *myProxy;
+	myProxy = [[[ETCollectionFilterProxy alloc]initWithCollection: self]
+	                                                      autorelease];
+	return [myProxy filteredCollectionWith: aBlock asBlock: YES];
+}
+#endif
+...@end
+...@implementation NSMutableIndexSet (ETCollectionMutationFilterElements)
+- (id) filter
+{
+	return [[[ETCollectionMutationFilterProxy alloc] initWithCollection:self]
+	                                                         autorelease];
+
+}
+#if defined (__clang__)
+- (void) filter: (BOOL(^)(id))aBlock
+{
+	ETCollectionMutationFilterProxy *myProxy;
+	myProxy = [[[ETCollectionMutationFilterProxy alloc] initWithCollection:self]
+	                                                            autorelease];
+	return [myProxy filterWith: aBlock asBlock: YES andTarget:&self];
+}
+#endif
+...@end
+...@implementation NSDictionary (ETCollectionFilterElements)
+#if defined (__clang__)
+- (id) filteredDictionary: (BOOL(^)(id))aBlock
+{
+	ETCollectionFilterProxy *myProxy;
+	myProxy = [[[ETCollectionFilterProxy alloc]initWithCollection: self]
+	                                                      autorelease];
+	return [myProxy filteredCollectionWith: aBlock asBlock: YES];
+}
+#endif
+...@end
+
+...@implementation NSMutableDictionary (ETCollectionMutationFilterElements)
+- (id) filter
+{
+	return [[[ETCollectionMutationFilterProxy alloc] initWithCollection:self]
+	                                                         autorelease];
+}
+#if defined (__clang__)
+- (void) filter: (BOOL(^)(id))aBlock
+{
+	ETCollectionMutationFilterProxy *myProxy;
+	myProxy = [[[ETCollectionMutationFilterProxy alloc] initWithCollection:self] 
+	                                                            autorelease];
+	[myProxy filterWith: aBlock asBlock: YES andTarget: &self];
+}
+#endif
+...@end
Index: Frameworks/EtoileFoundation/Source/ETCollectionMutation+map.m
===================================================================
--- Frameworks/EtoileFoundation/Source/ETCollectionMutation+map.m	(revision 0)
+++ Frameworks/EtoileFoundation/Source/ETCollectionMutation+map.m	(revision 0)
@@ -0,0 +1,196 @@
+#import "ETCollection+map.h"
+#import "ETCollection.h"
+#import "NSObject+Etoile.h"
+#import "ETCollectionHOMProxy.h"
+#import "Macros.h"
+
+...@interface ETCollectionMutationMapProxy : ETCollectionMutationHOMProxy 
+...@end
+
+...@implementation ETCollectionMutationMapProxy
+- (void)mapWith: (void*)blockOrInvocation asBlock: (BOOL)isBlock
+{
+	NSInvocation *anInvocation = nil;
+	SEL selector;
+	/*
+	 * For some collections (such as NSDictionary) the index of the object
+	 * needs to be tracked. 
+ 	 */
+	unsigned int objectIndex = 0;
+
+	/*
+	 * Also, for collections enforcing uniqueness of elements
+	 * (NSMutable*Set), we need to keep track of elements which were already
+	 * mapped.
+	 */
+	NSMutableArray* alreadyMapped = [[NSMutableArray alloc]init]; 
+
+	NSArray* content = [collection contentArray];
+	id<NSObject,ETCollection,ETCollectionMutation> theCollection;
+	theCollection = (id<NSObject,ETCollection,ETCollectionMutation>)collection;
+	[content retain];
+	FOREACHI(content, object)
+	{
+		id mapped = nil;
+		if(NO == isBlock)
+		{
+			NSInvocation *anInvocation = (NSInvocation*)blockOrInvocation;
+			SEL selector = [anInvocation selector];
+			if([object respondsToSelector:selector])
+			{
+				[anInvocation invokeWithTarget:object];
+				[anInvocation getReturnValue:&mapped];
+			}
+		}
+		#if defined (__clang__)
+		else
+		{
+			id(^theBlock)(id) = (id(^)(id))blockOrInvocation;
+			mapped = theBlock(object);
+		}
+		#endif
+		if (nil == mapped)
+		{
+			mapped = [NSNull null];
+		}
+		[alreadyMapped addObject: mapped];	
+
+		if([[theCollection class] isSubclassOfClass: 
+		                                   [NSMutableDictionary class]])
+		{
+			/* 
+			 * FIXME: -identifierAtIndex: uses -allKeys which is not
+			 * guaranteed to return the keys in any particular
+			 * order.
+			 */
+			NSString *key = [(NSDictionary*)collection
+			                 identifierAtIndex:objectIndex];
+			[(NSMutableDictionary*)theCollection 
+			                  setObject: mapped forKey:key];
+		}
+		else if ([[theCollection class] isSubclassOfClass:
+		                                  [NSMutableSet class]])
+		{
+			int i,count;
+			BOOL isCounted;
+			if([theCollection respondsToSelector:
+			                   @selector(countForObject:)])
+			{
+				count = [(NSCountedSet*)theCollection 
+				                countForObject: object];
+				isCounted = YES;
+			}
+			else
+			{
+				count = 1;
+				isCounted = NO;
+			}
+			for(i=0;i<count;i++)
+			{
+				if(NO == [alreadyMapped containsObject: object] ||
+				   YES == isCounted)
+				{
+					[theCollection removeObject: object];
+				}
+				[theCollection addObject: mapped];
+			}
+		}
+		else if ([[theCollection class] isSubclassOfClass:
+		                                 [NSMutableIndexSet class]])
+		{
+			if([mapped respondsToSelector:
+			             @selector(unsignedIntegerValue)])
+			{
+				if([alreadyMapped containsObject: object] == NO)
+				{
+					[(NSMutableIndexSet*)theCollection
+					  removeIndex: 
+				             [object unsignedIntegerValue]];
+				}
+				[(NSMutableIndexSet*)theCollection
+				    addIndex: [mapped unsignedIntegerValue]];
+			}
+		}
+		else
+		{
+			[(NSMutableArray*)theCollection replaceObjectAtIndex: 
+			                                            objectIndex
+			                                           withObject: 
+			                                                 mapped];
+		}
+		objectIndex++;
+	}
+	[alreadyMapped release];
+	[content release];
+}
+- (void) forwardInvocation:(NSInvocation*)anInvocation
+{
+
+	[self mapWith: anInvocation asBlock: NO];
+	//Actually, we don't care for the return value.
+	[anInvocation setReturnValue:&collection];
+}
+...@end
+
+//TODO: These could all go into a mixin. I just don't know how that works.
+...@implementation NSMutableArray (ETCollectionMutationMapElements)
+- (id) map
+{
+	return [[[ETCollectionMutationMapProxy alloc] initWithCollection:self] autorelease];
+}
+#if defined (__clang__)
+- (void) map: (id(^)(id))aBlock
+{
+	ETCollectionMutationMapProxy *myProxy;
+	myProxy = [[[ETCollectionMutationMapProxy alloc] initWithCollection:self] autorelease];
+	return [myProxy mapWith: aBlock asBlock: YES];
+}
+#endif
+...@end
+...@implementation NSMutableSet (ETCollectionMutationMapElements)
+- (id) map
+{
+	return [[[ETCollectionMutationMapProxy alloc] initWithCollection:self] autorelease];
+}
+#if defined (__clang__)
+- (void) map: (id(^)(id))aBlock
+{
+	ETCollectionMutationMapProxy *myProxy;
+	myProxy = [[[ETCollectionMutationMapProxy alloc] initWithCollection:self] autorelease];
+	return [myProxy mapWith: aBlock asBlock: YES];
+}
+#endif
+...@end
+
+...@implementation NSMutableIndexSet (ETCollectionMutationMapElements)
+- (id) map
+{
+	return [[[ETCollectionMutationMapProxy alloc] initWithCollection:self]
+	                                                         autorelease];
+
+}
+#if defined (__clang__)
+- (void) map: (id(^)(id))aBlock
+{
+	ETCollectionMutationMapProxy *myProxy;
+	myProxy = [[[ETCollectionMutationMapProxy alloc] initWithCollection:self] autorelease];
+	return [myProxy mapWith: aBlock asBlock: YES];
+}
+#endif
+...@end
+
+...@implementation NSMutableDictionary (ETCollectionMutationMapElements)
+- (id) map
+{
+	return [[[ETCollectionMutationMapProxy alloc] initWithCollection:self]
+	                                                         autorelease];
+}
+#if defined (__clang__)
+- (void) map: (id(^)(id))aBlock
+{
+	ETCollectionMutationMapProxy *myProxy;
+	myProxy = [[[ETCollectionMutationMapProxy alloc] initWithCollection:self] autorelease];
+	return [myProxy mapWith: aBlock asBlock: YES];
+}
+#endif
+...@end
Index: Frameworks/EtoileFoundation/GNUmakefile
===================================================================
--- Frameworks/EtoileFoundation/GNUmakefile	(revision 4786)
+++ Frameworks/EtoileFoundation/GNUmakefile	(working copy)
@@ -50,11 +50,14 @@
 	EtoileCompatibility.h \
 	ETCArray.h \
 	Macros.h \
-	NSArray+map.h \
 	NSObject+Mixins.h \
 	NSFileManager+TempFile.h \
 	UKPluginsRegistry.h \
 	ETCollection.h \
+	ETCollectionHOMProxy.h \
+	ETCollection+map.h \
+	ETCollection+fold.h \
+	ETCollection+filter.h \
 	ETFilter.h \
 	ETHistoryManager.h \
 	ETModelDescription.h \
Index: Frameworks/EtoileFoundation/Headers/EtoileFoundation.h
===================================================================
--- Frameworks/EtoileFoundation/Headers/EtoileFoundation.h	(revision 4786)
+++ Frameworks/EtoileFoundation/Headers/EtoileFoundation.h	(working copy)
@@ -40,7 +40,6 @@
 #import <EtoileFoundation/NSFileManager+TempFile.h>
 #import <EtoileFoundation/NSFileManager+NameForTempFile.h>
 #import <EtoileFoundation/UKPluginsRegistry.h>
-#import <EtoileFoundation/NSArray+map.h>
 #import <EtoileFoundation/NSObject+Etoile.h>
 #import <EtoileFoundation/NSObject+Model.h>
 #import <EtoileFoundation/NSIndexSet+Etoile.h>
@@ -49,6 +48,9 @@
 #import <EtoileFoundation/NSString+Etoile.h>
 #import <EtoileFoundation/NSURL+Etoile.h>
 #import <EtoileFoundation/ETCollection.h>
+#import <EtoileFoundation/ETCollection+map.h>
+#import <EtoileFoundation/ETCollection+filter.h>
+#import <EtoileFoundation/ETCollection+fold.h>
 #import <EtoileFoundation/ETPropertyValueCoding.h>
 #import <EtoileFoundation/ETObjectChain.h>
 #import <EtoileFoundation/ETFilter.h>
Index: Frameworks/EtoileFoundation/Headers/Macros.h
===================================================================
--- Frameworks/EtoileFoundation/Headers/Macros.h	(revision 4786)
+++ Frameworks/EtoileFoundation/Headers/Macros.h	(working copy)
@@ -49,6 +49,9 @@
 
 #define FOREACHE(collection,object,type,enumerator)\
 NSEnumerator * enumerator = [collection objectEnumerator];\
+FOREACHW(collection,object,type,enumerator)
+
+#define FOREACHW(collection,object,type,enumerator)\
 type object;\
 IMP next ## object ## in ## enumerator = \
 [enumerator methodForSelector:@selector(nextObject)];\
Index: Frameworks/EtoileFoundation/Headers/NSArray+map.h
===================================================================
--- Frameworks/EtoileFoundation/Headers/NSArray+map.h	(revision 4786)
+++ Frameworks/EtoileFoundation/Headers/NSArray+map.h	(working copy)
@@ -1,5 +0,0 @@
-#include <Foundation/Foundation.h>
-
-...@interface NSArray (AllElements)
-- (id) map;
-...@end
Index: Frameworks/EtoileFoundation/Headers/ETCollectionHOMProxy.h
===================================================================
--- Frameworks/EtoileFoundation/Headers/ETCollectionHOMProxy.h	(revision 0)
+++ Frameworks/EtoileFoundation/Headers/ETCollectionHOMProxy.h	(revision 0)
@@ -0,0 +1,17 @@
+#import <Foundation/Foundation.h>
+...@protocol ETCollection,ETCollectionMutation;
+...@interface ETCollectionHOMProxy : NSObject 
+{
+        id<ETCollection,NSObject> collection;
+}
+- (id) initWithCollection: (id<NSObject,ETCollection>) collection;
+
+/**
+ * Returns a mutable class for the collection.
+ */
+- (Class) mutableClassForCollection;
+...@end
+...@interface ETCollectionMutationHOMProxy : ETCollectionHOMProxy
+- (id) initWithCollection: (id<NSObject,ETCollection,ETCollectionMutation>)
+                                                                  collection;
+...@end
Index: Frameworks/EtoileFoundation/Headers/ETCollection+map.h
===================================================================
--- Frameworks/EtoileFoundation/Headers/ETCollection+map.h	(revision 0)
+++ Frameworks/EtoileFoundation/Headers/ETCollection+map.h	(revision 0)
@@ -0,0 +1,59 @@
+#include <Foundation/Foundation.h>
+
+...@interface NSArray (ETCollectionMapElements)
+- (id) mappedArray;
+#if defined (__clang__)
+- (id) mappedArray: (id(^)(id))aBlock;
+#endif
+...@end
+
+...@interface NSSet (ETCollectionMapElements)
+- (id) mappedSet;
+#if defined (__clang__)
+- (id) mappedSet: (id(^)(id))aBlock;
+#endif
+...@end
+
+...@interface NSIndexSet (ETCollectionMapElements)
+- (id) mappedIndexSet;
+#if defined (__clang__)
+- (id) mappedIndexSet: (id(^)(id))aBlock;
+#endif
+...@end
+
+...@interface NSDictionary (ETCollectionMapElements)
+- (id) mappedDictionary;
+#if defined (__clang__)
+- (id) mappedDictionary: (id(^)(id))aBlock;
+#endif
+...@end
+
+...@interface NSMutableArray (ETCollectionMutationMapElements)
+- (id) map;
+#if defined (__clang__)
+- (void) map: (id(^)(id))aBlock;
+#endif
+...@end
+
+...@interface NSMutableSet (ETCollectionMutationMapElements)
+- (id) map;
+#if defined (__clang__)
+- (void) map: (id(^)(id))aBlock;
+#endif
+...@end
+
+...@interface NSMutableIndexSet (ETCollectionMutationMapElements)
+- (id) map;
+#if defined (__clang__)
+- (void) map: (id(^)(id))aBlock;
+#endif
+...@end
+
+...@interface NSMutableDictionary (ETCollectionMutationMapElements)
+- (id) map;
+#if defined (__clang__)
+- (void) map: (id(^)(id))aBlock;
+#endif
+...@end
+
+
Index: Frameworks/EtoileFoundation/Headers/ETCollection+fold.h
===================================================================
--- Frameworks/EtoileFoundation/Headers/ETCollection+fold.h	(revision 0)
+++ Frameworks/EtoileFoundation/Headers/ETCollection+fold.h	(revision 0)
@@ -0,0 +1,34 @@
+#import <Foundation/Foundation.h>
+
+...@interface NSArray (ETCollectionFoldElements)
+- (id) leftFold;
+- (id) rightFold;
+#if defined (__clang__)
+- (id) inject: (id)initialValue into: (id(^)(id,id))aBlock
+    andInvert: (BOOL)shallInvert;
+- (id) inject: (id)initialValue into: (id(^)(id,id))aBlock;
+#endif
+...@end
+...@interface NSSet (ETCollectionFoldElements)
+- (id) fold;
+#if defined (__clang__)
+- (id) inject: (id)initialValue into: (id(^)(id,id))aBlock;
+#endif
+...@end
+
+...@interface NSIndexSet (ETCollectionFoldElements)
+- (id) fold;
+#if defined (__clang__)
+- (id) inject: (id)initialValue into: (id(^)(id,id))aBlock;
+#endif
+...@end
+
+...@interface NSDictionary (ETCollectionFoldElements)
+- (id) leftFold;
+- (id) rightFold;
+#if defined (__clang__)
+- (id) inject: (id)initialValue into: (id(^)(id,id))aBlock 
+    andInvert: (BOOL)shallInvert;
+- (id) inject: (id)initialValue into: (id(^)(id,id))aBlock;
+#endif
+...@end
Index: Frameworks/EtoileFoundation/Headers/ETCollection+filter.h
===================================================================
--- Frameworks/EtoileFoundation/Headers/ETCollection+filter.h	(revision 0)
+++ Frameworks/EtoileFoundation/Headers/ETCollection+filter.h	(revision 0)
@@ -0,0 +1,47 @@
+#import <Foundation/Foundation.h>
+
+...@interface NSArray (ETCollectionFilterElements)
+#if defined (__clang__)
+- (id) filteredArray: (BOOL(^)(id))aBlock;
+#endif
+...@end
+...@interface NSMutableArray (ETCollectionMutationFilterElements)
+- (id) filter;
+#if defined (__clang__)
+- (void) filter: (BOOL(^)(id))aBlock;
+#endif
+...@end
+...@interface NSSet (ETCollectionFilterElements)
+#if defined (__clang__)
+- (id) filteredSet: (BOOL(^)(id))aBlock;
+#endif
+...@end
+...@interface NSMutableSet (ETCollectionMutationFilterElements)
+- (id) filter;
+#if defined (__clang__)
+- (void) filter: (BOOL(^)(id))aBlock;
+#endif
+...@end
+
+...@interface NSIndexSet (ETCollectionFilterElements)
+#if defined (__clang__)
+- (id) filteredIndexSet: (BOOL(^)(id))aBlock;
+#endif
+...@end
+...@interface NSMutableIndexSet (ETCollectionMutationFilterElements)
+- (id) filter;
+#if defined (__clang__)
+- (void) filter: (BOOL(^)(id))aBlock;
+#endif
+...@end
+...@interface NSDictionary (ETCollectionFilterElements)
+#if defined (__clang__)
+- (id) filteredDictionary: (BOOL(^)(id))aBlock;
+#endif
+...@end
+...@interface NSMutableDictionary (ETCollectionMutationFilterElements)
+- (id) filter;
+#if defined (__clang__)
+- (void) filter: (BOOL(^)(id))aBlock;
+#endif
+...@end

_______________________________________________
Etoile-dev mailing list
Etoile-dev@gna.org
https://mail.gna.org/listinfo/etoile-dev

Reply via email to