From 24537a3b54fd25b061cc7cc4f3dcf48a65f9c3e9 Mon Sep 17 00:00:00 2001 From: Richard Frith-MacDonald Date: Sun, 16 Mar 2008 06:56:52 +0000 Subject: [PATCH] Add KVC aggregate operators git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@26309 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 6 ++ Source/NSArray.m | 223 ++++++++++++++++++++++++++++++++++++++++++++++ Source/NSSet.m | 224 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 453 insertions(+) diff --git a/ChangeLog b/ChangeLog index be6500171..350a9bf29 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-03-16 Richard Frith-Macdonald + + * Source/NSArray.m: + * Source/NSSet.m: + Add ([-valueForKeyPath:]) to implement KVC aggregate operators. + 2008-03-14 Nicola Pero * Source/NSDictionary.m ([-initWithObjectsAndKeys:], diff --git a/Source/NSArray.m b/Source/NSArray.m index 074130c5d..70ccff531 100644 --- a/Source/NSArray.m +++ b/Source/NSArray.m @@ -46,6 +46,8 @@ #import "Foundation/NSDebug.h" #import "Foundation/NSValue.h" #import "Foundation/NSNull.h" +#import "Foundation/NSKeyValueCoding.h" +#import "Foundation/NSSet.h" #import "Foundation/NSUserDefaults.h" #import "Foundation/NSIndexSet.h" // For private method _decodeArrayOfObjectsForKey: @@ -1313,6 +1315,227 @@ compare(id elem1, id elem2, void* context) return result; } +- (id) valueForKeyPath: (NSString*)path +{ + id result; + + if ([path hasPrefix: @"@"]) + { + NSRange r; + + r = [path rangeOfString: @"."]; + if (r.length == 0) + { + result = [self valueForKey: path]; + } + else + { + NSString *op = [path substringToIndex: r.location]; + NSString *rem = [path substringFromIndex: NSMaxRange(r)]; + unsigned count = [self count]; + + if ([op isEqualToString: @"@avg"] == YES) + { + double d = 0; + + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + while ((o = [e nextObject]) != nil) + { + d += [[o valueForKeyPath: rem] doubleValue]; + } + d /= count; + } + result = [NSNumber numberWithDouble: d]; + } + else if ([op isEqualToString: @"@max"] == YES) + { + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + while ((o = [e nextObject]) != nil) + { + o = [o valueForKeyPath: rem]; + if (result == nil + || [result compare: o] == NSOrderedAscending) + { + result = o; + } + } + } + } + else if ([op isEqualToString: @"@min"] == YES) + { + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + while ((o = [e nextObject]) != nil) + { + o = [o valueForKeyPath: rem]; + if (result == nil + || [result compare: o] == NSOrderedDescending) + { + result = o; + } + } + } + } + else if ([op isEqualToString: @"@sum"] == YES) + { + double d = 0; + + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + while ((o = [e nextObject]) != nil) + { + d += [[o valueForKeyPath: rem] doubleValue]; + } + } + result = [NSNumber numberWithDouble: d]; + } + else if ([op isEqualToString: @"@distinctUnionOfArrays"] == YES) + { + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + result = [NSMutableSet set]; + while ((o = [e nextObject]) != nil) + { + o = [o valueForKeyPath: rem]; + [result addObjectsFromArray: o]; + } + result = [result allObjects]; + } + else + { + result = [NSArray array]; + } + } + else if ([op isEqualToString: @"@distinctUnionOfObjects"] == YES) + { + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + result = [NSMutableSet set]; + while ((o = [e nextObject]) != nil) + { + o = [o valueForKeyPath: rem]; + [result addObject: o]; + } + result = [result allObjects]; + } + else + { + result = [NSArray array]; + } + } + else if ([op isEqualToString: @"@distinctUnionOfSets"] == YES) + { + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + result = [NSMutableSet set]; + while ((o = [e nextObject]) != nil) + { + o = [o valueForKeyPath: rem]; + [result addObjectsFromArray: [o allObjects]]; + } + result = [result allObjects]; + } + else + { + result = [NSArray array]; + } + } + else if ([op isEqualToString: @"@unionOfArrays"] == YES) + { + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + result = [GSMutableArray array]; + while ((o = [e nextObject]) != nil) + { + o = [o valueForKeyPath: rem]; + [result addObjectsFromArray: o]; + } + [result makeImmutableCopyOnFail: NO]; + } + else + { + result = [NSArray array]; + } + } + else if ([op isEqualToString: @"@unionOfObjects"] == YES) + { + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + result = [GSMutableArray array]; + while ((o = [e nextObject]) != nil) + { + o = [o valueForKeyPath: rem]; + [result addObject: o]; + } + [result makeImmutableCopyOnFail: NO]; + } + else + { + result = [NSArray array]; + } + } + else if ([op isEqualToString: @"@unionOfSets"] == YES) + { + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + result = [GSMutableArray array]; + while ((o = [e nextObject]) != nil) + { + o = [o valueForKeyPath: rem]; + [result addObjectsFromArray: [o allObjects]]; + } + [result makeImmutableCopyOnFail: NO]; + } + else + { + result = [NSArray array]; + } + } + else + { + result = [self valueForKeyPath: path]; + } + } + } + else + { + result = [super valueForKeyPath: path]; + } + + return result; +} @end diff --git a/Source/NSSet.m b/Source/NSSet.m index fe7b04748..476e17001 100644 --- a/Source/NSSet.m +++ b/Source/NSSet.m @@ -26,11 +26,14 @@ */ #include "config.h" +#include "Foundation/NSArray.h" #include "Foundation/NSSet.h" #include "Foundation/NSCoder.h" #include "Foundation/NSArray.h" #include "Foundation/NSEnumerator.h" +#include "Foundation/NSKeyValueCoding.h" #include "Foundation/NSString.h" +#include "Foundation/NSValue.h" #include "Foundation/NSException.h" #include "Foundation/NSObjCRuntime.h" #include "Foundation/NSDebug.h" @@ -613,6 +616,227 @@ static Class NSMutableSet_concrete_class; return [[self allObjects] descriptionWithLocale: locale]; } +- (id) valueForKeyPath: (NSString*)path +{ + id result; + + if ([path hasPrefix: @"@"]) + { + NSRange r; + + r = [path rangeOfString: @"."]; + if (r.length == 0) + { + result = [self valueForKey: path]; + } + else + { + NSString *op = [path substringToIndex: r.location]; + NSString *rem = [path substringFromIndex: NSMaxRange(r)]; + unsigned count = [self count]; + + if ([op isEqualToString: @"@avg"] == YES) + { + double d = 0; + + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + while ((o = [e nextObject]) != nil) + { + d += [[o valueForKeyPath: rem] doubleValue]; + } + d /= count; + } + result = [NSNumber numberWithDouble: d]; + } + else if ([op isEqualToString: @"@max"] == YES) + { + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + while ((o = [e nextObject]) != nil) + { + o = [o valueForKeyPath: rem]; + if (result == nil + || [result compare: o] == NSOrderedAscending) + { + result = o; + } + } + } + } + else if ([op isEqualToString: @"@min"] == YES) + { + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + while ((o = [e nextObject]) != nil) + { + o = [o valueForKeyPath: rem]; + if (result == nil + || [result compare: o] == NSOrderedDescending) + { + result = o; + } + } + } + } + else if ([op isEqualToString: @"@sum"] == YES) + { + double d = 0; + + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + while ((o = [e nextObject]) != nil) + { + d += [[o valueForKeyPath: rem] doubleValue]; + } + } + result = [NSNumber numberWithDouble: d]; + } + else if ([op isEqualToString: @"@distinctUnionOfArrays"] == YES) + { + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + result = [NSMutableSet set]; + while ((o = [e nextObject]) != nil) + { + o = [o valueForKeyPath: rem]; + [result addObjectsFromArray: o]; + } + result = [result allObjects]; + } + else + { + result = [NSArray array]; + } + } + else if ([op isEqualToString: @"@distinctUnionOfObjects"] == YES) + { + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + result = [NSMutableSet set]; + while ((o = [e nextObject]) != nil) + { + o = [o valueForKeyPath: rem]; + [result addObject: o]; + } + result = [result allObjects]; + } + else + { + result = [NSArray array]; + } + } + else if ([op isEqualToString: @"@distinctUnionOfSets"] == YES) + { + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + result = [NSMutableSet set]; + while ((o = [e nextObject]) != nil) + { + o = [o valueForKeyPath: rem]; + [result addObjectsFromArray: [o allObjects]]; + } + result = [result allObjects]; + } + else + { + result = [NSArray array]; + } + } + else if ([op isEqualToString: @"@unionOfArrays"] == YES) + { + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + result = [GSMutableArray array]; + while ((o = [e nextObject]) != nil) + { + o = [o valueForKeyPath: rem]; + [result addObjectsFromArray: o]; + } + [result makeImmutableCopyOnFail: NO]; + } + else + { + result = [NSArray array]; + } + } + else if ([op isEqualToString: @"@unionOfObjects"] == YES) + { + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + result = [GSMutableArray array]; + while ((o = [e nextObject]) != nil) + { + o = [o valueForKeyPath: rem]; + [result addObject: o]; + } + [result makeImmutableCopyOnFail: NO]; + } + else + { + result = [NSArray array]; + } + } + else if ([op isEqualToString: @"@unionOfSets"] == YES) + { + if (count > 0) + { + NSEnumerator *e = [self objectEnumerator]; + id o; + + result = [GSMutableArray array]; + while ((o = [e nextObject]) != nil) + { + o = [o valueForKeyPath: rem]; + [result addObjectsFromArray: [o allObjects]]; + } + [result makeImmutableCopyOnFail: NO]; + } + else + { + result = [NSArray array]; + } + } + else + { + result = [self valueForKeyPath: path]; + } + } + } + else + { + result = [super valueForKeyPath: path]; + } + + return result; +} @end