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
00031 @implementation _CPArrayEnumerator : CPEnumerator
00032 {
00033 CPArray _array;
00034 int _index;
00035 }
00036
00037 - (id)initWithArray:(CPArray)anArray
00038 {
00039 self = [super init];
00040
00041 if (self)
00042 {
00043 _array = anArray;
00044 _index = -1;
00045 }
00046
00047 return self;
00048 }
00049
00050 - (id)nextObject
00051 {
00052 if (++_index >= [_array count])
00053 return nil;
00054
00055 return [_array objectAtIndex:_index];
00056 }
00057
00058 @end
00059
00060
00061 @implementation _CPReverseArrayEnumerator : CPEnumerator
00062 {
00063 CPArray _array;
00064 int _index;
00065 }
00066
00067 - (id)initWithArray:(CPArray)anArray
00068 {
00069 self = [super init];
00070
00071 if (self)
00072 {
00073 _array = anArray;
00074 _index = [_array count];
00075 }
00076
00077 return self;
00078 }
00079
00080 - (id)nextObject
00081 {
00082 if (--_index < 0)
00083 return nil;
00084
00085 return [_array objectAtIndex:_index];
00086 }
00087
00088 @end
00089
00101 @implementation CPArray : CPObject
00102
00106 + (id)alloc
00107 {
00108 return [];
00109 }
00110
00114 + (id)array
00115 {
00116 return [[self alloc] init];
00117 }
00118
00124 + (id)arrayWithArray:(CPArray)anArray
00125 {
00126 return [[self alloc] initWithArray:anArray];
00127 }
00128
00134 + (id)arrayWithObject:(id)anObject
00135 {
00136 return [[self alloc] initWithObjects:anObject];
00137 }
00138
00144 + (id)arrayWithObjects:(id)anObject, ...
00145 {
00146 var i = 2,
00147 array = [[self alloc] init],
00148 argument;
00149
00150 for(; i < arguments.length && (argument = arguments[i]) != nil; ++i)
00151 array.push(argument);
00152
00153 return array;
00154 }
00155
00162 + (id)arrayWithObjects:(id)objects count:(unsigned)aCount
00163 {
00164 return [[self alloc] initWithObjects:objects count:aCount];
00165 }
00166
00171 - (id)init
00172 {
00173 return self;
00174 }
00175
00176
00182 - (id)initWithArray:(CPArray)anArray
00183 {
00184 self = [super init];
00185
00186 if (self)
00187 [self setArray:anArray];
00188
00189 return self;
00190 }
00191
00200 - (id)initWithArray:(CPArray)anArray copyItems:(BOOL)copyItems
00201 {
00202 if (!copyItems)
00203 return [self initWithArray:anArray];
00204
00205 self = [super init];
00206
00207 if (self)
00208 {
00209 var index = 0,
00210 count = [anArray count];
00211
00212 for(; index < count; ++index)
00213 {
00214 if (anArray[index].isa)
00215 self[index] = [anArray[index] copy];
00216
00217 else
00218 self[index] = anArray;
00219 }
00220 }
00221
00222 return self;
00223 }
00224
00228 - (id)initWithObjects:(Array)anArray, ...
00229 {
00230
00231 var i = 2,
00232 argument;
00233
00234 for(; i < arguments.length && (argument = arguments[i]) != nil; ++i)
00235 push(argument);
00236
00237 return self;
00238 }
00239
00246 - (id)initWithObjects:(id)objects count:(unsigned)aCount
00247 {
00248 self = [super init];
00249
00250 if (self)
00251 {
00252 var index = 0;
00253
00254 for(; index < aCount; ++index)
00255 push(objects[index]);
00256 }
00257
00258 return self;
00259 }
00260
00261
00266 - (BOOL)containsObject:(id)anObject
00267 {
00268 return [self indexOfObject:anObject] != CPNotFound;
00269 }
00270
00274 - (int)count
00275 {
00276 return length;
00277 }
00278
00286 - (int)indexOfObject:(id)anObject
00287 {
00288 if (anObject === nil)
00289 return CPNotFound;
00290
00291 var i = 0,
00292 count = length;
00293
00294
00295 if (anObject.isa)
00296 {
00297 for(; i < count; ++i)
00298 if([self[i] isEqual:anObject])
00299 return i;
00300 }
00301
00302
00303 else if (self.indexOf)
00304 return indexOf(anObject);
00305
00306 else
00307 for(; i < count; ++i)
00308 if(self[i] == anObject)
00309 return i;
00310
00311 return CPNotFound;
00312 }
00313
00322 - (int)indexOfObject:(id)anObject inRange:(CPRange)aRange
00323 {
00324 if (anObject === nil)
00325 return CPNotFound;
00326
00327 var i = aRange.location,
00328 count = MIN(CPMaxRange(aRange), length);
00329
00330
00331 if (anObject.isa)
00332 {
00333 for(; i < count; ++i)
00334 if([self[i] isEqual:anObject])
00335 return i;
00336 }
00337
00338 else
00339 for(; i < count; ++i)
00340 if(self[i] == anObject)
00341 return i;
00342
00343 return CPNotFound;
00344 }
00345
00351 - (int)indexOfObjectIdenticalTo:(id)anObject
00352 {
00353 if (anObject === nil)
00354 return CPNotFound;
00355
00356
00357
00358 if (self.indexOf)
00359 return indexOf(anObject);
00360
00361
00362 else
00363 {
00364 var index = 0,
00365 count = length;
00366
00367 for(; index < count; ++index)
00368 if(self[index] === anObject)
00369 return index;
00370 }
00371
00372 return CPNotFound;
00373 }
00374
00383 - (int)indexOfObjectIdenticalTo:(id)anObject inRange:(CPRange)aRange
00384 {
00385 if (anObject === nil)
00386 return CPNotFound;
00387
00388
00389
00390 if (self.indexOf)
00391 {
00392 var index = indexOf(anObject, aRange.location);
00393
00394 if (CPLocationInRange(index, aRange))
00395 return index;
00396 }
00397
00398
00399 else
00400 {
00401 var index = aRange.location,
00402 count = MIN(CPMaxRange(aRange), length);
00403
00404 for(; index < count; ++index)
00405 if(self[index] == anObject)
00406 return index;
00407 }
00408
00409 return CPNotFound;
00410 }
00411
00420 - (unsigned)indexOfObject:(id)anObject sortedBySelector:(SEL)aSelector
00421 {
00422 return [self indexOfObject:anObject sortedByFunction: function(lhs, rhs) { objj_msgSend(lhs, aSelector, rhs); }];
00423 }
00424
00437 - (unsigned)indexOfObject:(id)anObject sortedByFunction:(Function)aFunction
00438 {
00439 return [self indexOfObject:anObject sortedByFunction:aFunction context:nil];
00440 }
00441
00455 - (unsigned)indexOfObject:(id)anObject sortedByFunction:(Function)aFunction context:(id)aContext
00456 {
00457 if (!aFunction || anObject === undefined)
00458 return CPNotFound;
00459
00460 var mid, c, first = 0, last = length - 1;
00461 while (first <= last)
00462 {
00463 mid = FLOOR((first + last) / 2);
00464 c = aFunction(anObject, self[mid], aContext);
00465
00466 if (c > 0)
00467 first = mid + 1;
00468 else if (c < 0)
00469 last = mid - 1;
00470 else
00471 {
00472 while (mid < length - 1 && aFunction(anObject, self[mid+1], aContext) == CPOrderedSame)
00473 mid++;
00474
00475 return mid;
00476 }
00477 }
00478
00479 return CPNotFound;
00480 }
00481
00490 - (unsigned)indexOfObject:(id)anObject sortedByDescriptors:(CPArray)descriptors
00491 {
00492 return [self indexOfObject:anObject sortedByFunction:function(lhs, rhs)
00493 {
00494 var i = 0,
00495 count = [descriptors count],
00496 result = CPOrderedSame;
00497
00498 while (i < count)
00499 if((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame)
00500 return result;
00501
00502 return result;
00503 }];
00504 }
00505
00509 - (id)lastObject
00510 {
00511 var count = [self count];
00512
00513 if (!count) return nil;
00514
00515 return self[count - 1];
00516 }
00517
00522 - (id)objectAtIndex:(int)anIndex
00523 {
00524 if (anIndex >= length || anIndex < 0)
00525 [CPException raise:CPRangeException reason:@"index (" + anIndex + @") beyond bounds (" + length + @")"];
00526
00527 return self[anIndex];
00528 }
00529
00535 - (CPArray)objectsAtIndexes:(CPIndexSet)indexes
00536 {
00537 var index = CPNotFound,
00538 objects = [];
00539
00540 while((index = [indexes indexGreaterThanIndex:index]) !== CPNotFound)
00541 [objects addObject:[self objectAtIndex:index]];
00542
00543 return objects;
00544 }
00545
00551 - (CPEnumerator)objectEnumerator
00552 {
00553 return [[_CPArrayEnumerator alloc] initWithArray:self];
00554 }
00555
00561 - (CPEnumerator)reverseObjectEnumerator
00562 {
00563 return [[_CPReverseArrayEnumerator alloc] initWithArray:self];
00564 }
00565
00566
00572 - (void)makeObjectsPerformSelector:(SEL)aSelector
00573 {
00574 if (!aSelector)
00575 [CPException raise:CPInvalidArgumentException reason:"makeObjectsPerformSelector: 'aSelector' can't be nil"];
00576
00577 var index = 0,
00578 count = length;
00579
00580 for(; index < count; ++index)
00581 objj_msgSend(self[index], aSelector);
00582 }
00583
00590 - (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(id)anObject
00591 {
00592 if (!aSelector)
00593 [CPException raise:CPInvalidArgumentException reason:"makeObjectsPerformSelector:withObject 'aSelector' can't be nil"];
00594
00595 var index = 0,
00596 count = length;
00597
00598 for(; index < count; ++index)
00599 objj_msgSend(self[index], aSelector, anObject);
00600 }
00601
00602 - (void)makeObjectsPerformSelector:(SEL)aSelector withObjects:(CPArray)objects
00603 {
00604 if (!aSelector)
00605 [CPException raise:CPInvalidArgumentException reason:"makeObjectsPerformSelector:withObjects: 'aSelector' can't be nil"];
00606
00607 var index = 0,
00608 count = length,
00609 argumentsArray = [nil, aSelector].concat(objects || []);
00610
00611 for(; index < count; ++index)
00612 {
00613 argumentsArray[0] = self[index];
00614 objj_msgSend.apply(this, argumentsArray);
00615 }
00616 }
00617
00618
00619
00625 - (id)firstObjectCommonWithArray:(CPArray)anArray
00626 {
00627 if (![anArray count] || ![self count])
00628 return nil;
00629
00630 var i = 0,
00631 count = [self count];
00632
00633 for(; i < count; ++i)
00634 if([anArray containsObject:self[i]])
00635 return self[i];
00636
00637 return nil;
00638 }
00639
00643 - (BOOL)isEqualToArray:(id)anArray
00644 {
00645 if (self === anArray)
00646 return YES;
00647
00648 if(length != anArray.length)
00649 return NO;
00650
00651 var index = 0,
00652 count = [self count];
00653
00654 for(; index < count; ++index)
00655 {
00656 var lhs = self[index],
00657 rhs = anArray[index];
00658
00659
00660 if (lhs !== rhs && (lhs && !lhs.isa || rhs && !rhs.isa || ![lhs isEqual:rhs]))
00661 return NO;
00662 }
00663
00664 return YES;
00665 }
00666
00667 - (BOOL)isEqual:(id)anObject
00668 {
00669 if (self === anObject)
00670 return YES;
00671
00672 if(![anObject isKindOfClass:[CPArray class]])
00673 return NO;
00674
00675 return [self isEqualToArray:anObject];
00676 }
00677
00678
00685 - (CPArray)arrayByAddingObject:(id)anObject
00686 {
00687 if (anObject === nil || anObject === undefined)
00688 [CPException raise:CPInvalidArgumentException
00689 reason:"arrayByAddingObject: object can't be nil"];
00690
00691 var array = [self copy];
00692
00693 array.push(anObject);
00694
00695 return array;
00696 }
00697
00702 - (CPArray)arrayByAddingObjectsFromArray:(CPArray)anArray
00703 {
00704 return slice(0).concat(anArray);
00705 }
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00727 - (CPArray)subarrayWithRange:(CPRange)aRange
00728 {
00729 if (aRange.location < 0 || CPMaxRange(aRange) > length)
00730 [CPException raise:CPRangeException reason:"subarrayWithRange: aRange out of bounds"];
00731
00732 return slice(aRange.location, CPMaxRange(aRange));
00733 }
00734
00735
00736
00737
00738
00739 - (CPArray)sortedArrayUsingDescriptors:(CPArray)descriptors
00740 {
00741 var sorted = [self copy];
00742
00743 [sorted sortUsingDescriptors:descriptors];
00744
00745 return sorted;
00746 }
00747
00751 - (CPArray)sortedArrayUsingFunction:(Function)aFunction
00752 {
00753 return [self sortedArrayUsingFunction:aFunction context:nil];
00754 }
00755
00764 - (CPArray)sortedArrayUsingFunction:(Function)aFunction context:(id)aContext
00765 {
00766 var sorted = [self copy];
00767
00768 [sorted sortUsingFunction:aFunction context:aContext];
00769
00770 return sorted;
00771 }
00772
00777 - (CPArray)sortedArrayUsingSelector:(SEL)aSelector
00778 {
00779 var sorted = [self copy]
00780
00781 [sorted sortUsingSelector:aSelector];
00782
00783 return sorted;
00784 }
00785
00786
00787
00796 - (CPString)componentsJoinedByString:(CPString)aString
00797 {
00798
00799
00800 return join(aString);
00801 }
00802
00803
00804
00808 - (CPString)description
00809 {
00810 var index = 0,
00811 count = [self count],
00812 description = '(';
00813
00814 for(; index < count; ++index)
00815 {
00816 if (index === 0)
00817 description += '\n';
00818
00819 var object = [self objectAtIndex:index],
00820 objectDescription = object && object.isa ? [object description] : String(object);
00821
00822 description += "\t" + objectDescription.split('\n').join("\n\t");
00823
00824 if (index !== count - 1)
00825 description += ", ";
00826
00827 description += '\n';
00828 }
00829
00830 return description + ')';
00831 }
00832
00833
00841 - (CPArray)pathsMatchingExtensions:(CPArray)filterTypes
00842 {
00843 var index = 0,
00844 count = [self count],
00845 array = [];
00846
00847 for(; index < count; ++index)
00848 if (self[index].isa && [self[index] isKindOfClass:[CPString class]] && [filterTypes containsObject:[self[index] pathExtension]])
00849 array.push(self[index]);
00850
00851 return array;
00852 }
00853
00854
00860 - (void)setValue:(id)aValue forKey:(CPString)aKey
00861 {
00862 var i = 0,
00863 count = [self count];
00864
00865 for(; i < count; ++i)
00866 [self[i] setValue:aValue forKey:aKey];
00867 }
00868
00874 - (CPArray)valueForKey:(CPString)aKey
00875 {
00876 var i = 0,
00877 count = [self count],
00878 array = [];
00879
00880 for(; i < count; ++i)
00881 array.push([self[i] valueForKey:aKey]);
00882
00883 return array;
00884 }
00885
00886
00887
00892 - (id)copy
00893 {
00894 return slice(0);
00895 }
00896
00897 @end
00898
00899 @implementation CPArray(CPMutableArray)
00900
00901
00907 + (CPArray)arrayWithCapacity:(unsigned)aCapacity
00908 {
00909 return [[self alloc] initWithCapacity:aCapacity];
00910 }
00911
00916 - (id)initWithCapacity:(unsigned)aCapacity
00917 {
00918 return self;
00919 }
00920
00921
00926 - (void)addObject:(id)anObject
00927 {
00928 push(anObject);
00929 }
00930
00935 - (void)addObjectsFromArray:(CPArray)anArray
00936 {
00937 splice.apply(self, [length, 0].concat(anArray));
00938 }
00939
00945 - (void)insertObject:(id)anObject atIndex:(int)anIndex
00946 {
00947 splice(anIndex, 0, anObject);
00948 }
00949
00955 - (void)insertObjects:(CPArray)objects atIndexes:(CPIndexSet)indexes
00956 {
00957 var indexesCount = [indexes count],
00958 objectsCount = [objects count];
00959
00960 if(indexesCount !== objectsCount)
00961 [CPException raise:CPRangeException reason:"the counts of the passed-in array (" + objectsCount + ") and index set (" + indexesCount + ") must be identical."];
00962
00963 var lastIndex = [indexes lastIndex];
00964
00965 if(lastIndex >= [self count] + indexesCount)
00966 [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 + ")."];
00967
00968 var index = 0,
00969 currentIndex = [indexes firstIndex];
00970
00971 for (; index < objectsCount; ++index, currentIndex = [indexes indexGreaterThanIndex:currentIndex])
00972 [self insertObject:objects[index] atIndex:currentIndex];
00973 }
00974
00980 - (void)replaceObjectAtIndex:(int)anIndex withObject:(id)anObject
00981 {
00982 self[anIndex] = anObject;
00983 }
00984
00991 - (void)replaceObjectsAtIndexes:(CPIndexSet)anIndexSet withObjects:(CPArray)objects
00992 {
00993 var i = 0,
00994 index = [anIndexSet firstIndex];
00995
00996 while(index != CPNotFound)
00997 {
00998 [self replaceObjectAtIndex:index withObject:objects[i++]];
00999 index = [anIndexSet indexGreaterThanIndex:index];
01000 }
01001 }
01002
01011 - (void)replaceObjectsInRange:(CPRange)aRange withObjectsFromArray:(CPArray)anArray range:(CPRange)otherRange
01012 {
01013 if (!otherRange.location && otherRange.length == [anArray count])
01014 [self replaceObjectsInRange:aRange withObjectsFromArray:anArray];
01015 else
01016 splice.apply(self, [aRange.location, aRange.length].concat([anArray subarrayWithRange:otherRange]));
01017 }
01018
01026 - (void)replaceObjectsInRange:(CPRange)aRange withObjectsFromArray:(CPArray)anArray
01027 {
01028 splice.apply(self, [aRange.location, aRange.length].concat(anArray));
01029 }
01030
01035 - (void)setArray:(CPArray)anArray
01036 {
01037 if(self == anArray) return;
01038
01039 splice.apply(self, [0, length].concat(anArray));
01040 }
01041
01042
01046 - (void)removeAllObjects
01047 {
01048 splice(0, length);
01049 }
01050
01054 - (void)removeLastObject
01055 {
01056 pop();
01057 }
01058
01063 - (void)removeObject:(id)anObject
01064 {
01065 [self removeObject:anObject inRange:CPMakeRange(0, length)];
01066 }
01067
01073 - (void)removeObject:(id)anObject inRange:(CPRange)aRange
01074 {
01075 var index;
01076
01077 while ((index = [self indexOfObject:anObject inRange:aRange]) != CPNotFound)
01078 {
01079 [self removeObjectAtIndex:index];
01080 aRange = CPIntersectionRange(CPMakeRange(index, length - index), aRange);
01081 }
01082 }
01083
01088 - (void)removeObjectAtIndex:(int)anIndex
01089 {
01090 splice(anIndex, 1);
01091 }
01092
01097 - (void)removeObjectsAtIndexes:(CPIndexSet)anIndexSet
01098 {
01099 var index = [anIndexSet lastIndex];
01100
01101 while (index != CPNotFound)
01102 {
01103 [self removeObjectAtIndex:index];
01104 index = [anIndexSet indexLessThanIndex:index];
01105 }
01106 }
01107
01113 - (void)removeObjectIdenticalTo:(id)anObject
01114 {
01115 [self removeObjectIdenticalTo:anObject inRange:CPMakeRange(0, [self count])];
01116 }
01117
01125 - (void)removeObjectIdenticalTo:(id)anObject inRange:(CPRange)aRange
01126 {
01127 var index,
01128 count = [self count];
01129
01130 while ((index = [self indexOfObjectIdenticalTo:anObject inRange:aRange]) !== CPNotFound)
01131 {
01132 [self removeObjectAtIndex:index];
01133 aRange = CPIntersectionRange(CPMakeRange(index, (--count) - index), aRange);
01134 }
01135 }
01136
01141 - (void)removeObjectsInArray:(CPArray)anArray
01142 {
01143 var index = 0,
01144 count = [anArray count];
01145
01146 for (; index < count; ++index)
01147 [self removeObject:anArray[index]];
01148 }
01149
01154 - (void)removeObjectsInRange:(CPRange)aRange
01155 {
01156 splice(aRange.location, aRange.length);
01157 }
01158
01159
01165 - (void)exchangeObjectAtIndex:(unsigned)anIndex withObjectAtIndex:(unsigned)otherIndex
01166 {
01167 var temporary = self[anIndex];
01168 self[anIndex] = self[otherIndex];
01169 self[otherIndex] = temporary;
01170 }
01171
01172 - (CPArray)sortUsingDescriptors:(CPArray)descriptors
01173 {
01174 sort(function(lhs, rhs)
01175 {
01176 var i = 0,
01177 count = [descriptors count],
01178 result = CPOrderedSame;
01179
01180 while(i < count)
01181 if((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame)
01182 return result;
01183
01184 return result;
01185 });
01186 }
01187
01193 - (void)sortUsingFunction:(Function)aFunction context:(id)aContext
01194 {
01195 sort(function(lhs, rhs) { return aFunction(lhs, rhs, aContext); });
01196 }
01197
01202 - (void)sortUsingSelector:(SEL)aSelector
01203 {
01204 sort(function(lhs, rhs) { return objj_msgSend(lhs, aSelector, rhs); });
01205 }
01206
01207 @end
01208
01209 @implementation CPArray (CPCoding)
01210
01211 - (id)initWithCoder:(CPCoder)aCoder
01212 {
01213 return [aCoder decodeObjectForKey:@"CP.objects"];
01214 }
01215
01216 - (void)encodeWithCoder:(CPCoder)aCoder
01217 {
01218 [aCoder _encodeArrayOfObjects:self forKey:@"CP.objects"];
01219 }
01220
01221 @end
01222
01231 @implementation CPMutableArray : CPArray
01232
01233 @end
01234
01235 Array.prototype.isa = CPArray;
01236 [CPArray initialize];
01237