Optimisations for NSDictionary ... now about at the limit.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@4878 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
richard 1999-09-12 19:03:09 +00:00
parent 302c691e79
commit 85835779a2
3 changed files with 315 additions and 166 deletions

View file

@ -1,3 +1,9 @@
Sun Sep 12 20:22:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Source/NSDictionary.m: optimise by avoiding objc method lookup
overheads wherever possible.
* Source/NSGDictionary.m: likewise.
Fri Sep 3 11:57:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk> Fri Sep 3 11:57:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Source/NSString.m: speed up path handling a bit by caching * Source/NSString.m: speed up path handling a bit by caching

View file

@ -44,9 +44,18 @@
@class NSGDictionary; @class NSGDictionary;
@class NSGMutableDictionary; @class NSGMutableDictionary;
static Class NSArray_class;
static Class NSDictionary_abstract_class;
static Class NSMutableDictionary_abstract_class;
static Class NSDictionary_concrete_class; static Class NSDictionary_concrete_class;
static Class NSMutableDictionary_concrete_class; static Class NSMutableDictionary_concrete_class;
static SEL nxtSel = @selector(nextObject);
static SEL objSel = @selector(objectForKey:);
static SEL remSel = @selector(removeObjectForKey:);
static SEL setSel = @selector(setObject:forKey:);
static SEL appSel = @selector(appendString:);
+ (void) _setConcreteClass: (Class)c + (void) _setConcreteClass: (Class)c
{ {
NSDictionary_concrete_class = c; NSDictionary_concrete_class = c;
@ -71,23 +80,26 @@ static Class NSMutableDictionary_concrete_class;
{ {
if (self == [NSDictionary class]) if (self == [NSDictionary class])
{ {
NSArray_class = [NSArray class];
NSDictionary_abstract_class = [NSDictionary class];
NSMutableDictionary_abstract_class = [NSMutableDictionary class];
NSDictionary_concrete_class = [NSGDictionary class]; NSDictionary_concrete_class = [NSGDictionary class];
NSMutableDictionary_concrete_class = [NSGMutableDictionary class]; NSMutableDictionary_concrete_class = [NSGMutableDictionary class];
behavior_class_add_class (self, [NSDictionaryNonCore class]); behavior_class_add_class (self, [NSDictionaryNonCore class]);
} }
} }
+ allocWithZone: (NSZone*)z + (id) allocWithZone: (NSZone*)z
{ {
if ([self class] == [NSDictionary class]) if (self == NSDictionary_abstract_class)
return NSAllocateObject([self _concreteClass], 0, z); return NSAllocateObject(NSDictionary_concrete_class, 0, z);
return [super allocWithZone: z]; return [super allocWithZone: z];
} }
/* This is the designated initializer */ /* This is the designated initializer */
- initWithObjects: (id*)objects - (id) initWithObjects: (id*)objects
forKeys: (id*)keys forKeys: (id*)keys
count: (unsigned)count count: (unsigned)count
{ {
[self subclassResponsibility: _cmd]; [self subclassResponsibility: _cmd];
return 0; return 0;
@ -99,7 +111,7 @@ static Class NSMutableDictionary_concrete_class;
return 0; return 0;
} }
- objectForKey: (id)aKey - (id) objectForKey: (id)aKey
{ {
[self subclassResponsibility: _cmd]; [self subclassResponsibility: _cmd];
return 0; return 0;
@ -124,7 +136,7 @@ static Class NSMutableDictionary_concrete_class;
- (id) mutableCopyWithZone: (NSZone*)z - (id) mutableCopyWithZone: (NSZone*)z
{ {
return [[[[self class] _mutableConcreteClass] allocWithZone: z] return [[NSMutableDictionary_concrete_class allocWithZone: z]
initWithDictionary: self]; initWithDictionary: self];
} }
@ -168,8 +180,9 @@ static Class NSMutableDictionary_concrete_class;
- (id) initWithObjects: (NSArray*)objects forKeys: (NSArray*)keys - (id) initWithObjects: (NSArray*)objects forKeys: (NSArray*)keys
{ {
int objectCount = [objects count]; unsigned objectCount = [objects count];
id os[objectCount], ks[objectCount]; id os[objectCount];
id ks[objectCount];
if (objectCount != [keys count]) if (objectCount != [keys count])
{ {
@ -184,12 +197,12 @@ static Class NSMutableDictionary_concrete_class;
- (id) initWithObjectsAndKeys: (id)firstObject, ... - (id) initWithObjectsAndKeys: (id)firstObject, ...
{ {
va_list ap; va_list ap;
int capacity = 16; int capacity = 16;
int num_pairs = 0; int num_pairs = 0;
id *objects; id *objects;
id *keys; id *keys;
id arg; id arg;
int argi = 1; int argi = 1;
va_start (ap, firstObject); va_start (ap, firstObject);
if (firstObject == nil) if (firstObject == nil)
@ -234,15 +247,15 @@ static Class NSMutableDictionary_concrete_class;
return self; return self;
} }
+ dictionaryWithObjectsAndKeys: (id)firstObject, ... + (id) dictionaryWithObjectsAndKeys: (id)firstObject, ...
{ {
va_list ap; va_list ap;
int capacity = 16; int capacity = 16;
int num_pairs = 0; int num_pairs = 0;
id *objects; id *objects;
id *keys; id *keys;
id arg; id arg;
int argi = 1; int argi = 1;
va_start (ap, firstObject); va_start (ap, firstObject);
/* Gather all the arguments in a simple array, in preparation for /* Gather all the arguments in a simple array, in preparation for
@ -301,25 +314,30 @@ static Class NSMutableDictionary_concrete_class;
return [self initWithObjects: NULL forKeys: NULL count: 0]; return [self initWithObjects: NULL forKeys: NULL count: 0];
} }
- initWithDictionary: (NSDictionary*)other - (id) initWithDictionary: (NSDictionary*)other
{ {
return [self initWithDictionary: other copyItems: NO]; return [self initWithDictionary: other copyItems: NO];
} }
- initWithDictionary: (NSDictionary*)other copyItems: (BOOL)shouldCopy - (id) initWithDictionary: (NSDictionary*)other copyItems: (BOOL)shouldCopy
{ {
int c = [other count]; unsigned c = [other count];
id os[c], ks[c], k, e = [other keyEnumerator]; id os[c];
int i = 0; id ks[c];
id k;
NSEnumerator *e = [other keyEnumerator];
unsigned i = 0;
IMP nxtObj = [e methodForSelector: nxtSel];
IMP otherObj = [other methodForSelector: objSel];
if (shouldCopy) if (shouldCopy)
{ {
NSZone *z = [self zone]; NSZone *z = [self zone];
while ((k = [e nextObject])) while ((k = (*nxtObj)(e, nxtSel)) != nil)
{ {
ks[i] = k; ks[i] = k;
os[i] = [[other objectForKey: k] copyWithZone: z]; os[i] = [(*otherObj)(other, objSel, k) copyWithZone: z];
i++; i++;
} }
self = [self initWithObjects: os forKeys: ks count: i]; self = [self initWithObjects: os forKeys: ks count: i];
@ -333,17 +351,17 @@ static Class NSMutableDictionary_concrete_class;
} }
else else
{ {
while ((k = [e nextObject])) while ((k = (*nxtObj)(e, nxtSel)) != nil)
{ {
ks[i] = k; ks[i] = k;
os[i] = [other objectForKey: k]; os[i] = (*otherObj)(other, objSel, k);
i++; i++;
} }
return [self initWithObjects: os forKeys: ks count: c]; return [self initWithObjects: os forKeys: ks count: c];
} }
} }
- initWithContentsOfFile: (NSString*)path - (id) initWithContentsOfFile: (NSString*)path
{ {
NSString *myString; NSString *myString;
@ -363,7 +381,7 @@ static Class NSMutableDictionary_concrete_class;
} }
NS_ENDHANDLER NS_ENDHANDLER
RELEASE(myString); RELEASE(myString);
if ([result isKindOfClass: [NSDictionary class]]) if ([result isKindOfClass: NSDictionary_abstract_class])
{ {
[self initWithDictionary: result]; [self initWithDictionary: result];
return self; return self;
@ -382,77 +400,122 @@ static Class NSMutableDictionary_concrete_class;
- (BOOL) isEqual: other - (BOOL) isEqual: other
{ {
if ([other isKindOfClass: [NSDictionary class]]) if (other == self)
return YES;
if ([other isKindOfClass: NSDictionary_abstract_class])
return [self isEqualToDictionary: other]; return [self isEqualToDictionary: other];
return NO; return NO;
} }
- (BOOL) isEqualToDictionary: (NSDictionary*)other - (BOOL) isEqualToDictionary: (NSDictionary*)other
{ {
if ([self count] != [other count]) if (other == self)
return NO; return YES;
{
id k, e = [self keyEnumerator]; if ([self count] == [other count])
while ((k = [e nextObject])) {
{ NSEnumerator *e = [self keyEnumerator];
id o1 = [self objectForKey: k]; IMP nxtObj = [e methodForSelector: nxtSel];
id o2 = [other objectForKey: k]; IMP myObj = [self methodForSelector: objSel];
if (![o1 isEqual: o2]) IMP otherObj = [other methodForSelector: objSel];
return NO; id k;
/*
if (![[self objectForKey: k] isEqual: [other objectForKey: k]]) while ((k = (*nxtObj)(e, @selector(nextObject))) != nil)
return NO; */ {
} id o1 = (*myObj)(self, objSel, k);
} id o2 = (*otherObj)(other, objSel, k);
/* xxx Recheck this. */
return YES; if ([o1 isEqual: o2] == NO)
return NO;
}
return YES;
}
return NO;
} }
- (NSArray*) allKeys - (NSArray*) allKeys
{ {
id e = [self keyEnumerator]; unsigned c = [self count];
int i, c = [self count];
id k[c];
for (i = 0; i < c; i++) if (c == 0)
{ {
k[i] = [e nextObject]; return [NSArray_class array];
NSAssert (k[i], NSInternalInconsistencyException); }
else
{
NSEnumerator *e = [self keyEnumerator];
IMP nxtObj = [e methodForSelector: nxtSel];
id k[c];
unsigned i;
for (i = 0; i < c; i++)
{
k[i] = (*nxtObj)(e, nxtSel);
NSAssert (k[i], NSInternalInconsistencyException);
}
return AUTORELEASE([[NSArray_class allocWithZone: NSDefaultMallocZone()]
initWithObjects: k count: c]);
} }
NSAssert (![e nextObject], NSInternalInconsistencyException);
return AUTORELEASE([[NSArray allocWithZone: NSDefaultMallocZone()]
initWithObjects: k count: c]);
} }
- (NSArray*) allValues - (NSArray*) allValues
{ {
id e = [self objectEnumerator]; unsigned c = [self count];
int i, c = [self count];
id k[c];
for (i = 0; i < c; i++) if (c == 0)
{ {
k[i] = [e nextObject]; return [NSArray_class array];
NSAssert (k[i], NSInternalInconsistencyException); }
else
{
NSEnumerator *e = [self objectEnumerator];
IMP nxtObj = [e methodForSelector: nxtSel];
id k[c];
unsigned i;
for (i = 0; i < c; i++)
{
k[i] = (*nxtObj)(e, nxtSel);
}
return AUTORELEASE([[NSArray_class allocWithZone: NSDefaultMallocZone()]
initWithObjects: k count: c]);
} }
NSAssert (![e nextObject], NSInternalInconsistencyException);
return AUTORELEASE([[NSArray allocWithZone: NSDefaultMallocZone()]
initWithObjects: k count: c]);
} }
- (NSArray*) allKeysForObject: anObject - (NSArray*) allKeysForObject: (id)anObject
{ {
id k, e = [self keyEnumerator]; unsigned c = [self count];
id a[[self count]];
int c = 0;
while ((k = [e nextObject]))
if ([anObject isEqual: [self objectForKey: k]])
a[c++] = k;
if (c == 0) if (c == 0)
return nil; {
return AUTORELEASE([[NSArray allocWithZone: NSDefaultMallocZone()] return nil;
initWithObjects: a count: c]); }
else
{
static SEL eqSel = @selector(isEqual:);
NSEnumerator *e = [self keyEnumerator];
IMP nxtObj = [e methodForSelector: nxtSel];
IMP myObj = [self methodForSelector: objSel];
BOOL (*eqObj)(id, SEL, id);
id k;
id a[c];
eqObj = (BOOL (*)(id, SEL, id))[anObject methodForSelector: eqSel];
c = 0;
while ((k = (*nxtObj)(e, nxtSel)) != nil)
{
if ((*eqObj)(anObject, eqSel, (*myObj)(self, objSel, k)))
{
a[c++] = k;
}
}
if (c == 0)
return nil;
return AUTORELEASE([[NSArray_class allocWithZone: NSDefaultMallocZone()]
initWithObjects: a count: c]);
}
} }
struct foo { NSDictionary *d; SEL s; IMP i; }; struct foo { NSDictionary *d; SEL s; IMP i; };
@ -473,59 +536,73 @@ compareIt(id o1, id o2, void* context)
info.d = self; info.d = self;
info.s = comp; info.s = comp;
info.i = [self methodForSelector: @selector(objectForKey:)]; info.i = [self methodForSelector: objSel];
k = [[self allKeys] sortedArrayUsingFunction: compareIt context: &info]; k = [[self allKeys] sortedArrayUsingFunction: compareIt context: &info];
return k; return k;
} }
- (NSArray*) objectsForKeys: (NSArray*)keys notFoundMarker: (id)marker - (NSArray*) objectsForKeys: (NSArray*)keys notFoundMarker: (id)marker
{ {
int i, c = [keys count]; unsigned c = [keys count];
id obuf[c];
for (i = 0; i < c; i++) if (c == 0)
{ {
id o = [self objectForKey: [keys objectAtIndex: i]]; return [NSArray_class array];
}
if (o) else
obuf[i] = o; {
else unsigned i;
obuf[i] = marker; id obuf[c];
IMP myObj = [self methodForSelector: objSel];
[keys getObjects: obuf];
for (i = 0; i < c; i++)
{
id o = (*myObj)(self, objSel, obuf[i]);
if (o)
obuf[i] = o;
else
obuf[i] = marker;
}
return [NSArray_class arrayWithObjects: obuf count: c];
} }
return [NSArray arrayWithObjects: obuf count: c];
} }
- (BOOL)writeToFile: (NSString *)path atomically: (BOOL)useAuxiliaryFile - (BOOL) writeToFile: (NSString *)path atomically: (BOOL)useAuxiliaryFile
{ {
return [[self description] writeToFile: path atomically: useAuxiliaryFile]; return [[self description] writeToFile: path atomically: useAuxiliaryFile];
} }
- (NSString*) description - (NSString*) description
{ {
return [self descriptionWithLocale: nil]; return [self descriptionWithLocale: nil];
} }
- (NSString*) descriptionInStringsFileFormat - (NSString*) descriptionInStringsFileFormat
{ {
NSMutableString *result; NSMutableString *result;
NSEnumerator *enumerator; NSEnumerator *enumerator = [self keyEnumerator];
IMP nxtObj = [enumerator methodForSelector: nxtSel];
IMP myObj = [self methodForSelector: objSel];
IMP appImp;
id key; id key;
result = AUTORELEASE([[NSGMutableCString alloc] initWithCapacity: 1024]); result = AUTORELEASE([[NSGMutableCString alloc] initWithCapacity: 1024]);
enumerator = [self keyEnumerator]; appImp = [(NSObject*)result methodForSelector: appSel];
while ((key = [enumerator nextObject]) != nil) while ((key = (*nxtObj)(enumerator, nxtSel)) != nil)
{ {
id val = [self objectForKey: key]; id val = (*myObj)(self, objSel, key);
[key descriptionWithLocale: nil [key descriptionWithLocale: nil
to: (id<GNUDescriptionDestination>)result]; to: (id<GNUDescriptionDestination>)result];
if (val != nil && [val isEqualToString: @""] == NO) if (val != nil && [val isEqualToString: @""] == NO)
{ {
[result appendString: @" = "]; (*appImp)(result, appSel, @" = ");
[val descriptionWithLocale: nil [val descriptionWithLocale: nil
to: (id<GNUDescriptionDestination>)result]; to: (id<GNUDescriptionDestination>)result];
} }
[result appendString: @";\n"]; (*appImp)(result, appSel, @";\n");
} }
return result; return result;
@ -569,21 +646,17 @@ static NSString *indentStrings[] = {
indent: (unsigned int)level indent: (unsigned int)level
to: (id<GNUDescriptionDestination>)result to: (id<GNUDescriptionDestination>)result
{ {
NSEnumerator *enumerator; IMP myObj = [self methodForSelector: objSel];
id key;
BOOL canCompare = YES; BOOL canCompare = YES;
NSString *iBaseString; NSString *iBaseString;
NSString *iSizeString; NSString *iSizeString;
int i; unsigned i;
NSArray *keyArray = [self allKeys]; NSArray *keyArray = [self allKeys];
NSMutableArray *theKeys = [NSMutableArray arrayWithArray: keyArray]; unsigned numKeys = [keyArray count];
int numKeys = [theKeys count];
NSString *plists[numKeys]; NSString *plists[numKeys];
NSString *keys[numKeys]; NSString *keys[numKeys];
SEL appSel;
IMP appImp; IMP appImp;
appSel = @selector(appendString:);
appImp = [(NSObject*)result methodForSelector: appSel]; appImp = [(NSObject*)result methodForSelector: appSel];
if (level < sizeof(indentStrings)/sizeof(NSString*)) if (level < sizeof(indentStrings)/sizeof(NSString*))
@ -596,10 +669,10 @@ static NSString *indentStrings[] = {
else else
iSizeString = indentStrings[sizeof(indentStrings)/sizeof(NSString*)-1]; iSizeString = indentStrings[sizeof(indentStrings)/sizeof(NSString*)-1];
enumerator = [self keyEnumerator]; [keyArray getObjects: keys];
while ((key = [enumerator nextObject]) != nil) for (i = 0; i < numKeys; i++)
{ {
if ([key respondsToSelector: @selector(compare:)] == NO) if ([keys[i] respondsToSelector: @selector(compare:)] == NO)
{ {
canCompare = NO; canCompare = NO;
break; break;
@ -608,13 +681,55 @@ static NSString *indentStrings[] = {
if (canCompare) if (canCompare)
{ {
[theKeys sortUsingSelector: @selector(compare:)]; /*
* Shell sort algorithm taken from SortingInAction - a NeXT example
* good value for stride factor is not well-understood
* 3 is a fairly good choice (Sedgewick)
*/
#define STRIDE_FACTOR 3
unsigned c,d, stride;
BOOL found;
int count = numKeys;
stride = 1;
while (stride <= count)
stride = stride * STRIDE_FACTOR + 1;
while(stride > (STRIDE_FACTOR - 1))
{
// loop to sort for each value of stride
stride = stride / STRIDE_FACTOR;
for (c = stride; c < count; c++)
{
found = NO;
if (stride > c)
break;
d = c - stride;
while (!found)
{
// move to left until correct place
id a = keys[d + stride];
id b = keys[d];
if ([a compare: b] == NSOrderedAscending)
{
keys[d + stride] = b;
keys[d] = a;
if (stride > d)
break;
d -= stride; // jump by stride factor
}
else
{
found = YES;
}
}
}
}
} }
[theKeys getObjects: keys];
for (i = 0; i < numKeys; i++) for (i = 0; i < numKeys; i++)
{ {
plists[i] = [self objectForKey: keys[i]]; plists[i] = (*myObj)(self, objSel, keys[i]);
} }
(*appImp)(result, appSel, @"{\n"); (*appImp)(result, appSel, @"{\n");
@ -651,7 +766,7 @@ static NSString *indentStrings[] = {
@implementation NSMutableDictionary @implementation NSMutableDictionary
+ (void)initialize + (void) initialize
{ {
if (self == [NSMutableDictionary class]) if (self == [NSMutableDictionary class])
{ {
@ -660,14 +775,14 @@ static NSString *indentStrings[] = {
} }
} }
+ allocWithZone: (NSZone*)z + (id) allocWithZone: (NSZone*)z
{ {
if ([self class] == [NSMutableDictionary class]) if (self == NSMutableDictionary_abstract_class)
return NSAllocateObject([self _mutableConcreteClass], 0, z); return NSAllocateObject(NSMutableDictionary_concrete_class, 0, z);
return [super allocWithZone: z]; return [super allocWithZone: z];
} }
- copyWithZone: (NSZone*)z - (id) copyWithZone: (NSZone*)z
{ {
/* a deep copy */ /* a deep copy */
unsigned count = [self count]; unsigned count = [self count];
@ -677,9 +792,7 @@ static NSString *indentStrings[] = {
unsigned i; unsigned i;
id key; id key;
NSEnumerator *enumerator = [self keyEnumerator]; NSEnumerator *enumerator = [self keyEnumerator];
static SEL nxtSel = @selector(nextObject);
IMP nxtImp = [enumerator methodForSelector: nxtSel]; IMP nxtImp = [enumerator methodForSelector: nxtSel];
static SEL objSel = @selector(objectForKey:);
IMP objImp = [self methodForSelector: objSel]; IMP objImp = [self methodForSelector: objSel];
for (i = 0; (key = (*nxtImp)(enumerator, nxtSel)); i++) for (i = 0; (key = (*nxtImp)(enumerator, nxtSel)); i++)
@ -688,7 +801,7 @@ static NSString *indentStrings[] = {
objects[i] = (*objImp)(self, objSel, key); objects[i] = (*objImp)(self, objSel, key);
objects[i] = [objects[i] copyWithZone: z]; objects[i] = [objects[i] copyWithZone: z];
} }
newDictionary = [[[[self class] _concreteClass] allocWithZone: z] newDictionary = [[NSDictionary_concrete_class allocWithZone: z]
initWithObjects: objects initWithObjects: objects
forKeys: keys forKeys: keys
count: count]; count: count];
@ -702,7 +815,7 @@ static NSString *indentStrings[] = {
} }
/* This is the designated initializer */ /* This is the designated initializer */
- initWithCapacity: (unsigned)numItems - (id) initWithCapacity: (unsigned)numItems
{ {
[self subclassResponsibility: _cmd]; [self subclassResponsibility: _cmd];
return 0; return 0;
@ -733,31 +846,52 @@ static NSString *indentStrings[] = {
forKeys: (id*)keys forKeys: (id*)keys
count: (unsigned)count count: (unsigned)count
{ {
IMP setObj;
[self initWithCapacity: count]; [self initWithCapacity: count];
setObj = [self methodForSelector: setSel];
while (count--) while (count--)
[self setObject: objects[count] forKey: keys[count]]; (*setObj)(self, setSel, objects[count], keys[count]);
return self; return self;
} }
- (void) removeAllObjects - (void) removeAllObjects
{ {
id k, e = [self keyEnumerator]; id k;
while ((k = [e nextObject])) NSEnumerator *e = [self keyEnumerator];
[self removeObjectForKey: k]; IMP nxtObj = [e methodForSelector: nxtSel];
IMP remObj = [self methodForSelector: remSel];
while ((k = (*nxtObj)(e, nxtSel)) != nil)
(*remObj)(self, remSel, k);
} }
- (void) removeObjectsForKeys: (NSArray*)keyArray - (void) removeObjectsForKeys: (NSArray*)keyArray
{ {
int c = [keyArray count]; unsigned c = [keyArray count];
while (c--)
[self removeObjectForKey: [keyArray objectAtIndex: c]]; if (c)
{
id keys[c];
IMP remObj = [self methodForSelector: remSel];
[keyArray getObjects: keys];
while (c--)
{
(*remObj)(self, remSel, keys[c]);
}
}
} }
- (void) addEntriesFromDictionary: (NSDictionary*)other - (void) addEntriesFromDictionary: (NSDictionary*)other
{ {
id k, e = [other keyEnumerator]; id k;
while ((k = [e nextObject])) NSEnumerator *e = [other keyEnumerator];
[self setObject: [other objectForKey: k] forKey: k]; IMP nxtObj = [e methodForSelector: nxtSel];
IMP setObj = [self methodForSelector: setSel];
while ((k = (*nxtObj)(e, nxtSel)) != nil)
(*setObj)(self, setSel, [other objectForKey: k], k);
} }
- (void) setDictionary: (NSDictionary*)otherDictionary - (void) setDictionary: (NSDictionary*)otherDictionary

View file

@ -244,49 +244,58 @@ myEqual(id self, id other)
- (id) initWithDictionary: (NSDictionary*)other - (id) initWithDictionary: (NSDictionary*)other
copyItems: (BOOL)shouldCopy copyItems: (BOOL)shouldCopy
{ {
NSEnumerator *e = [other keyEnumerator];
NSZone *z = fastZone(self); NSZone *z = fastZone(self);
unsigned c = [other count]; unsigned c = [other count];
unsigned i;
GSIMapInitWithZoneAndCapacity(&map, z, c); GSIMapInitWithZoneAndCapacity(&map, z, c);
for (i = 0; i < c; i++)
if (c > 0)
{ {
GSIMapNode node; static SEL nxtSel = @selector(nextObject);
id k = [e nextObject]; static SEL objSel = @selector(objectForKey:);
id o = [other objectForKey: k]; NSEnumerator *e = [other keyEnumerator];
IMP nxtObj = [e methodForSelector: nxtSel];
IMP otherObj = [other methodForSelector: objSel];
unsigned i;
k = [k copyWithZone: z]; for (i = 0; i < c; i++)
if (k == nil)
{ {
AUTORELEASE(self); GSIMapNode node;
[NSException raise: NSInvalidArgumentException id k = (*nxtObj)(e, nxtSel);
format: @"Tried to init dictionary with nil key"]; id o = (*otherObj)(other, objSel, k);
}
if (shouldCopy)
{
o = [o copyWithZone: z];
}
else
{
o = RETAIN(o);
}
if (o == nil)
{
AUTORELEASE(self);
[NSException raise: NSInvalidArgumentException
format: @"Tried to init dictionary with nil value"];
}
node = GSIMapNodeForKey(&map, (GSIMapKey)k); k = [k copyWithZone: z];
if (node) if (k == nil)
{ {
RELEASE(node->value.obj); AUTORELEASE(self);
node->value.obj = o; [NSException raise: NSInvalidArgumentException
} format: @"Tried to init dictionary with nil key"];
else }
{ if (shouldCopy)
GSIMapAddPairNoRetain(&map, (GSIMapKey)k, (GSIMapVal)o); {
o = [o copyWithZone: z];
}
else
{
o = RETAIN(o);
}
if (o == nil)
{
AUTORELEASE(self);
[NSException raise: NSInvalidArgumentException
format: @"Tried to init dictionary with nil value"];
}
node = GSIMapNodeForKey(&map, (GSIMapKey)k);
if (node)
{
RELEASE(node->value.obj);
node->value.obj = o;
}
else
{
GSIMapAddPairNoRetain(&map, (GSIMapKey)k, (GSIMapVal)o);
}
} }
} }
return self; return self;