Add KVC aggregate operators

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@26309 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2008-03-16 06:56:52 +00:00
parent cf1a0d7780
commit bf72375a70
3 changed files with 453 additions and 0 deletions

View file

@ -1,3 +1,9 @@
2008-03-16 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSArray.m:
* Source/NSSet.m:
Add ([-valueForKeyPath:]) to implement KVC aggregate operators.
2008-03-14 Nicola Pero <nicola.pero@meta-innovation.com>
* Source/NSDictionary.m ([-initWithObjectsAndKeys:],

View file

@ -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

View file

@ -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