mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-31 00:30:53 +00:00
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:
parent
302c691e79
commit
85835779a2
3 changed files with 315 additions and 166 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue