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[_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[_index];
00085 }
00086
00087 @end
00088
00096 @implementation CPArray : CPObject
00097
00101 + (id)alloc
00102 {
00103 return [];
00104 }
00105
00109 + (id)array
00110 {
00111 return [[self alloc] init];
00112 }
00113
00119 + (id)arrayWithArray:(CPArray)anArray
00120 {
00121 return [[self alloc] initWithArray:anArray];
00122 }
00123
00129 + (id)arrayWithObject:(id)anObject
00130 {
00131 return [[self alloc] initWithObjects:anObject];
00132 }
00133
00139 + (id)arrayWithObjects:(id)anObject, ...
00140 {
00141 var i = 2,
00142 array = [[self alloc] init],
00143 argument;
00144
00145 for(; i < arguments.length && (argument = arguments[i]) != nil; ++i)
00146 array.push(argument);
00147
00148 return array;
00149 }
00150
00157 + (id)arrayWithObjects:(id)objects count:(unsigned)aCount
00158 {
00159 return [[self alloc] initWithObjects:objects count:aCount];
00160 }
00161
00166 - (id)init
00167 {
00168 return self;
00169 }
00170
00171
00177 - (id)initWithArray:(CPArray)anArray
00178 {
00179 self = [super init];
00180
00181 if (self)
00182 [self setArray:anArray];
00183
00184 return self;
00185 }
00186
00195 - (id)initWithArray:(CPArray)anArray copyItems:(BOOL)copyItems
00196 {
00197 if (!copyItems)
00198 return [self initWithArray:anArray];
00199
00200 self = [super init];
00201
00202 if (self)
00203 {
00204 var index = 0,
00205 count = [anArray count];
00206
00207 for(; index < count; ++i)
00208 {
00209 if (anArray[i].isa)
00210 self[i] = [anArray copy];
00211
00212 else
00213 self[i] = anArray;
00214 }
00215 }
00216
00217 return self;
00218 }
00219
00223 - (id)initWithObjects:(Array)anArray, ...
00224 {
00225
00226 var i = 2,
00227 argument;
00228
00229 for(; i < arguments.length && (argument = arguments[i]) != nil; ++i)
00230 push(argument);
00231
00232 return self;
00233 }
00234
00241 - (id)initWithObjects:(id)objects count:(unsigned)aCount
00242 {
00243 self = [super init];
00244
00245 if (self)
00246 {
00247 var index = 0;
00248
00249 for(; index < aCount; ++index)
00250 push(objects[index]);
00251 }
00252
00253 return self;
00254 }
00255
00260 - (unsigned)hash
00261 {
00262 if (self.__address == nil)
00263 self.__address = _objj_generateObjectHash();
00264
00265 return self.__address;
00266 }
00267
00268
00273 - (BOOL)containsObject:(id)anObject
00274 {
00275 return [self indexOfObject:anObject] != CPNotFound;
00276 }
00277
00281 - (int)count
00282 {
00283 return length;
00284 }
00285
00293 - (int)indexOfObject:(id)anObject
00294 {
00295 if (anObject === nil)
00296 return CPNotFound;
00297
00298 var i = 0,
00299 count = length;
00300
00301
00302 if (anObject.isa)
00303 {
00304 for(; i < count; ++i)
00305 if([self[i] isEqual:anObject])
00306 return i;
00307 }
00308
00309
00310 else if (self.indexOf)
00311 return indexOf(anObject);
00312
00313 else
00314 for(; i < count; ++i)
00315 if(self[i] == anObject)
00316 return i;
00317
00318 return CPNotFound;
00319 }
00320
00329 - (int)indexOfObject:(id)anObject inRange:(CPRange)aRange
00330 {
00331 if (anObject === nil)
00332 return CPNotFound;
00333
00334 var i = aRange.location,
00335 count = MIN(CPMaxRange(aRange), length);
00336
00337
00338 if (anObject.isa)
00339 {
00340 for(; i < count; ++i)
00341 if([self[i] isEqual:anObject])
00342 return i;
00343 }
00344
00345 else
00346 for(; i < count; ++i)
00347 if(self[i] == anObject)
00348 return i;
00349
00350 return CPNotFound;
00351 }
00352
00358 - (int)indexOfObjectIdenticalTo:(id)anObject
00359 {
00360 if (anObject === nil)
00361 return CPNotFound;
00362
00363
00364
00365 if (self.indexOf)
00366 return indexOf(anObject);
00367
00368
00369 else
00370 {
00371 var index = 0,
00372 count = length;
00373
00374 for(; index < count; ++index)
00375 if(self[index] == anObject)
00376 return index;
00377 }
00378
00379 return CPNotFound;
00380 }
00381
00390 - (int)indexOfObjectIdenticalTo:(id)anObject inRange:(CPRange)aRange
00391 {
00392 if (anObject === nil)
00393 return CPNotFound;
00394
00395
00396
00397 if (self.indexOf)
00398 {
00399 var index = indexOf(anObject, aRange.location);
00400
00401 if (CPLocationInRange(index, aRange))
00402 return index;
00403 }
00404
00405
00406 else
00407 {
00408 var index = aRange.location,
00409 count = MIN(CPMaxRange(aRange), length);
00410
00411 for(; index < count; ++index)
00412 if(self[index] == anObject)
00413 return index;
00414 }
00415
00416 return CPNotFound;
00417 }
00418
00427 - (unsigned)indexOfObject:(id)anObject sortedBySelector:(SEL)aSelector
00428 {
00429 return [self indexOfObject:anObject sortedByFunction: function(lhs, rhs) { objj_msgSend(lhs, aSelector, rhs); }];
00430 }
00431
00444 - (unsigned)indexOfObject:(id)anObject sortedByFunction:(Function)aFunction
00445 {
00446 return [self indexOfObject:anObject sortedByFunction:aFunction context:nil];
00447 }
00448
00462 - (unsigned)indexOfObject:(id)anObject sortedByFunction:(Function)aFunction context:(id)aContext
00463 {
00464 if (!aFunction || anObject === undefined)
00465 return CPNotFound;
00466
00467 var mid, c, first = 0, last = length - 1;
00468 while (first <= last)
00469 {
00470 mid = FLOOR((first + last) / 2);
00471 c = aFunction(anObject, self[mid], aContext);
00472
00473 if (c > 0)
00474 first = mid + 1;
00475 else if (c < 0)
00476 last = mid - 1;
00477 else
00478 {
00479 while (mid < length - 1 && aFunction(anObject, self[mid+1], aContext) == CPOrderedSame)
00480 mid++;
00481
00482 return mid;
00483 }
00484 }
00485
00486 return CPNotFound;
00487 }
00488
00497 - (unsigned)indexOfObject:(id)anObject sortedByDescriptors:(CPArray)descriptors
00498 {
00499 [self indexOfObject:anObject sortedByFunction:function(lhs, rhs)
00500 {
00501 var i = 0,
00502 count = [descriptors count],
00503 result = CPOrderedSame;
00504
00505 while (i < count)
00506 if((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame)
00507 return result;
00508
00509 return result;
00510 }];
00511 }
00512
00516 - (id)lastObject
00517 {
00518 var count = [self count];
00519
00520 if (!count) return nil;
00521
00522 return self[count - 1];
00523 }
00524
00529 - (id)objectAtIndex:(int)anIndex
00530 {
00531 return self[anIndex];
00532 }
00533
00539 - (CPArray)objectsAtIndexes:(CPIndexSet)indexes
00540 {
00541 var index = [indexes firstIndex],
00542 objects = [];
00543
00544 while(index != CPNotFound)
00545 {
00546 [objects addObject:self[index]];
00547 index = [indexes indexGreaterThanIndex:index];
00548 }
00549
00550 return objects;
00551 }
00552
00558 - (CPEnumerator)objectEnumerator
00559 {
00560 return [[_CPArrayEnumerator alloc] initWithArray:self];
00561 }
00562
00568 - (CPEnumerator)reverseObjectEnumerator
00569 {
00570 return [[_CPReverseArrayEnumerator alloc] initWithArray:self];
00571 }
00572
00573
00579 - (void)makeObjectsPerformSelector:(SEL)aSelector
00580 {
00581 if (!aSelector)
00582 [CPException raise:CPInvalidArgumentException reason:"makeObjectsPerformSelector: 'aSelector' can't be nil"];
00583
00584 var index = 0,
00585 count = length;
00586
00587 for(; index < count; ++index)
00588 objj_msgSend(self[index], aSelector);
00589 }
00590
00597 - (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(id)anObject
00598 {
00599 if (!aSelector)
00600 [CPException raise:CPInvalidArgumentException reason:"makeObjectsPerformSelector:withObject 'aSelector' can't be nil"];
00601
00602 var index = 0,
00603 count = length;
00604
00605 for(; index < count; ++index)
00606 objj_msgSend(self[index], aSelector, anObject);
00607 }
00608
00609
00615 - (id)firstObjectCommonWithArray:(CPArray)anArray
00616 {
00617 if (![anArray count] || ![self count])
00618 return nil;
00619
00620 var i = 0,
00621 count = [self count];
00622
00623 for(; i < count; ++i)
00624 if([anArray containsObject:self[i]])
00625 return self[i];
00626
00627 return nil;
00628 }
00629
00633 - (BOOL)isEqualToArray:(id)anArray
00634 {
00635 if (self === anArray)
00636 return YES;
00637
00638 if(length != anArray.length)
00639 return NO;
00640
00641 var index = 0,
00642 count = [self count];
00643
00644 for(; index < count; ++index)
00645 {
00646 var lhs = self[index],
00647 rhs = anArray[index];
00648
00649
00650 if (lhs !== rhs && (!lhs.isa || !rhs.isa || ![lhs isEqual:rhs]))
00651 return NO;
00652 }
00653
00654 return YES;
00655 }
00656
00657 - (BOOL)isEqual:(id)anObject
00658 {
00659 if (self === anObject)
00660 return YES;
00661
00662 if(![anObject isKindOfClass:[CPArray class]])
00663 return NO;
00664
00665 return [self isEqualToArray:anObject];
00666 }
00667
00668
00675 - (CPArray)arrayByAddingObject:(id)anObject
00676 {
00677 if (!anObject)
00678 [CPException raise:CPInvalidArgumentException
00679 reason:"arrayByAddingObject: object can't be nil"];
00680
00681 var array = [self copy];
00682
00683 array.push(anObject);
00684
00685 return array;
00686 }
00687
00692 - (CPArray)arrayByAddingObjectsFromArray:(CPArray)anArray
00693 {
00694 return slice(0).concat(anArray);
00695 }
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00717 - (CPArray)subarrayWithRange:(CPRange)aRange
00718 {
00719 if (aRange.location < 0 || CPMaxRange(aRange) > length)
00720 [CPException raise:CPRangeException reason:"subarrayWithRange: aRange out of bounds"];
00721
00722 return slice(aRange.location, CPMaxRange(aRange));
00723 }
00724
00725
00726
00727
00728
00729 - (CPArray)sortedArrayUsingDescriptors:(CPArray)descriptors
00730 {
00731 var sorted = [self copy];
00732
00733 [sorted sortUsingDescriptors:descriptors];
00734
00735 return sorted;
00736 }
00737
00746 - (CPArray)sortedArrayUsingFunction:(Function)aFunction context:(id)aContext
00747 {
00748 var sorted = [self copy];
00749
00750 [sorted sortUsingFunction:aFunction context:aContext];
00751
00752 return sorted;
00753 }
00754
00759 - (CPArray)sortedArrayUsingSelector:(SEL)aSelector
00760 {
00761 var sorted = [self copy]
00762
00763 [sorted sortUsingSelector:aSelector];
00764
00765 return sorted;
00766 }
00767
00768
00769
00778 - (CPString)componentsJoinedByString:(CPString)aString
00779 {
00780
00781
00782 return join(aString);
00783 }
00784
00785
00786
00790 - (CPString)description
00791 {
00792 var i = 0,
00793 count = [self count],
00794 description = '(';
00795
00796 for(; i < count; ++i)
00797 {
00798 if (self[i].isa) description += [self[i] description];
00799 else description += self[i];
00800
00801 if (i != count - 1) description += ", ";
00802 }
00803
00804 return description + ')';
00805 }
00806
00807
00815 - (CPArray)pathsMatchingExtensions:(CPArray)filterTypes
00816 {
00817 var index = 0,
00818 count = [self count],
00819 array = [];
00820
00821 for(; index < count; ++index)
00822 if (self[index].isa && [self[index] isKindOfClass:[CPString class]] && [filterTypes containsObject:[self[index] pathExtension]])
00823 array.push(self[index]);
00824
00825 return array;
00826 }
00827
00828
00834 - (void)setValue:(id)aValue forKey:(CPString)aKey
00835 {
00836 var i = 0,
00837 count = [self count];
00838
00839 for(; i < count; ++i)
00840 [self[i] setValue:aValue forKey:aKey];
00841 }
00842
00848 - (CPArray)valueForKey:(CPString)aKey
00849 {
00850 var i = 0,
00851 count = [self count],
00852 array = [];
00853
00854 for(; i < count; ++i)
00855 array.push([self[i] valueForKey:aKey]);
00856
00857 return array;
00858 }
00859
00860
00861
00866 - (id)copy
00867 {
00868 return slice(0);
00869 }
00870
00871 @end
00872
00873 @implementation CPArray(CPMutableArray)
00874
00875
00881 + (CPArray)arrayWithCapacity:(unsigned)aCapacity
00882 {
00883 return [[self alloc] initWithCapacity:aCapacity];
00884 }
00885
00890 - (id)initWithCapacity:(unsigned)aCapacity
00891 {
00892 return self;
00893 }
00894
00895
00900 - (void)addObject:(id)anObject
00901 {
00902 push(anObject);
00903 }
00904
00909 - (void)addObjectsFromArray:(CPArray)anArray
00910 {
00911 splice.apply(self, [length, 0].concat(anArray));
00912 }
00913
00919 - (void)insertObject:(id)anObject atIndex:(int)anIndex
00920 {
00921 splice(anIndex, 0, anObject);
00922 }
00923
00929 - (void)insertObjects:(CPArray)objects atIndexes:(CPIndexSet)indexes
00930 {
00931 var indexesCount = [indexes count],
00932 objectsCount = [objects count];
00933
00934 if(indexesCount !== objectsCount)
00935 [CPException raise:CPRangeException reason:"the counts of the passed-in array (" + objectsCount + ") and index set (" + indexesCount + ") must be identical."];
00936
00937 var lastIndex = [indexes lastIndex];
00938
00939 if(lastIndex >= [self count] + indexesCount)
00940 [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 + ")."];
00941
00942 var index = 0,
00943 currentIndex = [indexes firstIndex];
00944
00945 for (; index < objectsCount; ++index, currentIndex = [indexes indexGreaterThanIndex:currentIndex])
00946 [self insertObject:objects[index] atIndex:currentIndex];
00947 }
00948
00954 - (void)replaceObjectAtIndex:(int)anIndex withObject:(id)anObject
00955 {
00956 self[anIndex] = anObject;
00957 }
00958
00965 - (void)replaceObjectsAtIndexes:(CPIndexSet)anIndexSet withObjects:(CPArray)objects
00966 {
00967 var i = 0,
00968 index = [anIndexSet firstIndex];
00969
00970 while(index != CPNotFound)
00971 {
00972 [self replaceObjectAtIndex:index withObject:objects[i++]];
00973 index = [anIndexSet indexGreaterThanIndex:index];
00974 }
00975 }
00976
00985 - (void)replaceObjectsInRange:(CPRange)aRange withObjectsFromArray:(CPArray)anArray range:(CPRange)otherRange
00986 {
00987 if (!otherRange.location && otherRange.length == [anArray count])
00988 [self replaceObjectsInRange:aRange withObjectsFromArray:anArray];
00989 else
00990 splice.apply(self, [aRange.location, aRange.length].concat([anArray subarrayWithRange:otherRange]));
00991 }
00992
01000 - (void)replaceObjectsInRange:(CPRange)aRange withObjectsFromArray:(CPArray)anArray
01001 {
01002 splice.apply(self, [aRange.location, aRange.length].concat(anArray));
01003 }
01004
01009 - (void)setArray:(CPArray)anArray
01010 {
01011 if(self == anArray) return;
01012
01013 splice.apply(self, [0, length].concat(anArray));
01014 }
01015
01016
01020 - (void)removeAllObjects
01021 {
01022 splice(0, length);
01023 }
01024
01028 - (void)removeLastObject
01029 {
01030 pop();
01031 }
01032
01037 - (void)removeObject:(id)anObject
01038 {
01039 [self removeObject:anObject inRange:CPMakeRange(0, length)];
01040 }
01041
01047 - (void)removeObject:(id)anObject inRange:(CPRange)aRange
01048 {
01049 var index;
01050
01051 while ((index = [self indexOfObject:anObject inRange:aRange]) != CPNotFound)
01052 {
01053 [self removeObjectAtIndex:index];
01054 aRange = CPIntersectionRange(CPMakeRange(index, length - index), aRange);
01055 }
01056 }
01057
01062 - (void)removeObjectAtIndex:(int)anIndex
01063 {
01064 splice(anIndex, 1);
01065 }
01066
01071 - (void)removeObjectsAtIndexes:(CPIndexSet)anIndexSet
01072 {
01073 var index = [anIndexSet lastIndex];
01074
01075 while (index != CPNotFound)
01076 {
01077 [self removeObjectAtIndex:index];
01078 index = [anIndexSet indexSmallerThanIndex:index];
01079 }
01080 }
01081
01087 - (void)removeObjectIdenticalTo:(id)anObject
01088 {
01089 [self removeObjectIdenticalTo:anObject inRange:CPMakeRange(0, length)];
01090 }
01091
01099 - (void)removeObjectIdenticalTo:(id)anObject inRange:(CPRange)aRange
01100 {
01101 var index;
01102
01103 while ((index = [self indexOfObjectIdenticalTo:anObject inRange:aRange]) != CPNotFound)
01104 {
01105 [self removeObjectAtIndex:index];
01106 aRange = CPIntersectionRange(CPMakeRange(index, length - index), aRange);
01107 }
01108 }
01109
01114 - (void)removeObjectsInArray:(CPArray)anArray
01115 {
01116 var index = 0,
01117 count = [anArray count];
01118
01119 for (; index < count; ++index)
01120 [self removeObject:anArray[index]];
01121 }
01122
01127 - (void)removeObjectsInRange:(CPRange)aRange
01128 {
01129 splice(aRange.location, aRange.length);
01130 }
01131
01132
01138 - (void)exchangeObjectAtIndex:(unsigned)anIndex withObjectAtIndex:(unsigned)otherIndex
01139 {
01140 var temporary = self[anIndex];
01141 self[anIndex] = self[otherIndex];
01142 self[otherIndex] = temporary;
01143 }
01144
01145 - (CPArray)sortUsingDescriptors:(CPArray)descriptors
01146 {
01147 sort(function(lhs, rhs)
01148 {
01149 var i = 0,
01150 count = [descriptors count],
01151 result = CPOrderedSame;
01152
01153 while(i < count)
01154 if((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame)
01155 return result;
01156
01157 return result;
01158 });
01159 }
01160
01166 - (void)sortUsingFunction:(Function)aFunction context:(id)aContext
01167 {
01168 sort(function(lhs, rhs) { return aFunction(lhs, rhs, aContext); });
01169 }
01170
01175 - (void)sortUsingSelector:(SEL)aSelector
01176 {
01177 sort(function(lhs, rhs) { return objj_msgSend(lhs, aSelector, rhs); });
01178 }
01179
01180 @end
01181
01182 @implementation CPArray (CPCoding)
01183
01184 - (id)initWithCoder:(CPCoder)aCoder
01185 {
01186 return [aCoder _decodeArrayOfObjectsForKey:@"CP.objects"];
01187 }
01188
01189 - (void)encodeWithCoder:(CPCoder)aCoder
01190 {
01191 [aCoder _encodeArrayOfObjects:self forKey:@"CP.objects"];
01192 }
01193
01194 @end
01195
01201 @implementation CPMutableArray : CPArray
01202
01203 @end
01204
01205 Array.prototype.isa = CPArray;
01206 [CPArray initialize];
01207