00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 @import "CPObject.j"
00024 @import "CPRange.j"
00025 @import "CPEnumerator.j"
00026 @import "CPSortDescriptor.j"
00027 @import "CPException.j"
00028
00029
00030 @implementation _CPArrayEnumerator : CPEnumerator
00031 {
00032 CPArray _array;
00033 int _index;
00034 }
00035
00036 - (id)initWithArray:(CPArray)anArray
00037 {
00038 self = [super init];
00039
00040 if (self)
00041 {
00042 _array = anArray;
00043 _index = -1;
00044 }
00045
00046 return self;
00047 }
00048
00049 - (id)nextObject
00050 {
00051 if (++_index >= [_array count])
00052 return nil;
00053
00054 return [_array objectAtIndex:_index];
00055 }
00056
00057 @end
00058
00059
00060 @implementation _CPReverseArrayEnumerator : CPEnumerator
00061 {
00062 CPArray _array;
00063 int _index;
00064 }
00065
00066 - (id)initWithArray:(CPArray)anArray
00067 {
00068 self = [super init];
00069
00070 if (self)
00071 {
00072 _array = anArray;
00073 _index = [_array count];
00074 }
00075
00076 return self;
00077 }
00078
00079 - (id)nextObject
00080 {
00081 if (--_index < 0)
00082 return nil;
00083
00084 return [_array objectAtIndex:_index];
00085 }
00086
00087 @end
00088
00098 @implementation CPArray : CPObject
00099
00103 + (id)alloc
00104 {
00105 return [];
00106 }
00107
00111 + (id)array
00112 {
00113 return [[self alloc] init];
00114 }
00115
00121 + (id)arrayWithArray:(CPArray)anArray
00122 {
00123 return [[self alloc] initWithArray:anArray];
00124 }
00125
00131 + (id)arrayWithObject:(id)anObject
00132 {
00133 return [[self alloc] initWithObjects:anObject];
00134 }
00135
00141 + (id)arrayWithObjects:(id)anObject, ...
00142 {
00143 var i = 2,
00144 array = [[self alloc] init],
00145 argument;
00146
00147 for(; i < arguments.length && (argument = arguments[i]) != nil; ++i)
00148 array.push(argument);
00149
00150 return array;
00151 }
00152
00159 + (id)arrayWithObjects:(id)objects count:(unsigned)aCount
00160 {
00161 return [[self alloc] initWithObjects:objects count:aCount];
00162 }
00163
00168 - (id)init
00169 {
00170 return self;
00171 }
00172
00173
00179 - (id)initWithArray:(CPArray)anArray
00180 {
00181 self = [super init];
00182
00183 if (self)
00184 [self setArray:anArray];
00185
00186 return self;
00187 }
00188
00197 - (id)initWithArray:(CPArray)anArray copyItems:(BOOL)copyItems
00198 {
00199 if (!copyItems)
00200 return [self initWithArray:anArray];
00201
00202 self = [super init];
00203
00204 if (self)
00205 {
00206 var index = 0,
00207 count = [anArray count];
00208
00209 for(; index < count; ++i)
00210 {
00211 if (anArray[i].isa)
00212 self[i] = [anArray copy];
00213
00214 else
00215 self[i] = anArray;
00216 }
00217 }
00218
00219 return self;
00220 }
00221
00225 - (id)initWithObjects:(Array)anArray, ...
00226 {
00227
00228 var i = 2,
00229 argument;
00230
00231 for(; i < arguments.length && (argument = arguments[i]) != nil; ++i)
00232 push(argument);
00233
00234 return self;
00235 }
00236
00243 - (id)initWithObjects:(id)objects count:(unsigned)aCount
00244 {
00245 self = [super init];
00246
00247 if (self)
00248 {
00249 var index = 0;
00250
00251 for(; index < aCount; ++index)
00252 push(objects[index]);
00253 }
00254
00255 return self;
00256 }
00257
00262 - (unsigned)hash
00263 {
00264 if (self.__address == nil)
00265 self.__address = _objj_generateObjectHash();
00266
00267 return self.__address;
00268 }
00269
00270
00275 - (BOOL)containsObject:(id)anObject
00276 {
00277 return [self indexOfObject:anObject] != CPNotFound;
00278 }
00279
00283 - (int)count
00284 {
00285 return length;
00286 }
00287
00295 - (int)indexOfObject:(id)anObject
00296 {
00297 if (anObject === nil)
00298 return CPNotFound;
00299
00300 var i = 0,
00301 count = length;
00302
00303
00304 if (anObject.isa)
00305 {
00306 for(; i < count; ++i)
00307 if([self[i] isEqual:anObject])
00308 return i;
00309 }
00310
00311
00312 else if (self.indexOf)
00313 return indexOf(anObject);
00314
00315 else
00316 for(; i < count; ++i)
00317 if(self[i] == anObject)
00318 return i;
00319
00320 return CPNotFound;
00321 }
00322
00331 - (int)indexOfObject:(id)anObject inRange:(CPRange)aRange
00332 {
00333 if (anObject === nil)
00334 return CPNotFound;
00335
00336 var i = aRange.location,
00337 count = MIN(CPMaxRange(aRange), length);
00338
00339
00340 if (anObject.isa)
00341 {
00342 for(; i < count; ++i)
00343 if([self[i] isEqual:anObject])
00344 return i;
00345 }
00346
00347 else
00348 for(; i < count; ++i)
00349 if(self[i] == anObject)
00350 return i;
00351
00352 return CPNotFound;
00353 }
00354
00360 - (int)indexOfObjectIdenticalTo:(id)anObject
00361 {
00362 if (anObject === nil)
00363 return CPNotFound;
00364
00365
00366
00367 if (self.indexOf)
00368 return indexOf(anObject);
00369
00370
00371 else
00372 {
00373 var index = 0,
00374 count = length;
00375
00376 for(; index < count; ++index)
00377 if(self[index] == anObject)
00378 return index;
00379 }
00380
00381 return CPNotFound;
00382 }
00383
00392 - (int)indexOfObjectIdenticalTo:(id)anObject inRange:(CPRange)aRange
00393 {
00394 if (anObject === nil)
00395 return CPNotFound;
00396
00397
00398
00399 if (self.indexOf)
00400 {
00401 var index = indexOf(anObject, aRange.location);
00402
00403 if (CPLocationInRange(index, aRange))
00404 return index;
00405 }
00406
00407
00408 else
00409 {
00410 var index = aRange.location,
00411 count = MIN(CPMaxRange(aRange), length);
00412
00413 for(; index < count; ++index)
00414 if(self[index] == anObject)
00415 return index;
00416 }
00417
00418 return CPNotFound;
00419 }
00420
00429 - (unsigned)indexOfObject:(id)anObject sortedBySelector:(SEL)aSelector
00430 {
00431 return [self indexOfObject:anObject sortedByFunction: function(lhs, rhs) { objj_msgSend(lhs, aSelector, rhs); }];
00432 }
00433
00446 - (unsigned)indexOfObject:(id)anObject sortedByFunction:(Function)aFunction
00447 {
00448 return [self indexOfObject:anObject sortedByFunction:aFunction context:nil];
00449 }
00450
00464 - (unsigned)indexOfObject:(id)anObject sortedByFunction:(Function)aFunction context:(id)aContext
00465 {
00466 if (!aFunction || anObject === undefined)
00467 return CPNotFound;
00468
00469 var mid, c, first = 0, last = length - 1;
00470 while (first <= last)
00471 {
00472 mid = FLOOR((first + last) / 2);
00473 c = aFunction(anObject, self[mid], aContext);
00474
00475 if (c > 0)
00476 first = mid + 1;
00477 else if (c < 0)
00478 last = mid - 1;
00479 else
00480 {
00481 while (mid < length - 1 && aFunction(anObject, self[mid+1], aContext) == CPOrderedSame)
00482 mid++;
00483
00484 return mid;
00485 }
00486 }
00487
00488 return CPNotFound;
00489 }
00490
00499 - (unsigned)indexOfObject:(id)anObject sortedByDescriptors:(CPArray)descriptors
00500 {
00501 [self indexOfObject:anObject sortedByFunction:function(lhs, rhs)
00502 {
00503 var i = 0,
00504 count = [descriptors count],
00505 result = CPOrderedSame;
00506
00507 while (i < count)
00508 if((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame)
00509 return result;
00510
00511 return result;
00512 }];
00513 }
00514
00518 - (id)lastObject
00519 {
00520 var count = [self count];
00521
00522 if (!count) return nil;
00523
00524 return self[count - 1];
00525 }
00526
00531 - (id)objectAtIndex:(int)anIndex
00532 {
00533 return self[anIndex];
00534 }
00535
00541 - (CPArray)objectsAtIndexes:(CPIndexSet)indexes
00542 {
00543 var index = [indexes firstIndex],
00544 objects = [];
00545
00546 while(index != CPNotFound)
00547 {
00548 [objects addObject:self[index]];
00549 index = [indexes indexGreaterThanIndex:index];
00550 }
00551
00552 return objects;
00553 }
00554
00560 - (CPEnumerator)objectEnumerator
00561 {
00562 return [[_CPArrayEnumerator alloc] initWithArray:self];
00563 }
00564
00570 - (CPEnumerator)reverseObjectEnumerator
00571 {
00572 return [[_CPReverseArrayEnumerator alloc] initWithArray:self];
00573 }
00574
00575
00581 - (void)makeObjectsPerformSelector:(SEL)aSelector
00582 {
00583 if (!aSelector)
00584 [CPException raise:CPInvalidArgumentException reason:"makeObjectsPerformSelector: 'aSelector' can't be nil"];
00585
00586 var index = 0,
00587 count = length;
00588
00589 for(; index < count; ++index)
00590 objj_msgSend(self[index], aSelector);
00591 }
00592
00599 - (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(id)anObject
00600 {
00601 if (!aSelector)
00602 [CPException raise:CPInvalidArgumentException reason:"makeObjectsPerformSelector:withObject 'aSelector' can't be nil"];
00603
00604 var index = 0,
00605 count = length;
00606
00607 for(; index < count; ++index)
00608 objj_msgSend(self[index], aSelector, anObject);
00609 }
00610
00611
00617 - (id)firstObjectCommonWithArray:(CPArray)anArray
00618 {
00619 if (![anArray count] || ![self count])
00620 return nil;
00621
00622 var i = 0,
00623 count = [self count];
00624
00625 for(; i < count; ++i)
00626 if([anArray containsObject:self[i]])
00627 return self[i];
00628
00629 return nil;
00630 }
00631
00635 - (BOOL)isEqualToArray:(id)anArray
00636 {
00637 if (self === anArray)
00638 return YES;
00639
00640 if(length != anArray.length)
00641 return NO;
00642
00643 var index = 0,
00644 count = [self count];
00645
00646 for(; index < count; ++index)
00647 {
00648 var lhs = self[index],
00649 rhs = anArray[index];
00650
00651
00652 if (lhs !== rhs && (!lhs.isa || !rhs.isa || ![lhs isEqual:rhs]))
00653 return NO;
00654 }
00655
00656 return YES;
00657 }
00658
00659 - (BOOL)isEqual:(id)anObject
00660 {
00661 if (self === anObject)
00662 return YES;
00663
00664 if(![anObject isKindOfClass:[CPArray class]])
00665 return NO;
00666
00667 return [self isEqualToArray:anObject];
00668 }
00669
00670
00677 - (CPArray)arrayByAddingObject:(id)anObject
00678 {
00679 if (anObject === nil || anObject === undefined)
00680 [CPException raise:CPInvalidArgumentException
00681 reason:"arrayByAddingObject: object can't be nil"];
00682
00683 var array = [self copy];
00684
00685 array.push(anObject);
00686
00687 return array;
00688 }
00689
00694 - (CPArray)arrayByAddingObjectsFromArray:(CPArray)anArray
00695 {
00696 return slice(0).concat(anArray);
00697 }
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00719 - (CPArray)subarrayWithRange:(CPRange)aRange
00720 {
00721 if (aRange.location < 0 || CPMaxRange(aRange) > length)
00722 [CPException raise:CPRangeException reason:"subarrayWithRange: aRange out of bounds"];
00723
00724 return slice(aRange.location, CPMaxRange(aRange));
00725 }
00726
00727
00728
00729
00730
00731 - (CPArray)sortedArrayUsingDescriptors:(CPArray)descriptors
00732 {
00733 var sorted = [self copy];
00734
00735 [sorted sortUsingDescriptors:descriptors];
00736
00737 return sorted;
00738 }
00739
00743 - (CPArray)sortedArrayUsingFunction:(Function)aFunction
00744 {
00745 return [self sortedArrayUsingFunction:aFunction context:nil];
00746 }
00747
00756 - (CPArray)sortedArrayUsingFunction:(Function)aFunction context:(id)aContext
00757 {
00758 var sorted = [self copy];
00759
00760 [sorted sortUsingFunction:aFunction context:aContext];
00761
00762 return sorted;
00763 }
00764
00769 - (CPArray)sortedArrayUsingSelector:(SEL)aSelector
00770 {
00771 var sorted = [self copy]
00772
00773 [sorted sortUsingSelector:aSelector];
00774
00775 return sorted;
00776 }
00777
00778
00779
00788 - (CPString)componentsJoinedByString:(CPString)aString
00789 {
00790
00791
00792 return join(aString);
00793 }
00794
00795
00796
00800 - (CPString)description
00801 {
00802 var i = 0,
00803 count = [self count],
00804 description = '(';
00805
00806 for(; i < count; ++i)
00807 {
00808 if (self[i].isa) description += [self[i] description];
00809 else description += self[i];
00810
00811 if (i != count - 1) description += ", ";
00812 }
00813
00814 return description + ')';
00815 }
00816
00817
00825 - (CPArray)pathsMatchingExtensions:(CPArray)filterTypes
00826 {
00827 var index = 0,
00828 count = [self count],
00829 array = [];
00830
00831 for(; index < count; ++index)
00832 if (self[index].isa && [self[index] isKindOfClass:[CPString class]] && [filterTypes containsObject:[self[index] pathExtension]])
00833 array.push(self[index]);
00834
00835 return array;
00836 }
00837
00838
00844 - (void)setValue:(id)aValue forKey:(CPString)aKey
00845 {
00846 var i = 0,
00847 count = [self count];
00848
00849 for(; i < count; ++i)
00850 [self[i] setValue:aValue forKey:aKey];
00851 }
00852
00858 - (CPArray)valueForKey:(CPString)aKey
00859 {
00860 var i = 0,
00861 count = [self count],
00862 array = [];
00863
00864 for(; i < count; ++i)
00865 array.push([self[i] valueForKey:aKey]);
00866
00867 return array;
00868 }
00869
00870
00871
00876 - (id)copy
00877 {
00878 return slice(0);
00879 }
00880
00881 @end
00882
00883 @implementation CPArray(CPMutableArray)
00884
00885
00891 + (CPArray)arrayWithCapacity:(unsigned)aCapacity
00892 {
00893 return [[self alloc] initWithCapacity:aCapacity];
00894 }
00895
00900 - (id)initWithCapacity:(unsigned)aCapacity
00901 {
00902 return self;
00903 }
00904
00905
00910 - (void)addObject:(id)anObject
00911 {
00912 push(anObject);
00913 }
00914
00919 - (void)addObjectsFromArray:(CPArray)anArray
00920 {
00921 splice.apply(self, [length, 0].concat(anArray));
00922 }
00923
00929 - (void)insertObject:(id)anObject atIndex:(int)anIndex
00930 {
00931 splice(anIndex, 0, anObject);
00932 }
00933
00939 - (void)insertObjects:(CPArray)objects atIndexes:(CPIndexSet)indexes
00940 {
00941 var indexesCount = [indexes count],
00942 objectsCount = [objects count];
00943
00944 if(indexesCount !== objectsCount)
00945 [CPException raise:CPRangeException reason:"the counts of the passed-in array (" + objectsCount + ") and index set (" + indexesCount + ") must be identical."];
00946
00947 var lastIndex = [indexes lastIndex];
00948
00949 if(lastIndex >= [self count] + indexesCount)
00950 [CPException raise:CPRangeException reason:"the last index (" + lastIndex + ") must be less than the sum of the original count (" + [self count] + ") and the insertion count (" + indexesCount + ")."];
00951
00952 var index = 0,
00953 currentIndex = [indexes firstIndex];
00954
00955 for (; index < objectsCount; ++index, currentIndex = [indexes indexGreaterThanIndex:currentIndex])
00956 [self insertObject:objects[index] atIndex:currentIndex];
00957 }
00958
00964 - (void)replaceObjectAtIndex:(int)anIndex withObject:(id)anObject
00965 {
00966 self[anIndex] = anObject;
00967 }
00968
00975 - (void)replaceObjectsAtIndexes:(CPIndexSet)anIndexSet withObjects:(CPArray)objects
00976 {
00977 var i = 0,
00978 index = [anIndexSet firstIndex];
00979
00980 while(index != CPNotFound)
00981 {
00982 [self replaceObjectAtIndex:index withObject:objects[i++]];
00983 index = [anIndexSet indexGreaterThanIndex:index];
00984 }
00985 }
00986
00995 - (void)replaceObjectsInRange:(CPRange)aRange withObjectsFromArray:(CPArray)anArray range:(CPRange)otherRange
00996 {
00997 if (!otherRange.location && otherRange.length == [anArray count])
00998 [self replaceObjectsInRange:aRange withObjectsFromArray:anArray];
00999 else
01000 splice.apply(self, [aRange.location, aRange.length].concat([anArray subarrayWithRange:otherRange]));
01001 }
01002
01010 - (void)replaceObjectsInRange:(CPRange)aRange withObjectsFromArray:(CPArray)anArray
01011 {
01012 splice.apply(self, [aRange.location, aRange.length].concat(anArray));
01013 }
01014
01019 - (void)setArray:(CPArray)anArray
01020 {
01021 if(self == anArray) return;
01022
01023 splice.apply(self, [0, length].concat(anArray));
01024 }
01025
01026
01030 - (void)removeAllObjects
01031 {
01032 splice(0, length);
01033 }
01034
01038 - (void)removeLastObject
01039 {
01040 pop();
01041 }
01042
01047 - (void)removeObject:(id)anObject
01048 {
01049 [self removeObject:anObject inRange:CPMakeRange(0, length)];
01050 }
01051
01057 - (void)removeObject:(id)anObject inRange:(CPRange)aRange
01058 {
01059 var index;
01060
01061 while ((index = [self indexOfObject:anObject inRange:aRange]) != CPNotFound)
01062 {
01063 [self removeObjectAtIndex:index];
01064 aRange = CPIntersectionRange(CPMakeRange(index, length - index), aRange);
01065 }
01066 }
01067
01072 - (void)removeObjectAtIndex:(int)anIndex
01073 {
01074 splice(anIndex, 1);
01075 }
01076
01081 - (void)removeObjectsAtIndexes:(CPIndexSet)anIndexSet
01082 {
01083 var index = [anIndexSet lastIndex];
01084
01085 while (index != CPNotFound)
01086 {
01087 [self removeObjectAtIndex:index];
01088 index = [anIndexSet indexLessThanIndex:index];
01089 }
01090 }
01091
01097 - (void)removeObjectIdenticalTo:(id)anObject
01098 {
01099 [self removeObjectIdenticalTo:anObject inRange:CPMakeRange(0, length)];
01100 }
01101
01109 - (void)removeObjectIdenticalTo:(id)anObject inRange:(CPRange)aRange
01110 {
01111 var index;
01112
01113 while ((index = [self indexOfObjectIdenticalTo:anObject inRange:aRange]) != CPNotFound)
01114 {
01115 [self removeObjectAtIndex:index];
01116 aRange = CPIntersectionRange(CPMakeRange(index, length - index), aRange);
01117 }
01118 }
01119
01124 - (void)removeObjectsInArray:(CPArray)anArray
01125 {
01126 var index = 0,
01127 count = [anArray count];
01128
01129 for (; index < count; ++index)
01130 [self removeObject:anArray[index]];
01131 }
01132
01137 - (void)removeObjectsInRange:(CPRange)aRange
01138 {
01139 splice(aRange.location, aRange.length);
01140 }
01141
01142
01148 - (void)exchangeObjectAtIndex:(unsigned)anIndex withObjectAtIndex:(unsigned)otherIndex
01149 {
01150 var temporary = self[anIndex];
01151 self[anIndex] = self[otherIndex];
01152 self[otherIndex] = temporary;
01153 }
01154
01155 - (CPArray)sortUsingDescriptors:(CPArray)descriptors
01156 {
01157 sort(function(lhs, rhs)
01158 {
01159 var i = 0,
01160 count = [descriptors count],
01161 result = CPOrderedSame;
01162
01163 while(i < count)
01164 if((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame)
01165 return result;
01166
01167 return result;
01168 });
01169 }
01170
01176 - (void)sortUsingFunction:(Function)aFunction context:(id)aContext
01177 {
01178 sort(function(lhs, rhs) { return aFunction(lhs, rhs, aContext); });
01179 }
01180
01185 - (void)sortUsingSelector:(SEL)aSelector
01186 {
01187 sort(function(lhs, rhs) { return objj_msgSend(lhs, aSelector, rhs); });
01188 }
01189
01190 @end
01191
01192 @implementation CPArray (CPCoding)
01193
01194 - (id)initWithCoder:(CPCoder)aCoder
01195 {
01196 return [aCoder decodeObjectForKey:@"CP.objects"];
01197 }
01198
01199 - (void)encodeWithCoder:(CPCoder)aCoder
01200 {
01201 [aCoder _encodeArrayOfObjects:self forKey:@"CP.objects"];
01202 }
01203
01204 @end
01205
01211 @implementation CPMutableArray : CPArray
01212
01213 @end
01214
01215 Array.prototype.isa = CPArray;
01216 [CPArray initialize];
01217