API  0.9.7
 All Classes Files Functions Variables Macros Groups Pages
CPMutableArray.j
Go to the documentation of this file.
1 
2 
3 @class CPIndexSet
4 
13 @implementation CPMutableArray : CPArray
14 {
15  id __doxygen__;
16 }
17 
18 // Creating arrays
24 + (CPArray)arrayWithCapacity:(CPUInteger)aCapacity
25 {
26  return [[self alloc] initWithCapacity:aCapacity];
27 }
28 
33 /*- (id)initWithCapacity:(CPUInteger)aCapacity
34 {
35  return self;
36 }*/
37 
38 // Adding and replacing objects
43 - (void)addObject:(id)anObject
44 {
45  _CPRaiseInvalidAbstractInvocation(self, _cmd);
46 }
47 
52 - (void)addObjectsFromArray:(CPArray)anArray
53 {
54  var index = 0,
55  count = [anArray count];
56 
57  for (; index < count; ++index)
58  [self addObject:[anArray objectAtIndex:index]];
59 }
60 
66 - (void)insertObject:(id)anObject atIndex:(CPUInteger)anIndex
67 {
68  _CPRaiseInvalidAbstractInvocation(self, _cmd);
69 }
70 
76 - (void)insertObjects:(CPArray)objects atIndexes:(CPIndexSet)indexes
77 {
78  var indexesCount = [indexes count],
79  objectsCount = [objects count];
80 
81  if (indexesCount !== objectsCount)
82  [CPException raise:CPRangeException reason:"the counts of the passed-in array (" + objectsCount + ") and index set (" + indexesCount + ") must be identical."];
83 
84  var lastIndex = [indexes lastIndex];
85 
86  if (lastIndex >= [self count] + indexesCount)
87  [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 + ")."];
88 
89  var index = 0,
90  currentIndex = [indexes firstIndex];
91 
92  for (; index < objectsCount; ++index, currentIndex = [indexes indexGreaterThanIndex:currentIndex])
93  [self insertObject:[objects objectAtIndex:index] atIndex:currentIndex];
94 }
95 
96 - (CPUInteger)insertObject:(id)anObject inArraySortedByDescriptors:(CPArray)descriptors
97 {
98  var index,
99  count = [descriptors count];
100 
101  if (count)
102  index = [self indexOfObject:anObject
103  inSortedRange:nil
104  options:CPBinarySearchingInsertionIndex
105  usingComparator:function(lhs, rhs)
106  {
107  var index = 0,
108  result = CPOrderedSame;
109 
110  while (index < count && ((result = [[descriptors objectAtIndex:index] compareObject:lhs withObject:rhs]) === CPOrderedSame))
111  ++index;
112 
113  return result;
114  }];
115 
116  else
117  index = [self count];
118 
119  [self insertObject:anObject atIndex:index];
120 
121  return index;
122 }
123 
129 - (void)replaceObjectAtIndex:(CPUInteger)anIndex withObject:(id)anObject
130 {
131  _CPRaiseInvalidAbstractInvocation(self, _cmd);
132 }
133 
140 - (void)replaceObjectsAtIndexes:(CPIndexSet)indexes withObjects:(CPArray)objects
141 {
142  var i = 0,
143  index = [indexes firstIndex];
144 
145  while (index !== CPNotFound)
146  {
147  [self replaceObjectAtIndex:index withObject:[objects objectAtIndex:i++]];
148  index = [indexes indexGreaterThanIndex:index];
149  }
150 }
151 
160 - (void)replaceObjectsInRange:(CPRange)aRange withObjectsFromArray:(CPArray)anArray range:(CPRange)otherRange
161 {
162  [self removeObjectsInRange:aRange];
163 
164  if (otherRange && (otherRange.location !== 0 || otherRange.length !== [anArray count]))
165  anArray = [anArray subarrayWithRange:otherRange];
166 
167  var indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(aRange.location, [anArray count])];
168 
169  [self insertObjects:anArray atIndexes:indexes];
170 }
171 
179 - (void)replaceObjectsInRange:(CPRange)aRange withObjectsFromArray:(CPArray)anArray
180 {
181  [self replaceObjectsInRange:aRange withObjectsFromArray:anArray range:nil];
182 }
183 
188 - (void)setArray:(CPArray)anArray
189 {
190  if (self === anArray)
191  return;
192 
193  [self removeAllObjects];
194  [self addObjectsFromArray:anArray];
195 }
196 
197 // Removing Objects
201 - (void)removeAllObjects
202 {
203  while ([self count])
204  [self removeLastObject];
205 }
206 
210 - (void)removeLastObject
211 {
212  _CPRaiseInvalidAbstractInvocation(self, _cmd);
213 }
214 
219 - (void)removeObject:(id)anObject
220 {
221  [self removeObject:anObject inRange:CPMakeRange(0, [self count])];
222 }
223 
229 - (void)removeObject:(id)anObject inRange:(CPRange)aRange
230 {
231  var index;
232 
233  while ((index = [self indexOfObject:anObject inRange:aRange]) != CPNotFound)
234  {
235  [self removeObjectAtIndex:index];
236  aRange = CPIntersectionRange(CPMakeRange(index, [self count] - index), aRange);
237  }
238 }
239 
244 - (void)removeObjectAtIndex:(CPUInteger)anIndex
245 {
246  _CPRaiseInvalidAbstractInvocation(self, _cmd);
247 }
248 
253 - (void)removeObjectsAtIndexes:(CPIndexSet)anIndexSet
254 {
255  var index = [anIndexSet lastIndex];
256 
257  while (index !== CPNotFound)
258  {
259  [self removeObjectAtIndex:index];
260  index = [anIndexSet indexLessThanIndex:index];
261  }
262 }
263 
269 - (void)removeObjectIdenticalTo:(id)anObject
270 {
271  [self removeObjectIdenticalTo:anObject inRange:CPMakeRange(0, [self count])];
272 }
273 
281 - (void)removeObjectIdenticalTo:(id)anObject inRange:(CPRange)aRange
282 {
283  var index,
284  count = [self count];
285 
286  while ((index = [self indexOfObjectIdenticalTo:anObject inRange:aRange]) !== CPNotFound)
287  {
288  [self removeObjectAtIndex:index];
289  aRange = CPIntersectionRange(CPMakeRange(index, (--count) - index), aRange);
290  }
291 }
292 
297 - (void)removeObjectsInArray:(CPArray)anArray
298 {
299  var index = 0,
300  count = [anArray count];
301 
302  for (; index < count; ++index)
303  [self removeObject:[anArray objectAtIndex:index]];
304 }
305 
310 - (void)removeObjectsInRange:(CPRange)aRange
311 {
312  var index = aRange.location,
313  count = CPMaxRange(aRange);
314 
315  while (count-- > index)
316  [self removeObjectAtIndex:index];
317 }
318 
319 // Rearranging objects
325 - (void)exchangeObjectAtIndex:(CPUInteger)anIndex withObjectAtIndex:(CPUInteger)otherIndex
326 {
327  if (anIndex === otherIndex)
328  return;
329 
330  var temporary = [self objectAtIndex:anIndex];
331 
332  [self replaceObjectAtIndex:anIndex withObject:[self objectAtIndex:otherIndex]];
333  [self replaceObjectAtIndex:otherIndex withObject:temporary];
334 }
335 
336 - (void)sortUsingDescriptors:(CPArray)descriptors
337 {
338  var i = [descriptors count],
339  jsDescriptors = [];
340 
341  // Revert the order of the descriptors
342  while (i--)
343  {
344  var d = [descriptors objectAtIndex:i];
345  [jsDescriptors addObject:{ "k": [d key], "a": [d ascending], "s": [d selector]}];
346  }
347  sortArrayUsingJSDescriptors(self, jsDescriptors);
348 }
349 
355 - (void)sortUsingFunction:(Function)aFunction context:(id)aContext
356 {
357  sortArrayUsingFunction(self, aFunction, aContext);
358 }
359 
364 - (void)sortUsingSelector:(SEL)aSelector
365 {
366  sortArrayUsingFunction(self, selectorCompare, aSelector);
367 }
368 
369 @end
370 
371 @implementation CPArray (CPMutableCopying)
372 
373 - (id)mutableCopy
374 {
375  var r = [CPMutableArray new];
376  [r addObjectsFromArray:self];
377  return r;
378 }
379 
380 @end
381 
382 var selectorCompare = function(object1, object2, selector)
383 {
384  return [object1 performSelector:selector withObject:object2];
385 };
386 
387 var sortArrayUsingFunction = function(array, aFunction, aContext)
388 {
389  var h,
390  i,
391  j,
392  k,
393  l,
394  m,
395  n = array.length,
396  o;
397 
398  var A,
399  B = [];
400 
401  for (h = 1; h < n; h += h)
402  {
403  for (m = n - 1 - h; m >= 0; m -= h + h)
404  {
405  l = m - h + 1;
406  if (l < 0)
407  l = 0;
408 
409  for (i = 0, j = l; j <= m; i++, j++)
410  B[i] = array[j];
411 
412  for (i = 0, k = l; k < j && j <= m + h; k++)
413  {
414  A = array[j];
415  o = aFunction(A, B[i], aContext);
416 
417  if (o >= 0)
418  array[k] = B[i++];
419  else
420  {
421  array[k] = A;
422  j++;
423  }
424  }
425 
426  while (k < j)
427  array[k++] = B[i++];
428  }
429  }
430 }
431 
432 // This is for speed
433 var CPMutableArrayNull = [CPNull null];
434 
435 // Observe that the sort descriptors has the reversed order by the caller
436 var sortArrayUsingJSDescriptors = function(a, d)
437 {
438  var h,
439  i,
440  j,
441  k,
442  l,
443  m,
444  n = a.length,
445  dl = d.length - 1,
446  o,
447  c = {};
448 
449  var A,
450  B = [],
451  C1,
452  C2,
453  cn,
454  aUID,
455  bUID,
456  key,
457  dd,
458  value1,
459  value2,
460  cpNull = CPMutableArrayNull;
461 
462  if (dl < 0)
463  return;
464 
465  for (h = 1; h < n; h += h)
466  {
467  for (m = n - 1 - h; m >= 0; m -= h + h)
468  {
469  l = m - h + 1;
470 
471  if (l < 0)
472  l = 0;
473 
474  for (i = 0, j = l; j <= m; i++, j++)
475  B[i] = a[j];
476 
477  for (i = 0, k = l; k < j && j <= m + h; k++)
478  {
479  A = a[j];
480  aUID = A._UID;
481 
482  if (!aUID)
483  aUID = [A UID];
484 
485  C1 = c[aUID];
486 
487  if (!C1)
488  {
489  C1 = {};
490  cn = dl;
491 
492  do
493  {
494  key = d[cn].k;
495  C1[key] = [A valueForKeyPath:key];
496  } while (cn--)
497 
498  c[aUID] = C1;
499  }
500 
501  bUID = B[i]._UID;
502 
503  if (!bUID)
504  bUID = [B[i] UID];
505 
506  C2 = c[bUID];
507 
508  if (!C2)
509  {
510  C2 = {};
511  cn = dl;
512 
513  do
514  {
515  key = d[cn].k;
516  C2[key] = [B[i] valueForKeyPath:key];
517  } while (cn--)
518 
519  c[bUID] = C2;
520  }
521 
522  cn = dl;
523 
524  do
525  {
526  dd = d[cn];
527  key = dd.k;
528  value1 = C1[key];
529  value2 = C2[key];
530  if (value1 === nil || value1 === cpNull)
531  o = value2 === nil || value2 === cpNull ? CPOrderedSame : CPOrderedAscending;
532  else
533  o = value2 === nil || value2 === cpNull ? CPOrderedDescending : objj_msgSend(value1, dd.s, value2);
534 
535  if (o && !dd.a)
536  o = -o;
537  } while (cn-- && o == CPOrderedSame)
538 
539  if (o >= 0)
540  a[k] = B[i++];
541  else
542  {
543  a[k] = A;
544  j++;
545  }
546  }
547 
548  while (k < j)
549  a[k++] = B[i++];
550  }
551  }
552 }