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