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.