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