/* NSSet - Set object to store key/value pairs Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc. Written by: Andrew Kachites McCallum Created: Sep 1995 This file is part of the GNUstep Base 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; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #include #include #include #include #include #include #include #include @interface NSSetNonCore : NSSet @end @interface NSMutableSetNonCore: NSMutableSet @end @implementation NSSet static Class NSSet_abstract_class; static Class NSMutableSet_abstract_class; static Class NSSet_concrete_class; static Class NSMutableSet_concrete_class; + (void) initialize { if (self == [NSSet class]) { NSSet_abstract_class = [NSSet class]; NSMutableSet_abstract_class = [NSMutableSet class]; NSSet_concrete_class = [NSGSet class]; NSMutableSet_concrete_class = [NSGMutableSet class]; behavior_class_add_class(self, [NSSetNonCore class]); } } + (void) _setConcreteClass: (Class)c { NSSet_concrete_class = c; } + (void) _setMutableConcreteClass: (Class)c { NSMutableSet_concrete_class = c; } + (Class) _concreteClass { return NSSet_concrete_class; } + (Class) _mutableConcreteClass { return NSMutableSet_concrete_class; } + (id) set { return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()] init]); } + (id) setWithObjects: (id*)objects count: (unsigned)count { return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()] initWithObjects: objects count: count]); } + (id) setWithArray: (NSArray*)objects { return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()] initWithArray: objects]); } + (id) setWithObject: anObject { return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()] initWithObjects: &anObject count: 1]); } + (id) setWithObjects: firstObject, ... { id set; va_list ap; va_start(ap, firstObject); set = [[self allocWithZone: NSDefaultMallocZone()] initWithObjects: firstObject rest: ap]; va_end(ap); return AUTORELEASE(set); } + (id) setWithSet: (NSSet*)aSet { return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()] initWithSet: aSet]); } + (id) allocWithZone: (NSZone*)z { if (self == NSSet_abstract_class) return NSAllocateObject(NSSet_concrete_class, 0, z); return [super allocWithZone: z]; } /* This is the designated initializer */ - (id) initWithObjects: (id*)objects count: (unsigned)count { [self subclassResponsibility: _cmd]; return 0; } - (id) initWithCoder: (NSCoder*)aCoder { [self subclassResponsibility: _cmd]; return nil; } - (void) encodeWithCoder: (NSCoder*)aCoder { [self subclassResponsibility: _cmd]; } - (unsigned) count { [self subclassResponsibility: _cmd]; return 0; } - (id) member: anObject { return [self subclassResponsibility: _cmd]; return 0; } - (NSEnumerator*) objectEnumerator { return [self subclassResponsibility: _cmd]; } - (id) copyWithZone: (NSZone*)z { return RETAIN(self); } - (id) mutableCopyWithZone: (NSZone*)z { return [[[[self class] _mutableConcreteClass] allocWithZone: z] initWithSet: self]; } @end @implementation NSSetNonCore /* Same as NSArray */ - (id) initWithObjects: firstObject rest: (va_list)ap { register unsigned i; register unsigned curSize; auto unsigned prevSize; auto unsigned newSize; auto id *objsArray; auto id tmpId; /* Do initial allocation. */ prevSize = 3; curSize = 5; objsArray = (id*)NSZoneMalloc(NSDefaultMallocZone(), sizeof(id) * curSize); tmpId = firstObject; /* Loop through adding objects to array until a nil is * found. */ for (i = 0; tmpId != nil; i++) { /* Put id into array. */ objsArray[i] = tmpId; /* If the index equals the current size, increase size. */ if (i == curSize - 1) { /* Fibonacci series. Supposedly, for this application, * the fibonacci series will be more memory efficient. */ newSize = prevSize + curSize; prevSize = curSize; curSize = newSize; /* Reallocate object array. */ objsArray = (id*)NSZoneRealloc(NSDefaultMallocZone(), objsArray, sizeof(id) * curSize); } tmpId = va_arg(ap, id); } va_end( ap ); /* Put object ids into NSSet. */ self = [self initWithObjects: objsArray count: i]; NSZoneFree(NSDefaultMallocZone(), objsArray); return( self ); } /* Same as NSArray */ - (id) initWithObjects: firstObject, ... { va_list ap; va_start(ap, firstObject); self = [self initWithObjects: firstObject rest: ap]; va_end(ap); return self; } /* Override superclass's designated initializer */ - (id) init { return [self initWithObjects: NULL count: 0]; } - (id) initWithArray: (NSArray*)other { unsigned count = [other count]; if (count == 0) { return [self init]; } else { id objs[count]; [other getObjects: objs]; return [self initWithObjects: objs count: count]; } } - (id) initWithSet: (NSSet*)other copyItems: (BOOL)flag { unsigned c = [other count]; id os[c], o, e = [other objectEnumerator]; unsigned i = 0; while ((o = [e nextObject])) { if (flag) os[i] = [o copy]; else os[i] = o; i++; } self = [self initWithObjects: os count: c]; #if !GS_WITH_GC if (flag) while (i--) [os[i] release]; #endif return self; } - (id) initWithSet: (NSSet*)other { return [self initWithSet: other copyItems: NO]; } - (NSArray*) allObjects { id e = [self objectEnumerator]; unsigned i, c = [self count]; id k[c]; for (i = 0; i < c; i++) { k[i] = [e nextObject]; } return AUTORELEASE([[NSArray allocWithZone: NSDefaultMallocZone()] initWithObjects: k count: c]); } - (id) anyObject { if ([self count] == 0) return nil; else { id e = [self objectEnumerator]; return [e nextObject]; } } - (BOOL) containsObject: anObject { return (([self member: anObject]) ? YES : NO); } - (unsigned) hash { return [self count]; } - (void) makeObjectsPerform: (SEL)aSelector { id o, e = [self objectEnumerator]; while ((o = [e nextObject])) [o performSelector: aSelector]; } - (void) makeObjectsPerformSelector: (SEL)aSelector { id o, e = [self objectEnumerator]; while ((o = [e nextObject])) [o performSelector: aSelector]; } - (void) makeObjectsPerformSelector: (SEL)aSelector withObject: argument { id o, e = [self objectEnumerator]; while ((o = [e nextObject])) [o performSelector: aSelector withObject: argument]; } - (void) makeObjectsPerform: (SEL)aSelector withObject: argument { id o, e = [self objectEnumerator]; while ((o = [e nextObject])) [o performSelector: aSelector withObject: argument]; } - (BOOL) intersectsSet: (NSSet*) otherSet { id o = nil, e = nil; // -1. If this set is empty, this method should return NO. if ([self count] == 0) return NO; // 0. Loop for all members in otherSet e = [otherSet objectEnumerator]; while ((o = [e nextObject])) // 1. pick a member from otherSet. { if ([self member: o]) // 2. check the member is in this set(self). return YES; } return NO; } - (BOOL) isSubsetOfSet: (NSSet*) otherSet { id o = nil, e = nil; // -1. members of this set(self) <= that of otherSet if ([self count] > [otherSet count]) return NO; // 0. Loop for all members in this set(self). e = [self objectEnumerator]; while ((o = [e nextObject])) { // 1. check the member is in the otherSet. if ([otherSet member: o]) { // 1.1 if true -> continue, try to check the next member. continue ; } else { // 1.2 if false -> return NO; return NO; } } // 2. return YES; all members in this set are also in the otherSet. return YES; } - (BOOL) isEqual: other { if ([other isKindOfClass: [NSSet class]]) return [self isEqualToSet: other]; return NO; } - (BOOL) isEqualToSet: (NSSet*)other { if ([self count] != [other count]) return NO; else { id o, e = [self objectEnumerator]; while ((o = [e nextObject])) if (![other member: o]) return NO; } /* xxx Recheck this. */ return YES; } - (NSString*) description { return [self descriptionWithLocale: nil]; } - (NSString*) descriptionWithLocale: (NSDictionary*)locale { return [[self allObjects] descriptionWithLocale: locale]; } @end @implementation NSMutableSet + (void) initialize { if (self == [NSMutableSet class]) { behavior_class_add_class(self, [NSMutableSetNonCore class]); behavior_class_add_class(self, [NSSetNonCore class]); } } + (id) setWithCapacity: (unsigned)numItems { return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()] initWithCapacity: numItems]); } + (id) allocWithZone: (NSZone*)z { if (self == NSMutableSet_abstract_class) return NSAllocateObject(NSMutableSet_concrete_class, 0, z); return [super allocWithZone: z]; } - (id) copyWithZone: (NSZone*)z { return [[[[self class] _concreteClass] allocWithZone: z] initWithSet: self]; } /* This is the designated initializer */ - (id) initWithCapacity: (unsigned)numItems { return [self subclassResponsibility: _cmd]; } - (void) addObject: anObject { [self subclassResponsibility: _cmd]; } - (void) removeObject: anObject { [self subclassResponsibility: _cmd]; } @end @implementation NSMutableSetNonCore /* Override superclass's designated initializer */ - initWithObjects: (id*)objects count: (unsigned)count { [self initWithCapacity: count]; while (count--) [self addObject: objects[count]]; return self; } - (void) addObjectsFromArray: (NSArray*)array { unsigned i, c = [array count]; for (i = 0; i < c; i++) [self addObject: [array objectAtIndex: i]]; } - (void) unionSet: (NSSet*) other { id keys = [other objectEnumerator]; id key; while ((key = [keys nextObject])) [self addObject: key]; } - (void) intersectSet: (NSSet*) other { id keys = [self objectEnumerator]; id key; while ((key = [keys nextObject])) if ([other containsObject: key] == NO) [self removeObject: key]; } - (void) minusSet: (NSSet*) other { id keys = [other objectEnumerator]; id key; while ((key = [keys nextObject])) [self removeObject: key]; } - (void) removeAllObjects { [self subclassResponsibility: _cmd]; } @end