1/** NSSet - Set object to store key/value pairs 2 Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc. 3 4 Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu> 5 Created: Sep 1995 6 7 This file is part of the GNUstep Base Library. 8 9 This library is free software; you can redistribute it and/or 10 modify it under the terms of the GNU Lesser General Public 11 License as published by the Free Software Foundation; either 12 version 2 of the License, or (at your option) any later version. 13 14 This library is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 Lesser General Public License for more details. 18 19 You should have received a copy of the GNU Lesser General Public 20 License along with this library; if not, write to the Free 21 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 Boston, MA 02110 USA. 23 24 <title>NSSet class reference</title> 25 $Date$ $Revision$ 26 */ 27 28#import "common.h" 29#import "Foundation/NSArray.h" 30#import "Foundation/NSAutoreleasePool.h" 31#import "Foundation/NSSet.h" 32#import "Foundation/NSCoder.h" 33#import "Foundation/NSArray.h" 34#import "Foundation/NSEnumerator.h" 35#import "Foundation/NSKeyValueCoding.h" 36#import "Foundation/NSValue.h" 37#import "Foundation/NSException.h" 38// For private method _decodeArrayOfObjectsForKey: 39#import "Foundation/NSKeyedArchiver.h" 40#import "GSPrivate.h" 41#import "GSFastEnumeration.h" 42#import "GSDispatch.h" 43 44@class GSSet; 45@interface GSSet : NSObject // Help the compiler 46@end 47@class GSMutableSet; 48@interface GSMutableSet : NSObject // Help the compiler 49@end 50 51/** 52 * <code>NSSet</code> maintains an unordered collection of unique objects 53 * (according to [NSObject-isEqual:]). When a duplicate object is added 54 * to the set, it replaces its old copy. 55 */ 56@implementation NSSet 57 58static Class NSSet_abstract_class; 59static Class NSMutableSet_abstract_class; 60static Class NSSet_concrete_class; 61static Class NSMutableSet_concrete_class; 62 63+ (id) allocWithZone: (NSZone*)z 64{ 65 if (self == NSSet_abstract_class) 66 { 67 return NSAllocateObject(NSSet_concrete_class, 0, z); 68 } 69 else 70 { 71 return NSAllocateObject(self, 0, z); 72 } 73} 74 75+ (void) initialize 76{ 77 if (self == [NSSet class]) 78 { 79 NSSet_abstract_class = self; 80 NSSet_concrete_class = [GSSet class]; 81 [NSMutableSet class]; 82 } 83} 84 85/** 86 * New autoreleased empty set. 87 */ 88+ (id) set 89{ 90 return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()] init]); 91} 92 93/** 94 * New set containing (unique elements of) objects. 95 */ 96+ (id) setWithArray: (NSArray*)objects 97{ 98 return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()] 99 initWithArray: objects]); 100} 101 102/** 103 * New set containing single object anObject. 104 */ 105+ (id) setWithObject: anObject 106{ 107 return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()] 108 initWithObjects: &anObject count: 1]); 109} 110 111/** 112 * New set containing (unique elements of) objects. 113 */ 114+ (id) setWithObjects: (const id[])objects 115 count: (NSUInteger)count 116{ 117 return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()] 118 initWithObjects: objects count: count]); 119} 120 121/** 122 * New set with objects in given nil-terminated list. 123 */ 124+ (id) setWithObjects: firstObject, ... 125{ 126 id set; 127 128 GS_USEIDLIST(firstObject, 129 set = [[self allocWithZone: NSDefaultMallocZone()] 130 initWithObjects: __objects count: __count]); 131 return AUTORELEASE(set); 132} 133 134/** 135 * Copy constructor. 136 */ 137+ (id) setWithSet: (NSSet*)aSet 138{ 139 return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()] 140 initWithSet: aSet]); 141} 142 143- (Class) classForCoder 144{ 145 return NSSet_abstract_class; 146} 147 148/** 149 * Returns a new copy of the receiver.<br /> 150 * The default abstract implementation of a copy is to use the 151 * -initWithSet:copyItems: method with the flag set to YES.<br /> 152 * Concrete subclasses generally simply retain and return the receiver. 153 */ 154- (id) copyWithZone: (NSZone*)z 155{ 156 NSSet *copy = [NSSet_concrete_class allocWithZone: z]; 157 158 return [copy initWithSet: self copyItems: YES]; 159} 160 161/** 162 * Returns the number of objects stored in the set. 163 */ 164- (NSUInteger) count 165{ 166 [self subclassResponsibility: _cmd]; 167 return 0; 168} 169 170- (void) encodeWithCoder: (NSCoder*)aCoder 171{ 172 if ([aCoder allowsKeyedCoding]) 173 { 174 /* HACK ... MacOS-X seems to code differently if the coder is an 175 * actual instance of NSKeyedArchiver 176 */ 177 if ([aCoder class] == [NSKeyedArchiver class]) 178 { 179 [(NSKeyedArchiver*)aCoder _encodeArrayOfObjects: [self allObjects] 180 forKey: @"NS.objects"]; 181 } 182 else 183 { 184 unsigned i = 0; 185 NSEnumerator *e = [self objectEnumerator]; 186 id o; 187 188 while ((o = [e nextObject]) != nil) 189 { 190 NSString *key; 191 192 key = [NSString stringWithFormat: @"NS.object.%u", i++]; 193 [(NSKeyedArchiver*)aCoder encodeObject: o forKey: key]; 194 } 195 } 196 } 197 else 198 { 199 unsigned count = [self count]; 200 NSEnumerator *e = [self objectEnumerator]; 201 id o; 202 203 [aCoder encodeValueOfObjCType: @encode(unsigned) at: &count]; 204 while ((o = [e nextObject]) != nil) 205 { 206 [aCoder encodeValueOfObjCType: @encode(id) at: &o]; 207 } 208 } 209} 210 211- (id) initWithCoder: (NSCoder*)aCoder 212{ 213 Class c; 214 215 c = object_getClass(self); 216 if (c == NSSet_abstract_class) 217 { 218 DESTROY(self); 219 self = [NSSet_concrete_class allocWithZone: NSDefaultMallocZone()]; 220 return [self initWithCoder: aCoder]; 221 } 222 else if (c == NSMutableSet_abstract_class) 223 { 224 DESTROY(self); 225 self = [NSMutableSet_concrete_class allocWithZone: NSDefaultMallocZone()]; 226 return [self initWithCoder: aCoder]; 227 } 228 229 if ([aCoder allowsKeyedCoding]) 230 { 231 id array; 232 233 array = [(NSKeyedUnarchiver*)aCoder _decodeArrayOfObjectsForKey: 234 @"NS.objects"]; 235 if (array == nil) 236 { 237 unsigned i = 0; 238 NSString *key; 239 id val; 240 241 array = [NSMutableArray arrayWithCapacity: 2]; 242 key = [NSString stringWithFormat: @"NS.object.%u", i]; 243 val = [(NSKeyedUnarchiver*)aCoder decodeObjectForKey: key]; 244 245 while (val != nil) 246 { 247 [array addObject: val]; 248 i++; 249 key = [NSString stringWithFormat: @"NS.object.%u", i]; 250 val = [(NSKeyedUnarchiver*)aCoder decodeObjectForKey: key]; 251 } 252 } 253 self = [self initWithArray: array]; 254 } 255 else 256 { 257 unsigned count; 258 259 [aCoder decodeValueOfObjCType: @encode(unsigned) at: &count]; 260 if (count > 0) 261 { 262 unsigned i; 263 GS_BEGINIDBUF(objs, count); 264 265 for (i = 0; i < count; i++) 266 { 267 [aCoder decodeValueOfObjCType: @encode(id) at: &objs[i]]; 268 } 269 self = [self initWithObjects: objs count: count]; 270 while (count-- > 0) 271 { 272 [objs[count] release]; 273 } 274 GS_ENDIDBUF(); 275 } 276 } 277 return self; 278} 279 280/** 281 * <p>In MacOS-X class clusters do not have designated initialisers, 282 * and there is a general rule that -init is treated as the designated 283 * initialiser of the class cluster, but that other intitialisers 284 * may not work s expected an would need to be individually overridden 285 * in any subclass. 286 * </p> 287 * <p>GNUstep tries to make it easier to subclass a class cluster, 288 * by making class clusters follow the same convention as normal 289 * classes, so the designated initialiser is the <em>richest</em> 290 * initialiser. This means that all other initialisers call the 291 * documented designated initialiser (which calls -init only for 292 * MacOS-X compatibility), and anyone writing a subclass only needs 293 * to override that one initialiser in order to have all the other 294 * ones work. 295 * </p> 296 * <p>For MacOS-X compatibility, you may also need to override various 297 * other initialisers. Exactly which ones, you will need to determine 298 * by trial on a MacOS-X system ... and may vary between releases of 299 * MacOS-X. So to be safe, on MacOS-X you probably need to re-implement 300 * <em>all</em> the class cluster initialisers you might use in conjunction 301 * with your subclass. 302 * </p> 303 */ 304- (id) init 305{ 306 self = [super init]; 307 return self; 308} 309 310/** <init /> <override-subclass /> 311 * Initialize to contain (unique elements of) objects.<br /> 312 * Calls -init (which does nothing but maintain MacOS-X compatibility), 313 * and needs to be re-implemented in subclasses in order to have all 314 * other initialisers work. 315 */ 316- (id) initWithObjects: (const id[])objects 317 count: (NSUInteger)count 318{ 319 self = [self init]; 320 return self; 321} 322 323/** 324 * If anObject is in set, return it (the copy in the set). 325 */ 326- (id) member: (id)anObject 327{ 328 return [self subclassResponsibility: _cmd]; 329 return 0; 330} 331 332/** 333 * Returns a new instance containing the same objects as 334 * the receiver.<br /> 335 * The default implementation does this by calling the 336 * -initWithSet:copyItems: method on a newly created object, 337 * and passing it NO to tell it just to retain the items. 338 */ 339- (id) mutableCopyWithZone: (NSZone*)z 340{ 341 NSMutableSet *copy = [NSMutableSet_concrete_class allocWithZone: z]; 342 343 return [copy initWithSet: self copyItems: NO]; 344} 345 346/** 347 * Return enumerator over objects in set. Order is undefined. 348 */ 349- (NSEnumerator*) objectEnumerator 350{ 351 return [self subclassResponsibility: _cmd]; 352} 353 354/** 355 * Initialize with (unique elements of) objects in given nil-terminated list. 356 */ 357- (id) initWithObjects: firstObject, ... 358{ 359 GS_USEIDLIST(firstObject, 360 self = [self initWithObjects: __objects count: __count]); 361 return self; 362} 363 364/** 365 * Initialises a newly allocated set by adding all the objects 366 * in the supplied array to the set. 367 */ 368- (id) initWithArray: (NSArray*)other 369{ 370 unsigned count = [other count]; 371 372 if (count == 0) 373 { 374 return [self init]; 375 } 376 else 377 { 378 GS_BEGINIDBUF(objs, count); 379 380 if ([other isProxy]) 381 { 382 unsigned i; 383 384 for (i = 0; i < count; i++) 385 { 386 objs[i] = [other objectAtIndex: i]; 387 } 388 } 389 else 390 { 391 [other getObjects: objs]; 392 } 393 self = [self initWithObjects: objs count: count]; 394 GS_ENDIDBUF(); 395 return self; 396 } 397} 398 399/** 400 * Initialises a newly allocated set by adding all the objects 401 * in the supplied set. 402 */ 403- (id) initWithSet: (NSSet*)other copyItems: (BOOL)flag 404{ 405 unsigned c = [other count]; 406 id o, e = [other objectEnumerator]; 407 unsigned i = 0; 408 GS_BEGINIDBUF(os, c); 409 410 while ((o = [e nextObject])) 411 { 412 if (flag) 413 os[i] = [o copy]; 414 else 415 os[i] = o; 416 i++; 417 } 418 self = [self initWithObjects: os count: c]; 419 if (flag) 420 { 421 while (i--) 422 { 423 [os[i] release]; 424 } 425 } 426 GS_ENDIDBUF(); 427 return self; 428} 429 430/** 431 * Initialize with same items as other (items not copied). 432 */ 433- (id) initWithSet: (NSSet*)other 434{ 435 return [self initWithSet: other copyItems: NO]; 436} 437 438/** 439 * Return array of all objects in set. Order is undefined. 440 */ 441- (NSArray*) allObjects 442{ 443 id e = [self objectEnumerator]; 444 unsigned i; 445 unsigned c = [self count]; 446 NSArray *result = nil; 447 GS_BEGINIDBUF(k, c); 448 449 for (i = 0; i < c; i++) 450 { 451 k[i] = [e nextObject]; 452 } 453 return AUTORELEASE([[NSArray allocWithZone: NSDefaultMallocZone()] 454 initWithObjects: k count: c]); 455 GS_ENDIDBUF(); 456 return result; 457} 458 459/** 460 * Return an arbitrary object from set, or nil if this is empty set. 461 */ 462- (id) anyObject 463{ 464 if ([self count] == 0) 465 return nil; 466 else 467 { 468 id e = [self objectEnumerator]; 469 return [e nextObject]; 470 } 471} 472 473/** 474 * Return whether set contains an object equal to this one according 475 * to [NSObject-isEqual:]. 476 */ 477- (BOOL) containsObject: (id)anObject 478{ 479 return (([self member: anObject]) ? YES : NO); 480} 481 482- (NSUInteger) hash 483{ 484 return [self count]; 485} 486 487/** 488 * Send each object given message (with no arguments). 489 * Identical to [-makeObjectsPerformSelector:]. 490 */ 491- (void) makeObjectsPerform: (SEL)aSelector 492{ 493 id o, e = [self objectEnumerator]; 494 495 while ((o = [e nextObject])) 496 [o performSelector: aSelector]; 497} 498 499/** 500 * Send each object given message (with no arguments). 501 * Identical to [-makeObjectsPerform:]. 502 */ 503- (void) makeObjectsPerformSelector: (SEL)aSelector 504{ 505 id o, e = [self objectEnumerator]; 506 507 while ((o = [e nextObject])) 508 [o performSelector: aSelector]; 509} 510 511/** 512 * Send each object given message with given argument. 513 * Identical to [-makeObjectsPerform:withObject:]. 514 */ 515- (void) makeObjectsPerformSelector: (SEL)aSelector withObject: argument 516{ 517 id o, e = [self objectEnumerator]; 518 519 while ((o = [e nextObject])) 520 [o performSelector: aSelector withObject: argument]; 521} 522 523/** 524 * Send each object given message with given argument. 525 * Identical to [-makeObjectsPerformSelector:withObject:]. 526 */ 527- (void) makeObjectsPerform: (SEL)aSelector withObject: argument 528{ 529 id o, e = [self objectEnumerator]; 530 531 while ((o = [e nextObject])) 532 [o performSelector: aSelector withObject: argument]; 533} 534 535/** 536 * Return whether set intersection with otherSet is non-empty. 537 */ 538- (BOOL) intersectsSet: (NSSet*) otherSet 539{ 540 id o = nil, e = nil; 541 542 // -1. If this set is empty, this method should return NO. 543 if ([self count] == 0) 544 return NO; 545 546 // 0. Loop for all members in otherSet 547 e = [otherSet objectEnumerator]; 548 while ((o = [e nextObject])) // 1. pick a member from otherSet. 549 { 550 if ([self member: o]) // 2. check the member is in this set(self). 551 return YES; 552 } 553 return NO; 554} 555 556/** 557 * Return whether subset of otherSet. 558 */ 559- (BOOL) isSubsetOfSet: (NSSet*) otherSet 560{ 561 id o = nil, e = nil; 562 563 // -1. members of this set(self) <= that of otherSet 564 if ([self count] > [otherSet count]) 565 return NO; 566 567 // 0. Loop for all members in this set(self). 568 e = [self objectEnumerator]; 569 while ((o = [e nextObject])) 570 { 571 // 1. check the member is in the otherSet. 572 if ([otherSet member: o]) 573 { 574 // 1.1 if true -> continue, try to check the next member. 575 continue ; 576 } 577 else 578 { 579 // 1.2 if false -> return NO; 580 return NO; 581 } 582 } 583 // 2. return YES; all members in this set are also in the otherSet. 584 return YES; 585} 586 587- (BOOL) isEqual: (id)other 588{ 589 if ([other isKindOfClass: [NSSet class]]) 590 return [self isEqualToSet: other]; 591 return NO; 592} 593 594- (NSUInteger)_countForObject: (id)object 595{ 596 return 1; 597} 598 599/** 600 * Return whether each set is subset of the other. 601 */ 602- (BOOL) isEqualToSet: (NSSet*)other 603{ 604 if ([self count] != [other count]) 605 return NO; 606 else 607 { 608 id o, e = [self objectEnumerator]; 609 610 while ((o = [e nextObject])) 611 { 612 if (![other member: o]) 613 { 614 return NO; 615 } 616 else 617 { 618 if ([self _countForObject: o] != [other _countForObject: o]) 619 { 620 return NO; 621 } 622 } 623 } 624 } 625 /* xxx Recheck this. */ 626 return YES; 627} 628 629/** 630 * Returns listing of objects in set. 631 */ 632- (NSString*) description 633{ 634 return [self descriptionWithLocale: nil]; 635} 636 637/** 638 * Returns listing of objects in set. 639 */ 640- (NSString*) descriptionWithLocale: (id)locale 641{ 642 return [[self allObjects] descriptionWithLocale: locale]; 643} 644 645- (id) valueForKey: (NSString*)key 646{ 647 NSEnumerator *e = [self objectEnumerator]; 648 id object = nil; 649 NSMutableSet *results = [NSMutableSet setWithCapacity: [self count]]; 650 651 while ((object = [e nextObject]) != nil) 652 { 653 id result = [object valueForKey: key]; 654 655 if (result == nil) 656 continue; 657 658 [results addObject: result]; 659 } 660 return results; 661} 662 663- (id) valueForKeyPath: (NSString*)path 664{ 665 id result = (id) nil; 666 667 if ([path hasPrefix: @"@"]) 668 { 669 NSRange r; 670 671 r = [path rangeOfString: @"."]; 672 if (r.length == 0) 673 { 674 if ([path isEqualToString: @"@count"] == YES) 675 { 676 result = [NSNumber numberWithUnsignedInteger: [self count]]; 677 } 678 else 679 { 680 result = [self valueForKey: path]; 681 } 682 } 683 else 684 { 685 NSString *op = [path substringToIndex: r.location]; 686 NSString *rem = [path substringFromIndex: NSMaxRange(r)]; 687 unsigned count = [self count]; 688 689 if ([op isEqualToString: @"@count"] == YES) 690 { 691 result = [NSNumber numberWithUnsignedInteger: count]; 692 } 693 else if ([op isEqualToString: @"@avg"] == YES) 694 { 695 double d = 0; 696 697 if (count > 0) 698 { 699 NSEnumerator *e = [self objectEnumerator]; 700 id o; 701 702 while ((o = [e nextObject]) != nil) 703 { 704 d += [[o valueForKeyPath: rem] doubleValue]; 705 } 706 d /= count; 707 } 708 result = [NSNumber numberWithDouble: d]; 709 } 710 else if ([op isEqualToString: @"@max"] == YES) 711 { 712 if (count > 0) 713 { 714 NSEnumerator *e = [self objectEnumerator]; 715 id o; 716 717 while ((o = [e nextObject]) != nil) 718 { 719 o = [o valueForKeyPath: rem]; 720 if (result == nil 721 || [result compare: o] == NSOrderedAscending) 722 { 723 result = o; 724 } 725 } 726 } 727 } 728 else if ([op isEqualToString: @"@min"] == YES) 729 { 730 if (count > 0) 731 { 732 NSEnumerator *e = [self objectEnumerator]; 733 id o; 734 735 while ((o = [e nextObject]) != nil) 736 { 737 o = [o valueForKeyPath: rem]; 738 if (result == nil 739 || [result compare: o] == NSOrderedDescending) 740 { 741 result = o; 742 } 743 } 744 } 745 } 746 else if ([op isEqualToString: @"@sum"] == YES) 747 { 748 double d = 0; 749 750 if (count > 0) 751 { 752 NSEnumerator *e = [self objectEnumerator]; 753 id o; 754 755 while ((o = [e nextObject]) != nil) 756 { 757 d += [[o valueForKeyPath: rem] doubleValue]; 758 } 759 } 760 result = [NSNumber numberWithDouble: d]; 761 } 762 else if ([op isEqualToString: @"@distinctUnionOfArrays"] == YES) 763 { 764 if (count > 0) 765 { 766 NSEnumerator *e = [self objectEnumerator]; 767 id o; 768 769 result = [NSMutableSet set]; 770 while ((o = [e nextObject]) != nil) 771 { 772 o = [o valueForKeyPath: rem]; 773 [result addObjectsFromArray: o]; 774 } 775 result = [result allObjects]; 776 } 777 else 778 { 779 result = [NSArray array]; 780 } 781 } 782 else if ([op isEqualToString: @"@distinctUnionOfObjects"] == YES) 783 { 784 if (count > 0) 785 { 786 NSEnumerator *e = [self objectEnumerator]; 787 id o; 788 789 result = [NSMutableSet set]; 790 while ((o = [e nextObject]) != nil) 791 { 792 o = [o valueForKeyPath: rem]; 793 [result addObject: o]; 794 } 795 result = [result allObjects]; 796 } 797 else 798 { 799 result = [NSArray array]; 800 } 801 } 802 else if ([op isEqualToString: @"@distinctUnionOfSets"] == YES) 803 { 804 if (count > 0) 805 { 806 NSEnumerator *e = [self objectEnumerator]; 807 id o; 808 809 result = [NSMutableSet set]; 810 while ((o = [e nextObject]) != nil) 811 { 812 o = [o valueForKeyPath: rem]; 813 [result addObjectsFromArray: [o allObjects]]; 814 } 815 result = [result allObjects]; 816 } 817 else 818 { 819 result = [NSArray array]; 820 } 821 } 822 else if ([op isEqualToString: @"@unionOfArrays"] == YES) 823 { 824 if (count > 0) 825 { 826 NSEnumerator *e = [self objectEnumerator]; 827 id o; 828 829 result = [GSMutableArray array]; 830 while ((o = [e nextObject]) != nil) 831 { 832 o = [o valueForKeyPath: rem]; 833 [result addObjectsFromArray: o]; 834 } 835 result = GS_IMMUTABLE(result); 836 } 837 else 838 { 839 result = [NSArray array]; 840 } 841 } 842 else if ([op isEqualToString: @"@unionOfObjects"] == YES) 843 { 844 if (count > 0) 845 { 846 NSEnumerator *e = [self objectEnumerator]; 847 id o; 848 849 result = [GSMutableArray array]; 850 while ((o = [e nextObject]) != nil) 851 { 852 o = [o valueForKeyPath: rem]; 853 [result addObject: o]; 854 } 855 result = GS_IMMUTABLE(result); 856 } 857 else 858 { 859 result = [NSArray array]; 860 } 861 } 862 else if ([op isEqualToString: @"@unionOfSets"] == YES) 863 { 864 if (count > 0) 865 { 866 NSEnumerator *e = [self objectEnumerator]; 867 id o; 868 869 result = [GSMutableArray array]; 870 while ((o = [e nextObject]) != nil) 871 { 872 o = [o valueForKeyPath: rem]; 873 [result addObjectsFromArray: [o allObjects]]; 874 } 875 result = GS_IMMUTABLE(result); 876 } 877 else 878 { 879 result = [NSArray array]; 880 } 881 } 882 else 883 { 884 result = [super valueForKeyPath: path]; 885 } 886 } 887 } 888 else 889 { 890 result = [super valueForKeyPath: path]; 891 } 892 893 return result; 894} 895 896- (void) enumerateObjectsUsingBlock: (GSSetEnumeratorBlock)aBlock 897{ 898 [self enumerateObjectsWithOptions: 0 usingBlock: aBlock]; 899} 900 901- (void) enumerateObjectsWithOptions: (NSEnumerationOptions)opts 902 usingBlock: (GSSetEnumeratorBlock)aBlock 903{ 904 BLOCK_SCOPE BOOL shouldStop = NO; 905 id<NSFastEnumeration> enumerator = self; 906 907 GS_DISPATCH_CREATE_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts) 908 FOR_IN (id, obj, enumerator) 909 { 910 GS_DISPATCH_SUBMIT_BLOCK(enumQueueGroup,enumQueue, if (shouldStop == NO) {, }, aBlock, obj, &shouldStop); 911 if (shouldStop) 912 { 913 break; 914 } 915 } 916 END_FOR_IN(enumerator) 917 GS_DISPATCH_TEARDOWN_QUEUE_AND_GROUP_FOR_ENUMERATION(enumQueue, opts) 918} 919 920- (NSSet *) objectsPassingTest: (GSSetFilterBlock)aBlock 921{ 922 return [self objectsWithOptions: 0 passingTest: aBlock]; 923} 924 925- (NSSet *) objectsWithOptions: (NSEnumerationOptions)opts 926 passingTest: (GSSetFilterBlock)aBlock 927{ 928 BOOL shouldStop = NO; 929 id<NSFastEnumeration> enumerator = self; 930 NSMutableSet *resultSet; 931 932 resultSet = [NSMutableSet setWithCapacity: [self count]]; 933 934 FOR_IN (id, obj, enumerator) 935 { 936 BOOL include = CALL_BLOCK(aBlock, obj, &shouldStop); 937 938 if (include) 939 { 940 [resultSet addObject:obj]; 941 } 942 if (shouldStop) 943 { 944 break; 945 } 946 } 947 END_FOR_IN(enumerator) 948 949 return GS_IMMUTABLE(resultSet); 950} 951 952/** Return a set formed by adding anObject to the receiver. 953 */ 954- (NSSet *) setByAddingObject: (id)anObject 955{ 956 NSMutableSet *m; 957 NSSet *s; 958 959 m = [self mutableCopy]; 960 [m addObject: anObject]; 961 s = [m copy]; 962 [m release]; 963 return [s autorelease]; 964} 965 966/** Return a set formed by adding the contents of other to the receiver. 967 */ 968- (NSSet *) setByAddingObjectsFromArray: (NSArray *)other 969{ 970 NSMutableSet *m; 971 NSSet *s; 972 973 m = [self mutableCopy]; 974 [m addObjectsFromArray: other]; 975 s = [m copy]; 976 [m release]; 977 return [s autorelease]; 978} 979 980/** Return a set formed as a union of the receiver and other. 981 */ 982- (NSSet *) setByAddingObjectsFromSet: (NSSet *)other 983{ 984 NSMutableSet *m; 985 NSSet *s; 986 987 m = [self mutableCopy]; 988 [m unionSet: other]; 989 s = [m copy]; 990 [m release]; 991 return [s autorelease]; 992} 993 994- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state 995 objects: (id*)stackbuf 996 count: (NSUInteger)len 997{ 998 [self subclassResponsibility: _cmd]; 999 return 0; 1000} 1001 1002@end 1003 1004 1005/** 1006 * Mutable version of [NSSet]. 1007 */ 1008@implementation NSMutableSet 1009 1010+ (void) initialize 1011{ 1012 if (self == [NSMutableSet class]) 1013 { 1014 NSMutableSet_abstract_class = self; 1015 NSMutableSet_concrete_class = [GSMutableSet class]; 1016 } 1017} 1018 1019/** 1020 * New autoreleased instance with given capacity. 1021 */ 1022+ (id) setWithCapacity: (NSUInteger)numItems 1023{ 1024 return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()] 1025 initWithCapacity: numItems]); 1026} 1027 1028+ (id) allocWithZone: (NSZone*)z 1029{ 1030 if (self == NSMutableSet_abstract_class) 1031 { 1032 return NSAllocateObject(NSMutableSet_concrete_class, 0, z); 1033 } 1034 else 1035 { 1036 return NSAllocateObject(self, 0, z); 1037 } 1038} 1039 1040- (Class) classForCoder 1041{ 1042 return NSMutableSet_abstract_class; 1043} 1044 1045/** <init /> <override-subclass /> 1046 * Initialises a newly allocated set to contain no objects but 1047 * to have space available to hold the specified number of items.<br /> 1048 * Additions of items to a set initialised 1049 * with an appropriate capacity will be more efficient than addition 1050 * of items otherwise.<br /> 1051 * Calls -init (which does nothing but maintain MacOS-X compatibility), 1052 * and needs to be re-implemented in subclasses in order to have all 1053 * other initialisers work. 1054 */ 1055- (id) initWithCapacity: (NSUInteger)numItems 1056{ 1057 self = [self init]; 1058 return self; 1059} 1060 1061/** 1062 * Adds anObject to the set.<br /> 1063 * The object is retained by the set. 1064 */ 1065- (void) addObject: (id)anObject 1066{ 1067 [self subclassResponsibility: _cmd]; 1068} 1069 1070/** 1071 * Removes the anObject from the receiver. 1072 */ 1073- (void) removeObject: (id)anObject 1074{ 1075 [self subclassResponsibility: _cmd]; 1076} 1077 1078- (id) initWithObjects: (const id[])objects 1079 count: (NSUInteger)count 1080{ 1081 self = [self initWithCapacity: count]; 1082 if (self != nil) 1083 { 1084 while (count--) 1085 { 1086 [self addObject: objects[count]]; 1087 } 1088 } 1089 return self; 1090} 1091 1092/** 1093 * Adds all the objects in the array to the receiver. 1094 */ 1095- (void) addObjectsFromArray: (NSArray*)array 1096{ 1097 unsigned i, c = [array count]; 1098 1099 for (i = 0; i < c; i++) 1100 { 1101 [self addObject: [array objectAtIndex: i]]; 1102 } 1103} 1104 1105/** 1106 * Removes from the receiver all the objects it contains 1107 * which are not also in other. 1108 */ 1109- (void) intersectSet: (NSSet*) other 1110{ 1111 if (other != self) 1112 { 1113 id keys = [self objectEnumerator]; 1114 id key; 1115 1116 while ((key = [keys nextObject])) 1117 { 1118 if ([other containsObject: key] == NO) 1119 { 1120 [self removeObject: key]; 1121 } 1122 } 1123 } 1124} 1125 1126/** 1127 * Removes from the receiver all the objects that are in 1128 * other. 1129 */ 1130- (void) minusSet: (NSSet*) other 1131{ 1132 if (other == self) 1133 { 1134 [self removeAllObjects]; 1135 } 1136 else 1137 { 1138 id keys = [other objectEnumerator]; 1139 id key; 1140 1141 while ((key = [keys nextObject])) 1142 { 1143 [self removeObject: key]; 1144 } 1145 } 1146} 1147 1148/** 1149 * Removes all objects from the receiver. 1150 */ 1151- (void) removeAllObjects 1152{ 1153 [self subclassResponsibility: _cmd]; 1154} 1155 1156/** 1157 * Removes all objects from the receiver then adds the 1158 * objects from other. If the receiver <em>is</em> 1159 * other, the method has no effect. 1160 */ 1161- (void) setSet: (NSSet*)other 1162{ 1163 if (other == self) 1164 { 1165 return; 1166 } 1167 if (other == nil) 1168 { 1169 NSWarnMLog(@"Setting mutable set to nil"); 1170 [self removeAllObjects]; 1171 } 1172 else 1173 { 1174 IF_NO_GC([other retain];) // In case it's held by us 1175 [self removeAllObjects]; 1176 [self unionSet: other]; 1177 RELEASE(other); 1178 } 1179} 1180 1181/** 1182 1183 * Adds all the objects from other to the receiver. 1184 */ 1185- (void) unionSet: (NSSet*) other 1186{ 1187 if (other != self) 1188 { 1189 id keys = [other objectEnumerator]; 1190 id key; 1191 1192 while ((key = [keys nextObject])) 1193 { 1194 [self addObject: key]; 1195 } 1196 } 1197} 1198 1199@end 1200