Hi again,

This really is fun! I never thought that implementing fold would be that much
easier. I have attached a patch and sample code on which I would like to
get some feedback. I know that there is quite some duplicated code that
should be refactored into a more generic implementation for arbitrary
collections and HOM-variations. What else is there that could be done
to improve this? 

Cheers,


Niels
Index: Frameworks/EtoileFoundation/Source/NSArray+fold.m
===================================================================
--- Frameworks/EtoileFoundation/Source/NSArray+fold.m	(revision 0)
+++ Frameworks/EtoileFoundation/Source/NSArray+fold.m	(revision 0)
@@ -0,0 +1,118 @@
+#import "NSArray+fold.h"
+#import "Macros.h"
+
+...@interface NSArrayFoldProxy : NSObject {
+	NSArray * array;
+	BOOL inverse;
+}
+- (id) initWithArray:(NSArray*)anArray forInverse: (BOOL)shallInvert; 
+...@end
+
+...@implementation NSArrayFoldProxy
+- (id) initWithArray:(NSArray*)anArray forInverse: (BOOL)shallInvert
+{
+	SELFINIT;
+	array = [anArray retain];
+	inverse = shallInvert;
+	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];
+	NSMethodSignature *theSig = [anInvocation methodSignature];
+	NSMutableArray * mappedArray = [NSMutableArray array];
+
+	int argNum = [theSig numberOfArguments];
+	
+	/* 
+	 * This array represents the index of every argument that points to the
+	 * array we are folding.
+	 */
+	int selfArgs[argNum];
+	memset(selfArgs,0,argNum);
+	int i;
+	for(i=2;i<argNum;i++)
+	{
+
+		//we only care for objects. 
+		const char* type = [theSig getArgumentTypeAtIndex: i];
+		if(strcmp("@",type)==0)
+		{
+			id anArg;
+			[anInvocation getArgument:&anArg atIndex:i];
+			//compare this pointer to our array ivar
+			if(anArg==array)
+			{
+				selfArgs[i]=i;
+			}
+		}
+	}
+	NSEnumerator *arrayEnumerator;
+	if (inverse == NO)
+	{
+		arrayEnumerator = [array objectEnumerator];
+	}
+	else
+	{
+		arrayEnumerator = [array reverseObjectEnumerator];
+	}
+
+	id collector = nil;
+	FOREACHW(array, object,id,arrayEnumerator)
+	{
+		if([object respondsToSelector:selector])
+		{
+			/*
+			 * replace all occurences of the array we are folding
+			 * with an reference to the single object
+			 */
+			for(i=2;i<argNum;i++)
+			{
+				if(selfArgs[i]!=0)
+				{
+					[anInvocation setArgument: &object
+					                 atIndex: i];
+				}
+			}
+			if (nil == collector)
+			{//we have not yet collected any results
+				collector = object;
+			}
+			else
+			{//invoke the method on the result obtained so far
+				[anInvocation invokeWithTarget: collector];
+				//update the collector with the new result.
+				[anInvocation getReturnValue: &collector];
+			}
+		}
+	}
+	[anInvocation setReturnValue:&collector];
+}
+DEALLOC(
+	[array release];
+)
+...@end
+
+...@implementation NSArray (FoldAllElements)
+- (id) foldLeft
+{
+	return [[[NSArrayFoldProxy alloc] initWithArray:self forInverse: NO] 
+	                                                         autorelease];
+}
+- (id) foldRight
+{
+	return [[[NSArrayFoldProxy alloc] initWithArray:self forInverse: YES]
+	                                                          autorelease];
+}
+...@end
Index: Frameworks/EtoileFoundation/Source/NSArray+map.m
===================================================================
--- Frameworks/EtoileFoundation/Source/NSArray+map.m	(revision 4786)
+++ Frameworks/EtoileFoundation/Source/NSArray+map.m	(working copy)
@@ -36,7 +36,14 @@
 			[anInvocation invokeWithTarget:object];
 			id mapped;
 			[anInvocation getReturnValue:&mapped];
-			[mappedArray addObject:mapped];
+			if (nil == mapped)
+			{
+				[mappedArray addObject: [NSNull null]];
+			}
+			else
+			{
+				[mappedArray addObject:mapped];
+			}
 		}
 	}
 	[anInvocation setReturnValue:&mappedArray];
Index: Frameworks/EtoileFoundation/Source/GNUmakefile
===================================================================
--- Frameworks/EtoileFoundation/Source/GNUmakefile	(revision 4786)
+++ Frameworks/EtoileFoundation/Source/GNUmakefile	(working copy)
@@ -14,6 +14,7 @@
 #
 libEtoileFoundation_OBJC_FILES = \
 	NSArray+map.m \
+	NSArray+fold.m \
 	NSObject+Mixins.m \
 	NSObject+Prototypes.m \
 	NSFileManager+TempFile.m\
Index: Frameworks/EtoileFoundation/GNUmakefile
===================================================================
--- Frameworks/EtoileFoundation/GNUmakefile	(revision 4786)
+++ Frameworks/EtoileFoundation/GNUmakefile	(working copy)
@@ -51,6 +51,7 @@
 	ETCArray.h \
 	Macros.h \
 	NSArray+map.h \
+	NSArray+fold.h \
 	NSObject+Mixins.h \
 	NSFileManager+TempFile.h \
 	UKPluginsRegistry.h \
Index: Frameworks/EtoileFoundation/Headers/NSArray+fold.h
===================================================================
--- Frameworks/EtoileFoundation/Headers/NSArray+fold.h	(revision 0)
+++ Frameworks/EtoileFoundation/Headers/NSArray+fold.h	(revision 0)
@@ -0,0 +1,16 @@
+#include <Foundation/Foundation.h>
+
+...@interface NSArray (FoldAllElements)
+/**
+ * Folds the array from the left. When sending this message, replace any
+ * argument of the folding method on which the fold shall occur with the
+ * receiver. You will need to cast it to an appropriate type for the folding
+ * method.
+ */
+- (id) foldLeft;
+
+/**
+ * Folds the array from the right. Usage notes as per -foldLeft;.
+ */
+- (id) foldRight;
+...@end
Index: Frameworks/EtoileFoundation/Headers/EtoileFoundation.h
===================================================================
--- Frameworks/EtoileFoundation/Headers/EtoileFoundation.h	(revision 4786)
+++ Frameworks/EtoileFoundation/Headers/EtoileFoundation.h	(working copy)
@@ -41,6 +41,7 @@
 #import <EtoileFoundation/NSFileManager+NameForTempFile.h>
 #import <EtoileFoundation/UKPluginsRegistry.h>
 #import <EtoileFoundation/NSArray+map.h>
+#import <EtoileFoundation/NSArray+fold.h>
 #import <EtoileFoundation/NSObject+Etoile.h>
 #import <EtoileFoundation/NSObject+Model.h>
 #import <EtoileFoundation/NSIndexSet+Etoile.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)];\
#import <Foundation/Foundation.h>
#import <EtoileFoundation/EtoileFoundation.h>
int main (void)
{
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        NSArray *input = A(@"one",@"two",@"three");
        NSString *foldedL, *foldedR;
        foldedL = (NSString*)[[input foldLeft]stringByAppendingString:
                                                      (NSString*)lower];
        foldedR = (NSString*)[[input foldRight]stringByAppendingString:
                                                      (NSString*)lower];
        NSLog(@"%@",foldedL);
        NSLog(@"%@",foldedR);
        [pool release];
        return 0;
}
_______________________________________________
Etoile-dev mailing list
Etoile-dev@gna.org
https://mail.gna.org/listinfo/etoile-dev

Reply via email to