![]() |
API 0.9.5
|
00001 /* 00002 * CPSet.j 00003 * Foundation 00004 * 00005 * Created by Bailey Carlson 00006 * Extended by Ross Boucher 00007 * Extended by Nabil Elisa 00008 * Rewritten by Francisco Tolmasky 00009 * Copyright 2008, 280 North, Inc. 00010 * 00011 * This library is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU Lesser General Public 00013 * License as published by the Free Software Foundation; either 00014 * version 2.1 of the License, or (at your option) any later version. 00015 * 00016 * This library is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00019 * Lesser General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU Lesser General Public 00022 * License along with this library; if not, write to the Free Software 00023 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00024 * 00025 */ 00026 @implementation CPSet : CPObject 00027 { 00028 id __doxygen__; 00029 } 00030 00031 + (id)alloc 00032 { 00033 if (self === [CPSet class] || self === [CPMutableSet class]) 00034 return [_CPPlaceholderSet alloc]; 00035 00036 return [super alloc]; 00037 } 00038 00039 /* 00040 Creates and returns an empty set. 00041 */ 00042 + (id)set 00043 { 00044 return [[self alloc] init]; 00045 } 00046 00047 /* 00048 Creates and returns a set containing a uniqued collection of those objects contained in a given array. 00049 @param anArray array containing the objects to add to the new set. If the same object appears more than once objects, it is added only once to the returned set. 00050 */ 00051 + (id)setWithArray:(CPArray)anArray 00052 { 00053 return [[self alloc] initWithArray:anArray]; 00054 } 00055 00056 /* 00057 Creates and returns a set that contains a single given object. 00058 @param anObject The object to add to the new set. 00059 */ 00060 + (id)setWithObject:(id)anObject 00061 { 00062 return [[self alloc] initWithObjects:anObject]; 00063 } 00064 00065 /* 00066 Creates and returns a set containing a specified number of objects from a given array of objects. 00067 @param objects A array of objects to add to the new set. If the same object appears more than once objects, it is added only once to the returned set. 00068 @param count The number of objects from objects to add to the new set. 00069 */ 00070 + (id)setWithObjects:(id)objects count:(CPUInteger)count 00071 { 00072 return [[self alloc] initWithObjects:objects count:count]; 00073 } 00074 00075 /* 00076 Creates and returns a set containing the objects in a given argument list. 00077 @param anObject The first object to add to the new set. 00078 @param ... A comma-separated list of objects, ending with nil, to add to the new set. If the same object appears more than once objects, it is added only once to the returned set. 00079 */ 00080 + (id)setWithObjects:(id)anObject, ... 00081 { 00082 var argumentsArray = Array.prototype.slice.apply(arguments); 00083 00084 argumentsArray[0] = [self alloc]; 00085 argumentsArray[1] = @selector(initWithObjects:); 00086 00087 return objj_msgSend.apply(this, argumentsArray); 00088 } 00089 00090 /* 00091 Creates and returns a set containing the objects from another set. 00092 @param aSet A set containing the objects to add to the new set. 00093 */ 00094 + (id)setWithSet:(CPSet)set 00095 { 00096 return [[self alloc] initWithSet:set]; 00097 } 00098 00099 - (id)setByAddingObject:(id)anObject 00100 { 00101 return [[self class] setWithArray:[[self allObjects] arrayByAddingObject:anObject]]; 00102 } 00103 00104 - (id)setByAddingObjectsFromSet:(CPSet)aSet 00105 { 00106 return [self setByAddingObjectsFromArray:[aSet allObjects]]; 00107 } 00108 00109 - (id)setByAddingObjectsFromArray:(CPArray)anArray 00110 { 00111 return [[self class] setWithArray:[[self allObjects] arrayByAddingObjectsFromArray:anArray]]; 00112 } 00113 00114 /* 00115 Basic initializer, returns an empty set 00116 */ 00117 - (id)init 00118 { 00119 return [self initWithObjects:nil count:0]; 00120 } 00121 00122 /* 00123 Initializes a newly allocated set with the objects that are contained in a given array. 00124 @param array An array of objects to add to the new set. If the same object appears more than once in array, it is represented only once in the returned set. 00125 */ 00126 - (id)initWithArray:(CPArray)anArray 00127 { 00128 return [self initWithObjects:anArray count:[anArray count]]; 00129 } 00130 00131 /* 00132 Initializes a newly allocated set with members taken from the specified list of objects. 00133 @param anObject The first object to add to the new set. 00134 @param ... A comma-separated list of objects, ending with nil, to add to the new set. If the same object appears more than once in the list, it is represented only once in the returned set. 00135 */ 00136 - (id)initWithObjects:(id)anObject, ... 00137 { 00138 var index = 2, 00139 count = arguments.length; 00140 00141 for (; index < count; ++index) 00142 if (arguments[index] === nil) 00143 break; 00144 00145 return [self initWithObjects:Array.prototype.slice.call(arguments, 2, index) count:index - 2]; 00146 } 00147 00148 - (id)initWithObjects:(CPArray)objects count:(CPUInteger)aCount 00149 { 00150 if (self === _CPSharedPlaceholderSet) 00151 return [[_CPConcreteMutableSet alloc] initWithObjects:objects count:aCount]; 00152 00153 return [super init]; 00154 } 00155 00156 /* 00157 Initializes a newly allocated set and adds to it objects from another given set. 00158 */ 00159 - (id)initWithSet:(CPSet)aSet 00160 { 00161 return [self initWithArray:[aSet allObjects]]; 00162 } 00163 00164 /* 00165 Initializes a newly allocated set and adds to it members of another given set. Only included for compatability. 00166 */ 00167 - (id)initWithSet:(CPSet)aSet copyItems:(BOOL)shouldCopyItems 00168 { 00169 if (shouldCopyItems) 00170 return [aSet valueForKey:@"copy"]; 00171 00172 return [self initWithSet:aSet]; 00173 } 00174 00175 /* 00176 Returns the number of members in the receiver. 00177 */ 00178 - (CPUInteger)count 00179 { 00180 _CPRaiseInvalidAbstractInvocation(self, _cmd); 00181 } 00182 00183 /* 00184 Returns an array containing the receiver’s members, or an empty array if the receiver has no members. 00185 */ 00186 - (CPArray)allObjects 00187 { 00188 var objects = [], 00189 object, 00190 objectEnumerator = [self objectEnumerator]; 00191 00192 while ((object = [objectEnumerator nextObject]) !== nil) 00193 objects.push(object); 00194 00195 return objects; 00196 } 00197 00198 /* 00199 Returns one of the objects in the receiver, or nil if the receiver contains no objects. 00200 */ 00201 - (id)anyObject 00202 { 00203 return [[self objectEnumerator] nextObject]; 00204 } 00205 00206 /* 00207 Returns a Boolean value that indicates whether a given object is present in the receiver. 00208 @param anObject The object for which to test membership of the receiver. 00209 */ 00210 - (BOOL)containsObject:(id)anObject 00211 { 00212 return [self member:anObject] !== nil; 00213 } 00214 00215 - (void)filteredSetUsingPredicate:(CPPredicate)aPredicate 00216 { 00217 var objects = [], 00218 object, 00219 objectEnumerator = [self objectEnumerator]; 00220 00221 while ((object = [objectEnumerator nextObject]) !== nil) 00222 if ([aPredicate evaluateWithObject:object]) 00223 objects.push(object); 00224 00225 return [[[self class] alloc] initWithArray:objects]; 00226 } 00227 00228 /* 00229 Sends to each object in the receiver a message specified by a given selector. 00230 @param aSelector A selector that specifies the message to send to the members of the receiver. The method must not take any arguments. It should not have the side effect of modifying the receiver. This value must not be NULL. 00231 */ 00232 - (void)makeObjectsPerformSelector:(SEL)aSelector 00233 { 00234 [self makeObjectsPerformSelector:aSelector withObjects:nil]; 00235 } 00236 00237 /* 00238 Sends to each object in the receiver a message specified by a given selector. 00239 @param aSelector A selector that specifies the message to send to the receiver's members. The method must take a single argument of type id. The method should not, as a side effect, modify the receiver. The value must not be NULL. 00240 @param anObject The object to pass as an argument to the method specified by aSelector. 00241 */ 00242 - (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(id)anObject 00243 { 00244 [self makeObjectsPerformSelector:aSelector withObjects:[anObject]]; 00245 } 00246 00247 /* 00248 Sends to each object in the receiver a message specified by a given selector. 00249 @param aSelector A selector that specifies the message to send to the receiver's members. The method must take a single argument of type id. The method should not, as a side effect, modify the receiver. The value must not be NULL. 00250 @param objects The objects to pass as an argument to the method specified by aSelector. 00251 */ 00252 - (void)makeObjectsPerformSelector:(SEL)aSelector withObjects:(CPArray)objects 00253 { 00254 var object, 00255 objectEnumerator = [self objectEnumerator], 00256 argumentsArray = [nil, aSelector].concat(objects || []); 00257 00258 while ((object = [objectEnumerator nextObject]) !== nil) 00259 { 00260 argumentsArray[0] = object; 00261 objj_msgSend.apply(this, argumentsArray); 00262 } 00263 } 00264 00265 /* 00266 Determines whether the receiver contains an object equal to a given object, and returns that object if it is present. 00267 @param anObject The object for which to test for membership of the receiver. 00268 */ 00269 - (id)member:(id)anObject 00270 { 00271 _CPRaiseInvalidAbstractInvocation(self, _cmd); 00272 } 00273 00274 - (CPEnumerator)objectEnumerator 00275 { 00276 _CPRaiseInvalidAbstractInvocation(self, _cmd); 00277 } 00278 00279 - (void)enumerateObjectsUsingBlock:(Function)aFunction 00280 { 00281 var object, 00282 objectEnumerator = [self objectEnumerator]; 00283 00284 while ((object = [objectEnumerator nextObject]) !== nil) 00285 if (aFunction(object)) 00286 break; 00287 } 00288 00289 // FIXME: stop is broken. 00290 - (CPSet)objectsPassingTest:(Function)aFunction 00291 { 00292 var objects = [], 00293 object = nil, 00294 objectEnumerator = [self objectEnumerator]; 00295 00296 while ((object = [objectEnumerator nextObject]) !== nil) 00297 if (aFunction(object)) 00298 objects.push(object); 00299 00300 return [[[self class] alloc] initWithArray:objects]; 00301 } 00302 00303 /* 00304 Returns a Boolean value that indicates whether every object in the receiver is also present in another given set. 00305 @param set The set with which to compare the receiver. 00306 */ 00307 - (BOOL)isSubsetOfSet:(CPSet)aSet 00308 { 00309 var object = nil, 00310 objectEnumerator = [self objectEnumerator]; 00311 00312 while ((object = [objectEnumerator nextObject]) !== nil) 00313 if (![aSet containsObject:object]) 00314 return NO; 00315 00316 return YES; 00317 } 00318 00319 /* 00320 Returns a Boolean value that indicates whether at least one object in the receiver is also present in another given set. 00321 @param set The set with which to compare the receiver. 00322 */ 00323 - (BOOL)intersectsSet:(CPSet)aSet 00324 { 00325 if (self === aSet) 00326 // The empty set intersects nothing 00327 return [self count] > 0; 00328 00329 var object = nil, 00330 objectEnumerator = [self objectEnumerator]; 00331 00332 while ((object = [objectEnumerator nextObject]) !== nil) 00333 if ([aSet containsObject:object]) 00334 return YES; 00335 00336 return NO; 00337 } 00338 00339 /* 00340 Compares the receiver to another set. 00341 @param set The set with which to compare the receiver. 00342 */ 00343 - (BOOL)isEqualToSet:(CPSet)aSet 00344 { 00345 return [self isEqual:aSet]; 00346 } 00347 00348 - (BOOL)isEqual:(CPSet)aSet 00349 { 00350 // If both are subsets of each other, they are equal 00351 return self === aSet || 00352 [aSet isKindOfClass:[CPSet class]] && 00353 ([self count] === [aSet count] && 00354 [aSet isSubsetOfSet:self]); 00355 } 00356 00357 - (CPString)description 00358 { 00359 var string = "{(\n", 00360 objects = [self allObjects], 00361 index = 0, 00362 count = [objects count]; 00363 00364 for (; index < count; ++index) 00365 { 00366 var object = objects[index]; 00367 00368 string += "\t" + String(object).split('\n').join("\n\t") + "\n"; 00369 } 00370 00371 return string + ")}"; 00372 } 00373 00374 @end 00375 00376 @implementation CPSet (CPCopying) 00377 00378 - (id)copy 00379 { 00380 return [[self class] setWithSet:self]; 00381 } 00382 00383 - (id)mutableCopy 00384 { 00385 return [self copy]; 00386 } 00387 00388 @end 00389 00390 var CPSetObjectsKey = @"CPSetObjectsKey"; 00391 00392 @implementation CPSet (CPCoding) 00393 00394 - (id)initWithCoder:(CPCoder)aCoder 00395 { 00396 return [self initWithArray:[aCoder decodeObjectForKey:CPSetObjectsKey]]; 00397 } 00398 00399 - (void)encodeWithCoder:(CPCoder)aCoder 00400 { 00401 [aCoder encodeObject:[self allObjects] forKey:CPSetObjectsKey]; 00402 } 00403 00404 @end 00405 00406 @implementation CPSet (CPKeyValueCoding) 00407 00408 - (id)valueForKey:(CPString)aKey 00409 { 00410 if (aKey === "@count") 00411 return [self count]; 00412 00413 var valueSet = [CPSet set], 00414 object, 00415 objectEnumerator = [self objectEnumerator]; 00416 00417 while ((object = [objectEnumerator nextObject]) !== nil) 00418 { 00419 var value = [object valueForKey:aKey]; 00420 00421 [valueSet addObject:value]; 00422 } 00423 00424 return valueSet; 00425 } 00426 00427 - (void)setValue:(id)aValue forKey:(CPString)aKey 00428 { 00429 var object, 00430 objectEnumerator = [self objectEnumerator]; 00431 00432 while ((object = [objectEnumerator nextObject]) !== nil) 00433 [object setValue:aValue forKey:aKey]; 00434 } 00435 00436 @end 00437 00438 var _CPSharedPlaceholderSet = nil; 00439 @implementation _CPPlaceholderSet : CPSet 00440 { 00441 id __doxygen__; 00442 } 00443 00444 + (id)alloc 00445 { 00446 if (!_CPSharedPlaceholderSet) 00447 _CPSharedPlaceholderSet = [super alloc]; 00448 00449 return _CPSharedPlaceholderSet; 00450 } 00451 00452 @end 00453 00454 // This will be correctly solved when we move to true immutable/mutable pairs.