This is GCDictionary.m in view mode; [Download] [Up]
/*
Copyright (C) 1996
Ovidiu Predescu <ovidiu@bx.logicnet.ro>
Mircea Oancea <mircea@jupiter.elcom.pub.ro>
Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>
This file is part of the FoundationExtensions library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.
If not, write to the Free Software Foundation,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <config.h>
#include <Foundation/NSString.h>
#include <extensions/objc-runtime.h>
#include <extensions/GCDictionary.h>
#include <extensions/NSException.h>
#include <extensions/exceptions/GeneralExceptions.h>
#include <extensions/GCObject.h>
#include <extensions/GarbageCollector.h>
#include "common.h"
/*
* TODO: copyWithZone:
*/
@interface _GCDictionaryKeyEnumerator : NSObject
{
GCDictionary* dict;
NSMapEnumerator enumerator;
}
- initWithDictionary:_dict;
- nextObject;
@end /* _GCDictionaryKeyEnumerator */
@implementation _GCDictionaryKeyEnumerator
- initWithDictionary:_dict
{
dict = [_dict retain];
enumerator = [dict __keyEnumerator];
return self;
}
- (void)dealloc
{
[dict release];
[super dealloc];
}
- nextObject
{
GCObjectCollectable *keyStruct, *valueStruct;
return NSNextMapEnumeratorPair(&enumerator,
(void**)&keyStruct, (void**)&valueStruct) ? keyStruct->object : nil;
}
@end /* _GCDictionaryKeyEnumerator */
@implementation GCDictionary
static unsigned __GCHashObject(NSMapTable *table,
const GCObjectCollectable* objectStruct)
{
return [objectStruct->object hash];
}
static BOOL __GCCompareObjects(
NSMapTable *table,
const GCObjectCollectable* objectStruct1,
const GCObjectCollectable* objectStruct2)
{
return [objectStruct1->object isEqual:objectStruct2->object];
}
static void __GCRetainObjects(NSMapTable *table,
const GCObjectCollectable* objectStruct)
{
[objectStruct->object retain];
}
static void __GCReleaseObjects(NSMapTable *table,
GCObjectCollectable* objectStruct)
{
if([GarbageCollector isGarbageCollecting]) {
if(!objectStruct->isGarbageCollectable)
[objectStruct->object release];
}
else
[objectStruct->object release];
Free(objectStruct);
}
static NSString* __GCDescribeObjects(NSMapTable *table,
const GCObjectCollectable* objectStruct)
{
return [objectStruct->object description];
}
static const NSMapTableKeyCallBacks GCOwnedStructMapKeyCallBacks = {
(unsigned(*)(NSMapTable *, const void *))__GCHashObject,
(BOOL(*)(NSMapTable *, const void *, const void *))__GCCompareObjects,
(void (*)(NSMapTable *, const void *anObject))__GCRetainObjects,
(void (*)(NSMapTable *, void *anObject))__GCReleaseObjects,
(NSString *(*)(NSMapTable *, const void *))__GCDescribeObjects,
(const void *)NULL
};
static const NSMapTableValueCallBacks GCOwnedStructValueCallBacks = {
(void (*)(NSMapTable *, const void *))__GCRetainObjects,
(void (*)(NSMapTable *, void *))__GCReleaseObjects,
(NSString *(*)(NSMapTable *, const void *))__GCDescribeObjects
};
+ (void)initialize
{
static BOOL initialized = NO;
if(!initialized) {
initialized = YES;
class_add_behavior(self, [GCObject class]);
}
}
- (void)_createTableWithSize:(unsigned)size
{
table = NSCreateMapTableWithZone(GCOwnedStructMapKeyCallBacks,
GCOwnedStructValueCallBacks, size, [self zone]);
}
- (id)initWithDictionary:(NSDictionary*)dictionary
{
id keys = [dictionary keyEnumerator];
id key;
[self _createTableWithSize:([dictionary count] * 4) / 3];
while ((key = [keys nextObject])) {
GCObjectCollectable* keyStruct = Malloc(sizeof(GCObjectCollectable));
GCObjectCollectable* valueStruct = Malloc(sizeof(GCObjectCollectable));
id value = [dictionary objectForKey:key];
keyStruct->object = key;
keyStruct->isGarbageCollectable = [key isGarbageCollectable];
valueStruct->object = value;
valueStruct->isGarbageCollectable = [value isGarbageCollectable];
NSMapInsert(table, keyStruct, valueStruct);
}
return self;
}
- (id)initWithObjects:(id*)objects
forKeys:(id*)keys
count:(unsigned int)count
{
[self _createTableWithSize:(count * 4) / 3];
if (!count)
return self;
while(count--) {
GCObjectCollectable* keyStruct;
GCObjectCollectable* valueStruct;
if (!keys[count] || !objects[count])
THROW([[InvalidArgumentException alloc]
initWithReason:@"Nil object to be added in dictionary"]);
keyStruct = Malloc(sizeof(GCObjectCollectable));
valueStruct = Malloc(sizeof(GCObjectCollectable));
keyStruct->object = keys[count];
keyStruct->isGarbageCollectable = [keys[count] isGarbageCollectable];
valueStruct->object = objects[count];
valueStruct->isGarbageCollectable
= [objects[count] isGarbageCollectable];
NSMapInsert(table, keyStruct, valueStruct);
}
return self;
}
- (void)dealloc
{
NSFreeMapTable(table);
[super dealloc];
}
- (NSEnumerator *)keyEnumerator
{
return [[[_GCDictionaryKeyEnumerator alloc]
initWithDictionary:self]
autorelease];
}
- (id)objectForKey:(id)key
{
GCObjectCollectable keyStruct = { key, 0 };
GCObjectCollectable* valueStruct = NSMapGet(table,
(void**)&keyStruct);
return valueStruct ? valueStruct->object : nil;
}
- (unsigned int)count
{
return NSCountMapTable(table);
}
- (id)copy
{
return [self copyWithZone:NSDefaultMallocZone()];
}
- (id)copyWithZone:(NSZone*)zone
{
if (zone == [self zone])
return [self retain];
else return [[isa allocWithZone:zone] initWithDictionary:self];
}
- (id)mutableCopy
{
return [self mutableCopyWithZone:NSDefaultMallocZone()];
}
- (id)mutableCopyWithZone:(NSZone*)zone
{
return [[GCMutableDictionary allocWithZone:zone]
initWithDictionary:self];
}
/* Private */
- (NSMapEnumerator)__keyEnumerator
{
return NSEnumerateMapTable(table);
}
- (void)gcDecrementRefCountOfContainedObjects
{
NSMapEnumerator enumerator = NSEnumerateMapTable(table);
GCObjectCollectable *keyStruct, *valueStruct;
while(NSNextMapEnumeratorPair(&enumerator,
(void**)&keyStruct, (void**)&valueStruct)) {
if(keyStruct->isGarbageCollectable)
[keyStruct->object gcDecrementRefCount];
if(valueStruct->isGarbageCollectable)
[valueStruct->object gcDecrementRefCount];
}
}
- (BOOL)gcIncrementRefCountOfContainedObjects
{
NSMapEnumerator enumerator;
GCObjectCollectable *keyStruct, *valueStruct;
if([(id)self gcAlreadyVisited])
return NO;
[(id)self gcSetVisited:YES];
enumerator = NSEnumerateMapTable(table);
while(NSNextMapEnumeratorPair(&enumerator,
(void**)&keyStruct, (void**)&valueStruct)) {
if(keyStruct->isGarbageCollectable) {
[keyStruct->object gcIncrementRefCount];
[keyStruct->object gcIncrementRefCountOfContainedObjects];
}
if(valueStruct->isGarbageCollectable) {
[valueStruct->object gcIncrementRefCount];
[valueStruct->object gcIncrementRefCountOfContainedObjects];
}
}
return YES;
}
@end /* GCDictionary */
@implementation GCMutableDictionary
+ (void)initialize
{
static BOOL initialized = NO;
if(!initialized) {
initialized = YES;
class_add_behavior(self, [GCDictionary class]);
}
}
- (id)init
{
return [self initWithCapacity:0];
}
- (id)initWithCapacity:(unsigned int)aNumItems
{
[(id)self _createTableWithSize:(aNumItems * 4) / 3];
return self;
}
- (id)copyWithZone:(NSZone*)zone
{
return [[GCDictionary allocWithZone:zone] initWithDictionary:self];
}
- (void)setObject:(id)anObject forKey:(id)aKey
{
GCObjectCollectable *keyStruct = Malloc(sizeof(GCObjectCollectable));
GCObjectCollectable *valueStruct = Malloc(sizeof(GCObjectCollectable));
keyStruct->object = aKey;
keyStruct->isGarbageCollectable = [aKey isGarbageCollectable];
valueStruct->object = anObject;
valueStruct->isGarbageCollectable = [anObject isGarbageCollectable];
NSMapInsert(table, keyStruct, valueStruct);
}
- (void)removeObjectForKey:(id)key
{
GCObjectCollectable keyStruct = { key, 0 };
NSMapRemove(table, (void**)&keyStruct);
}
- (void)removeAllObjects
{
NSResetMapTable(table);
}
@end /* GCMutableDictionary */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.