Line data Source code
1 0 : /* 2 : 3 : OOWeakSet.m 4 : 5 : Written by Jens Ayton in 2012 for Oolite. 6 : This code is hereby placed in the public domain. 7 : 8 : */ 9 : 10 : #import "OOWeakSet.h" 11 : 12 : 13 : 14 0 : @interface OOWeakRefUnpackingEnumerator: NSEnumerator 15 : { 16 : @private 17 0 : NSEnumerator *_enumerator; 18 : } 19 : 20 0 : - (id) initWithEnumerator:(NSEnumerator *)enumerator; 21 : 22 0 : + (instancetype) enumeratorWithCollection:(id)collection; // Collection must implement -objectEnumerator 23 : 24 : @end 25 : 26 : 27 : @interface OOWeakSet (OOPrivate) 28 : 29 0 : - (void) compact; // Remove any zeroed entries. 30 : 31 : @end 32 : 33 : 34 : @implementation OOWeakSet 35 : 36 : - (id) init 37 : { 38 : return [self initWithCapacity:0]; 39 : } 40 : 41 : 42 : - (id) initWithCapacity:(NSUInteger)capacity 43 : { 44 : if ((self = [super init])) 45 : { 46 : _objects = [[NSMutableSet alloc] initWithCapacity:capacity]; 47 : if (_objects == NULL) 48 : { 49 : [self release]; 50 : return nil; 51 : } 52 : } 53 : return self; 54 : } 55 : 56 : 57 : + (instancetype) set 58 : { 59 : return [[[self alloc] init] autorelease]; 60 : } 61 : 62 : 63 : + (instancetype) setWithCapacity:(NSUInteger)capacity 64 : { 65 : return [[[self alloc] initWithCapacity:capacity] autorelease]; 66 : } 67 : 68 : 69 0 : - (void) dealloc 70 : { 71 : DESTROY(_objects); 72 : 73 : [super dealloc]; 74 : } 75 : 76 : 77 0 : - (NSString *) description 78 : { 79 : NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p>{", [self class], self]; 80 : NSEnumerator *selfEnum = [self objectEnumerator]; 81 : id object = nil; 82 : BOOL first = YES; 83 : while ((object = [selfEnum nextObject])) 84 : { 85 : if (!first) [result appendString:@", "]; 86 : else first = NO; 87 : 88 : NSString *desc = nil; 89 : if ([object respondsToSelector:@selector(shortDescription)]) desc = [object shortDescription]; 90 : else desc = [object description]; 91 : 92 : [result appendString:desc]; 93 : } 94 : 95 : [result appendString:@"}"]; 96 : return result; 97 : } 98 : 99 : 100 : // MARK: Protocol conformance 101 : 102 0 : - (id) copyWithZone:(NSZone *)zone 103 : { 104 : [self compact]; 105 : OOWeakSet *result = [[OOWeakSet allocWithZone:zone] init]; 106 : [result addObjectsByEnumerating:[self objectEnumerator]]; 107 : return result; 108 : } 109 : 110 : 111 0 : - (id) mutableCopyWithZone:(NSZone *)zone 112 : { 113 : return [self copyWithZone:zone]; 114 : } 115 : 116 : 117 0 : - (BOOL) isEqual:(id)other 118 : { 119 : if (![other isKindOfClass:[OOWeakSet class]]) return NO; 120 : if ([self count] != [other count]) return NO; 121 : 122 : BOOL result = YES; 123 : NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 124 : NSEnumerator *selfEnum = [self objectEnumerator]; 125 : id object = nil; 126 : while ((object = [selfEnum nextObject])) 127 : { 128 : if (![other containsObject:object]) 129 : { 130 : result = NO; 131 : break; 132 : } 133 : } 134 : DESTROY(pool); 135 : 136 : return result; 137 : } 138 : 139 : 140 : // MARK: Meat and potatoes 141 : 142 : - (NSUInteger) count 143 : { 144 : [self compact]; 145 : return [_objects count]; 146 : } 147 : 148 : 149 : - (BOOL) containsObject:(id<OOWeakReferenceSupport>)object 150 : { 151 : [self compact]; 152 : OOWeakReference *weakObj = [object weakRetain]; 153 : BOOL result = [_objects containsObject:weakObj]; 154 : [weakObj release]; 155 : return result; 156 : } 157 : 158 : 159 : - (NSEnumerator *) objectEnumerator 160 : { 161 : return [OOWeakRefUnpackingEnumerator enumeratorWithCollection:_objects]; 162 : } 163 : 164 : 165 : - (void) addObject:(id<OOWeakReferenceSupport>)object 166 : { 167 : if (object == nil) return; 168 : NSAssert([object conformsToProtocol:@protocol(OOWeakReferenceSupport)], @"Attempt to add object to OOWeakSet which does not conform to OOWeakReferenceSupport."); 169 : 170 : OOWeakReference *weakObj = [object weakRetain]; 171 : [_objects addObject:weakObj]; 172 : [weakObj release]; 173 : } 174 : 175 : 176 : - (void) removeObject:(id<OOWeakReferenceSupport>)object 177 : { 178 : OOWeakReference *weakObj = [object weakRetain]; 179 : [_objects removeObject:weakObj]; 180 : [weakObj release]; 181 : } 182 : 183 : 184 : - (void) addObjectsByEnumerating:(NSEnumerator *)enumerator 185 : { 186 : id object = nil; 187 : [self compact]; 188 : while ((object = [enumerator nextObject])) 189 : { 190 : [self addObject:object]; 191 : } 192 : } 193 : 194 : 195 : - (void) makeObjectsPerformSelector:(SEL)selector 196 : { 197 : OOWeakReference *weakRef = nil; 198 : foreach (weakRef, _objects) 199 : { 200 : [[weakRef weakRefUnderlyingObject] performSelector:selector]; 201 : } 202 : } 203 : 204 : 205 : - (void) makeObjectsPerformSelector:(SEL)selector withObject:(id)argument 206 : { 207 : OOWeakReference *weakRef = nil; 208 : foreach (weakRef, _objects) 209 : { 210 : [[weakRef weakRefUnderlyingObject] performSelector:selector withObject:argument]; 211 : } 212 : } 213 : 214 : 215 : - (NSArray *) allObjects 216 : { 217 : NSMutableArray *result = [NSMutableArray arrayWithCapacity:[_objects count]]; 218 : OOWeakReference *weakRef = nil; 219 : foreach (weakRef, _objects) 220 : { 221 : id object = [weakRef weakRefUnderlyingObject]; 222 : if (object != nil) [result addObject:object]; 223 : } 224 : 225 : #ifdef NDEBUG 226 : return result; 227 : #else 228 : return [NSArray arrayWithArray:result]; 229 : #endif 230 : } 231 : 232 : 233 : - (void) removeAllObjects 234 : { 235 : [_objects removeAllObjects]; 236 : } 237 : 238 : 239 0 : - (void) compact 240 : { 241 : OOWeakReference *weakRef = nil; 242 : BOOL compactRequired = NO; 243 : foreach (weakRef, _objects) 244 : { 245 : if ([weakRef weakRefUnderlyingObject] == nil) 246 : { 247 : compactRequired = YES; 248 : break; 249 : } 250 : } 251 : 252 : if (compactRequired) 253 : { 254 : NSMutableSet *newObjects = [[NSMutableSet alloc] initWithCapacity:[_objects count]]; 255 : foreach (weakRef, _objects) 256 : { 257 : if ([weakRef weakRefUnderlyingObject] != nil) 258 : { 259 : [newObjects addObject:weakRef]; 260 : } 261 : } 262 : 263 : [_objects release]; 264 : _objects = newObjects; 265 : } 266 : } 267 : 268 : @end 269 : 270 : 271 : @implementation OOWeakRefUnpackingEnumerator 272 : 273 : - (id) initWithEnumerator:(NSEnumerator *)enumerator 274 : { 275 : if (enumerator == nil) 276 : { 277 : [self release]; 278 : return nil; 279 : } 280 : 281 : if ((self = [super init])) 282 : { 283 : _enumerator = [enumerator retain]; 284 : } 285 : 286 : return self; 287 : } 288 : 289 : 290 : + (instancetype) enumeratorWithCollection:(id)collection 291 : { 292 : return [[[self alloc] initWithEnumerator:[collection objectEnumerator]] autorelease]; 293 : } 294 : 295 : 296 0 : - (void) dealloc 297 : { 298 : [_enumerator release]; 299 : 300 : [super dealloc]; 301 : } 302 : 303 : 304 0 : - (id) nextObject 305 : { 306 : id next = nil; 307 : while ((next = [_enumerator nextObject])) 308 : { 309 : next = [next weakRefUnderlyingObject]; 310 : if (next != nil) return next; 311 : } 312 : 313 : return nil; 314 : } 315 : 316 : @end