2001-12-17 14:31:42 +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.
|
2005-02-22 11:22:44 +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
|
2005-02-22 11:22:44 +00:00
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
This file is part of the GNUstep Base Library.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
1995-04-03 22:59:20 +00:00
|
|
|
This library is free software; you can redistribute it and/or
|
2007-09-14 11:36:11 +00:00
|
|
|
modify it under the terms of the GNU Lesser General Public
|
1995-04-03 22:59:20 +00:00
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-08 10:38:33 +00:00
|
|
|
version 2 of the License, or (at your option) any later version.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
1995-04-03 22:59:20 +00:00
|
|
|
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.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2007-09-14 11:36:11 +00:00
|
|
|
You should have received a copy of the GNU Lesser General Public
|
1995-04-03 22:59:20 +00:00
|
|
|
License along with this library; if not, write to the Free
|
2006-03-24 13:47:41 +00:00
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02111 USA.
|
2001-12-18 16:54:15 +00:00
|
|
|
|
|
|
|
<title>NSDictionary class reference</title>
|
|
|
|
$Date$ $Revision$
|
1995-04-04 16:15:31 +00:00
|
|
|
*/
|
1995-04-03 22:59:20 +00:00
|
|
|
|
2010-02-19 08:12:46 +00:00
|
|
|
#import "common.h"
|
2010-02-14 10:48:10 +00:00
|
|
|
#import "Foundation/NSDictionary.h"
|
|
|
|
#import "Foundation/NSArray.h"
|
|
|
|
#import "Foundation/NSData.h"
|
|
|
|
#import "Foundation/NSException.h"
|
|
|
|
#import "Foundation/NSAutoreleasePool.h"
|
|
|
|
#import "Foundation/NSFileManager.h"
|
|
|
|
#import "Foundation/NSCoder.h"
|
2012-03-27 17:05:19 +00:00
|
|
|
#import "Foundation/NSLock.h"
|
2012-03-20 20:17:45 +00:00
|
|
|
#import "Foundation/NSSet.h"
|
2010-02-14 10:48:10 +00:00
|
|
|
#import "Foundation/NSValue.h"
|
|
|
|
#import "Foundation/NSKeyValueCoding.h"
|
|
|
|
#import "Foundation/NSUserDefaults.h"
|
2004-01-27 21:51:33 +00:00
|
|
|
// For private method _decodeArrayOfObjectsForKey:
|
2010-02-14 10:48:10 +00:00
|
|
|
#import "Foundation/NSKeyedArchiver.h"
|
|
|
|
#import "GSPrivate.h"
|
2011-07-24 13:09:22 +00:00
|
|
|
#import "GSFastEnumeration.h"
|
2012-03-27 17:05:19 +00:00
|
|
|
#import "GSDispatch.h"
|
1995-04-03 22:59:20 +00:00
|
|
|
|
2006-10-09 17:21:51 +00:00
|
|
|
static BOOL GSMacOSXCompatiblePropertyLists(void)
|
|
|
|
{
|
2006-10-20 10:56:27 +00:00
|
|
|
if (GSPrivateDefaultsFlag(NSWriteOldStylePropertyLists) == YES)
|
2006-10-09 17:21:51 +00:00
|
|
|
return NO;
|
2006-10-20 10:56:27 +00:00
|
|
|
return GSPrivateDefaultsFlag(GSMacOSXCompatible);
|
2006-10-09 17:21:51 +00:00
|
|
|
}
|
|
|
|
|
2005-07-08 11:48:37 +00:00
|
|
|
@class GSDictionary;
|
|
|
|
@interface GSDictionary : NSObject // Help the compiler
|
|
|
|
@end
|
|
|
|
@class GSMutableDictionary;
|
|
|
|
@interface GSMutableDictionary : NSObject // Help the compiler
|
|
|
|
@end
|
|
|
|
|
|
|
|
extern void GSPropertyListMake(id,NSDictionary*,BOOL,BOOL,unsigned,id*);
|
|
|
|
|
|
|
|
|
|
|
|
static Class NSArray_class;
|
|
|
|
static Class NSDictionaryClass;
|
|
|
|
static Class NSMutableDictionaryClass;
|
|
|
|
static Class GSDictionaryClass;
|
|
|
|
static Class GSMutableDictionaryClass;
|
|
|
|
|
|
|
|
static SEL eqSel;
|
|
|
|
static SEL nxtSel;
|
|
|
|
static SEL objSel;
|
|
|
|
static SEL remSel;
|
|
|
|
static SEL setSel;
|
|
|
|
static SEL appSel;
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
/**
|
|
|
|
* <p>This class and its subclasses store key-value pairs, where the key and
|
|
|
|
* the value are objects. A great many utility methods for working with
|
|
|
|
* dictionaries are provided as part of this class, including the ability to
|
|
|
|
* retrieve multiple entries simultaneously, obtain sorted contents, and
|
|
|
|
* read/write from/to a serialized representation.</p>
|
|
|
|
*
|
2007-03-19 10:42:16 +00:00
|
|
|
* <p>The keys are copied and values are retained by the implementation,
|
|
|
|
* and both are released when either their entry is dropped or the entire
|
|
|
|
* dictionary is deallocated.<br />
|
|
|
|
* As in the OS X implementation, keys must therefore implement the
|
|
|
|
* [(NSCopying)] protocol.
|
2004-07-29 15:30:47 +00:00
|
|
|
* </p>
|
2004-06-22 22:40:40 +00:00
|
|
|
*
|
|
|
|
* <p>Objects of this class are immutable. For a mutable version, use the
|
|
|
|
* [NSMutableDictionary] subclass.</p>
|
|
|
|
*
|
|
|
|
* <p>The basic functionality in <code>NSDictionary</code> is similar to that
|
|
|
|
* in Java's <code>HashMap</code>, and like that class it includes no locking
|
|
|
|
* code and is not thread-safe. If the contents will be modified and
|
|
|
|
* accessed from multiple threads you should enclose critical operations
|
|
|
|
* within locks (see [NSLock]).</p>
|
|
|
|
*/
|
2005-02-22 11:22:44 +00:00
|
|
|
@implementation NSDictionary
|
1995-04-03 22:59:20 +00:00
|
|
|
|
1995-06-30 14:21:45 +00:00
|
|
|
+ (void) initialize
|
|
|
|
{
|
1997-10-16 23:56:27 +00:00
|
|
|
if (self == [NSDictionary 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:);
|
2008-12-04 18:04:00 +00:00
|
|
|
NSArray_class = [NSArray class];
|
|
|
|
NSDictionaryClass = self;
|
|
|
|
GSDictionaryClass = [GSDictionary class];
|
|
|
|
[NSMutableDictionary class];
|
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
|
|
|
}
|
|
|
|
|
2012-03-22 20:58:27 +00:00
|
|
|
/**
|
|
|
|
* Returns a new copy of the receiver.<br />
|
|
|
|
* The default abstract implementation of a copy is to use the
|
|
|
|
* -initWithDictionary:copyItems: method with the flag set to YES.<br />
|
|
|
|
* Immutable subclasses generally simply retain and return the receiver.
|
|
|
|
*/
|
|
|
|
- (id) copyWithZone: (NSZone*)z
|
|
|
|
{
|
|
|
|
NSDictionary *copy = [NSDictionaryClass allocWithZone: z];
|
|
|
|
|
|
|
|
return [copy initWithDictionary: self copyItems: NO];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns an unsigned integer which is the number of elements
|
|
|
|
* stored in the dictionary.
|
|
|
|
*/
|
|
|
|
- (NSUInteger) count
|
|
|
|
{
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) enumerateKeysAndObjectsUsingBlock:
|
|
|
|
(GSKeysAndObjectsEnumeratorBlock)aBlock
|
|
|
|
{
|
|
|
|
[self enumerateKeysAndObjectsWithOptions: 0
|
|
|
|
usingBlock: aBlock];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) enumerateKeysAndObjectsWithOptions: (NSEnumerationOptions)opts
|
|
|
|
usingBlock: (GSKeysAndObjectsEnumeratorBlock)aBlock
|
|
|
|
{
|
|
|
|
/*
|
2012-03-27 17:05:19 +00:00
|
|
|
* NOTE: According to the Cocoa documentation, NSEnumerationReverse is
|
|
|
|
* undefined for NSDictionary. NSEnumerationConcurrent will be handled through
|
|
|
|
* the GS_DISPATCH_* macros if libdispatch is available.
|
2012-03-22 20:58:27 +00:00
|
|
|
*/
|
|
|
|
id<NSFastEnumeration> enumerator = [self keyEnumerator];
|
|
|
|
SEL objectForKeySelector = @selector(objectForKey:);
|
|
|
|
IMP objectForKey = [self methodForSelector: objectForKeySelector];
|
2012-03-27 17:05:19 +00:00
|
|
|
BLOCK_SCOPE BOOL shouldStop = NO;
|
2012-03-22 20:58:27 +00:00
|
|
|
id obj;
|
|
|
|
|
2012-03-27 17:05:19 +00:00
|
|
|
GS_DISPATCH_CREATE_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
|
2012-03-22 20:58:27 +00:00
|
|
|
FOR_IN(id, key, enumerator)
|
|
|
|
obj = (*objectForKey)(self, objectForKeySelector, key);
|
2012-03-27 17:05:19 +00:00
|
|
|
GS_DISPATCH_SUBMIT_BLOCK(enumQueueGroup, enumQueue, if (shouldStop){return;};, return;, aBlock, key, obj, &shouldStop);
|
2012-03-22 20:58:27 +00:00
|
|
|
if (YES == shouldStop)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
END_FOR_IN(enumerator)
|
2012-03-27 17:05:19 +00:00
|
|
|
GS_DISPATCH_TEARDOWN_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
|
2012-03-22 20:58:27 +00:00
|
|
|
}
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
/**
|
2004-09-07 05:43:20 +00:00
|
|
|
* <p>In MacOS-X class clusters do not have designated initialisers,
|
|
|
|
* and there is a general rule that -init is treated as the designated
|
|
|
|
* initialiser of the class cluster, but that other intitialisers
|
|
|
|
* may not work s expected an would need to be individually overridden
|
|
|
|
* in any subclass.
|
|
|
|
* </p>
|
|
|
|
* <p>GNUstep tries to make it easier to subclass a class cluster,
|
|
|
|
* by making class clusters follow the same convention as normal
|
|
|
|
* classes, so the designated initialiser is the <em>richest</em>
|
|
|
|
* initialiser. This means that all other initialisers call the
|
|
|
|
* documented designated initialiser (which calls -init only for
|
|
|
|
* MacOS-X compatibility), and anyone writing a subclass only needs
|
|
|
|
* to override that one initialiser in order to have all the other
|
|
|
|
* ones work.
|
|
|
|
* </p>
|
|
|
|
* <p>For MacOS-X compatibility, you may also need to override various
|
|
|
|
* other initialisers. Exactly which ones, you will need to determine
|
|
|
|
* by trial on a MacOS-X system ... and may vary between releases of
|
|
|
|
* MacOS-X. So to be safe, on MacOS-X you probably need to re-implement
|
|
|
|
* <em>all</em> the class cluster initialisers you might use in conjunction
|
|
|
|
* with your subclass.
|
|
|
|
* </p>
|
|
|
|
*/
|
|
|
|
- (id) init
|
|
|
|
{
|
|
|
|
self = [super init];
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** <init /> <override-subclass />
|
2004-06-22 22:40:40 +00:00
|
|
|
* Initializes contents to the given objects and keys.
|
|
|
|
* The two arrays must have the same size.
|
|
|
|
* The n th element of the objects array is associated with the n th
|
2004-09-07 05:43:20 +00:00
|
|
|
* element of the keys array.<br />
|
|
|
|
* Calls -init (which does nothing but maintain MacOS-X compatibility),
|
|
|
|
* and needs to be re-implemented in subclasses in order to have all
|
|
|
|
* other initialisers work.
|
2002-08-20 10:22:05 +00:00
|
|
|
*/
|
2011-07-24 13:09:22 +00:00
|
|
|
- (id) initWithObjects: (const id[])objects
|
2013-12-05 13:16:36 +00:00
|
|
|
forKeys: (const id <NSCopying>[])keys
|
2009-02-23 20:42:32 +00:00
|
|
|
count: (NSUInteger)count
|
1997-10-16 23:56:27 +00:00
|
|
|
{
|
2004-09-07 05:43:20 +00:00
|
|
|
self = [self init];
|
|
|
|
return self;
|
1997-10-16 23:56:27 +00:00
|
|
|
}
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
/**
|
2012-03-22 20:58:27 +00:00
|
|
|
* Return an enumerator object containing all the keys of the dictionary.
|
2002-08-20 10:22:05 +00:00
|
|
|
*/
|
2012-03-22 20:58:27 +00:00
|
|
|
- (NSEnumerator*) keyEnumerator
|
1997-10-16 23:56:27 +00:00
|
|
|
{
|
2013-04-14 17:50:00 +00:00
|
|
|
return [self subclassResponsibility: _cmd];
|
1997-10-16 23:56:27 +00:00
|
|
|
}
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
/**
|
|
|
|
* Returns the object in the dictionary corresponding to aKey, or nil if
|
|
|
|
* the key is not present.
|
|
|
|
*/
|
1999-09-12 19:03:09 +00:00
|
|
|
- (id) objectForKey: (id)aKey
|
1997-10-16 23:56:27 +00:00
|
|
|
{
|
2013-04-14 17:50:00 +00:00
|
|
|
return [self subclassResponsibility: _cmd];
|
1997-10-16 23:56:27 +00:00
|
|
|
}
|
|
|
|
|
2012-04-06 12:23:10 +00:00
|
|
|
- (id) objectForKeyedSubscript: (id)aKey
|
|
|
|
{
|
|
|
|
return [self objectForKey: aKey];
|
|
|
|
}
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
/**
|
|
|
|
* Return an enumerator object containing all the objects of the dictionary.
|
|
|
|
*/
|
1997-10-16 23:56:27 +00:00
|
|
|
- (NSEnumerator*) objectEnumerator
|
|
|
|
{
|
2013-04-14 17:50:00 +00:00
|
|
|
return [self subclassResponsibility: _cmd];
|
1997-10-16 23:56:27 +00:00
|
|
|
}
|
|
|
|
|
2003-01-20 17:18:06 +00:00
|
|
|
/**
|
|
|
|
* Returns a new instance containing the same objects as
|
|
|
|
* the receiver.<br />
|
|
|
|
* The default implementation does this by calling the
|
|
|
|
* -initWithDictionary:copyItems: method on a newly created object,
|
|
|
|
* and passing it NO to tell it just to retain the items.
|
|
|
|
*/
|
1999-07-03 19:59:44 +00:00
|
|
|
- (id) mutableCopyWithZone: (NSZone*)z
|
1998-07-30 16:34:32 +00:00
|
|
|
{
|
2003-01-20 17:18:06 +00:00
|
|
|
NSMutableDictionary *copy = [NSMutableDictionaryClass allocWithZone: z];
|
|
|
|
|
|
|
|
return [copy initWithDictionary: self copyItems: NO];
|
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];
|
|
|
|
|
2004-01-28 07:33:20 +00:00
|
|
|
if ([aCoder allowsKeyedCoding])
|
2000-10-16 12:35:42 +00:00
|
|
|
{
|
2004-06-14 05:27:54 +00:00
|
|
|
id key;
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
if ([aCoder class] == [NSKeyedArchiver class])
|
2004-01-28 07:33:20 +00:00
|
|
|
{
|
2004-06-14 05:27:54 +00:00
|
|
|
NSArray *keys = [self allKeys];
|
|
|
|
id objects = [NSMutableArray arrayWithCapacity: count];
|
2004-01-28 07:33:20 +00:00
|
|
|
|
2004-06-14 05:27:54 +00:00
|
|
|
for (i = 0; i < count; i++)
|
2004-01-28 07:33:20 +00:00
|
|
|
{
|
2004-06-14 05:27:54 +00:00
|
|
|
key = [keys objectAtIndex: i];
|
|
|
|
[objects addObject: [self objectForKey: key]];
|
2004-01-28 07:33:20 +00:00
|
|
|
}
|
2004-06-14 05:27:54 +00:00
|
|
|
[(NSKeyedArchiver*)aCoder _encodeArrayOfObjects: keys
|
|
|
|
forKey: @"NS.keys"];
|
|
|
|
[(NSKeyedArchiver*)aCoder _encodeArrayOfObjects: objects
|
|
|
|
forKey: @"NS.objects"];
|
|
|
|
}
|
|
|
|
else if (count > 0)
|
|
|
|
{
|
|
|
|
NSEnumerator *enumerator = [self keyEnumerator];
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
while ((key = [enumerator nextObject]) != nil)
|
2004-01-28 07:33:20 +00:00
|
|
|
{
|
2004-06-14 05:27:54 +00:00
|
|
|
NSString *s;
|
|
|
|
|
|
|
|
s = [NSString stringWithFormat: @"NS.key.%u", i];
|
|
|
|
[aCoder encodeObject: key forKey: s];
|
|
|
|
s = [NSString stringWithFormat: @"NS.object.%u", i];
|
|
|
|
[aCoder encodeObject: [self objectForKey: key] forKey: s];
|
|
|
|
i++;
|
2004-01-28 07:33:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(unsigned) at: &count];
|
|
|
|
if (count > 0)
|
2000-10-16 12:35:42 +00:00
|
|
|
{
|
2004-01-28 07:33:20 +00:00
|
|
|
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:)];
|
2000-10-16 12:35:42 +00:00
|
|
|
|
2004-01-28 07:33:20 +00:00
|
|
|
while ((key = (*nxt)(enumerator, @selector(nextObject))) != nil)
|
|
|
|
{
|
|
|
|
id val = (*ofk)(self, @selector(objectForKey:), key);
|
|
|
|
|
|
|
|
(*enc)(aCoder, @selector(encodeObject:), key);
|
|
|
|
(*enc)(aCoder, @selector(encodeObject:), val);
|
|
|
|
}
|
2000-10-16 12:35:42 +00:00
|
|
|
}
|
|
|
|
}
|
1998-07-30 16:34:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id) initWithCoder: (NSCoder*)aCoder
|
|
|
|
{
|
2004-01-27 21:51:33 +00:00
|
|
|
if ([aCoder allowsKeyedCoding])
|
2000-10-16 12:35:42 +00:00
|
|
|
{
|
2011-10-24 14:33:30 +00:00
|
|
|
id keys = nil;
|
|
|
|
id objects = nil;
|
|
|
|
|
|
|
|
if ([aCoder containsValueForKey: @"NS.keys"])
|
|
|
|
{
|
|
|
|
keys = [(NSKeyedUnarchiver*)aCoder _decodeArrayOfObjectsForKey:
|
|
|
|
@"NS.keys"];
|
|
|
|
objects = [(NSKeyedUnarchiver*)aCoder _decodeArrayOfObjectsForKey:
|
|
|
|
@"NS.objects"];
|
|
|
|
}
|
|
|
|
else if ([aCoder containsValueForKey: @"dict.sortedKeys"])
|
|
|
|
{
|
|
|
|
keys = [aCoder decodeObjectForKey: @"dict.sortedKeys"];
|
|
|
|
objects = [aCoder decodeObjectForKey: @"dict.values"];
|
|
|
|
}
|
2004-01-28 07:33:20 +00:00
|
|
|
|
|
|
|
if (keys == nil)
|
|
|
|
{
|
|
|
|
unsigned i = 0;
|
|
|
|
NSString *key;
|
|
|
|
id val;
|
|
|
|
|
|
|
|
keys = [NSMutableArray arrayWithCapacity: 2];
|
|
|
|
objects = [NSMutableArray arrayWithCapacity: 2];
|
|
|
|
key = [NSString stringWithFormat: @"NS.object.%u", i];
|
|
|
|
val = [(NSKeyedUnarchiver*)aCoder decodeObjectForKey: key];
|
2000-10-16 12:35:42 +00:00
|
|
|
|
2004-01-28 07:33:20 +00:00
|
|
|
while (val != nil)
|
|
|
|
{
|
|
|
|
[objects addObject: val];
|
|
|
|
key = [NSString stringWithFormat: @"NS.key.%u", i];
|
|
|
|
val = [(NSKeyedUnarchiver*)aCoder decodeObjectForKey: key];
|
|
|
|
[keys addObject: val];
|
|
|
|
i++;
|
|
|
|
key = [NSString stringWithFormat: @"NS.object.%u", i];
|
|
|
|
val = [(NSKeyedUnarchiver*)aCoder decodeObjectForKey: key];
|
|
|
|
}
|
|
|
|
}
|
2004-01-27 21:51:33 +00:00
|
|
|
self = [self initWithObjects: objects forKeys: keys];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
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;
|
2012-03-20 20:17:45 +00:00
|
|
|
|
2004-01-27 21:51:33 +00:00
|
|
|
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);
|
2000-10-16 12:35:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return self;
|
1998-07-30 16:34:32 +00:00
|
|
|
}
|
1997-10-16 23:56:27 +00:00
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
/**
|
|
|
|
* Returns a new autoreleased empty dictionary.
|
|
|
|
*/
|
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
|
|
|
}
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
/**
|
|
|
|
* Returns a newly created dictionary with the keys and objects
|
|
|
|
* of otherDictionary.
|
|
|
|
* (The keys and objects are not copied.)
|
|
|
|
*/
|
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
|
|
|
}
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
/**
|
|
|
|
* Returns a dictionary created using the given objects and keys.
|
|
|
|
* The two arrays must have the same size.
|
|
|
|
* The n th element of the objects array is associated with the n th
|
|
|
|
* element of the keys array.
|
|
|
|
*/
|
2011-07-24 13:09:22 +00:00
|
|
|
+ (id) dictionaryWithObjects: (const id[])objects
|
2013-12-05 13:16:36 +00:00
|
|
|
forKeys: (const id <NSCopying>[])keys
|
2009-02-23 20:42:32 +00:00
|
|
|
count: (NSUInteger)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
|
|
|
}
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
- (NSUInteger) hash
|
1998-10-27 08:12:49 +00:00
|
|
|
{
|
|
|
|
return [self count];
|
|
|
|
}
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
/**
|
|
|
|
* Initialises a dictionary created using the given objects and keys.
|
|
|
|
* The two arrays must have the same size.
|
|
|
|
* The n th element of the objects array is associated with the n th
|
|
|
|
* element of the keys array.
|
|
|
|
*/
|
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];
|
2005-02-22 11:22:44 +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
|
|
|
}
|
2004-03-16 09:53:01 +00:00
|
|
|
else
|
|
|
|
{
|
2004-09-10 15:10:54 +00:00
|
|
|
GS_BEGINIDBUF(o, objectCount*2);
|
2004-03-16 09:53:01 +00:00
|
|
|
|
2008-07-06 09:18:30 +00:00
|
|
|
if ([objects isProxy])
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
for (i = 0; i < objectCount; i++)
|
|
|
|
{
|
|
|
|
o[i] = [objects objectAtIndex: i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[objects getObjects: o];
|
|
|
|
}
|
|
|
|
if ([keys isProxy])
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
for (i = 0; i < objectCount; i++)
|
|
|
|
{
|
|
|
|
o[objectCount + i] = [keys objectAtIndex: i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[keys getObjects: o + objectCount];
|
|
|
|
}
|
2004-03-16 09:53:01 +00:00
|
|
|
self = [self initWithObjects: o
|
|
|
|
forKeys: o + objectCount
|
|
|
|
count: objectCount];
|
2004-09-10 15:10:54 +00:00
|
|
|
GS_ENDIDBUF();
|
2004-03-16 09:53:01 +00:00
|
|
|
}
|
|
|
|
return self;
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
/**
|
|
|
|
* Initialises a dictionary created using the list given as argument.
|
2008-03-14 17:13:41 +00:00
|
|
|
* The list is alternately composed of objects and keys and
|
|
|
|
* terminated by nil. Thus, the list's length must be even,
|
|
|
|
* followed by nil.
|
2002-08-20 10:22:05 +00:00
|
|
|
*/
|
1998-10-31 05:17:54 +00:00
|
|
|
- (id) initWithObjectsAndKeys: (id)firstObject, ...
|
|
|
|
{
|
2003-04-07 08:26:40 +00:00
|
|
|
GS_USEIDPAIRLIST(firstObject,
|
|
|
|
self = [self initWithObjects: __objects forKeys: __pairs count: __count/2]);
|
1998-10-31 05:17:54 +00:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
/**
|
|
|
|
* Returns a dictionary created using the list given as argument.
|
2008-03-14 17:13:41 +00:00
|
|
|
* The list is alternately composed of objects and keys and
|
|
|
|
* terminated by nil. Thus, the list's length must be even,
|
|
|
|
* followed by nil.
|
2002-08-20 10:22:05 +00:00
|
|
|
*/
|
1999-09-12 19:03:09 +00:00
|
|
|
+ (id) dictionaryWithObjectsAndKeys: (id)firstObject, ...
|
1996-10-25 23:43:00 +00:00
|
|
|
{
|
2003-04-07 08:26:40 +00:00
|
|
|
id o = [self allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
|
|
|
GS_USEIDPAIRLIST(firstObject,
|
|
|
|
o = [o initWithObjects: __objects forKeys: __pairs count: __count/2]);
|
|
|
|
return AUTORELEASE(o);
|
1996-10-25 23:43:00 +00:00
|
|
|
}
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
/**
|
|
|
|
* Returns a dictionary created using the given objects and keys.
|
|
|
|
* The two arrays must have the same length.
|
|
|
|
* The n th element of the objects array is associated with the n th
|
|
|
|
* element of the keys array.
|
|
|
|
*/
|
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
|
|
|
}
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
/**
|
|
|
|
* Returns a dictionary containing only one object which is associated
|
|
|
|
* with a key.
|
|
|
|
*/
|
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
|
|
|
}
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
/**
|
|
|
|
* Initializes with the keys and objects of otherDictionary.
|
|
|
|
* (The keys and objects are not copied.)
|
|
|
|
*/
|
2002-02-03 17:21:20 +00:00
|
|
|
- (id) initWithDictionary: (NSDictionary*)otherDictionary
|
1998-10-27 08:12:49 +00:00
|
|
|
{
|
2002-02-03 17:21:20 +00:00
|
|
|
return [self initWithDictionary: otherDictionary copyItems: NO];
|
1998-10-27 08:12:49 +00:00
|
|
|
}
|
|
|
|
|
2002-02-03 17:21:20 +00:00
|
|
|
/**
|
|
|
|
* Initialise dictionary with the keys and values of otherDictionary.
|
|
|
|
* If the shouldCopy flag is YES then the values are copied into the
|
2007-03-19 10:42:16 +00:00
|
|
|
* newly initialised dictionary, otherwise they are simply retained,
|
|
|
|
* on the assumption that it is safe to retain the keys from another
|
|
|
|
* dictionary since that other dictionary mwill have copied the keys
|
|
|
|
* originally to ensure that they are immutable.
|
2002-02-03 17:21:20 +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 k;
|
|
|
|
NSEnumerator *e = [other keyEnumerator];
|
|
|
|
unsigned i = 0;
|
|
|
|
IMP nxtObj = [e methodForSelector: nxtSel];
|
|
|
|
IMP otherObj = [other methodForSelector: objSel];
|
2004-09-10 15:10:54 +00:00
|
|
|
GS_BEGINIDBUF(o, c*2);
|
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)
|
|
|
|
{
|
2004-03-16 09:53:01 +00:00
|
|
|
o[i] = k;
|
|
|
|
o[c + i] = [(*otherObj)(other, objSel, k) copyWithZone: z];
|
2000-03-28 14:29:37 +00:00
|
|
|
i++;
|
|
|
|
}
|
2004-03-16 09:53:01 +00:00
|
|
|
self = [self initWithObjects: o + c forKeys: o count: i];
|
|
|
|
while (i-- > 0)
|
2000-03-28 14:29:37 +00:00
|
|
|
{
|
2004-03-16 09:53:01 +00:00
|
|
|
[o[c + i] release];
|
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)
|
|
|
|
{
|
2004-03-16 09:53:01 +00:00
|
|
|
o[i] = k;
|
|
|
|
o[c + i] = (*otherObj)(other, objSel, k);
|
2000-03-28 14:29:37 +00:00
|
|
|
i++;
|
|
|
|
}
|
2004-03-16 09:53:01 +00:00
|
|
|
self = [self initWithObjects: o + c forKeys: o count: c];
|
1998-10-27 08:12:49 +00:00
|
|
|
}
|
2004-09-10 15:10:54 +00:00
|
|
|
GS_ENDIDBUF();
|
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
|
|
|
}
|
|
|
|
|
2002-03-21 09:45:30 +00:00
|
|
|
/**
|
|
|
|
* <p>Initialises the dictionary with the contents of the specified file,
|
|
|
|
* which must contain a dictionary in property-list format.
|
|
|
|
* </p>
|
|
|
|
* <p>In GNUstep, the property-list format may be either the OpenStep
|
2004-06-22 22:40:40 +00:00
|
|
|
* format (ASCII data), or the MacOS-X format (UTF-8 XML data) ... this
|
2002-03-21 09:45:30 +00:00
|
|
|
* method will recognise which it is.
|
|
|
|
* </p>
|
|
|
|
* <p>If there is a failure to load the file for any reason, the receiver
|
|
|
|
* will be released and the method will return nil.
|
|
|
|
* </p>
|
2002-10-04 09:08:09 +00:00
|
|
|
* <p>Works by invoking [NSString-initWithContentsOfFile:] and
|
2005-02-22 11:22:44 +00:00
|
|
|
* [NSString-propertyList] then checking that the result is a dictionary.
|
2002-10-04 09:08:09 +00:00
|
|
|
* </p>
|
2002-03-21 09:45:30 +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;
|
|
|
|
|
2002-10-04 09:08:09 +00:00
|
|
|
myString = [[NSString allocWithZone: NSDefaultMallocZone()]
|
1999-05-06 14:42:26 +00:00
|
|
|
initWithContentsOfFile: path];
|
2002-10-04 09:08:09 +00:00
|
|
|
if (myString == nil)
|
2002-10-04 03:11:16 +00:00
|
|
|
{
|
2002-10-04 09:08:09 +00:00
|
|
|
DESTROY(self);
|
2002-10-04 03:11:16 +00:00
|
|
|
}
|
2002-10-04 09:08:09 +00:00
|
|
|
else
|
1997-01-06 22:43:08 +00:00
|
|
|
{
|
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];
|
2002-10-04 09:08:09 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSWarnMLog(@"Contents of file '%@' does not contain a dictionary",
|
|
|
|
path);
|
|
|
|
DESTROY(self);
|
1997-09-13 17:52:31 +00:00
|
|
|
}
|
1997-01-06 22:43:08 +00:00
|
|
|
}
|
2002-10-04 09:08:09 +00:00
|
|
|
return self;
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
2003-07-15 16:35:11 +00:00
|
|
|
/**
|
|
|
|
* <p>Initialises the dictionary with the contents of the specified URL,
|
|
|
|
* which must contain a dictionary in property-list format.
|
|
|
|
* </p>
|
|
|
|
* <p>In GNUstep, the property-list format may be either the OpenStep
|
2004-06-22 22:40:40 +00:00
|
|
|
* format (ASCII data), or the MacOS-X format (UTF-8 XML data) ... this
|
2003-07-15 16:35:11 +00:00
|
|
|
* method will recognise which it is.
|
|
|
|
* </p>
|
|
|
|
* <p>If there is a failure to load the URL for any reason, the receiver
|
|
|
|
* will be released and the method will return nil.
|
|
|
|
* </p>
|
|
|
|
* <p>Works by invoking [NSString-initWithContentsOfURL:] and
|
2005-02-22 11:22:44 +00:00
|
|
|
* [NSString-propertyList] then checking that the result is a dictionary.
|
2003-07-15 16:35:11 +00:00
|
|
|
* </p>
|
|
|
|
*/
|
|
|
|
- (id) initWithContentsOfURL: (NSURL*)aURL
|
|
|
|
{
|
|
|
|
NSString *myString;
|
|
|
|
|
|
|
|
myString = [[NSString allocWithZone: NSDefaultMallocZone()]
|
|
|
|
initWithContentsOfURL: aURL];
|
|
|
|
if (myString == nil)
|
|
|
|
{
|
|
|
|
DESTROY(self);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
id result;
|
|
|
|
|
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
result = [myString propertyList];
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
result = nil;
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
|
|
|
RELEASE(myString);
|
|
|
|
if ([result isKindOfClass: NSDictionaryClass])
|
|
|
|
{
|
|
|
|
self = [self initWithDictionary: result];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSWarnMLog(@"Contents of URL '%@' does not contain a dictionary",
|
|
|
|
aURL);
|
|
|
|
DESTROY(self);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
/**
|
|
|
|
* Returns a dictionary using the file located at path.
|
|
|
|
* The file must be a property list containing a dictionary as its root object.
|
|
|
|
*/
|
|
|
|
+ (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
|
|
|
}
|
|
|
|
|
2003-07-15 16:35:11 +00:00
|
|
|
/**
|
|
|
|
* Returns a dictionary using the contents of aURL.
|
|
|
|
* The URL must be a property list containing a dictionary as its root object.
|
|
|
|
*/
|
|
|
|
+ (id) dictionaryWithContentsOfURL: (NSURL*)aURL
|
|
|
|
{
|
|
|
|
return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()]
|
|
|
|
initWithContentsOfURL: aURL]);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
/**
|
|
|
|
* Two dictionaries are equal if they each hold the same number of
|
|
|
|
* entries, each key in one <code>isEqual</code> to a key in the other,
|
|
|
|
* and, for a given key, the corresponding value objects also satisfy
|
|
|
|
* <code>isEqual</code>.
|
|
|
|
*/
|
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);
|
|
|
|
|
2001-06-17 15:30:23 +00:00
|
|
|
if (o1 == o2)
|
|
|
|
continue;
|
2000-03-28 14:29:37 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
/**
|
|
|
|
* Returns an array containing all the dictionary's keys.
|
|
|
|
*/
|
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];
|
|
|
|
unsigned i;
|
2004-03-16 09:53:01 +00:00
|
|
|
id result;
|
2004-09-10 15:10:54 +00:00
|
|
|
GS_BEGINIDBUF(k, c);
|
1999-09-12 19:03:09 +00:00
|
|
|
|
|
|
|
for (i = 0; i < c; i++)
|
|
|
|
{
|
|
|
|
k[i] = (*nxtObj)(e, nxtSel);
|
|
|
|
NSAssert (k[i], NSInternalInconsistencyException);
|
|
|
|
}
|
2004-03-16 09:53:01 +00:00
|
|
|
result = [[NSArray_class allocWithZone: NSDefaultMallocZone()]
|
|
|
|
initWithObjects: k count: c];
|
2004-09-10 15:10:54 +00:00
|
|
|
GS_ENDIDBUF();
|
2004-03-16 09:53:01 +00:00
|
|
|
return AUTORELEASE(result);
|
1995-05-05 18:31:51 +00:00
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
/**
|
|
|
|
* Returns an array containing all the dictionary's objects.
|
|
|
|
*/
|
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];
|
2004-03-16 09:53:01 +00:00
|
|
|
id result;
|
1999-09-12 19:03:09 +00:00
|
|
|
unsigned i;
|
2004-09-10 15:10:54 +00:00
|
|
|
GS_BEGINIDBUF(k, c);
|
1999-09-12 19:03:09 +00:00
|
|
|
|
|
|
|
for (i = 0; i < c; i++)
|
|
|
|
{
|
|
|
|
k[i] = (*nxtObj)(e, nxtSel);
|
|
|
|
}
|
2004-03-16 09:53:01 +00:00
|
|
|
result = [[NSArray_class allocWithZone: NSDefaultMallocZone()]
|
|
|
|
initWithObjects: k count: c];
|
2004-09-10 15:10:54 +00:00
|
|
|
GS_ENDIDBUF();
|
2004-03-16 09:53:01 +00:00
|
|
|
return AUTORELEASE(result);
|
1995-05-05 18:31:51 +00:00
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
2012-03-20 20:17:45 +00:00
|
|
|
|
2011-07-24 13:09:22 +00:00
|
|
|
- (void)getObjects: (__unsafe_unretained id[])objects
|
2016-02-22 21:04:18 +00:00
|
|
|
andKeys: (__unsafe_unretained id<NSCopying>[])keys
|
2011-07-24 13:09:22 +00:00
|
|
|
{
|
2016-07-26 23:24:56 +00:00
|
|
|
NSUInteger i=0;
|
2011-07-24 13:09:22 +00:00
|
|
|
FOR_IN(id, key, self)
|
2016-07-26 23:24:56 +00:00
|
|
|
if (keys != NULL) keys[i] = key;
|
|
|
|
if (objects != NULL) objects[i] = [self objectForKey: key];
|
|
|
|
i++;
|
2011-07-24 13:09:22 +00:00
|
|
|
END_FOR_IN(self)
|
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
/**
|
|
|
|
* Returns an array containing all the dictionary's keys that are
|
|
|
|
* associated with anObject.
|
|
|
|
*/
|
1999-09-12 19:03:09 +00:00
|
|
|
- (NSArray*) allKeysForObject: (id)anObject
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
2001-06-17 15:30:23 +00:00
|
|
|
unsigned c;
|
1995-05-05 18:31:51 +00:00
|
|
|
|
2001-06-17 15:30:23 +00:00
|
|
|
if (anObject == nil || (c = [self count]) == 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;
|
2004-03-16 09:53:01 +00:00
|
|
|
id result;
|
2004-09-10 15:10:54 +00:00
|
|
|
GS_BEGINIDBUF(a, [self count]);
|
1999-09-12 19:03:09 +00:00
|
|
|
|
|
|
|
eqObj = (BOOL (*)(id, SEL, id))[anObject methodForSelector: eqSel];
|
|
|
|
c = 0;
|
|
|
|
while ((k = (*nxtObj)(e, nxtSel)) != nil)
|
|
|
|
{
|
2001-06-17 15:30:23 +00:00
|
|
|
id o = (*myObj)(self, objSel, k);
|
|
|
|
|
|
|
|
if (o == anObject || (*eqObj)(anObject, eqSel, o))
|
1999-09-12 19:03:09 +00:00
|
|
|
{
|
|
|
|
a[c++] = k;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (c == 0)
|
2004-03-16 09:53:01 +00:00
|
|
|
{
|
|
|
|
result = nil;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result = [[NSArray_class allocWithZone: NSDefaultMallocZone()]
|
|
|
|
initWithObjects: a count: c];
|
|
|
|
}
|
2004-09-10 15:10:54 +00:00
|
|
|
GS_ENDIDBUF();
|
2004-03-16 09:53:01 +00:00
|
|
|
return AUTORELEASE(result);
|
1999-09-12 19:03:09 +00:00
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1998-10-27 09:35:06 +00:00
|
|
|
struct foo { NSDictionary *d; SEL s; IMP i; };
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2017-03-27 09:00:35 +00:00
|
|
|
static NSInteger
|
1998-01-19 15:20:15 +00:00
|
|
|
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);
|
2009-02-23 20:42:32 +00:00
|
|
|
return (NSInteger)(intptr_t)[o1 performSelector: f->s withObject: o2];
|
1998-01-19 15:20:15 +00:00
|
|
|
}
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
/**
|
|
|
|
* Returns ordered array of the keys sorted according to the values they
|
|
|
|
* correspond to. To sort the values, a message with selector comp is
|
|
|
|
* send to each value with another value as argument, as in
|
|
|
|
* <code>[a comp: b]</code>. The comp method should return
|
|
|
|
* <code>NSOrderedSame</code>, <code>NSOrderedAscending</code>, or
|
|
|
|
* <code>NSOrderedDescending</code> as appropriate.
|
|
|
|
*/
|
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
|
|
|
}
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
/**
|
|
|
|
* Multiple version of [-objectForKey:]. Objects for each key in keys are
|
|
|
|
* looked up and placed into return array in same order. For each key that
|
|
|
|
* has no corresponding value in this dictionary, marker is put into the
|
|
|
|
* array in its place.
|
|
|
|
*/
|
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;
|
|
|
|
IMP myObj = [self methodForSelector: objSel];
|
2004-03-16 09:53:01 +00:00
|
|
|
id result;
|
2004-09-10 15:10:54 +00:00
|
|
|
GS_BEGINIDBUF(obuf, c);
|
1998-01-19 15:20:15 +00:00
|
|
|
|
2008-07-06 09:18:30 +00:00
|
|
|
if ([keys isProxy])
|
|
|
|
{
|
|
|
|
for (i = 0; i < c; i++)
|
|
|
|
{
|
|
|
|
obuf[i] = [keys objectAtIndex: i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[keys getObjects: obuf];
|
|
|
|
}
|
1999-09-12 19:03:09 +00:00
|
|
|
for (i = 0; i < c; i++)
|
|
|
|
{
|
|
|
|
id o = (*myObj)(self, objSel, obuf[i]);
|
|
|
|
|
2004-03-16 09:53:01 +00:00
|
|
|
if (o == nil)
|
|
|
|
{
|
|
|
|
obuf[i] = marker;
|
|
|
|
}
|
1999-09-12 19:03:09 +00:00
|
|
|
else
|
2004-03-16 09:53:01 +00:00
|
|
|
{
|
|
|
|
obuf[i] = o;
|
|
|
|
}
|
1999-09-12 19:03:09 +00:00
|
|
|
}
|
2004-03-16 09:53:01 +00:00
|
|
|
result = [[NSArray_class allocWithZone: NSDefaultMallocZone()]
|
|
|
|
initWithObjects: obuf count: c];
|
2004-09-10 15:10:54 +00:00
|
|
|
GS_ENDIDBUF();
|
2004-03-16 09:53:01 +00:00
|
|
|
return AUTORELEASE(result);
|
1998-01-19 15:20:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-21 10:27:05 +00:00
|
|
|
- (NSSet*) keysOfEntriesWithOptions: (NSEnumerationOptions)opts
|
|
|
|
passingTest: (GSKeysAndObjectsPredicateBlock)aPredicate
|
2012-03-20 20:17:45 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* See -enumerateKeysAndObjectsWithOptions:usingBlock: for note about
|
|
|
|
* NSEnumerationOptions.
|
|
|
|
*/
|
2012-09-21 10:27:05 +00:00
|
|
|
id<NSFastEnumeration> enumerator = [self keyEnumerator];
|
|
|
|
SEL objectForKeySelector = @selector(objectForKey:);
|
|
|
|
IMP objectForKey = [self methodForSelector: objectForKeySelector];
|
|
|
|
BLOCK_SCOPE BOOL shouldStop = NO;
|
|
|
|
NSMutableSet *buildSet = [NSMutableSet new];
|
|
|
|
SEL addObjectSelector = @selector(addObject:);
|
|
|
|
IMP addObject = [buildSet methodForSelector: addObjectSelector];
|
|
|
|
NSSet *resultSet = nil;
|
|
|
|
id obj = nil;
|
|
|
|
BLOCK_SCOPE NSLock *setLock = nil;
|
|
|
|
|
|
|
|
if (opts & NSEnumerationConcurrent)
|
|
|
|
{
|
|
|
|
setLock = [NSLock new];
|
|
|
|
}
|
|
|
|
GS_DISPATCH_CREATE_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
|
|
|
|
FOR_IN(id, key, enumerator)
|
|
|
|
obj = (*objectForKey)(self, objectForKeySelector, key);
|
|
|
|
#if (__has_feature(blocks) && (GS_USE_LIBDISPATCH == 1))
|
|
|
|
dispatch_group_async(enumQueueGroup, enumQueue, ^(void){
|
|
|
|
if (shouldStop)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (aPredicate(key, obj, &shouldStop))
|
|
|
|
{
|
|
|
|
[setLock lock];
|
|
|
|
addObject(buildSet, addObjectSelector, key);
|
|
|
|
[setLock unlock];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
#else
|
|
|
|
if (CALL_BLOCK(aPredicate, key, obj, &shouldStop))
|
|
|
|
{
|
|
|
|
addObject(buildSet, addObjectSelector, key);
|
|
|
|
}
|
|
|
|
#endif
|
2012-03-27 17:05:19 +00:00
|
|
|
|
2012-09-21 10:27:05 +00:00
|
|
|
if (YES == shouldStop)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
END_FOR_IN(enumerator)
|
|
|
|
GS_DISPATCH_TEARDOWN_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts)
|
|
|
|
[setLock release];
|
|
|
|
resultSet = [NSSet setWithSet: buildSet];
|
|
|
|
[buildSet release];
|
|
|
|
return resultSet;
|
2012-03-20 20:17:45 +00:00
|
|
|
}
|
|
|
|
|
2012-03-22 20:58:27 +00:00
|
|
|
- (NSSet*) keysOfEntriesPassingTest: (GSKeysAndObjectsPredicateBlock)aPredicate
|
2012-03-20 20:17:45 +00:00
|
|
|
{
|
|
|
|
return [self keysOfEntriesWithOptions: 0
|
|
|
|
passingTest: aPredicate];
|
|
|
|
}
|
|
|
|
|
2002-03-21 09:45:30 +00:00
|
|
|
/**
|
|
|
|
* <p>Writes the contents of the dictionary to the file specified by path.
|
|
|
|
* The file contents will be in property-list format ... under GNUstep
|
|
|
|
* this is either OpenStep style (ASCII characters using \U hexadecimal
|
|
|
|
* escape sequences for unicode), or MacOS-X style (XML in the UTF8
|
|
|
|
* character set).
|
|
|
|
* </p>
|
|
|
|
* <p>If the useAuxiliaryFile flag is YES, the file write operation is
|
|
|
|
* atomic ... the data is written to a temporary file, which is then
|
|
|
|
* renamed to the actual file name.
|
|
|
|
* </p>
|
|
|
|
* <p>If the conversion of data into the correct property-list format fails
|
|
|
|
* or the write operation fails, the method returns NO, otherwise it
|
|
|
|
* returns YES.
|
|
|
|
* </p>
|
|
|
|
* <p>NB. The fact that the file is in property-list format does not
|
|
|
|
* necessarily mean that it can be used to reconstruct the dictionary using
|
|
|
|
* the -initWithContentsOfFile: method. If the original dictionary contains
|
|
|
|
* non-property-list objects, the descriptions of those objects will
|
|
|
|
* have been written, and reading in the file as a property-list will
|
|
|
|
* result in a new dictionary containing the string descriptions.
|
|
|
|
* </p>
|
|
|
|
*/
|
1999-09-12 19:03:09 +00:00
|
|
|
- (BOOL) writeToFile: (NSString *)path atomically: (BOOL)useAuxiliaryFile
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
2006-10-18 15:36:52 +00:00
|
|
|
NSDictionary *loc;
|
2002-11-10 09:29:45 +00:00
|
|
|
NSString *desc = nil;
|
2002-11-27 16:39:17 +00:00
|
|
|
NSData *data;
|
2001-09-08 05:11:58 +00:00
|
|
|
|
2006-10-18 15:36:52 +00:00
|
|
|
loc = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
|
2001-09-08 05:11:58 +00:00
|
|
|
if (GSMacOSXCompatiblePropertyLists() == YES)
|
|
|
|
{
|
2002-11-27 13:56:00 +00:00
|
|
|
GSPropertyListMake(self, loc, YES, NO, 2, &desc);
|
2002-11-27 16:39:17 +00:00
|
|
|
data = [desc dataUsingEncoding: NSUTF8StringEncoding];
|
2001-09-08 05:11:58 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-11-27 13:56:00 +00:00
|
|
|
GSPropertyListMake(self, loc, NO, NO, 2, &desc);
|
2002-11-27 16:39:17 +00:00
|
|
|
data = [desc dataUsingEncoding: NSASCIIStringEncoding];
|
2001-09-08 05:11:58 +00:00
|
|
|
}
|
2002-11-27 16:39:17 +00:00
|
|
|
return [data writeToFile: path atomically: useAuxiliaryFile];
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
2002-03-21 09:45:30 +00:00
|
|
|
/**
|
|
|
|
* <p>Writes the contents of the dictionary to the specified url.
|
|
|
|
* This functions just like -writeToFile:atomically: except that the
|
|
|
|
* output may be written to any URL, not just a local file.
|
|
|
|
* </p>
|
|
|
|
*/
|
2001-07-16 07:08:47 +00:00
|
|
|
- (BOOL) writeToURL: (NSURL *)url atomically: (BOOL)useAuxiliaryFile
|
|
|
|
{
|
2006-10-18 15:36:52 +00:00
|
|
|
NSDictionary *loc;
|
2002-11-10 09:29:45 +00:00
|
|
|
NSString *desc = nil;
|
2002-11-27 16:39:17 +00:00
|
|
|
NSData *data;
|
2001-09-08 05:15:19 +00:00
|
|
|
|
2006-10-18 15:36:52 +00:00
|
|
|
loc = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
|
2001-09-08 05:15:19 +00:00
|
|
|
if (GSMacOSXCompatiblePropertyLists() == YES)
|
|
|
|
{
|
2002-11-27 13:56:00 +00:00
|
|
|
GSPropertyListMake(self, loc, YES, NO, 2, &desc);
|
2002-11-27 16:39:17 +00:00
|
|
|
data = [desc dataUsingEncoding: NSUTF8StringEncoding];
|
2001-09-08 05:15:19 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-11-27 13:56:00 +00:00
|
|
|
GSPropertyListMake(self, loc, NO, NO, 2, &desc);
|
2002-11-27 16:39:17 +00:00
|
|
|
data = [desc dataUsingEncoding: NSASCIIStringEncoding];
|
2001-09-08 05:15:19 +00:00
|
|
|
}
|
2001-07-16 07:08:47 +00:00
|
|
|
|
2002-11-27 16:39:17 +00:00
|
|
|
return [data writeToURL: url atomically: useAuxiliaryFile];
|
2001-07-16 07:08:47 +00:00
|
|
|
}
|
|
|
|
|
2002-11-11 11:34:21 +00:00
|
|
|
/**
|
|
|
|
* Returns the result of invoking -descriptionWithLocale:indent: with a nil
|
|
|
|
* locale and zero indent.
|
|
|
|
*/
|
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
|
|
|
}
|
|
|
|
|
2002-11-11 11:34:21 +00:00
|
|
|
/**
|
|
|
|
* Returns the receiver as a text property list strings file format.<br />
|
|
|
|
* See [NSString-propertyListFromStringsFileFormat] for details.<br />
|
|
|
|
* The order of the items is undefined.
|
|
|
|
*/
|
1998-01-19 15:20:15 +00:00
|
|
|
- (NSString*) descriptionInStringsFileFormat
|
|
|
|
{
|
2002-11-10 09:29:45 +00:00
|
|
|
NSMutableString *result = nil;
|
1999-09-12 19:03:09 +00:00
|
|
|
NSEnumerator *enumerator = [self keyEnumerator];
|
|
|
|
IMP nxtObj = [enumerator methodForSelector: nxtSel];
|
|
|
|
IMP myObj = [self methodForSelector: objSel];
|
1998-12-18 17:05:44 +00:00
|
|
|
id key;
|
1998-01-19 15:20:15 +00:00
|
|
|
|
1999-09-12 19:03:09 +00:00
|
|
|
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
|
|
|
|
2002-11-27 13:56:00 +00:00
|
|
|
GSPropertyListMake(key, nil, NO, YES, 0, &result);
|
1998-12-18 17:05:44 +00:00
|
|
|
if (val != nil && [val isEqualToString: @""] == NO)
|
|
|
|
{
|
2002-11-10 09:29:45 +00:00
|
|
|
[result appendString: @" = "];
|
2002-11-27 13:56:00 +00:00
|
|
|
GSPropertyListMake(val, nil, NO, YES, 0, &result);
|
1998-12-18 17:05:44 +00:00
|
|
|
}
|
2002-11-10 09:29:45 +00:00
|
|
|
[result appendString: @";\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
|
|
|
}
|
|
|
|
|
2002-11-11 11:34:21 +00:00
|
|
|
/**
|
|
|
|
* Returns the result of invoking -descriptionWithLocale:indent: with
|
|
|
|
* a zero indent.
|
|
|
|
*/
|
2011-02-23 11:52:17 +00:00
|
|
|
- (NSString*) descriptionWithLocale: (id)locale
|
1998-01-19 15:20:15 +00:00
|
|
|
{
|
1998-12-18 17:05:44 +00:00
|
|
|
return [self descriptionWithLocale: locale indent: 0];
|
1998-01-19 15:20:15 +00:00
|
|
|
}
|
|
|
|
|
2002-11-11 11:34:21 +00:00
|
|
|
/**
|
|
|
|
* Returns the receiver as a text property list in the traditional format.<br />
|
|
|
|
* See [NSString-propertyList] for details.<br />
|
|
|
|
* If locale is nil, no formatting is done, otherwise entries are formatted
|
|
|
|
* according to the locale, and indented according to level.<br />
|
|
|
|
* Unless locale is nil, a level of zero indents items by four spaces,
|
|
|
|
* while a level of one indents them by a tab.<br />
|
2005-11-28 15:41:35 +00:00
|
|
|
* If the keys in the dictionary respond to [NSObject-compare:], the items are
|
2002-11-11 11:34:21 +00:00
|
|
|
* listed by key in ascending order. If not, the order in which the
|
|
|
|
* items are listed is undefined.
|
|
|
|
*/
|
2011-02-23 11:52:17 +00:00
|
|
|
- (NSString*) descriptionWithLocale: (id)locale
|
2009-02-23 20:42:32 +00:00
|
|
|
indent: (NSUInteger)level
|
1998-01-19 15:20:15 +00:00
|
|
|
{
|
2002-11-10 09:29:45 +00:00
|
|
|
NSMutableString *result = nil;
|
2000-09-22 18:55:21 +00:00
|
|
|
|
2002-11-27 13:56:00 +00:00
|
|
|
GSPropertyListMake(self, locale, NO, YES, level == 1 ? 3 : 2, &result);
|
2001-09-08 05:11:58 +00:00
|
|
|
return result;
|
1998-12-18 17:05:44 +00:00
|
|
|
}
|
|
|
|
|
2002-02-27 09:25:30 +00:00
|
|
|
/**
|
|
|
|
* Default implementation for this class is to return the value stored in
|
2006-03-24 13:47:41 +00:00
|
|
|
* the dictionary under the specified key, or nil if there is no value.<br />
|
|
|
|
* However, if the key begins with '@' that character is stripped from
|
|
|
|
* it and the superclass implementation of the method is used.
|
2002-02-27 09:25:30 +00:00
|
|
|
*/
|
|
|
|
- (id) valueForKey: (NSString*)key
|
|
|
|
{
|
2012-03-20 20:17:45 +00:00
|
|
|
id o;
|
2002-02-27 17:41:31 +00:00
|
|
|
|
2006-03-24 13:47:41 +00:00
|
|
|
if ([key hasPrefix: @"@"] == YES)
|
2002-02-27 17:41:31 +00:00
|
|
|
{
|
2006-03-24 13:47:41 +00:00
|
|
|
o = [super valueForKey: [key substringFromIndex: 1]];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
o = [self objectForKey: key];
|
2002-02-27 17:41:31 +00:00
|
|
|
}
|
|
|
|
return o;
|
2002-02-27 09:25:30 +00:00
|
|
|
}
|
2012-03-20 20:17:45 +00:00
|
|
|
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
|
2011-07-24 13:09:22 +00:00
|
|
|
objects: (__unsafe_unretained id[])stackbuf
|
2009-12-29 16:21:01 +00:00
|
|
|
count: (NSUInteger)len
|
|
|
|
{
|
2013-04-14 17:50:00 +00:00
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
return 0;
|
2009-12-29 16:21:01 +00:00
|
|
|
}
|
2015-07-15 14:14:21 +00:00
|
|
|
|
2015-07-16 08:44:15 +00:00
|
|
|
- (NSUInteger) sizeInBytesExcluding: (NSHashTable*)exclude
|
2015-07-15 14:14:21 +00:00
|
|
|
{
|
2015-07-16 08:44:15 +00:00
|
|
|
NSUInteger size = [super sizeInBytesExcluding: exclude];
|
2015-07-15 14:14:21 +00:00
|
|
|
|
|
|
|
if (size > 0)
|
|
|
|
{
|
|
|
|
NSUInteger count = [self count];
|
|
|
|
|
|
|
|
size += 3 * sizeof(void*) * count;
|
|
|
|
if (count > 0)
|
|
|
|
{
|
2015-07-16 09:30:57 +00:00
|
|
|
NSEnumerator *enumerator = [self keyEnumerator];
|
2016-02-22 21:04:18 +00:00
|
|
|
NSObject<NSCopying> *k = nil;
|
2015-07-15 14:14:21 +00:00
|
|
|
|
|
|
|
while ((k = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
NSObject *o = [self objectForKey: k];
|
|
|
|
|
2015-07-16 08:44:15 +00:00
|
|
|
size += [k sizeInBytesExcluding: exclude];
|
|
|
|
size += [o sizeInBytesExcluding: exclude];
|
2015-07-15 14:14:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
@end
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Mutable version of [NSDictionary].
|
|
|
|
*/
|
1995-04-03 22:59:20 +00:00
|
|
|
@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])
|
|
|
|
{
|
2008-12-04 18:04:00 +00:00
|
|
|
NSMutableDictionaryClass = self;
|
|
|
|
GSMutableDictionaryClass = [GSMutableDictionary class];
|
1997-10-16 23:56:27 +00:00
|
|
|
}
|
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];
|
|
|
|
NSDictionary *newDictionary;
|
|
|
|
unsigned i;
|
|
|
|
id key;
|
|
|
|
NSEnumerator *enumerator = [self keyEnumerator];
|
|
|
|
IMP nxtImp = [enumerator methodForSelector: nxtSel];
|
|
|
|
IMP objImp = [self methodForSelector: objSel];
|
2004-09-10 15:10:54 +00:00
|
|
|
GS_BEGINIDBUF(o, count*2);
|
1999-04-08 12:17:15 +00:00
|
|
|
|
|
|
|
for (i = 0; (key = (*nxtImp)(enumerator, nxtSel)); i++)
|
|
|
|
{
|
2004-03-16 09:53:01 +00:00
|
|
|
o[i] = key;
|
|
|
|
o[count + i] = (*objImp)(self, objSel, key);
|
|
|
|
o[count + i] = [o[count + i] copyWithZone: z];
|
1999-04-08 12:17:15 +00:00
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
newDictionary = [[GSDictionaryClass allocWithZone: z]
|
2004-03-16 09:53:01 +00:00
|
|
|
initWithObjects: o + count
|
|
|
|
forKeys: o
|
1999-04-08 12:17:15 +00:00
|
|
|
count: count];
|
2004-03-16 09:53:01 +00:00
|
|
|
while (i-- > 0)
|
1999-04-08 12:17:15 +00:00
|
|
|
{
|
2004-03-16 09:53:01 +00:00
|
|
|
[o[count + i] release];
|
1999-04-08 12:17:15 +00:00
|
|
|
}
|
2004-09-10 15:10:54 +00:00
|
|
|
GS_ENDIDBUF();
|
2004-03-16 09:53:01 +00:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2004-09-07 05:43:20 +00:00
|
|
|
/** <init /> <override-subclass />
|
|
|
|
* Initializes an empty dictionary with memory preallocated for given number
|
|
|
|
* of entries. Although memory space will be grown as needed when entries
|
|
|
|
* are added, this can avoid the reallocate-and-copy process if the size of
|
|
|
|
* the ultimate contents is known in advance.<br />
|
|
|
|
* Calls -init (which does nothing but maintain MacOS-X compatibility),
|
|
|
|
* and needs to be re-implemented in subclasses in order to have all
|
|
|
|
* other initialisers work.
|
2004-06-22 22:40:40 +00:00
|
|
|
*/
|
2009-02-23 20:42:32 +00:00
|
|
|
- (id) initWithCapacity: (NSUInteger)numItems
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
2004-09-07 05:43:20 +00:00
|
|
|
self = [self init];
|
|
|
|
return self;
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
/**
|
|
|
|
* Adds entry for aKey, mapping to anObject. If either is nil, an exception
|
|
|
|
* is raised. If aKey already in dictionary, the value it maps to is
|
2007-03-19 10:42:16 +00:00
|
|
|
* silently replaced. The value anObject is retained, but aKey is copied
|
|
|
|
* (because a dictionary key must be immutable) and must therefore implement
|
|
|
|
* the [(NSCopying)] protocol.)
|
2004-06-22 22:40:40 +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
|
|
|
}
|
|
|
|
|
2012-04-06 12:23:10 +00:00
|
|
|
- (void) setObject: (id)anObject forKeyedSubscript: (id)aKey
|
|
|
|
{
|
|
|
|
[self setObject: anObject forKey: aKey];
|
|
|
|
}
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
/**
|
|
|
|
* Remove key-value mapping for given key aKey. No error if there is no
|
|
|
|
* mapping for the key. A warning will be generated if aKey is nil.
|
|
|
|
*/
|
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
|
|
|
}
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
/**
|
|
|
|
* Returns an empty dictionary with memory preallocated for given number of
|
|
|
|
* entries. Although memory space will be grown as needed when entries are
|
|
|
|
* added, this can avoid the reallocate-and-copy process if the size of the
|
|
|
|
* ultimate contents is known in advance.
|
|
|
|
*/
|
2009-02-23 20:42:32 +00:00
|
|
|
+ (id) dictionaryWithCapacity: (NSUInteger)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 */
|
2004-06-22 22:40:40 +00:00
|
|
|
/**
|
|
|
|
* Initializes contents to the given objects and keys.
|
|
|
|
* The two arrays must have the same size.
|
|
|
|
* The n th element of the objects array is associated with the n th
|
|
|
|
* element of the keys array.
|
|
|
|
*/
|
2011-07-24 13:09:22 +00:00
|
|
|
- (id) initWithObjects: (const id[])objects
|
2013-12-05 13:16:36 +00:00
|
|
|
forKeys: (const id <NSCopying>[])keys
|
2009-02-23 20:42:32 +00:00
|
|
|
count: (NSUInteger)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
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
/**
|
|
|
|
* Clears out this dictionary by removing all entries.
|
|
|
|
*/
|
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
|
|
|
}
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
/**
|
|
|
|
* Remove entries specified by the given keyArray. No error is generated if
|
|
|
|
* no mapping exists for a key or one is nil, although a console warning is
|
|
|
|
* produced in the latter case.
|
|
|
|
*/
|
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
|
|
|
{
|
|
|
|
IMP remObj = [self methodForSelector: remSel];
|
2004-09-10 15:10:54 +00:00
|
|
|
GS_BEGINIDBUF(keys, c);
|
1999-09-12 19:03:09 +00:00
|
|
|
|
2008-07-06 09:18:30 +00:00
|
|
|
if ([keyArray isProxy])
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
for (i = 0; i < c; i++)
|
|
|
|
{
|
|
|
|
keys[i] = [keyArray objectAtIndex: i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[keyArray getObjects: keys];
|
|
|
|
}
|
1999-09-12 19:03:09 +00:00
|
|
|
while (c--)
|
|
|
|
{
|
|
|
|
(*remObj)(self, remSel, keys[c]);
|
|
|
|
}
|
2004-09-10 15:10:54 +00:00
|
|
|
GS_ENDIDBUF();
|
1999-09-12 19:03:09 +00:00
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
2002-02-03 17:21:20 +00:00
|
|
|
/**
|
|
|
|
* Merges information from otherDictionary into the receiver.
|
|
|
|
* If a key exists in both dictionaries, the value from otherDictionary
|
2005-11-06 13:53:40 +00:00
|
|
|
* replaces that which was originally in the receiver.
|
2002-02-03 17:21:20 +00:00
|
|
|
*/
|
|
|
|
- (void) addEntriesFromDictionary: (NSDictionary*)otherDictionary
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
2002-02-03 17:21:20 +00:00
|
|
|
if (otherDictionary != nil && otherDictionary != self)
|
2000-03-28 14:29:37 +00:00
|
|
|
{
|
|
|
|
id k;
|
2002-02-03 17:21:20 +00:00
|
|
|
NSEnumerator *e = [otherDictionary keyEnumerator];
|
2000-03-28 14:29:37 +00:00
|
|
|
IMP nxtObj = [e methodForSelector: nxtSel];
|
2002-02-03 17:21:20 +00:00
|
|
|
IMP getObj = [otherDictionary 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
|
|
|
{
|
2002-02-03 17:21:20 +00:00
|
|
|
(*setObj)(self, setSel, (*getObj)(otherDictionary, objSel, k), k);
|
2001-01-09 08:40:09 +00:00
|
|
|
}
|
2000-03-28 14:29:37 +00:00
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
/**
|
|
|
|
* Remove all entries, then add all entries from otherDictionary.
|
|
|
|
*/
|
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
|
|
|
|
2002-02-27 09:25:30 +00:00
|
|
|
/**
|
|
|
|
* Default implementation for this class is equivalent to the
|
|
|
|
* -setObject:forKey: method unless value is nil, in which case
|
|
|
|
* it is equivalent to -removeObjectForKey:
|
|
|
|
*/
|
|
|
|
- (void) takeStoredValue: (id)value forKey: (NSString*)key
|
|
|
|
{
|
|
|
|
if (value == nil)
|
|
|
|
{
|
|
|
|
[self removeObjectForKey: key];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[self setObject: value forKey: key];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Default implementation for this class is equivalent to the
|
|
|
|
* -setObject:forKey: method unless value is nil, in which case
|
|
|
|
* it is equivalent to -removeObjectForKey:
|
|
|
|
*/
|
|
|
|
- (void) takeValue: (id)value forKey: (NSString*)key
|
|
|
|
{
|
|
|
|
if (value == nil)
|
|
|
|
{
|
|
|
|
[self removeObjectForKey: key];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[self setObject: value forKey: key];
|
|
|
|
}
|
|
|
|
}
|
2004-02-24 19:43:34 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Default implementation for this class is equivalent to the
|
|
|
|
* -setObject:forKey: method unless value is nil, in which case
|
|
|
|
* it is equivalent to -removeObjectForKey:
|
|
|
|
*/
|
|
|
|
- (void) setValue: (id)value forKey: (NSString*)key
|
|
|
|
{
|
|
|
|
if (value == nil)
|
|
|
|
{
|
|
|
|
[self removeObjectForKey: key];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[self setObject: value forKey: key];
|
|
|
|
}
|
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
@end
|