mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 00:41:02 +00:00
Review of KVC and improvements by Chris Farber
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@25313 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
bf24d21cb4
commit
6848cb6de9
7 changed files with 1385 additions and 9 deletions
17
ChangeLog
17
ChangeLog
|
@ -1,3 +1,20 @@
|
|||
2007-07-10 Chris Farber <chris@chrisfarber.net>
|
||||
|
||||
* Source/NSArray.m ([NSArray -objectsAtIndexes:]): New method.
|
||||
([NSMutableArray -removeObjectsAtIndexes:]): New method.
|
||||
* Headers/Foundation/NSArray.h: Added the new methods.
|
||||
|
||||
* Source/NSKeyValueCoding.m ([-mutableArrayValueForKey:]): New
|
||||
method. ([-mutableArrayValueForKeyPath:]): New method.
|
||||
([-mutableSetValueForKey:]): New method.
|
||||
([-mutableSetValueForKeyPath:]): New method.
|
||||
([-valueForUndefinedKey:]): Include key and object in the reason
|
||||
of an NSUndefinedKeyException.
|
||||
* Headers/Foundation/NSKeyValueCoding.h: Added the new methods.
|
||||
|
||||
* Source/NSKeyValueMutableSet.m: New file.
|
||||
* Source/NSKeyValueMutableArray.m: New file.
|
||||
|
||||
2007-07-10 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/win32/GSFileHandleWin32.m: Fixup for pipes as suggested by
|
||||
|
|
|
@ -35,6 +35,7 @@ extern "C" {
|
|||
|
||||
@class NSString;
|
||||
@class NSURL;
|
||||
@class NSIndexSet;
|
||||
|
||||
@interface NSArray : NSObject <NSCoding, NSCopying, NSMutableCopying>
|
||||
|
||||
|
@ -72,6 +73,7 @@ extern "C" {
|
|||
|
||||
- (id) lastObject;
|
||||
- (id) objectAtIndex: (unsigned)index; // Primitive
|
||||
- (NSArray *) objectsAtIndexes: (NSIndexSet *)indexes;
|
||||
|
||||
- (id) firstObjectCommonWithArray: (NSArray*)otherArray;
|
||||
- (BOOL) isEqualToArray: (NSArray*)otherArray;
|
||||
|
@ -126,6 +128,7 @@ extern "C" {
|
|||
- (id) initWithCapacity: (unsigned)numItems; // Primitive
|
||||
- (void) insertObject: (id)anObject atIndex: (unsigned)index; // Primitive
|
||||
- (void) removeObjectAtIndex: (unsigned)index; // Primitive
|
||||
- (void) removeObjectsAtIndexes: (NSIndexSet *)indexes;
|
||||
- (void) replaceObjectAtIndex: (unsigned)index
|
||||
withObject: (id)anObject; // Primitive
|
||||
- (void) replaceObjectsInRange: (NSRange)aRange
|
||||
|
|
|
@ -37,6 +37,8 @@ extern "C" {
|
|||
|
||||
@class NSArray;
|
||||
@class NSMutableArray;
|
||||
@class NSSet;
|
||||
@class NSMutableSet;
|
||||
@class NSDictionary;
|
||||
@class NSError;
|
||||
@class NSString;
|
||||
|
@ -91,17 +93,57 @@ GS_EXPORT NSString* const NSUndefinedKeyException;
|
|||
- (void) handleTakeValue: (id)anObject forUnboundKey: (NSString*)aKey;
|
||||
|
||||
/**
|
||||
* <strong>Not implemented</strong> ... I don't know what this method
|
||||
* is good for ... do we need to copy MacOS-X and implement it?
|
||||
* Returns a mutable array value for a given key. This method:
|
||||
* <orderedlist>
|
||||
* <item>Searches the receiver for methods matching the patterns
|
||||
* insertObject:in<Key>AtIndex: and removeObjectFrom<Key>AtIndex:. If both
|
||||
* methods are found, each message sent to the proxy array will result in the
|
||||
* invocation of one or more of these methods. If
|
||||
* replaceObjectIn<Key>AtIndex:withObject: is also found in the receiver it
|
||||
* will be used when appropriate for better performance.</item>
|
||||
* <item>If the set of methods is not found, searches the receiver for a the
|
||||
* method set<Key>:. Each message sent to the proxy array will result in
|
||||
* the invocation of set<Key>:</item>
|
||||
* <item>If the previous do not match, and accessInstanceVariablesDirectly
|
||||
* returns YES, searches for an instance variable matching _<key> or
|
||||
* <key> (in that order). If the instance variable is found, messages sent
|
||||
* to the proxy object will be forwarded to the instance variable.</item>
|
||||
* <item>If none of the previous are found, raises an NSUndefinedKeyException
|
||||
*/
|
||||
- (NSMutableArray*) mutableArrayValueForKey: (NSString*)aKey;
|
||||
|
||||
/**
|
||||
* <strong>Not implemented</strong> ... I don't know what this method
|
||||
* is good for ... do we need to copy MacOS-X and implement it?
|
||||
* Returns a mutable array value for the given key path.
|
||||
*/
|
||||
- (NSMutableArray*) mutableArrayValueForKeyPath: (NSString*)aKey;
|
||||
|
||||
/**
|
||||
* Returns a mutable set value for a given key. This method:
|
||||
* <orderedlist>
|
||||
* <item>Searches the receiver for methods matching the patterns
|
||||
* add<Key>Object:, remove<Key>Object:, add<Key>:, and remove<Key>:, which
|
||||
* correspond to the NSMutableSet methods addObject:, removeObject:,
|
||||
* unionSet:, and minusSet:, respectively. If at least one addition
|
||||
* and one removal method are found, each message sent to the proxy set
|
||||
* will result in the invocation of one or more of these methods. If
|
||||
* intersect<Key>: or set<Key>: is also found in the receiver, the method(s)
|
||||
* will be used when appropriate for better performance.</item>
|
||||
* <item>If the set of methods is not found, searches the receiver for a the
|
||||
* method set<Key>:. Each message sent to the proxy set will result in
|
||||
* the invocation of set<Key>:</item>
|
||||
* <item>If the previous do not match, and accessInstanceVariablesDirectly
|
||||
* returns YES, searches for an instance variable matching _<key> or
|
||||
* <key> (in that order). If the instance variable is found, messages sent
|
||||
* to the proxy object will be forwarded to the instance variable.</item>
|
||||
* <item>If none of the previous are found, raises an NSUndefinedKeyException
|
||||
*/
|
||||
- (NSMutableSet*) mutableSetValueForKey: (NSString *)aKey;
|
||||
|
||||
/**
|
||||
* Returns a mutable set value for the given key path.
|
||||
*/
|
||||
- (NSMutableSet*) mutableSetValueForKeyPath: (NSString*)aKey;
|
||||
|
||||
/**
|
||||
* This method is invoked by the NSKeyValueCoding mechanism when an attempt
|
||||
* is made to set an null value for a scalar attribute. This implementation
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "Foundation/NSValue.h"
|
||||
#include "Foundation/NSNull.h"
|
||||
#include "Foundation/NSUserDefaults.h"
|
||||
#include "Foundation/NSIndexSet.h"
|
||||
// For private method _decodeArrayOfObjectsForKey:
|
||||
#include "Foundation/NSKeyedArchiver.h"
|
||||
#include "GNUstepBase/GSCategories.h"
|
||||
|
@ -835,6 +836,21 @@ static SEL rlSel;
|
|||
return nil;
|
||||
}
|
||||
|
||||
- (NSArray *) objectsAtIndexes: (NSIndexSet *)indexes
|
||||
{
|
||||
//FIXME: probably slow!
|
||||
NSMutableArray * group = [NSMutableArray arrayWithCapacity: [indexes count]];
|
||||
|
||||
unsigned i = [indexes firstIndex];
|
||||
while (i != NSNotFound)
|
||||
{
|
||||
[group addObject: [self objectAtIndex: i]];
|
||||
i = [indexes indexGreaterThanIndex: i];
|
||||
}
|
||||
|
||||
return [group copy];
|
||||
}
|
||||
|
||||
- (BOOL) isEqual: (id)anObject
|
||||
{
|
||||
if (self == anObject)
|
||||
|
@ -844,6 +860,7 @@ static SEL rlSel;
|
|||
return NO;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns YES if the receiver is equal to otherArray, NO otherwise.
|
||||
*/
|
||||
|
@ -1706,6 +1723,22 @@ compare(id elem1, id elem2, void* context)
|
|||
[self addObjectsFromArray: otherArray];
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes objects from the receiver at the indices supplied by an NSIndexSet
|
||||
*/
|
||||
- (void) removeObjectsAtIndexes: (NSIndexSet *)indexes
|
||||
{
|
||||
unsigned count = [indexes count];
|
||||
unsigned indexArray[count];
|
||||
|
||||
[indexes getIndexes: indexArray
|
||||
maxCount:count
|
||||
inIndexRange: NULL];
|
||||
|
||||
[self removeObjectsFromIndices: indexArray
|
||||
numIndices: count];
|
||||
}
|
||||
|
||||
/**
|
||||
* Supplied with a C array of indices containing count values, this method
|
||||
* removes all corresponding objects from the receiver. The objects are
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "Foundation/NSAutoreleasePool.h"
|
||||
#include "Foundation/NSString.h"
|
||||
#include "Foundation/NSArray.h"
|
||||
#include "Foundation/NSSet.h"
|
||||
#include "Foundation/NSException.h"
|
||||
#include "Foundation/NSZone.h"
|
||||
#include "Foundation/NSDebug.h"
|
||||
|
@ -38,6 +39,11 @@
|
|||
#include "Foundation/NSKeyValueCoding.h"
|
||||
#include "Foundation/NSNull.h"
|
||||
|
||||
/* For the NSKeyValueMutableArray and NSKeyValueMutableSet classes
|
||||
*/
|
||||
#include "NSKeyValueMutableArray.m"
|
||||
#include "NSKeyValueMutableSet.m"
|
||||
|
||||
/* For backward compatibility NSUndefinedKeyException is actually the same
|
||||
* as the older NSUnknownKeyException
|
||||
*/
|
||||
|
@ -247,17 +253,78 @@ static id ValueForKey(NSObject *self, const char *key, unsigned size)
|
|||
[exp raise];
|
||||
}
|
||||
|
||||
- (NSMutableSet*) mutableSetValueForKey: (NSString*)aKey
|
||||
{
|
||||
return [NSKeyValueMutableSet setForKey:aKey ofObject:self];
|
||||
}
|
||||
|
||||
- (NSMutableSet*) mutableSetValueForKeyPath: (NSString*)aKey
|
||||
{
|
||||
unsigned size = [aKey length] * 8;
|
||||
char buf[size+1];
|
||||
unsigned start = 0;
|
||||
unsigned end = 0;
|
||||
id o = self;
|
||||
|
||||
[aKey getCString: buf
|
||||
maxLength: size+1
|
||||
encoding: NSUTF8StringEncoding];
|
||||
size = strlen(buf);
|
||||
while (start < size && o != nil)
|
||||
{
|
||||
end = start;
|
||||
while (end < size && buf[end] != '.')
|
||||
{
|
||||
end++;
|
||||
}
|
||||
aKey = [[NSString alloc] initWithBytes: buf + start
|
||||
length: end - start
|
||||
encoding: NSUTF8StringEncoding];
|
||||
AUTORELEASE(aKey);
|
||||
if (end == size)
|
||||
o = [o mutableSetValueForKey: aKey];
|
||||
else
|
||||
o = [o valueForKey: aKey];
|
||||
start = ++end;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
- (NSMutableArray*) mutableArrayValueForKey: (NSString*)aKey
|
||||
{
|
||||
[self notImplemented: _cmd];
|
||||
return nil;
|
||||
return [NSKeyValueMutableArray arrayForKey:aKey ofObject:self];
|
||||
}
|
||||
|
||||
- (NSMutableArray*) mutableArrayValueForKeyPath: (NSString*)aKey
|
||||
{
|
||||
[self notImplemented: _cmd];
|
||||
return nil;
|
||||
unsigned size = [aKey length] * 8;
|
||||
char buf[size+1];
|
||||
unsigned start = 0;
|
||||
unsigned end = 0;
|
||||
id o = self;
|
||||
|
||||
[aKey getCString: buf
|
||||
maxLength: size+1
|
||||
encoding: NSUTF8StringEncoding];
|
||||
size = strlen(buf);
|
||||
while (start < size && o != nil)
|
||||
{
|
||||
end = start;
|
||||
while (end < size && buf[end] != '.')
|
||||
{
|
||||
end++;
|
||||
}
|
||||
aKey = [[NSString alloc] initWithBytes: buf + start
|
||||
length: end - start
|
||||
encoding: NSUTF8StringEncoding];
|
||||
AUTORELEASE(aKey);
|
||||
if (end == size)
|
||||
o = [o mutableArrayValueForKey: aKey];
|
||||
else
|
||||
o = [o valueForKey: aKey];
|
||||
start = ++end;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
- (void) setNilValueForKey: (NSString*)aKey
|
||||
|
@ -819,8 +886,11 @@ static id ValueForKey(NSObject *self, const char *key, unsigned size)
|
|||
self, @"NSTargetObjectUserInfoKey",
|
||||
(aKey ? (id)aKey : (id)@"(nil)"), @"NSUnknownUserInfoKey",
|
||||
nil];
|
||||
NSString * reason = [NSString stringWithFormat:
|
||||
@"Unable to find value for key \"%@\" of object %@ (%@)",
|
||||
aKey, self, [self class]];
|
||||
exp = [NSException exceptionWithName: NSUndefinedKeyException
|
||||
reason: @"Unable to find value for key"
|
||||
reason: reason
|
||||
userInfo: dict];
|
||||
|
||||
[exp raise];
|
||||
|
|
514
Source/NSKeyValueMutableArray.m
Normal file
514
Source/NSKeyValueMutableArray.m
Normal file
|
@ -0,0 +1,514 @@
|
|||
/* Mutable array proxies for GNUstep's KeyValueCoding
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Chris Farber <chris@chrisfarber.net>
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
|
||||
$Date: 2007-06-08 04:04:14 -0400 (Fri, 08 Jun 2007) $ $Revision: 25230 $
|
||||
*/
|
||||
|
||||
#import "Foundation/NSInvocation.h"
|
||||
#import "Foundation/NSIndexSet.h"
|
||||
#import "Foundation/NSKeyValueObserving.h"
|
||||
|
||||
@interface NSKeyValueMutableArray : NSMutableArray
|
||||
{
|
||||
@protected
|
||||
id object;
|
||||
NSString * key;
|
||||
NSMutableArray * array;
|
||||
BOOL otherChangeInProgress;
|
||||
}
|
||||
|
||||
+ (NSKeyValueMutableArray *)arrayForKey:(NSString *)aKey ofObject:(id)anObject;
|
||||
- (id) initWithKey:(NSString *)aKey ofObject:(id)anObject;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSKeyValueFastMutableArray : NSKeyValueMutableArray
|
||||
{
|
||||
@private
|
||||
NSInvocation * insertObjectInvocation;
|
||||
NSInvocation * removeObjectInvocation;
|
||||
NSInvocation * replaceObjectInvocation;
|
||||
}
|
||||
|
||||
+ (id) arrayForKey: (NSString *)aKey ofObject: (id)anObject
|
||||
withCapitalizedKey: (const char *)capitalized;
|
||||
|
||||
- (id) initWithKey: (NSString *)aKey ofObject: (id)anObject
|
||||
withCapitalizedKey: (const char *)capitalized;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSKeyValueSlowMutableArray : NSKeyValueMutableArray
|
||||
{
|
||||
@private
|
||||
NSInvocation * setArrayInvocation;
|
||||
}
|
||||
|
||||
+ (id) arrayForKey: (NSString *)aKey ofObject: (id)anObject
|
||||
withCapitalizedKey: (const char *)capitalized;
|
||||
|
||||
- (id) initWithKey: (NSString *)aKey ofObject: (id)anObject
|
||||
withCapitalizedKey: (const char *)capitalized;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSKeyValueIvarMutableArray : NSKeyValueMutableArray
|
||||
{
|
||||
@private
|
||||
}
|
||||
|
||||
+ (id) arrayForKey: (NSString *)aKey ofObject: (id)anObject;
|
||||
|
||||
- (id) initWithKey: (NSString *)aKey ofObject: (id)anObject;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation NSKeyValueMutableArray
|
||||
|
||||
+ (NSKeyValueMutableArray *)arrayForKey:(NSString *)aKey ofObject:(id)anObject;
|
||||
{
|
||||
NSKeyValueMutableArray * proxy;
|
||||
unsigned size = [aKey maximumLengthOfBytesUsingEncoding:
|
||||
NSASCIIStringEncoding];
|
||||
char key[size + 1];
|
||||
[aKey getCString: key
|
||||
maxLength: size + 1
|
||||
encoding: NSASCIIStringEncoding];
|
||||
if (islower(*key))
|
||||
{
|
||||
*key = toupper(*key);
|
||||
}
|
||||
|
||||
proxy = [NSKeyValueFastMutableArray arrayForKey: aKey
|
||||
ofObject: anObject
|
||||
withCapitalizedKey: key];
|
||||
if (proxy == nil)
|
||||
{
|
||||
proxy = [NSKeyValueSlowMutableArray arrayForKey: aKey
|
||||
ofObject: anObject
|
||||
withCapitalizedKey: key];
|
||||
|
||||
if (proxy == nil)
|
||||
{
|
||||
proxy = [NSKeyValueIvarMutableArray arrayForKey: aKey
|
||||
ofObject: anObject];
|
||||
}
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
|
||||
- (id) initWithKey:(NSString *)aKey ofObject:(id)anObject
|
||||
{
|
||||
[super init];
|
||||
|
||||
object = anObject;
|
||||
key = [aKey copy];
|
||||
otherChangeInProgress = NO;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (unsigned) count
|
||||
{
|
||||
if (array == nil)
|
||||
{
|
||||
array = [object valueForKey: key];
|
||||
}
|
||||
return [array count];
|
||||
}
|
||||
|
||||
- (id) objectAtIndex: (unsigned)index
|
||||
{
|
||||
if (array == nil)
|
||||
{
|
||||
array = [object valueForKey: key];
|
||||
}
|
||||
return [array objectAtIndex: index];
|
||||
}
|
||||
|
||||
- (void) addObject: (id)anObject
|
||||
{
|
||||
[self insertObject: anObject atIndex: [self count]];
|
||||
}
|
||||
|
||||
- (void)removeLastObject
|
||||
{
|
||||
[self removeObjectAtIndex: ([self count] - 1)];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSKeyValueFastMutableArray
|
||||
|
||||
+ (id) arrayForKey: (NSString *)aKey ofObject: (id)anObject
|
||||
withCapitalizedKey: (char *)capitalized
|
||||
{
|
||||
return [[[self alloc] initWithKey:aKey ofObject:anObject
|
||||
withCapitalizedKey:capitalized] autorelease];
|
||||
}
|
||||
|
||||
- (id) initWithKey: (NSString *)aKey ofObject: (id)anObject
|
||||
withCapitalizedKey: (const char *)capitalized
|
||||
{
|
||||
SEL insert;
|
||||
SEL remove;
|
||||
SEL replace;
|
||||
|
||||
|
||||
insert = NSSelectorFromString
|
||||
([NSString stringWithFormat: @"insertObject:in%sAtIndex:", capitalized]);
|
||||
remove = NSSelectorFromString
|
||||
([NSString stringWithFormat: @"removeObjectFrom%sAtIndex:", capitalized]);
|
||||
if (!([anObject respondsToSelector:insert] &&
|
||||
[anObject respondsToSelector:remove]))
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
replace = NSSelectorFromString
|
||||
([NSString stringWithFormat: @"replaceObjectIn%sAtIndex:withObject:", capitalized]);
|
||||
|
||||
[super initWithKey:aKey ofObject:anObject];
|
||||
|
||||
insertObjectInvocation = [[NSInvocation invocationWithMethodSignature:
|
||||
[anObject methodSignatureForSelector:insert]] retain];
|
||||
[insertObjectInvocation setTarget: anObject];
|
||||
[insertObjectInvocation setSelector:insert];
|
||||
removeObjectInvocation = [[NSInvocation invocationWithMethodSignature:
|
||||
[anObject methodSignatureForSelector:remove]] retain];
|
||||
[removeObjectInvocation setTarget: anObject];
|
||||
[removeObjectInvocation setSelector:remove];
|
||||
if ([anObject respondsToSelector:replace])
|
||||
{
|
||||
replaceObjectInvocation = [[NSInvocation invocationWithMethodSignature:
|
||||
[anObject methodSignatureForSelector:replace]] retain];
|
||||
[replaceObjectInvocation setTarget: anObject];
|
||||
[replaceObjectInvocation setSelector:replace];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[insertObjectInvocation release];
|
||||
[removeObjectInvocation release];
|
||||
[replaceObjectInvocation release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) removeObjectAtIndex: (unsigned)index
|
||||
{
|
||||
NSIndexSet * indexes;
|
||||
if (!otherChangeInProgress)
|
||||
{
|
||||
indexes = [NSIndexSet indexSetWithIndex: index];
|
||||
[object willChange: NSKeyValueChangeRemoval
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
}
|
||||
[removeObjectInvocation setArgument:&index atIndex:2];
|
||||
[removeObjectInvocation invoke];
|
||||
if (!otherChangeInProgress)
|
||||
{
|
||||
[object didChange: NSKeyValueChangeRemoval
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) insertObject: (id)anObject atIndex: (unsigned)index
|
||||
{
|
||||
NSIndexSet * indexes;
|
||||
if (!otherChangeInProgress)
|
||||
{
|
||||
indexes = [NSIndexSet indexSetWithIndex: index];
|
||||
[object willChange: NSKeyValueChangeInsertion
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
}
|
||||
[insertObjectInvocation setArgument:&anObject atIndex:2];
|
||||
[insertObjectInvocation setArgument:&index atIndex:3];
|
||||
[insertObjectInvocation invoke];
|
||||
if (!otherChangeInProgress)
|
||||
{
|
||||
[object didChange: NSKeyValueChangeInsertion
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) replaceObjectAtIndex: (unsigned)index withObject: (id)anObject
|
||||
{
|
||||
NSIndexSet * indexes;
|
||||
BOOL triggerNotifications = !otherChangeInProgress;
|
||||
if (triggerNotifications)
|
||||
{
|
||||
otherChangeInProgress = YES;
|
||||
indexes = [NSIndexSet indexSetWithIndex: index];
|
||||
[object willChange: NSKeyValueChangeReplacement
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
}
|
||||
if (replaceObjectInvocation)
|
||||
{
|
||||
[replaceObjectInvocation setArgument:&index atIndex:2];
|
||||
[replaceObjectInvocation setArgument:&anObject atIndex:3];
|
||||
[replaceObjectInvocation invoke];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self removeObjectAtIndex:index];
|
||||
[self insertObject:anObject atIndex:index];
|
||||
}
|
||||
if (triggerNotifications)
|
||||
{
|
||||
[object didChange: NSKeyValueChangeReplacement
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
otherChangeInProgress = NO;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSKeyValueSlowMutableArray
|
||||
|
||||
+ (id) arrayForKey: (NSString *)aKey ofObject: (id)anObject
|
||||
withCapitalizedKey: (const char *)capitalized
|
||||
{
|
||||
return [[[self alloc] initWithKey:aKey ofObject:anObject
|
||||
withCapitalizedKey:capitalized] autorelease];
|
||||
}
|
||||
|
||||
- (id) initWithKey: (NSString *)aKey ofObject: (id)anObject
|
||||
withCapitalizedKey: (const char *)capitalized;
|
||||
|
||||
{
|
||||
SEL set = NSSelectorFromString([NSString stringWithFormat:
|
||||
@"set%s:", capitalized]);
|
||||
|
||||
if (![anObject respondsToSelector: set])
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
[super initWithKey:aKey ofObject:anObject];
|
||||
|
||||
setArrayInvocation = [[NSInvocation invocationWithMethodSignature:
|
||||
[anObject methodSignatureForSelector:set]] retain];
|
||||
[setArrayInvocation setSelector:set];
|
||||
[setArrayInvocation setTarget:anObject];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) removeObjectAtIndex: (unsigned)index
|
||||
{
|
||||
NSIndexSet * indexes;
|
||||
NSMutableArray * temp;
|
||||
|
||||
if (!otherChangeInProgress)
|
||||
{
|
||||
indexes = [NSIndexSet indexSetWithIndex: index];
|
||||
[object willChange: NSKeyValueChangeRemoval
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
}
|
||||
|
||||
temp = [NSMutableArray arrayWithArray:[object valueForKey:key]];
|
||||
[temp removeObjectAtIndex:index];
|
||||
|
||||
[setArrayInvocation setArgument:&temp atIndex:2];
|
||||
[setArrayInvocation invoke];
|
||||
|
||||
if (!otherChangeInProgress)
|
||||
{
|
||||
[object didChange: NSKeyValueChangeRemoval
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) insertObject: (id)anObject atIndex: (unsigned)index
|
||||
{
|
||||
NSIndexSet * indexes;
|
||||
NSMutableArray * temp;
|
||||
|
||||
if (!otherChangeInProgress)
|
||||
{
|
||||
indexes = [NSIndexSet indexSetWithIndex: index];
|
||||
[object willChange: NSKeyValueChangeInsertion
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
}
|
||||
|
||||
temp = [NSMutableArray arrayWithArray:[object valueForKey:key]];
|
||||
[temp insertObject:anObject atIndex:index];
|
||||
|
||||
[setArrayInvocation setArgument:&temp atIndex:2];
|
||||
[setArrayInvocation invoke];
|
||||
|
||||
if (!otherChangeInProgress)
|
||||
{
|
||||
[object didChange: NSKeyValueChangeInsertion
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) replaceObjectAtIndex: (unsigned)index withObject: (id)anObject
|
||||
{
|
||||
NSIndexSet * indexes;
|
||||
NSMutableArray * temp;
|
||||
|
||||
if (!otherChangeInProgress)
|
||||
{
|
||||
indexes = [NSIndexSet indexSetWithIndex: index];
|
||||
[object willChange: NSKeyValueChangeReplacement
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
}
|
||||
|
||||
temp = [NSMutableArray arrayWithArray:[object valueForKey:key]];
|
||||
[temp removeObjectAtIndex:index];
|
||||
[temp insertObject:anObject atIndex:index];
|
||||
|
||||
[setArrayInvocation setArgument:&temp atIndex:2];
|
||||
[setArrayInvocation invoke];
|
||||
|
||||
if (!otherChangeInProgress)
|
||||
{
|
||||
[object didChange: NSKeyValueChangeReplacement
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation NSKeyValueIvarMutableArray
|
||||
|
||||
+ (id)arrayForKey: (NSString *)key ofObject: (id)anObject
|
||||
{
|
||||
return [[[self alloc] initWithKey:key ofObject:anObject] autorelease];
|
||||
}
|
||||
|
||||
- (id) initWithKey: (NSString *)aKey ofObject: (id)anObject
|
||||
{
|
||||
[super initWithKey: aKey ofObject: anObject];
|
||||
|
||||
{
|
||||
unsigned size = [aKey maximumLengthOfBytesUsingEncoding:NSASCIIStringEncoding];
|
||||
char cKey[size + 2];
|
||||
char *cKeyPtr = &cKey[0];
|
||||
const char *type = 0;
|
||||
BOOL found;
|
||||
int offset;
|
||||
|
||||
cKey[0] = '_';
|
||||
[aKey getCString:cKeyPtr + 1
|
||||
maxLength:size + 1
|
||||
encoding:NSASCIIStringEncoding];
|
||||
|
||||
if (!GSObjCFindVariable (anObject, cKeyPtr, &type, &size, &offset))
|
||||
found = GSObjCFindVariable (anObject, ++cKeyPtr, &type, &size, &offset);
|
||||
if (found)
|
||||
{
|
||||
array = GSObjCGetVal (anObject, cKeyPtr, NULL, type, size, offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
array = [object valueForKey: key];
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) addObject: (id)anObject
|
||||
{
|
||||
NSIndexSet * indexes = [NSIndexSet indexSetWithIndex: [array count]];
|
||||
[object willChange: NSKeyValueChangeInsertion
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
[array addObject:anObject];
|
||||
[object didChange: NSKeyValueChangeInsertion
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
}
|
||||
|
||||
- (void) removeObjectAtIndex: (unsigned)index
|
||||
{
|
||||
NSIndexSet * indexes = [NSIndexSet indexSetWithIndex: index];
|
||||
[object willChange: NSKeyValueChangeRemoval
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
[array removeObjectAtIndex:index];
|
||||
[object didChange: NSKeyValueChangeRemoval
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
}
|
||||
|
||||
- (void) insertObject: (id)anObject atIndex: (unsigned)index
|
||||
{
|
||||
NSIndexSet * indexes = [NSIndexSet indexSetWithIndex: index];
|
||||
[object willChange: NSKeyValueChangeInsertion
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
[array insertObject: anObject atIndex: index];
|
||||
[object didChange: NSKeyValueChangeInsertion
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
}
|
||||
|
||||
- (void) removeLastObject
|
||||
{
|
||||
NSIndexSet * indexes = [NSIndexSet indexSetWithIndex: [array count] - 1];
|
||||
[object willChange: NSKeyValueChangeRemoval
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
[array removeObjectAtIndex: [indexes firstIndex]];
|
||||
[object didChange: NSKeyValueChangeRemoval
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
}
|
||||
|
||||
- (void) replaceObjectAtIndex: (unsigned)index withObject: (id)anObject
|
||||
{
|
||||
NSIndexSet * indexes = [NSIndexSet indexSetWithIndex: index];
|
||||
[object willChange: NSKeyValueChangeReplacement
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
[array replaceObjectAtIndex: index withObject: anObject];
|
||||
[object didChange: NSKeyValueChangeReplacement
|
||||
valuesAtIndexes: indexes
|
||||
forKey: key];
|
||||
}
|
||||
|
||||
|
||||
@end
|
697
Source/NSKeyValueMutableSet.m
Normal file
697
Source/NSKeyValueMutableSet.m
Normal file
|
@ -0,0 +1,697 @@
|
|||
/* Mutable set proxies for GNUstep's KeyValueCoding
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Chris Farber <chris@chrisfarber.net>
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
|
||||
$Date: 2007-06-08 04:04:14 -0400 (Fri, 08 Jun 2007) $ $Revision: 25230 $
|
||||
*/
|
||||
|
||||
#import "Foundation/NSInvocation.h"
|
||||
|
||||
@interface NSKeyValueMutableSet : NSMutableSet
|
||||
{
|
||||
@protected
|
||||
id object;
|
||||
NSString * key;
|
||||
NSMutableSet * set;
|
||||
BOOL changeInProgress;
|
||||
}
|
||||
|
||||
+ (NSKeyValueMutableSet *)setForKey:(NSString *)aKey ofObject:(id)anObject;
|
||||
- (id) initWithKey:(NSString *)aKey ofObject:(id)anObject;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSKeyValueFastMutableSet : NSKeyValueMutableSet
|
||||
{
|
||||
@private
|
||||
NSInvocation * addObjectInvocation;
|
||||
NSInvocation * removeObjectInvocation;
|
||||
NSInvocation * addSetInvocation;
|
||||
NSInvocation * removeSetInvocation;
|
||||
NSInvocation * intersectInvocation;
|
||||
NSInvocation * setSetInvocation;
|
||||
}
|
||||
|
||||
+ (id) setForKey: (NSString *)aKey ofObject: (id)anObject
|
||||
withCapitalizedKey: (const char *)capitalized;
|
||||
|
||||
- (id) initWithKey: (NSString *)aKey ofObject: (id)anObject
|
||||
withCapitalizedKey: (const char *)capitalized;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSKeyValueSlowMutableSet : NSKeyValueMutableSet
|
||||
{
|
||||
@private
|
||||
NSInvocation * setSetInvocation;
|
||||
}
|
||||
|
||||
+ (id) setForKey: (NSString *)aKey ofObject: (id)anObject
|
||||
withCapitalizedKey: (const char *)capitalized;
|
||||
|
||||
- (id) initWithKey: (NSString *)aKey ofObject: (id)anObject
|
||||
withCapitalizedKey: (const char *)capitalized;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSKeyValueIvarMutableSet : NSKeyValueMutableSet
|
||||
{
|
||||
@private
|
||||
}
|
||||
|
||||
+ (id) setForKey: (NSString *)aKey ofObject: (id)anObject;
|
||||
|
||||
- (id) initWithKey: (NSString *)aKey ofObject: (id)anObject;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation NSKeyValueMutableSet
|
||||
|
||||
+ (NSKeyValueMutableSet *)setForKey:(NSString *)aKey ofObject:(id)anObject;
|
||||
{
|
||||
unsigned size = [aKey maximumLengthOfBytesUsingEncoding:
|
||||
NSASCIIStringEncoding];
|
||||
char key[size + 1];
|
||||
|
||||
[aKey getCString: key
|
||||
maxLength: size + 1
|
||||
encoding: NSASCIIStringEncoding];
|
||||
if (islower(*key))
|
||||
{
|
||||
*key = toupper(*key);
|
||||
}
|
||||
|
||||
NSKeyValueMutableSet * proxy;
|
||||
|
||||
proxy = [NSKeyValueFastMutableSet setForKey:aKey
|
||||
ofObject:anObject
|
||||
withCapitalizedKey:key];
|
||||
if (proxy == nil)
|
||||
{
|
||||
proxy = [NSKeyValueSlowMutableSet setForKey:aKey
|
||||
ofObject:anObject
|
||||
withCapitalizedKey:key];
|
||||
|
||||
if (proxy == nil)
|
||||
{
|
||||
proxy = [NSKeyValueIvarMutableSet setForKey:aKey
|
||||
ofObject:anObject];
|
||||
}
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
|
||||
- (id) initWithKey:(NSString *)aKey ofObject:(id)anObject
|
||||
{
|
||||
[super init];
|
||||
|
||||
object = anObject;
|
||||
key = [aKey copy];
|
||||
changeInProgress = NO;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (unsigned) count
|
||||
{
|
||||
if (set == nil)
|
||||
{
|
||||
set = [object valueForKey: key];
|
||||
}
|
||||
return [set count];
|
||||
}
|
||||
|
||||
- (id) member: (id)anObject
|
||||
{
|
||||
if (set == nil)
|
||||
{
|
||||
set = [object valueForKey: key];
|
||||
}
|
||||
return [set member: anObject];
|
||||
}
|
||||
|
||||
- (NSEnumerator *) objectEnumerator
|
||||
{
|
||||
if (set == nil)
|
||||
{
|
||||
set = [object valueForKey: key];
|
||||
}
|
||||
return [set objectEnumerator];
|
||||
}
|
||||
|
||||
- (void) removeAllObjects
|
||||
{
|
||||
if (set == nil)
|
||||
{
|
||||
set = [object valueForKey: key];
|
||||
}
|
||||
[set removeAllObjects];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSKeyValueFastMutableSet
|
||||
|
||||
+ (id) setForKey: (NSString *)aKey ofObject: (id)anObject
|
||||
withCapitalizedKey: (char *)capitalized
|
||||
{
|
||||
return [[[self alloc] initWithKey: aKey
|
||||
ofObject: anObject
|
||||
withCapitalizedKey: capitalized] autorelease];
|
||||
}
|
||||
|
||||
- (id) initWithKey: (NSString *)aKey ofObject: (id)anObject
|
||||
withCapitalizedKey: (const char *)capitalized
|
||||
{
|
||||
SEL addObject;
|
||||
SEL removeObject;
|
||||
SEL addSet;
|
||||
SEL removeSet;
|
||||
SEL intersect;
|
||||
SEL setSet;
|
||||
BOOL canAdd = NO;
|
||||
BOOL canRemove = NO;
|
||||
|
||||
|
||||
addObject = NSSelectorFromString
|
||||
([NSString stringWithFormat: @"add%sObject:", capitalized]);
|
||||
removeObject = NSSelectorFromString
|
||||
([NSString stringWithFormat: @"remove%sObject:", capitalized]);
|
||||
addSet = NSSelectorFromString
|
||||
([NSString stringWithFormat: @"add%s:", capitalized]);
|
||||
removeSet = NSSelectorFromString
|
||||
([NSString stringWithFormat: @"remove%s:", capitalized]);
|
||||
|
||||
if ([anObject respondsToSelector:addObject])
|
||||
{
|
||||
canAdd = YES;
|
||||
addObjectInvocation = [[NSInvocation invocationWithMethodSignature:
|
||||
[anObject methodSignatureForSelector: addObject]] retain];
|
||||
[addObjectInvocation setTarget: anObject];
|
||||
[addObjectInvocation setSelector: addObject];
|
||||
}
|
||||
if ([anObject respondsToSelector:removeObject])
|
||||
{
|
||||
canRemove = YES;
|
||||
removeObjectInvocation = [[NSInvocation invocationWithMethodSignature:
|
||||
[anObject methodSignatureForSelector: removeObject]] retain];
|
||||
[removeObjectInvocation setTarget: anObject];
|
||||
[removeObjectInvocation setSelector: removeObject];
|
||||
}
|
||||
if ([anObject respondsToSelector:addSet])
|
||||
{
|
||||
canAdd = YES;
|
||||
addSetInvocation = [[NSInvocation invocationWithMethodSignature:
|
||||
[anObject methodSignatureForSelector: addSet]] retain];
|
||||
[addSetInvocation setTarget: anObject];
|
||||
[addSetInvocation setSelector: addSet];
|
||||
}
|
||||
if ([anObject respondsToSelector:removeSet])
|
||||
{
|
||||
canRemove = YES;
|
||||
removeSetInvocation = [[NSInvocation invocationWithMethodSignature:
|
||||
[anObject methodSignatureForSelector: removeSet]] retain];
|
||||
[removeSetInvocation setTarget: anObject];
|
||||
[removeSetInvocation setSelector: removeSet];
|
||||
}
|
||||
|
||||
if (!canAdd || !canRemove)
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
[super initWithKey: aKey ofObject: anObject];
|
||||
|
||||
intersect = NSSelectorFromString
|
||||
([NSString stringWithFormat: @"intersect%s:", capitalized]);
|
||||
setSet = NSSelectorFromString
|
||||
([NSString stringWithFormat: @"set%s:", capitalized]);
|
||||
|
||||
if ([anObject respondsToSelector: intersect])
|
||||
{
|
||||
intersectInvocation = [[NSInvocation invocationWithMethodSignature:
|
||||
[anObject methodSignatureForSelector: intersect]] retain];
|
||||
[intersectInvocation setTarget: anObject];
|
||||
[intersectInvocation setSelector: intersect];
|
||||
}
|
||||
if ([anObject respondsToSelector: setSet])
|
||||
{
|
||||
setSetInvocation = [[NSInvocation invocationWithMethodSignature:
|
||||
[anObject methodSignatureForSelector: setSet]] retain];
|
||||
[setSetInvocation setTarget: anObject];
|
||||
[setSetInvocation setSelector: setSet];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[setSetInvocation release];
|
||||
[intersectInvocation release];
|
||||
[removeSetInvocation release];
|
||||
[addSetInvocation release];
|
||||
[removeObjectInvocation release];
|
||||
[addObjectInvocation release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) addObject: (id)anObject
|
||||
{
|
||||
if (addObjectInvocation)
|
||||
{
|
||||
if (!changeInProgress)
|
||||
{
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueUnionSetMutation
|
||||
usingObjects: [NSSet setWithObject:anObject]];
|
||||
}
|
||||
[addObjectInvocation setArgument: &anObject atIndex: 2];
|
||||
[addObjectInvocation invoke];
|
||||
if (!changeInProgress)
|
||||
{
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueUnionSetMutation
|
||||
usingObjects: [NSSet setWithObject:anObject]];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[self unionSet: [NSSet setWithObject: anObject]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) unionSet: (NSSet *)aSet
|
||||
{
|
||||
changeInProgress = YES;
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueUnionSetMutation
|
||||
usingObjects: aSet];
|
||||
if (addSetInvocation)
|
||||
{
|
||||
[addSetInvocation setArgument: &aSet atIndex: 2];
|
||||
[addSetInvocation invoke];
|
||||
}
|
||||
else
|
||||
[super unionSet:aSet];
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueUnionSetMutation
|
||||
usingObjects: aSet];
|
||||
changeInProgress = NO;
|
||||
}
|
||||
|
||||
- (void) removeObject: (id)anObject
|
||||
{
|
||||
if (removeObjectInvocation)
|
||||
{
|
||||
if (!changeInProgress)
|
||||
{
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueMinusSetMutation
|
||||
usingObjects: [NSSet setWithObject: anObject]];
|
||||
}
|
||||
[removeObjectInvocation setArgument: &anObject atIndex: 2];
|
||||
[removeObjectInvocation invoke];
|
||||
if (!changeInProgress)
|
||||
{
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueMinusSetMutation
|
||||
usingObjects: [NSSet setWithObject: anObject]];
|
||||
}
|
||||
}
|
||||
else
|
||||
[self minusSet:[NSSet setWithObject:anObject]];
|
||||
}
|
||||
|
||||
- (void) minusSet: (NSSet *)aSet
|
||||
{
|
||||
changeInProgress = YES;
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueMinusSetMutation
|
||||
usingObjects: aSet];
|
||||
if (removeSetInvocation)
|
||||
{
|
||||
[removeSetInvocation setArgument: &aSet atIndex: 2];
|
||||
[removeSetInvocation invoke];
|
||||
}
|
||||
else
|
||||
{
|
||||
[super minusSet: aSet];
|
||||
}
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueMinusSetMutation
|
||||
usingObjects: aSet];
|
||||
changeInProgress = NO;
|
||||
}
|
||||
|
||||
- (void) intersectSet: (NSSet *)aSet
|
||||
{
|
||||
changeInProgress = YES;
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueIntersectSetMutation
|
||||
usingObjects: aSet];
|
||||
if (intersectInvocation)
|
||||
{
|
||||
[intersectInvocation setArgument: &aSet atIndex: 2];
|
||||
[intersectInvocation invoke];
|
||||
}
|
||||
else
|
||||
{
|
||||
[super intersectSet: aSet];
|
||||
}
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueIntersectSetMutation
|
||||
usingObjects: aSet];
|
||||
changeInProgress = NO;
|
||||
}
|
||||
|
||||
- (void) setSet: (NSSet *)aSet
|
||||
{
|
||||
changeInProgress = YES;
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueSetSetMutation
|
||||
usingObjects: aSet];
|
||||
if (setSetInvocation)
|
||||
{
|
||||
[setSetInvocation setArgument: &aSet atIndex: 2];
|
||||
[setSetInvocation invoke];
|
||||
}
|
||||
else
|
||||
{
|
||||
[super setSet: aSet];
|
||||
}
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueSetSetMutation
|
||||
usingObjects: aSet];
|
||||
changeInProgress = NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSKeyValueSlowMutableSet
|
||||
|
||||
+ (id) setForKey: (NSString *)aKey ofObject: (id)anObject
|
||||
withCapitalizedKey: (const char *)capitalized
|
||||
{
|
||||
return [[[self alloc] initWithKey:aKey ofObject:anObject
|
||||
withCapitalizedKey:capitalized] autorelease];
|
||||
}
|
||||
|
||||
- (id) initWithKey: (NSString *)aKey ofObject: (id)anObject
|
||||
withCapitalizedKey: (const char *)capitalized;
|
||||
|
||||
{
|
||||
SEL setSelector = NSSelectorFromString([NSString stringWithFormat:
|
||||
@"set%s:", capitalized]);
|
||||
|
||||
if (![anObject respondsToSelector:setSelector])
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
[super initWithKey:aKey ofObject:anObject];
|
||||
|
||||
setSetInvocation = [[NSInvocation invocationWithMethodSignature:
|
||||
[anObject methodSignatureForSelector:setSelector]] retain];
|
||||
[setSetInvocation setSelector:setSelector];
|
||||
[setSetInvocation setTarget:anObject];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) setSet: (id)aSet
|
||||
{
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueSetSetMutation
|
||||
usingObjects: aSet];
|
||||
[setSetInvocation setArgument: &aSet atIndex: 2];
|
||||
[setSetInvocation invoke];
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueSetSetMutation
|
||||
usingObjects: aSet];
|
||||
}
|
||||
|
||||
- (void) removeAllObjects
|
||||
{
|
||||
NSSet * theSet = [NSSet setWithSet: [object valueForKey: key]];
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueMinusSetMutation
|
||||
usingObjects: theSet];
|
||||
NSSet * nothing = [NSSet set];
|
||||
[setSetInvocation setArgument: ¬hing atIndex: 2];
|
||||
[setSetInvocation invoke];
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueMinusSetMutation
|
||||
usingObjects: theSet];
|
||||
}
|
||||
|
||||
- (void) addObject: (id)anObject
|
||||
{
|
||||
NSSet * unionSet = [NSSet setWithObject:anObject];
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueUnionSetMutation
|
||||
usingObjects: unionSet];
|
||||
NSMutableSet * temp = [NSMutableSet setWithSet:[object valueForKey:key]];
|
||||
[temp addObject:anObject];
|
||||
[setSetInvocation setArgument: &temp atIndex: 2];
|
||||
[setSetInvocation invoke];
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueUnionSetMutation
|
||||
usingObjects: unionSet];
|
||||
}
|
||||
|
||||
- (void) removeObject: (id)anObject
|
||||
{
|
||||
NSSet * minusSet = [NSSet setWithObject:anObject];
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueMinusSetMutation
|
||||
usingObjects: minusSet];
|
||||
NSMutableSet * temp = [NSMutableSet setWithSet: [object valueForKey: key]];
|
||||
[temp removeObject:anObject];
|
||||
[setSetInvocation setArgument: &temp atIndex: 2];
|
||||
[setSetInvocation invoke];
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueMinusSetMutation
|
||||
usingObjects: minusSet];
|
||||
}
|
||||
|
||||
- (void) unionSet: (id)anObject
|
||||
{
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueUnionSetMutation
|
||||
usingObjects: anObject];
|
||||
NSMutableSet * temp = [NSMutableSet setWithSet: [object valueForKey: key]];
|
||||
[temp unionSet:anObject];
|
||||
[setSetInvocation setArgument: &temp atIndex: 2];
|
||||
[setSetInvocation invoke];
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueUnionSetMutation
|
||||
usingObjects: anObject];
|
||||
}
|
||||
|
||||
- (void) minusSet: (id)anObject
|
||||
{
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueMinusSetMutation
|
||||
usingObjects: anObject];
|
||||
NSMutableSet * temp = [NSMutableSet setWithSet: [object valueForKey: key]];
|
||||
[temp minusSet:anObject];
|
||||
[setSetInvocation setArgument: &temp atIndex: 2];
|
||||
[setSetInvocation invoke];
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueMinusSetMutation
|
||||
usingObjects: anObject];
|
||||
}
|
||||
|
||||
- (void) intersectSet: (id)anObject
|
||||
{
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueIntersectSetMutation
|
||||
usingObjects: anObject];
|
||||
NSMutableSet * temp = [NSMutableSet setWithSet: [object valueForKey: key]];
|
||||
[temp intersectSet:anObject];
|
||||
[setSetInvocation setArgument: &temp atIndex: 2];
|
||||
[setSetInvocation invoke];
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueIntersectSetMutation
|
||||
usingObjects: anObject];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation NSKeyValueIvarMutableSet
|
||||
|
||||
+ (id)setForKey: (NSString *)key ofObject: (id)anObject
|
||||
{
|
||||
return [[[self alloc] initWithKey:key ofObject:anObject] autorelease];
|
||||
}
|
||||
|
||||
- (id) initWithKey: (NSString *)aKey ofObject: (id)anObject
|
||||
{
|
||||
[super initWithKey: aKey ofObject: anObject];
|
||||
|
||||
unsigned size = [aKey maximumLengthOfBytesUsingEncoding: NSASCIIStringEncoding];
|
||||
char cKey[size + 2];
|
||||
char *cKeyPtr = &cKey[0];
|
||||
const char *type = 0;
|
||||
|
||||
int offset;
|
||||
|
||||
|
||||
cKey[0] = '_';
|
||||
[aKey getCString: cKeyPtr + 1
|
||||
maxLength: size + 1
|
||||
encoding: NSASCIIStringEncoding];
|
||||
if (!GSObjCFindVariable (anObject, cKeyPtr, &type, &size, &offset))
|
||||
{
|
||||
GSObjCFindVariable (anObject, ++cKeyPtr, &type, &size, &offset);
|
||||
}
|
||||
set = GSObjCGetVal (anObject, cKeyPtr, NULL, type, size, offset);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (unsigned) count
|
||||
{
|
||||
return [set count];
|
||||
}
|
||||
|
||||
- (NSArray *) allObjects
|
||||
{
|
||||
return [set allObjects];
|
||||
}
|
||||
|
||||
- (BOOL) containsObject: (id)anObject
|
||||
{
|
||||
return [set containsObject: anObject];
|
||||
}
|
||||
|
||||
- (id) member: (id)anObject
|
||||
{
|
||||
return [set member: anObject];
|
||||
}
|
||||
|
||||
- (void) addObject: (id)anObject
|
||||
{
|
||||
if (!changeInProgress)
|
||||
{
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueUnionSetMutation
|
||||
usingObjects: [NSSet setWithObject:anObject]];
|
||||
}
|
||||
[set addObject:anObject];
|
||||
if (!changeInProgress)
|
||||
{
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueUnionSetMutation
|
||||
usingObjects: [NSSet setWithObject:anObject]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeObject: (id)anObject
|
||||
{
|
||||
if (!changeInProgress)
|
||||
{
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueMinusSetMutation
|
||||
usingObjects: [NSSet setWithObject:anObject]];
|
||||
}
|
||||
[set removeObject:anObject];
|
||||
if (!changeInProgress)
|
||||
{
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueMinusSetMutation
|
||||
usingObjects: [NSSet setWithObject:anObject]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unionSet: (id)anObject
|
||||
{
|
||||
if (!changeInProgress)
|
||||
{
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueUnionSetMutation
|
||||
usingObjects: [NSSet setWithObject:anObject]];
|
||||
}
|
||||
[set unionSet:anObject];
|
||||
if (!changeInProgress)
|
||||
{
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueUnionSetMutation
|
||||
usingObjects: [NSSet setWithObject:anObject]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)minusSet: (id)anObject
|
||||
{
|
||||
if (!changeInProgress)
|
||||
{
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueMinusSetMutation
|
||||
usingObjects: [NSSet setWithObject:anObject]];
|
||||
}
|
||||
[set minusSet:anObject];
|
||||
if (!changeInProgress)
|
||||
{
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueMinusSetMutation
|
||||
usingObjects: [NSSet setWithObject:anObject]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)intersectSet: (id)anObject
|
||||
{
|
||||
if (!changeInProgress)
|
||||
{
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueIntersectSetMutation
|
||||
usingObjects: [NSSet setWithObject:anObject]];
|
||||
}
|
||||
[set intersectSet:anObject];
|
||||
if (!changeInProgress)
|
||||
{
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueIntersectSetMutation
|
||||
usingObjects: [NSSet setWithObject:anObject]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setSet: (id)anObject
|
||||
{
|
||||
if (!changeInProgress)
|
||||
{
|
||||
[object willChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueSetSetMutation
|
||||
usingObjects: [NSSet setWithObject:anObject]];
|
||||
}
|
||||
[set setSet:anObject];
|
||||
if (!changeInProgress)
|
||||
{
|
||||
[object didChangeValueForKey: key
|
||||
withSetMutation: NSKeyValueSetSetMutation
|
||||
usingObjects: [NSSet setWithObject:anObject]];
|
||||
}
|
||||
}
|
||||
@end
|
Loading…
Reference in a new issue