1995-04-03 22:59:20 +00:00
|
|
|
/* NSDictionary - Dictionary object to store key/value pairs
|
1997-01-06 22:43:08 +00:00
|
|
|
Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
|
1995-04-04 16:15:31 +00:00
|
|
|
|
1996-04-17 20:17:45 +00:00
|
|
|
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
1995-05-05 18:31:51 +00:00
|
|
|
From skeleton by: Adam Fedor <fedor@boulder.colorado.edu>
|
1995-04-03 22:59:20 +00:00
|
|
|
Date: Mar 1995
|
1995-04-04 16:15:31 +00:00
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
This file is part of the GNUstep Base Library.
|
1995-04-04 16:15:31 +00:00
|
|
|
|
1995-04-03 22:59:20 +00:00
|
|
|
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.
|
1995-04-04 16:15:31 +00:00
|
|
|
|
1995-04-03 22:59:20 +00:00
|
|
|
You should have received a copy of the GNU Library General Public
|
|
|
|
License along with this library; if not, write to the Free
|
1999-09-09 02:56:20 +00:00
|
|
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
1995-04-04 16:15:31 +00:00
|
|
|
*/
|
1995-04-03 22:59:20 +00:00
|
|
|
|
1997-11-06 00:51:23 +00:00
|
|
|
#include <config.h>
|
1998-12-20 21:27:47 +00:00
|
|
|
#include <base/behavior.h>
|
1995-04-17 21:13:20 +00:00
|
|
|
#include <Foundation/NSDictionary.h>
|
1995-05-05 18:31:51 +00:00
|
|
|
#include <Foundation/NSArray.h>
|
|
|
|
#include <Foundation/NSUtilities.h>
|
1998-01-19 15:20:15 +00:00
|
|
|
#include <Foundation/NSString.h>
|
|
|
|
#include <Foundation/NSException.h>
|
|
|
|
#include <Foundation/NSAutoreleasePool.h>
|
1998-12-02 21:00:54 +00:00
|
|
|
#include <Foundation/NSFileManager.h>
|
2000-03-17 13:13:08 +00:00
|
|
|
#include <Foundation/NSUserDefaults.h>
|
2000-10-16 12:35:42 +00:00
|
|
|
#include <Foundation/NSCoder.h>
|
1999-12-01 19:36:20 +00:00
|
|
|
#include <Foundation/NSDebug.h>
|
2000-10-31 11:05:23 +00:00
|
|
|
#include <Foundation/NSObjCRuntime.h>
|
1995-04-03 22:59:20 +00:00
|
|
|
|
|
|
|
@implementation NSDictionary
|
|
|
|
|
2001-01-09 09:17:31 +00:00
|
|
|
@class GSDictionary;
|
|
|
|
@class GSMutableDictionary;
|
1998-10-01 16:07:02 +00:00
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
static Class NSArray_class;
|
2001-01-09 09:17:31 +00:00
|
|
|
static Class NSDictionaryClass;
|
|
|
|
static Class NSMutableDictionaryClass;
|
|
|
|
static Class GSDictionaryClass;
|
|
|
|
static Class GSMutableDictionaryClass;
|
1995-06-30 14:21:45 +00:00
|
|
|
|
2000-10-30 18:00:27 +00:00
|
|
|
static SEL eqSel;
|
|
|
|
static SEL nxtSel;
|
|
|
|
static SEL objSel;
|
|
|
|
static SEL remSel;
|
|
|
|
static SEL setSel;
|
|
|
|
static SEL appSel;
|
1999-09-12 19:03:09 +00:00
|
|
|
|
1995-06-30 14:21:45 +00:00
|
|
|
+ (void) initialize
|
|
|
|
{
|
1997-10-16 23:56:27 +00:00
|
|
|
if (self == [NSDictionary class])
|
|
|
|
{
|
1999-09-12 19:03:09 +00:00
|
|
|
NSArray_class = [NSArray class];
|
2001-01-09 09:17:31 +00:00
|
|
|
NSDictionaryClass = [NSDictionary class];
|
|
|
|
NSMutableDictionaryClass = [NSMutableDictionary class];
|
|
|
|
GSDictionaryClass = [GSDictionary class];
|
|
|
|
GSMutableDictionaryClass = [GSMutableDictionary class];
|
2000-10-30 18:00:27 +00:00
|
|
|
|
|
|
|
eqSel = @selector(isEqual:);
|
|
|
|
nxtSel = @selector(nextObject);
|
|
|
|
objSel = @selector(objectForKey:);
|
|
|
|
remSel = @selector(removeObjectForKey:);
|
|
|
|
setSel = @selector(setObject:forKey:);
|
|
|
|
appSel = @selector(appendString:);
|
1997-10-16 23:56:27 +00:00
|
|
|
}
|
1995-06-30 14:21:45 +00:00
|
|
|
}
|
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
2001-01-09 09:17:31 +00:00
|
|
|
if (self == NSDictionaryClass)
|
2000-08-07 22:00:31 +00:00
|
|
|
{
|
2001-01-09 09:17:31 +00:00
|
|
|
return NSAllocateObject(GSDictionaryClass, 0, z);
|
2000-08-07 22:00:31 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return NSAllocateObject(self, 0, z);
|
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1997-10-16 23:56:27 +00:00
|
|
|
/* This is the designated initializer */
|
1999-09-12 19:03:09 +00:00
|
|
|
- (id) initWithObjects: (id*)objects
|
|
|
|
forKeys: (id*)keys
|
|
|
|
count: (unsigned)count
|
1997-10-16 23:56:27 +00:00
|
|
|
{
|
1999-04-08 12:17:15 +00:00
|
|
|
[self subclassResponsibility: _cmd];
|
1997-10-16 23:56:27 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (unsigned) count
|
|
|
|
{
|
1999-04-08 12:17:15 +00:00
|
|
|
[self subclassResponsibility: _cmd];
|
1997-10-16 23:56:27 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
- (id) objectForKey: (id)aKey
|
1997-10-16 23:56:27 +00:00
|
|
|
{
|
1999-04-08 12:17:15 +00:00
|
|
|
[self subclassResponsibility: _cmd];
|
1997-10-16 23:56:27 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSEnumerator*) keyEnumerator
|
|
|
|
{
|
1999-04-08 12:17:15 +00:00
|
|
|
[self subclassResponsibility: _cmd];
|
1997-10-16 23:56:27 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSEnumerator*) objectEnumerator
|
|
|
|
{
|
1999-04-08 12:17:15 +00:00
|
|
|
[self subclassResponsibility: _cmd];
|
1997-10-16 23:56:27 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
1999-07-03 19:59:44 +00:00
|
|
|
- (id) copyWithZone: (NSZone*)z
|
1998-07-30 16:34:32 +00:00
|
|
|
{
|
1999-07-03 19:59:44 +00:00
|
|
|
return RETAIN(self);
|
1998-07-30 16:34:32 +00:00
|
|
|
}
|
|
|
|
|
1999-07-03 19:59:44 +00:00
|
|
|
- (id) mutableCopyWithZone: (NSZone*)z
|
1998-07-30 16:34:32 +00:00
|
|
|
{
|
2001-01-09 09:17:31 +00:00
|
|
|
return [[GSMutableDictionaryClass allocWithZone: z]
|
1999-04-08 12:17:15 +00:00
|
|
|
initWithDictionary: self];
|
1998-07-30 16:34:32 +00:00
|
|
|
}
|
|
|
|
|
2000-10-16 12:35:42 +00:00
|
|
|
- (Class) classForCoder
|
|
|
|
{
|
2001-01-09 09:17:31 +00:00
|
|
|
return NSDictionaryClass;
|
2000-10-16 12:35:42 +00:00
|
|
|
}
|
|
|
|
|
1998-07-30 16:34:32 +00:00
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
|
|
|
{
|
2000-10-16 12:35:42 +00:00
|
|
|
unsigned count = [self count];
|
|
|
|
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(unsigned) at: &count];
|
|
|
|
if (count > 0)
|
|
|
|
{
|
|
|
|
NSEnumerator *enumerator = [self keyEnumerator];
|
|
|
|
id key;
|
|
|
|
IMP enc;
|
|
|
|
IMP nxt;
|
|
|
|
IMP ofk;
|
|
|
|
|
|
|
|
nxt = [enumerator methodForSelector: @selector(nextObject)];
|
|
|
|
enc = [aCoder methodForSelector: @selector(encodeObject:)];
|
|
|
|
ofk = [self methodForSelector: @selector(objectForKey:)];
|
|
|
|
|
|
|
|
while ((key = (*nxt)(enumerator, @selector(nextObject))) != nil)
|
|
|
|
{
|
|
|
|
id val = (*ofk)(self, @selector(objectForKey:), key);
|
|
|
|
|
|
|
|
(*enc)(aCoder, @selector(encodeObject:), key);
|
|
|
|
(*enc)(aCoder, @selector(encodeObject:), val);
|
|
|
|
}
|
|
|
|
}
|
1998-07-30 16:34:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id) initWithCoder: (NSCoder*)aCoder
|
|
|
|
{
|
2000-10-16 12:35:42 +00:00
|
|
|
unsigned count;
|
|
|
|
|
|
|
|
[aCoder decodeValueOfObjCType: @encode(unsigned) at: &count];
|
|
|
|
if (count > 0)
|
|
|
|
{
|
|
|
|
id *keys = NSZoneMalloc(NSDefaultMallocZone(), sizeof(id)*count);
|
|
|
|
id *vals = NSZoneMalloc(NSDefaultMallocZone(), sizeof(id)*count);
|
|
|
|
unsigned i;
|
|
|
|
IMP dec;
|
|
|
|
|
|
|
|
dec = [aCoder methodForSelector: @selector(decodeObject)];
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
keys[i] = (*dec)(aCoder, @selector(decodeObject));
|
|
|
|
vals[i] = (*dec)(aCoder, @selector(decodeObject));
|
|
|
|
}
|
|
|
|
self = [self initWithObjects: vals forKeys: keys count: count];
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), keys);
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), vals);
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
1998-07-30 16:34:32 +00:00
|
|
|
}
|
1997-10-16 23:56:27 +00:00
|
|
|
|
1999-07-03 19:59:44 +00:00
|
|
|
+ (id) dictionary
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1999-07-03 19:59:44 +00:00
|
|
|
return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()] init]);
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1999-07-03 19:59:44 +00:00
|
|
|
+ (id) dictionaryWithDictionary: (NSDictionary*)otherDictionary
|
1998-03-23 20:49:54 +00:00
|
|
|
{
|
1999-07-03 19:59:44 +00:00
|
|
|
return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()]
|
|
|
|
initWithDictionary: otherDictionary]);
|
1998-03-23 20:49:54 +00:00
|
|
|
}
|
|
|
|
|
1999-07-03 19:59:44 +00:00
|
|
|
+ (id) dictionaryWithObjects: (id*)objects
|
|
|
|
forKeys: (id*)keys
|
|
|
|
count: (unsigned)count
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1999-07-03 19:59:44 +00:00
|
|
|
return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()]
|
|
|
|
initWithObjects: objects forKeys: keys count: count]);
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1998-10-27 08:12:49 +00:00
|
|
|
- (unsigned) hash
|
|
|
|
{
|
|
|
|
return [self count];
|
|
|
|
}
|
|
|
|
|
1999-06-24 19:30:29 +00:00
|
|
|
- (id) initWithObjects: (NSArray*)objects forKeys: (NSArray*)keys
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1999-09-12 19:03:09 +00:00
|
|
|
unsigned objectCount = [objects count];
|
|
|
|
id os[objectCount];
|
|
|
|
id ks[objectCount];
|
1995-05-05 18:31:51 +00:00
|
|
|
|
1998-10-27 08:12:49 +00:00
|
|
|
if (objectCount != [keys count])
|
1995-05-05 18:31:51 +00:00
|
|
|
{
|
1998-10-27 08:12:49 +00:00
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
format: @"init with obj and key arrays of different sizes"];
|
1995-05-05 18:31:51 +00:00
|
|
|
}
|
1998-10-27 08:12:49 +00:00
|
|
|
[objects getObjects: os];
|
|
|
|
[keys getObjects: ks];
|
1999-04-08 12:17:15 +00:00
|
|
|
return [self initWithObjects: os forKeys: ks count: objectCount];
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1998-10-31 05:17:54 +00:00
|
|
|
- (id) initWithObjectsAndKeys: (id)firstObject, ...
|
|
|
|
{
|
|
|
|
va_list ap;
|
1999-09-12 19:03:09 +00:00
|
|
|
int capacity = 16;
|
|
|
|
int num_pairs = 0;
|
|
|
|
id *objects;
|
|
|
|
id *keys;
|
|
|
|
id arg;
|
|
|
|
int argi = 1;
|
1998-10-31 05:17:54 +00:00
|
|
|
|
|
|
|
va_start (ap, firstObject);
|
1999-01-11 17:28:51 +00:00
|
|
|
if (firstObject == nil)
|
1998-10-31 05:17:54 +00:00
|
|
|
{
|
|
|
|
return [self init];
|
|
|
|
}
|
|
|
|
/* Gather all the arguments in a simple array, in preparation for
|
|
|
|
calling the designated initializer. */
|
1999-09-28 11:10:34 +00:00
|
|
|
objects = (id*)NSZoneMalloc(NSDefaultMallocZone(), sizeof(id) * capacity);
|
|
|
|
keys = (id*)NSZoneMalloc(NSDefaultMallocZone(), sizeof(id) * capacity);
|
1998-10-31 05:17:54 +00:00
|
|
|
|
|
|
|
objects[num_pairs] = firstObject;
|
|
|
|
/* Keep grabbing arguments until we get a nil... */
|
|
|
|
while ((arg = va_arg (ap, id)))
|
|
|
|
{
|
|
|
|
if (num_pairs >= capacity)
|
|
|
|
{
|
|
|
|
/* Must increase capacity in order to fit additional ARG's. */
|
|
|
|
capacity *= 2;
|
1999-09-28 11:10:34 +00:00
|
|
|
objects = (id*)NSZoneRealloc(NSDefaultMallocZone(), objects,
|
|
|
|
sizeof(id) * capacity);
|
|
|
|
keys = (id*)NSZoneRealloc(NSDefaultMallocZone(), keys,
|
|
|
|
sizeof(id) * capacity);
|
1998-10-31 05:17:54 +00:00
|
|
|
}
|
|
|
|
/* ...and alternately dump them into OBJECTS and KEYS */
|
|
|
|
if (argi++ % 2 == 0)
|
|
|
|
objects[num_pairs] = arg;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
keys[num_pairs] = arg;
|
|
|
|
num_pairs++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (argi %2 != 0)
|
|
|
|
{
|
1999-09-28 11:10:34 +00:00
|
|
|
NSZoneFree(NSDefaultMallocZone(), objects);
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), keys);
|
1998-10-31 05:17:54 +00:00
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
format: @"init dictionary with nil key"];
|
|
|
|
}
|
|
|
|
self = [self initWithObjects: objects forKeys: keys count: num_pairs];
|
1999-09-28 11:10:34 +00:00
|
|
|
NSZoneFree(NSDefaultMallocZone(), objects);
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), keys);
|
1998-10-31 05:17:54 +00:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
+ (id) dictionaryWithObjectsAndKeys: (id)firstObject, ...
|
1996-10-25 23:43:00 +00:00
|
|
|
{
|
|
|
|
va_list ap;
|
1999-09-12 19:03:09 +00:00
|
|
|
int capacity = 16;
|
|
|
|
int num_pairs = 0;
|
|
|
|
id *objects;
|
|
|
|
id *keys;
|
|
|
|
id arg;
|
|
|
|
int argi = 1;
|
1996-10-25 23:43:00 +00:00
|
|
|
|
|
|
|
va_start (ap, firstObject);
|
|
|
|
/* Gather all the arguments in a simple array, in preparation for
|
|
|
|
calling the designated initializer. */
|
1999-09-28 11:10:34 +00:00
|
|
|
objects = (id*)NSZoneMalloc(NSDefaultMallocZone(), sizeof(id) * capacity);
|
|
|
|
keys = (id*)NSZoneMalloc(NSDefaultMallocZone(), sizeof(id) * capacity);
|
1996-10-25 23:43:00 +00:00
|
|
|
if (firstObject != nil)
|
|
|
|
{
|
1998-10-01 16:07:02 +00:00
|
|
|
NSDictionary *d;
|
1996-10-25 23:43:00 +00:00
|
|
|
objects[num_pairs] = firstObject;
|
|
|
|
/* Keep grabbing arguments until we get a nil... */
|
|
|
|
while ((arg = va_arg (ap, id)))
|
|
|
|
{
|
|
|
|
if (num_pairs >= capacity)
|
|
|
|
{
|
|
|
|
/* Must increase capacity in order to fit additional ARG's. */
|
|
|
|
capacity *= 2;
|
1999-09-28 11:10:34 +00:00
|
|
|
objects = (id*)NSZoneRealloc(NSDefaultMallocZone(), objects,
|
|
|
|
sizeof(id) * capacity);
|
|
|
|
keys = (id*)NSZoneRealloc(NSDefaultMallocZone(), keys,
|
|
|
|
sizeof(id) * capacity);
|
1996-10-25 23:43:00 +00:00
|
|
|
}
|
|
|
|
/* ...and alternately dump them into OBJECTS and KEYS */
|
|
|
|
if (argi++ % 2 == 0)
|
|
|
|
objects[num_pairs] = arg;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
keys[num_pairs] = arg;
|
|
|
|
num_pairs++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NSAssert (argi % 2 == 0, NSInvalidArgumentException);
|
1999-07-03 19:59:44 +00:00
|
|
|
d = AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()]
|
|
|
|
initWithObjects: objects forKeys: keys count: num_pairs]);
|
1999-09-28 11:10:34 +00:00
|
|
|
NSZoneFree(NSDefaultMallocZone(), objects);
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), keys);
|
1998-10-01 16:07:02 +00:00
|
|
|
return d;
|
1996-10-25 23:43:00 +00:00
|
|
|
}
|
|
|
|
/* FIRSTOBJECT was nil; just return an empty NSDictionary object. */
|
|
|
|
return [self dictionary];
|
|
|
|
}
|
|
|
|
|
1999-07-03 19:59:44 +00:00
|
|
|
+ (id) dictionaryWithObjects: (NSArray*)objects forKeys: (NSArray*)keys
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1999-07-03 19:59:44 +00:00
|
|
|
return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()]
|
|
|
|
initWithObjects: objects forKeys: keys]);
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1999-07-03 19:59:44 +00:00
|
|
|
+ (id) dictionaryWithObject: (id)object forKey: (id)key
|
1998-07-30 16:34:32 +00:00
|
|
|
{
|
1999-07-03 19:59:44 +00:00
|
|
|
return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()]
|
|
|
|
initWithObjects: &object forKeys: &key count: 1]);
|
1998-07-30 16:34:32 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
/* Override superclass's designated initializer */
|
1999-07-03 19:59:44 +00:00
|
|
|
- (id) init
|
1995-05-05 18:31:51 +00:00
|
|
|
{
|
1999-04-08 12:17:15 +00:00
|
|
|
return [self initWithObjects: NULL forKeys: NULL count: 0];
|
1995-05-05 18:31:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
- (id) initWithDictionary: (NSDictionary*)other
|
1998-10-27 08:12:49 +00:00
|
|
|
{
|
|
|
|
return [self initWithDictionary: other copyItems: NO];
|
|
|
|
}
|
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
- (id) initWithDictionary: (NSDictionary*)other copyItems: (BOOL)shouldCopy
|
1995-05-05 18:31:51 +00:00
|
|
|
{
|
1999-09-12 19:03:09 +00:00
|
|
|
unsigned c = [other count];
|
1995-05-05 18:31:51 +00:00
|
|
|
|
2000-03-28 14:29:37 +00:00
|
|
|
if (c > 0)
|
1998-10-27 08:12:49 +00:00
|
|
|
{
|
2000-03-28 14:29:37 +00:00
|
|
|
id os[c];
|
|
|
|
id ks[c];
|
|
|
|
id k;
|
|
|
|
NSEnumerator *e = [other keyEnumerator];
|
|
|
|
unsigned i = 0;
|
|
|
|
IMP nxtObj = [e methodForSelector: nxtSel];
|
|
|
|
IMP otherObj = [other methodForSelector: objSel];
|
1998-10-27 08:12:49 +00:00
|
|
|
|
2000-03-28 14:29:37 +00:00
|
|
|
if (shouldCopy)
|
1998-10-27 08:12:49 +00:00
|
|
|
{
|
2000-03-28 14:29:37 +00:00
|
|
|
NSZone *z = [self zone];
|
|
|
|
|
|
|
|
while ((k = (*nxtObj)(e, nxtSel)) != nil)
|
|
|
|
{
|
|
|
|
ks[i] = k;
|
|
|
|
os[i] = [(*otherObj)(other, objSel, k) copyWithZone: z];
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
self = [self initWithObjects: os forKeys: ks count: i];
|
1999-07-03 19:59:44 +00:00
|
|
|
#if !GS_WITH_GC
|
2000-03-28 14:29:37 +00:00
|
|
|
while (i > 0)
|
|
|
|
{
|
|
|
|
[os[--i] release];
|
|
|
|
}
|
1999-07-03 19:59:44 +00:00
|
|
|
#endif
|
2000-03-28 14:29:37 +00:00
|
|
|
}
|
|
|
|
else
|
1998-10-27 08:12:49 +00:00
|
|
|
{
|
2000-03-28 14:29:37 +00:00
|
|
|
while ((k = (*nxtObj)(e, nxtSel)) != nil)
|
|
|
|
{
|
|
|
|
ks[i] = k;
|
|
|
|
os[i] = (*otherObj)(other, objSel, k);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
self = [self initWithObjects: os forKeys: ks count: c];
|
1998-10-27 08:12:49 +00:00
|
|
|
}
|
1995-05-05 18:31:51 +00:00
|
|
|
}
|
2000-03-28 14:29:37 +00:00
|
|
|
return self;
|
1995-05-05 18:31:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
- (id) initWithContentsOfFile: (NSString*)path
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1997-01-06 22:43:08 +00:00
|
|
|
NSString *myString;
|
|
|
|
|
1999-05-06 14:42:26 +00:00
|
|
|
myString = [[NSString allocWithZone: NSDefaultMallocZone()]
|
|
|
|
initWithContentsOfFile: path];
|
1997-01-06 22:43:08 +00:00
|
|
|
if (myString)
|
|
|
|
{
|
1999-02-04 13:51:29 +00:00
|
|
|
id result;
|
1999-02-01 10:36:05 +00:00
|
|
|
|
1999-02-04 13:51:29 +00:00
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
result = [myString propertyList];
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
result = nil;
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
1999-07-03 19:59:44 +00:00
|
|
|
RELEASE(myString);
|
2001-01-09 09:17:31 +00:00
|
|
|
if ([result isKindOfClass: NSDictionaryClass])
|
1997-09-13 17:52:31 +00:00
|
|
|
{
|
2001-01-26 12:09:35 +00:00
|
|
|
self = [self initWithDictionary: result];
|
1997-09-13 17:52:31 +00:00
|
|
|
return self;
|
|
|
|
}
|
1997-01-06 22:43:08 +00:00
|
|
|
}
|
1998-05-13 19:25:38 +00:00
|
|
|
NSLog(@"Contents of file does not contain a dictionary");
|
1999-07-03 19:59:44 +00:00
|
|
|
RELEASE(self);
|
1997-01-06 22:43:08 +00:00
|
|
|
return nil;
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1999-07-03 19:59:44 +00:00
|
|
|
+ (id) dictionaryWithContentsOfFile: (NSString *)path
|
1997-01-09 16:05:09 +00:00
|
|
|
{
|
1999-07-03 19:59:44 +00:00
|
|
|
return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()]
|
|
|
|
initWithContentsOfFile: path]);
|
1997-01-09 16:05:09 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
- (BOOL) isEqual: other
|
|
|
|
{
|
1999-09-12 19:03:09 +00:00
|
|
|
if (other == self)
|
|
|
|
return YES;
|
|
|
|
|
2001-01-09 09:17:31 +00:00
|
|
|
if ([other isKindOfClass: NSDictionaryClass])
|
1999-04-08 12:17:15 +00:00
|
|
|
return [self isEqualToDictionary: other];
|
1999-09-12 19:03:09 +00:00
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
return NO;
|
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
- (BOOL) isEqualToDictionary: (NSDictionary*)other
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
2000-03-28 14:29:37 +00:00
|
|
|
unsigned count;
|
1999-09-12 19:03:09 +00:00
|
|
|
|
2000-03-28 14:29:37 +00:00
|
|
|
if (other == self)
|
1999-09-12 19:03:09 +00:00
|
|
|
{
|
2000-03-28 14:29:37 +00:00
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
count = [self count];
|
|
|
|
if (count == [other count])
|
|
|
|
{
|
|
|
|
if (count > 0)
|
1999-09-12 19:03:09 +00:00
|
|
|
{
|
2000-03-28 14:29:37 +00:00
|
|
|
NSEnumerator *e = [self keyEnumerator];
|
|
|
|
IMP nxtObj = [e methodForSelector: nxtSel];
|
|
|
|
IMP myObj = [self methodForSelector: objSel];
|
|
|
|
IMP otherObj = [other methodForSelector: objSel];
|
|
|
|
id k;
|
1999-09-12 19:03:09 +00:00
|
|
|
|
2000-03-28 14:29:37 +00:00
|
|
|
while ((k = (*nxtObj)(e, @selector(nextObject))) != nil)
|
|
|
|
{
|
|
|
|
id o1 = (*myObj)(self, objSel, k);
|
|
|
|
id o2 = (*otherObj)(other, objSel, k);
|
|
|
|
|
|
|
|
if ([o1 isEqual: o2] == NO)
|
|
|
|
return NO;
|
|
|
|
}
|
1999-09-12 19:03:09 +00:00
|
|
|
}
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
return NO;
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
- (NSArray*) allKeys
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1999-09-12 19:03:09 +00:00
|
|
|
unsigned c = [self count];
|
1995-05-05 18:31:51 +00:00
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
if (c == 0)
|
1995-05-05 18:31:51 +00:00
|
|
|
{
|
1999-09-12 19:03:09 +00:00
|
|
|
return [NSArray_class array];
|
|
|
|
}
|
|
|
|
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]);
|
1995-05-05 18:31:51 +00:00
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
- (NSArray*) allValues
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1999-09-12 19:03:09 +00:00
|
|
|
unsigned c = [self count];
|
1995-05-05 18:31:51 +00:00
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
if (c == 0)
|
|
|
|
{
|
|
|
|
return [NSArray_class array];
|
|
|
|
}
|
|
|
|
else
|
1995-05-05 18:31:51 +00:00
|
|
|
{
|
1999-09-12 19:03:09 +00:00
|
|
|
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]);
|
1995-05-05 18:31:51 +00:00
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
- (NSArray*) allKeysForObject: (id)anObject
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1999-09-12 19:03:09 +00:00
|
|
|
unsigned c = [self count];
|
1995-05-05 18:31:51 +00:00
|
|
|
|
1998-10-27 08:12:49 +00:00
|
|
|
if (c == 0)
|
1999-09-12 19:03:09 +00:00
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
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]);
|
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1998-10-27 09:35:06 +00:00
|
|
|
struct foo { NSDictionary *d; SEL s; IMP i; };
|
1998-01-19 15:20:15 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
compareIt(id o1, id o2, void* context)
|
|
|
|
{
|
|
|
|
struct foo *f = (struct foo*)context;
|
1998-10-27 09:35:06 +00:00
|
|
|
o1 = (*f->i)(f->d, @selector(objectForKey:), o1);
|
|
|
|
o2 = (*f->i)(f->d, @selector(objectForKey:), o2);
|
1998-01-19 15:20:15 +00:00
|
|
|
return (int)[o1 performSelector: f->s withObject: o2];
|
|
|
|
}
|
|
|
|
|
1999-06-24 19:30:29 +00:00
|
|
|
- (NSArray*) keysSortedByValueUsingSelector: (SEL)comp
|
1998-01-19 15:20:15 +00:00
|
|
|
{
|
|
|
|
struct foo info;
|
|
|
|
id k;
|
|
|
|
|
|
|
|
info.d = self;
|
|
|
|
info.s = comp;
|
1999-09-12 19:03:09 +00:00
|
|
|
info.i = [self methodForSelector: objSel];
|
1998-01-19 15:20:15 +00:00
|
|
|
k = [[self allKeys] sortedArrayUsingFunction: compareIt context: &info];
|
1999-06-24 19:30:29 +00:00
|
|
|
return k;
|
1998-01-19 15:20:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray*) objectsForKeys: (NSArray*)keys notFoundMarker: (id)marker
|
|
|
|
{
|
1999-09-12 19:03:09 +00:00
|
|
|
unsigned c = [keys count];
|
1998-01-19 15:20:15 +00:00
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
if (c == 0)
|
|
|
|
{
|
|
|
|
return [NSArray_class array];
|
|
|
|
}
|
|
|
|
else
|
1998-01-19 15:20:15 +00:00
|
|
|
{
|
1999-09-12 19:03:09 +00:00
|
|
|
unsigned i;
|
|
|
|
id obuf[c];
|
|
|
|
IMP myObj = [self methodForSelector: objSel];
|
1998-01-19 15:20:15 +00:00
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
[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];
|
1998-01-19 15:20:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
- (BOOL) writeToFile: (NSString *)path atomically: (BOOL)useAuxiliaryFile
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
2000-03-17 13:13:08 +00:00
|
|
|
NSDictionary *loc;
|
|
|
|
NSString *desc;
|
|
|
|
|
|
|
|
loc = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
|
|
|
|
desc = [self descriptionWithLocale: loc indent: 0];
|
|
|
|
|
|
|
|
return [desc writeToFile: path atomically: useAuxiliaryFile];
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1998-01-19 15:20:15 +00:00
|
|
|
- (NSString*) description
|
|
|
|
{
|
2000-03-17 13:13:08 +00:00
|
|
|
return [self descriptionWithLocale: nil indent: 0];
|
1998-01-19 15:20:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString*) descriptionInStringsFileFormat
|
|
|
|
{
|
1999-05-26 17:09:21 +00:00
|
|
|
NSMutableString *result;
|
1999-09-12 19:03:09 +00:00
|
|
|
NSEnumerator *enumerator = [self keyEnumerator];
|
|
|
|
IMP nxtObj = [enumerator methodForSelector: nxtSel];
|
|
|
|
IMP myObj = [self methodForSelector: objSel];
|
|
|
|
IMP appImp;
|
1998-12-18 17:05:44 +00:00
|
|
|
id key;
|
1998-01-19 15:20:15 +00:00
|
|
|
|
2000-10-09 04:41:18 +00:00
|
|
|
result = AUTORELEASE([[NSMutableString alloc] initWithCapacity: 1024]);
|
1999-09-12 19:03:09 +00:00
|
|
|
appImp = [(NSObject*)result methodForSelector: appSel];
|
|
|
|
while ((key = (*nxtObj)(enumerator, nxtSel)) != nil)
|
1998-12-18 17:05:44 +00:00
|
|
|
{
|
1999-09-12 19:03:09 +00:00
|
|
|
id val = (*myObj)(self, objSel, key);
|
1998-12-18 17:05:44 +00:00
|
|
|
|
|
|
|
[key descriptionWithLocale: nil
|
2000-03-17 13:13:08 +00:00
|
|
|
indent: 0
|
1998-12-18 17:05:44 +00:00
|
|
|
to: (id<GNUDescriptionDestination>)result];
|
|
|
|
if (val != nil && [val isEqualToString: @""] == NO)
|
|
|
|
{
|
1999-09-12 19:03:09 +00:00
|
|
|
(*appImp)(result, appSel, @" = ");
|
1998-12-18 17:05:44 +00:00
|
|
|
[val descriptionWithLocale: nil
|
2000-03-17 13:13:08 +00:00
|
|
|
indent: 0
|
1998-12-18 17:05:44 +00:00
|
|
|
to: (id<GNUDescriptionDestination>)result];
|
|
|
|
}
|
1999-09-12 19:03:09 +00:00
|
|
|
(*appImp)(result, appSel, @";\n");
|
1998-01-19 15:20:15 +00:00
|
|
|
}
|
|
|
|
|
1998-12-18 17:05:44 +00:00
|
|
|
return result;
|
1998-01-19 15:20:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString*) descriptionWithLocale: (NSDictionary*)locale
|
|
|
|
{
|
1998-12-18 17:05:44 +00:00
|
|
|
return [self descriptionWithLocale: locale indent: 0];
|
1998-01-19 15:20:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString*) descriptionWithLocale: (NSDictionary*)locale
|
|
|
|
indent: (unsigned int)level
|
|
|
|
{
|
2000-09-22 18:55:21 +00:00
|
|
|
extern BOOL GSMacOSXCompatiblePropertyLists();
|
1998-12-18 17:05:44 +00:00
|
|
|
|
2000-09-22 18:55:21 +00:00
|
|
|
if (GSMacOSXCompatiblePropertyLists() == YES)
|
|
|
|
{
|
|
|
|
extern NSString *GSXMLPlMake(id obj, NSDictionary *loc, unsigned lev);
|
|
|
|
|
|
|
|
return GSXMLPlMake(self, locale, level);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSMutableString *result;
|
|
|
|
|
2000-10-09 04:41:18 +00:00
|
|
|
result = AUTORELEASE([[NSMutableString alloc] initWithCapacity:
|
2000-09-22 18:55:21 +00:00
|
|
|
20*[self count]]);
|
|
|
|
[self descriptionWithLocale: locale
|
|
|
|
indent: level
|
|
|
|
to: (id<GNUDescriptionDestination>)result];
|
|
|
|
return result;
|
|
|
|
}
|
1998-12-18 17:05:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static NSString *indentStrings[] = {
|
|
|
|
@"",
|
|
|
|
@" ",
|
|
|
|
@"\t",
|
|
|
|
@"\t ",
|
|
|
|
@"\t\t",
|
|
|
|
@"\t\t ",
|
|
|
|
@"\t\t\t",
|
|
|
|
@"\t\t\t ",
|
|
|
|
@"\t\t\t\t",
|
|
|
|
@"\t\t\t\t ",
|
|
|
|
@"\t\t\t\t\t",
|
|
|
|
@"\t\t\t\t\t ",
|
|
|
|
@"\t\t\t\t\t\t"
|
|
|
|
};
|
|
|
|
|
|
|
|
- (void) descriptionWithLocale: (NSDictionary*)locale
|
|
|
|
indent: (unsigned int)level
|
|
|
|
to: (id<GNUDescriptionDestination>)result
|
|
|
|
{
|
1999-09-12 19:03:09 +00:00
|
|
|
IMP myObj = [self methodForSelector: objSel];
|
|
|
|
unsigned i;
|
1998-12-18 17:05:44 +00:00
|
|
|
NSArray *keyArray = [self allKeys];
|
1999-09-12 19:03:09 +00:00
|
|
|
unsigned numKeys = [keyArray count];
|
1998-12-18 17:05:44 +00:00
|
|
|
NSString *plists[numKeys];
|
|
|
|
NSString *keys[numKeys];
|
|
|
|
IMP appImp;
|
|
|
|
|
|
|
|
appImp = [(NSObject*)result methodForSelector: appSel];
|
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
[keyArray getObjects: keys];
|
1998-01-19 15:20:15 +00:00
|
|
|
|
2000-03-19 09:23:41 +00:00
|
|
|
if (locale == nil)
|
1998-12-18 17:05:44 +00:00
|
|
|
{
|
2000-03-19 09:23:41 +00:00
|
|
|
for (i = 0; i < numKeys; i++)
|
1999-12-01 19:36:20 +00:00
|
|
|
{
|
2000-03-19 09:23:41 +00:00
|
|
|
plists[i] = (*myObj)(self, objSel, keys[i]);
|
1999-12-01 19:36:20 +00:00
|
|
|
}
|
1998-01-19 15:20:15 +00:00
|
|
|
|
2000-03-17 13:13:08 +00:00
|
|
|
(*appImp)(result, appSel, @"{");
|
|
|
|
for (i = 0; i < numKeys; i++)
|
|
|
|
{
|
|
|
|
id o = plists[i];
|
1998-01-19 15:20:15 +00:00
|
|
|
|
2000-03-17 13:13:08 +00:00
|
|
|
[keys[i] descriptionWithLocale: nil indent: 0 to: result];
|
2000-03-19 09:23:41 +00:00
|
|
|
(*appImp)(result, appSel, @" = ");
|
2000-03-17 13:13:08 +00:00
|
|
|
[o descriptionWithLocale: nil indent: 0 to: result];
|
2000-03-19 09:23:41 +00:00
|
|
|
(*appImp)(result, appSel, @"; ");
|
2000-03-17 13:13:08 +00:00
|
|
|
}
|
|
|
|
(*appImp)(result, appSel, @"}");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSString *iBaseString;
|
|
|
|
NSString *iSizeString;
|
2000-03-19 09:23:41 +00:00
|
|
|
BOOL canCompare = YES;
|
|
|
|
Class lastClass = 0;
|
1998-01-19 15:20:15 +00:00
|
|
|
|
2000-03-17 13:13:08 +00:00
|
|
|
if (level < sizeof(indentStrings)/sizeof(id))
|
|
|
|
{
|
|
|
|
iBaseString = indentStrings[level];
|
|
|
|
}
|
|
|
|
else
|
1998-12-18 17:05:44 +00:00
|
|
|
{
|
2000-03-17 13:13:08 +00:00
|
|
|
iBaseString = indentStrings[sizeof(indentStrings)/sizeof(id)-1];
|
1998-01-19 15:20:15 +00:00
|
|
|
}
|
2000-03-17 13:13:08 +00:00
|
|
|
level++;
|
|
|
|
if (level < sizeof(indentStrings)/sizeof(id))
|
1998-12-18 17:05:44 +00:00
|
|
|
{
|
2000-03-17 13:13:08 +00:00
|
|
|
iSizeString = indentStrings[level];
|
1998-12-18 17:05:44 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-03-17 13:13:08 +00:00
|
|
|
iSizeString = indentStrings[sizeof(indentStrings)/sizeof(id)-1];
|
1998-01-19 15:20:15 +00:00
|
|
|
}
|
|
|
|
|
2000-03-19 09:23:41 +00:00
|
|
|
for (i = 0; i < numKeys; i++)
|
|
|
|
{
|
2000-10-31 16:17:33 +00:00
|
|
|
if (GSObjCClass(keys[i]) == lastClass)
|
2000-03-19 09:23:41 +00:00
|
|
|
continue;
|
|
|
|
if ([keys[i] respondsToSelector: @selector(compare:)] == NO)
|
|
|
|
{
|
|
|
|
canCompare = NO;
|
|
|
|
break;
|
|
|
|
}
|
2000-10-31 16:17:33 +00:00
|
|
|
lastClass = GSObjCClass(keys[i]);
|
2000-03-19 09:23:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (canCompare == YES)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* 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;
|
2001-03-03 14:49:11 +00:00
|
|
|
NSComparisonResult (*comp)(id, SEL, id) = 0;
|
2000-03-19 09:23:41 +00:00
|
|
|
int count = numKeys;
|
|
|
|
#ifdef GSWARN
|
|
|
|
BOOL badComparison = NO;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
stride = 1;
|
|
|
|
while (stride <= count)
|
|
|
|
{
|
|
|
|
stride = stride * STRIDE_FACTOR + 1;
|
|
|
|
}
|
|
|
|
lastClass = 0;
|
|
|
|
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];
|
|
|
|
Class x;
|
|
|
|
NSComparisonResult r;
|
|
|
|
|
2000-10-31 16:17:33 +00:00
|
|
|
x = GSObjCClass(a);
|
2000-03-19 09:23:41 +00:00
|
|
|
if (x != lastClass)
|
|
|
|
{
|
|
|
|
lastClass = x;
|
|
|
|
comp = (NSComparisonResult (*)(id, SEL, id))
|
|
|
|
[a methodForSelector: @selector(compare:)];
|
|
|
|
}
|
|
|
|
r = (*comp)(a, @selector(compare:), b);
|
|
|
|
if (r < 0)
|
|
|
|
{
|
|
|
|
#ifdef GSWARN
|
|
|
|
if (r != NSOrderedAscending)
|
|
|
|
{
|
|
|
|
badComparison = YES;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
keys[d + stride] = b;
|
|
|
|
keys[d] = a;
|
|
|
|
if (stride > d)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
d -= stride; // jump by stride factor
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#ifdef GSWARN
|
|
|
|
if (r != NSOrderedDescending && r != NSOrderedSame)
|
|
|
|
{
|
|
|
|
badComparison = YES;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
found = YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef GSWARN
|
|
|
|
if (badComparison == YES)
|
|
|
|
{
|
|
|
|
NSWarnMLog(@"Detected bad return value from comparison", 0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < numKeys; i++)
|
|
|
|
{
|
|
|
|
plists[i] = (*myObj)(self, objSel, keys[i]);
|
|
|
|
}
|
|
|
|
|
2000-03-17 13:13:08 +00:00
|
|
|
(*appImp)(result, appSel, @"{\n");
|
|
|
|
for (i = 0; i < numKeys; i++)
|
|
|
|
{
|
|
|
|
id o = plists[i];
|
|
|
|
|
|
|
|
(*appImp)(result, appSel, iSizeString);
|
|
|
|
[keys[i] descriptionWithLocale: nil indent: 0 to: result];
|
|
|
|
(*appImp)(result, appSel, @" = ");
|
|
|
|
[o descriptionWithLocale: locale indent: level to: result];
|
|
|
|
(*appImp)(result, appSel, @";\n");
|
|
|
|
}
|
|
|
|
(*appImp)(result, appSel, iBaseString);
|
|
|
|
(*appImp)(result, appSel, @"}");
|
1998-12-18 17:05:44 +00:00
|
|
|
}
|
1998-01-19 15:20:15 +00:00
|
|
|
}
|
|
|
|
|
1995-04-03 22:59:20 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NSMutableDictionary
|
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
+ (void) initialize
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1997-10-16 23:56:27 +00:00
|
|
|
if (self == [NSMutableDictionary class])
|
|
|
|
{
|
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
2001-01-09 09:17:31 +00:00
|
|
|
if (self == NSMutableDictionaryClass)
|
2000-08-07 22:00:31 +00:00
|
|
|
{
|
2001-01-09 09:17:31 +00:00
|
|
|
return NSAllocateObject(GSMutableDictionaryClass, 0, z);
|
2000-08-07 22:00:31 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return NSAllocateObject(self, 0, z);
|
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
- (id) copyWithZone: (NSZone*)z
|
1999-04-08 12:17:15 +00:00
|
|
|
{
|
|
|
|
/* a deep copy */
|
|
|
|
unsigned count = [self count];
|
|
|
|
id keys[count];
|
|
|
|
id objects[count];
|
|
|
|
NSDictionary *newDictionary;
|
|
|
|
unsigned i;
|
|
|
|
id key;
|
|
|
|
NSEnumerator *enumerator = [self keyEnumerator];
|
|
|
|
IMP nxtImp = [enumerator methodForSelector: nxtSel];
|
|
|
|
IMP objImp = [self methodForSelector: objSel];
|
|
|
|
|
|
|
|
for (i = 0; (key = (*nxtImp)(enumerator, nxtSel)); i++)
|
|
|
|
{
|
|
|
|
keys[i] = key;
|
|
|
|
objects[i] = (*objImp)(self, objSel, key);
|
|
|
|
objects[i] = [objects[i] copyWithZone: z];
|
|
|
|
}
|
2001-01-09 09:17:31 +00:00
|
|
|
newDictionary = [[GSDictionaryClass allocWithZone: z]
|
1999-04-08 12:17:15 +00:00
|
|
|
initWithObjects: objects
|
|
|
|
forKeys: keys
|
|
|
|
count: count];
|
1999-07-03 19:59:44 +00:00
|
|
|
#if !GS_WITH_GC
|
1999-04-08 12:17:15 +00:00
|
|
|
while (i > 0)
|
|
|
|
{
|
|
|
|
[objects[--i] release];
|
|
|
|
}
|
1999-07-03 19:59:44 +00:00
|
|
|
#endif
|
1999-04-08 12:17:15 +00:00
|
|
|
return newDictionary;
|
|
|
|
}
|
|
|
|
|
2000-10-16 12:35:42 +00:00
|
|
|
- (Class) classForCoder
|
|
|
|
{
|
2001-01-09 09:17:31 +00:00
|
|
|
return NSMutableDictionaryClass;
|
2000-10-16 12:35:42 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
/* This is the designated initializer */
|
1999-09-12 19:03:09 +00:00
|
|
|
- (id) initWithCapacity: (unsigned)numItems
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1999-04-08 12:17:15 +00:00
|
|
|
[self subclassResponsibility: _cmd];
|
1995-04-04 16:15:31 +00:00
|
|
|
return 0;
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1999-04-08 12:17:15 +00:00
|
|
|
- (void) setObject: anObject forKey: (id)aKey
|
1997-10-16 23:56:27 +00:00
|
|
|
{
|
1999-04-08 12:17:15 +00:00
|
|
|
[self subclassResponsibility: _cmd];
|
1997-10-16 23:56:27 +00:00
|
|
|
}
|
|
|
|
|
1999-04-08 12:17:15 +00:00
|
|
|
- (void) removeObjectForKey: (id)aKey
|
1997-10-16 23:56:27 +00:00
|
|
|
{
|
1999-04-08 12:17:15 +00:00
|
|
|
[self subclassResponsibility: _cmd];
|
1997-10-16 23:56:27 +00:00
|
|
|
}
|
|
|
|
|
1999-07-03 19:59:44 +00:00
|
|
|
+ (id) dictionaryWithCapacity: (unsigned)numItems
|
1997-10-16 23:56:27 +00:00
|
|
|
{
|
1999-07-03 19:59:44 +00:00
|
|
|
return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()]
|
|
|
|
initWithCapacity: numItems]);
|
1997-10-16 23:56:27 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
/* Override superclass's designated initializer */
|
1999-07-03 19:59:44 +00:00
|
|
|
- (id) initWithObjects: (id*)objects
|
|
|
|
forKeys: (id*)keys
|
|
|
|
count: (unsigned)count
|
1995-05-05 18:31:51 +00:00
|
|
|
{
|
2001-01-26 12:09:35 +00:00
|
|
|
self = [self initWithCapacity: count];
|
|
|
|
if (self != nil)
|
2001-01-09 08:40:09 +00:00
|
|
|
{
|
2001-01-26 12:09:35 +00:00
|
|
|
IMP setObj;
|
|
|
|
|
|
|
|
setObj = [self methodForSelector: setSel];
|
|
|
|
while (count--)
|
|
|
|
{
|
|
|
|
(*setObj)(self, setSel, objects[count], keys[count]);
|
|
|
|
}
|
2001-01-09 08:40:09 +00:00
|
|
|
}
|
1995-05-05 18:31:51 +00:00
|
|
|
return self;
|
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
- (void) removeAllObjects
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1999-09-12 19:03:09 +00:00
|
|
|
id k;
|
|
|
|
NSEnumerator *e = [self keyEnumerator];
|
|
|
|
IMP nxtObj = [e methodForSelector: nxtSel];
|
|
|
|
IMP remObj = [self methodForSelector: remSel];
|
|
|
|
|
|
|
|
while ((k = (*nxtObj)(e, nxtSel)) != nil)
|
2001-01-09 08:40:09 +00:00
|
|
|
{
|
|
|
|
(*remObj)(self, remSel, k);
|
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
- (void) removeObjectsForKeys: (NSArray*)keyArray
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1999-09-12 19:03:09 +00:00
|
|
|
unsigned c = [keyArray count];
|
|
|
|
|
2000-03-28 14:29:37 +00:00
|
|
|
if (c > 0)
|
1999-09-12 19:03:09 +00:00
|
|
|
{
|
|
|
|
id keys[c];
|
|
|
|
IMP remObj = [self methodForSelector: remSel];
|
|
|
|
|
|
|
|
[keyArray getObjects: keys];
|
|
|
|
while (c--)
|
|
|
|
{
|
|
|
|
(*remObj)(self, remSel, keys[c]);
|
|
|
|
}
|
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
- (void) addEntriesFromDictionary: (NSDictionary*)other
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
2001-01-09 08:40:09 +00:00
|
|
|
if (other != nil && other != self)
|
2000-03-28 14:29:37 +00:00
|
|
|
{
|
|
|
|
id k;
|
|
|
|
NSEnumerator *e = [other keyEnumerator];
|
|
|
|
IMP nxtObj = [e methodForSelector: nxtSel];
|
2001-01-09 08:40:09 +00:00
|
|
|
IMP getObj = [other methodForSelector: objSel];
|
2000-03-28 14:29:37 +00:00
|
|
|
IMP setObj = [self methodForSelector: setSel];
|
1999-09-12 19:03:09 +00:00
|
|
|
|
2000-03-28 14:29:37 +00:00
|
|
|
while ((k = (*nxtObj)(e, nxtSel)) != nil)
|
2001-01-09 08:40:09 +00:00
|
|
|
{
|
|
|
|
(*setObj)(self, setSel, (*getObj)(other, objSel, k), k);
|
|
|
|
}
|
2000-03-28 14:29:37 +00:00
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1998-01-19 15:20:15 +00:00
|
|
|
- (void) setDictionary: (NSDictionary*)otherDictionary
|
|
|
|
{
|
|
|
|
[self removeAllObjects];
|
|
|
|
[self addEntriesFromDictionary: otherDictionary];
|
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
|
|
|
|
@end
|