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
[email protected]
https://mail.gna.org/listinfo/etoile-dev