/Foundation/NSArray/NSMutableArray.m

https://code.google.com/p/cocotron/ · Objective C · 503 lines · 367 code · 118 blank · 18 comment · 61 complexity · 6b75e3c6e35c49886646f69875a5bc29 MD5 · raw file

  1. /* Copyright (c) 2006-2007 Christopher J. W. Lloyd
  2. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
  3. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  4. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  5. #import <Foundation/NSArray.h>
  6. #import <Foundation/NSObjCRuntime.h>
  7. #import <Foundation/NSRaise.h>
  8. #import <Foundation/NSMutableArray_concrete.h>
  9. #import <Foundation/NSAutoreleasePool-private.h>
  10. #import <Foundation/NSPropertyListReader.h>
  11. #import <Foundation/NSPredicate.h>
  12. #import <Foundation/NSSortDescriptor.h>
  13. #import <Foundation/NSIndexSet.h>
  14. #import <Foundation/NSRaiseException.h>
  15. #include <string.h>
  16. #include <stdlib.h>
  17. @implementation NSMutableArray
  18. +allocWithZone:(NSZone *)zone {
  19. if(self==[NSMutableArray class])
  20. return NSAllocateObject([NSMutableArray_concrete class],0,zone);
  21. return NSAllocateObject(self,0,zone);
  22. }
  23. -initWithObjects:(id *)objects count:(NSUInteger)count {
  24. NSUInteger i;
  25. if((self=[self initWithCapacity:count])==nil)
  26. return nil;
  27. for(i=0;i<count;i++)
  28. [self addObject:objects[i]];
  29. return self;
  30. }
  31. -initWithCapacity:(NSUInteger)capacity {
  32. NSInvalidAbstractInvocation();
  33. return nil;
  34. }
  35. -copy {
  36. return [[NSArray allocWithZone:NULL] initWithArray:self];
  37. }
  38. -copyWithZone:(NSZone *)zone {
  39. return [[NSArray allocWithZone:zone] initWithArray:self];
  40. }
  41. -(Class)classForCoder {
  42. return [NSMutableArray class];
  43. }
  44. +array {
  45. if(self==[NSMutableArray class])
  46. return NSAutorelease(NSMutableArray_concreteNewWithCapacity(NULL,0));
  47. return [[[self allocWithZone:NULL] init] autorelease];
  48. }
  49. +arrayWithContentsOfFile:(NSString *)path {
  50. return [NSPropertyListReader arrayWithContentsOfFile:path];
  51. }
  52. +arrayWithObject:object {
  53. if(self==[NSMutableArray class])
  54. return NSAutorelease(NSMutableArray_concreteNew(NULL,&object,1));
  55. return [[[self allocWithZone:NULL]
  56. initWithObjects:&object count:1] autorelease];
  57. }
  58. +arrayWithCapacity:(NSUInteger)capacity {
  59. if(self==[NSMutableArray class])
  60. return NSAutorelease(NSMutableArray_concreteNewWithCapacity(NULL,capacity));
  61. return [[[self allocWithZone:NULL] initWithCapacity:capacity] autorelease];
  62. }
  63. +arrayWithObjects:first,... {
  64. NSUInteger i,count=0;
  65. id *objects=NULL;
  66. if(first!=nil){
  67. va_list arguments;
  68. va_start(arguments,first);
  69. count=1;
  70. while(va_arg(arguments,id)!=nil)
  71. count++;
  72. va_end(arguments);
  73. objects=__builtin_alloca(sizeof(id)*count);
  74. va_start(arguments,first);
  75. objects[0]=first;
  76. for(i=1;i<count;i++)
  77. objects[i]=va_arg(arguments,id);
  78. va_end(arguments);
  79. }
  80. if(self==[NSMutableArray class])
  81. return NSAutorelease(NSMutableArray_concreteNew(NULL,objects,count));
  82. return [[[self allocWithZone:NULL] initWithObjects:objects count:count] autorelease];
  83. }
  84. -(void)addObject:object {
  85. NSInvalidAbstractInvocation();
  86. }
  87. -(void)addObjectsFromArray:(NSArray *)other {
  88. NSUInteger i,count=[other count];
  89. for(i=0;i<count;i++)
  90. [self addObject:[other objectAtIndex:i]];
  91. }
  92. -(void)removeObjectAtIndex:(NSUInteger)index {
  93. NSInvalidAbstractInvocation();
  94. }
  95. -(void)removeAllObjects {
  96. NSInteger count=[self count];
  97. while(--count>=0)
  98. [self removeObjectAtIndex:count];
  99. }
  100. -(void)removeLastObject {
  101. [self removeObjectAtIndex:[self count]-1];
  102. }
  103. -(void)removeObject:object {
  104. NSInteger count=[self count];
  105. while(--count>=0){
  106. id check=[self objectAtIndex:count];
  107. if([check isEqual:object])
  108. [self removeObjectAtIndex:count];
  109. }
  110. }
  111. -(void)removeObject:object inRange:(NSRange)range {
  112. NSInteger pos=NSMaxRange(range);
  113. if(pos>[self count])
  114. NSRaiseException(NSRangeException,self,_cmd,@"range %@ beyond count %d",
  115. NSStringFromRange(range),[self count]);
  116. while(--pos>=range.location){
  117. id check=[self objectAtIndex:pos];
  118. if([check isEqual:object])
  119. [self removeObjectAtIndex:pos];
  120. }
  121. }
  122. -(void)removeObjectIdenticalTo:object {
  123. NSInteger count=[self count];
  124. while(--count>=0){
  125. id check=[self objectAtIndex:count];
  126. if(check==object)
  127. [self removeObjectAtIndex:count];
  128. }
  129. }
  130. -(void)removeObjectIdenticalTo:object inRange:(NSRange)range {
  131. NSInteger pos=NSMaxRange(range);
  132. if(pos>[self count])
  133. NSRaiseException(NSRangeException,self,_cmd,@"range %@ beyond count %d",
  134. NSStringFromRange(range),[self count]);
  135. while(--pos>=range.location){
  136. id check=[self objectAtIndex:pos];
  137. if(check==object)
  138. [self removeObjectAtIndex:pos];
  139. }
  140. }
  141. -(void)removeObjectsInRange:(NSRange)range {
  142. NSInteger pos=NSMaxRange(range);
  143. if(range.length==0)
  144. return;
  145. if(pos>[self count])
  146. NSRaiseException(NSRangeException,self,_cmd,@"range %@ beyond count %d",NSStringFromRange(range),[self count]);
  147. while(--pos>=range.location && pos>=0)
  148. [self removeObjectAtIndex:pos];
  149. }
  150. static inline void memswp(void* a, void* b, size_t width)
  151. {
  152. if (width == sizeof(void*)) {
  153. // Optimization for pointer sized swap:
  154. void* tmp;
  155. tmp = *(void**)a;
  156. *(void**)a = *(void**)b;
  157. *(void**)b = tmp;
  158. return;
  159. }
  160. // default uses memcpy:
  161. char tmp[width];
  162. memcpy(tmp, a, width);
  163. memcpy(a, b, width);
  164. memcpy(b, tmp, width);
  165. }
  166. // iterative mergesort based on
  167. // http://www.inf.fh-flensburg.de/lang/algorithmen/sortieren/merge/mergiter.htm
  168. static int mergesortL(void *base, size_t nel, size_t width, int (*compar)(const
  169. void *, const void *))
  170. {
  171. NSInteger h, i, j, k, l, m, n = nel;
  172. void* A; // points to an element
  173. void* B = NSZoneMalloc(NULL,(n/2 + 1) * width); // points to a temp array
  174. for (h = 1; h < n; h += h) {
  175. for (m = n - 1 - h; m >= 0; m -= h + h) {
  176. l = m - h + 1;
  177. if (l < 0)
  178. l = 0;
  179. // Copy first half of the array into helper B:
  180. j = m+1;
  181. memcpy(B, base + (l * width), (j-l) * width);
  182. for (i = 0, k = l; k < j && j <= m + h; k++) {
  183. A = base + (width * j); // A = [self objectAtIndex:j];
  184. if (compar(A, B + (i * width)) > 0) {
  185. memswp(base+(k*width), B+(i*width), width); i+=1;
  186. } else {
  187. memswp(base+(k*width), A, width); j+=1;
  188. }
  189. }
  190. while (k < j) // This loop could be optimized
  191. memswp(base+(k++*width), B+(i++*width), width);
  192. }
  193. }
  194. free(B);
  195. return 0;
  196. }
  197. static int _nsmutablearraycompareindices(const void* v1, const void* v2)
  198. {
  199. int i1 = (*(int*)v1);
  200. int i2 = (*(int*)v2);
  201. int result = i1 == i2 ? 0 : (i1<i2 ? -1 : 1);
  202. return result;
  203. }
  204. -(void) removeObjectsFromIndices: (NSUInteger*) indices
  205. numIndices: (NSUInteger) count
  206. {
  207. if (count) {
  208. NSUInteger lastIndex = NSNotFound;
  209. NSUInteger sortedIndices[count];
  210. NSInteger i;
  211. memcpy(sortedIndices, indices, sizeof(NSUInteger)*count);
  212. mergesortL(sortedIndices, sizeof(NSUInteger), count,
  213. &_nsmutablearraycompareindices);
  214. for(i=count-1;i>=0;i--) {
  215. NSUInteger index = sortedIndices[i];
  216. if (index!=lastIndex) {
  217. [self removeObjectAtIndex: index];
  218. }
  219. lastIndex = index;
  220. }
  221. }
  222. }
  223. -(void)removeObjectsInArray:(NSArray *)other {
  224. NSInteger count=[other count];
  225. while(--count>=0){
  226. id object=[other objectAtIndex:count];
  227. [self removeObject:object];
  228. }
  229. }
  230. -(void)removeObjectsAtIndexes:(NSIndexSet *)indexes {
  231. NSUInteger index = [indexes lastIndex];
  232. while(index != NSNotFound)
  233. {
  234. [self removeObjectAtIndex:index];
  235. index = [indexes indexLessThanIndex:index];
  236. }
  237. }
  238. -(void)insertObject:object atIndex:(NSUInteger)index {
  239. NSInvalidAbstractInvocation();
  240. }
  241. -(void)insertObjects:(NSArray *)objects atIndexes:(NSIndexSet *)indexes {
  242. NSInteger i;
  243. NSInteger index = [indexes firstIndex];
  244. for(i = 0; i < [objects count]; i++)
  245. {
  246. [self insertObject:[objects objectAtIndex:i] atIndex:index];
  247. index = [indexes indexGreaterThanIndex:index];
  248. }
  249. }
  250. -(void)setArray:(NSArray *)other {
  251. [self removeAllObjects];
  252. [self addObjectsFromArray:other];
  253. }
  254. -(void)replaceObjectAtIndex:(NSUInteger)index withObject:object {
  255. NSInvalidAbstractInvocation();
  256. }
  257. -(void)replaceObjectsInRange:(NSRange)range
  258. withObjectsFromArray:(NSArray *)array {
  259. [self replaceObjectsInRange:range withObjectsFromArray:array range:NSMakeRange(0,[array count])];
  260. }
  261. -(void)replaceObjectsInRange:(NSRange)range
  262. withObjectsFromArray:(NSArray *)array range:(NSRange)arrayRange {
  263. NSInteger i;
  264. for(i=0;i<range.length && i<arrayRange.length;i++)
  265. [self replaceObjectAtIndex:range.location+i withObject:[array objectAtIndex:arrayRange.location+i]];
  266. if(i<range.length)
  267. [self removeObjectsInRange:NSMakeRange(range.location+i,range.length-i)];
  268. if(i<arrayRange.length){
  269. for(;i<arrayRange.length;i++)
  270. [self insertObject:[array objectAtIndex:arrayRange.location+i] atIndex:range.location+i];
  271. }
  272. }
  273. -(void)replaceObjectsAtIndexes:(NSIndexSet *)indexes withObjects:(NSArray *)objects
  274. {
  275. NSUInteger index = [indexes firstIndex];
  276. for (id object in objects)
  277. {
  278. [self replaceObjectAtIndex:index withObject:object];
  279. index = [indexes indexGreaterThanIndex:index];
  280. }
  281. }
  282. -(void)exchangeObjectAtIndex:(NSUInteger)index withObjectAtIndex:(NSUInteger)other {
  283. id object=[[self objectAtIndex:index] retain];
  284. id otherObject=[self objectAtIndex:other];
  285. [self replaceObjectAtIndex:index withObject:otherObject];
  286. [self replaceObjectAtIndex:other withObject:object];
  287. [object release];
  288. }
  289. static NSInteger selectorCompare(id object1,id object2,void *userData){
  290. SEL selector=userData;
  291. return (NSComparisonResult)[object1 performSelector:selector withObject:object2];
  292. }
  293. -(void)sortUsingSelector:(SEL)selector {
  294. [self sortUsingFunction:selectorCompare context:(void *)selector];
  295. }
  296. // iterative mergesort based on
  297. // http://www.inf.fh-flensburg.de/lang/algorithmen/sortieren/merge/mergiter.htm ...
  298. // ... using a comparison function
  299. -(void)sortUsingFunction:(NSInteger (*)(id, id, void *))compare context:(void *)context
  300. {
  301. NSInteger h, i, j, k, l, m, n = [self count];
  302. id A, *B = NSZoneMalloc(NULL,(n/2 + 1) * sizeof(id));
  303. // to prevent retain counts from temporarily hitting zero.
  304. for(i=0;i<n;i++)
  305. [[self objectAtIndex:i] retain];
  306. for (h = 1; h < n; h += h)
  307. {
  308. for (m = n - 1 - h; m >= 0; m -= h + h)
  309. {
  310. l = m - h + 1;
  311. if (l < 0)
  312. l = 0;
  313. for (i = 0, j = l; j <= m; i++, j++)
  314. B[i] = [self objectAtIndex:j];
  315. for (i = 0, k = l; k < j && j <= m + h; k++)
  316. {
  317. A = [self objectAtIndex:j];
  318. if (compare(A, B[i], context) == NSOrderedDescending)
  319. [self replaceObjectAtIndex:k withObject:B[i++]];
  320. else
  321. {
  322. [self replaceObjectAtIndex:k withObject:A];
  323. j++;
  324. }
  325. }
  326. while (k < j)
  327. [self replaceObjectAtIndex:k++ withObject:B[i++]];
  328. }
  329. }
  330. for(i=0;i<n;i++)
  331. [[self objectAtIndex:i] release];
  332. free(B);
  333. }
  334. static NSComparisonResult compareObjectsUsingDescriptors(id A, id B, void *descriptorsX) {
  335. NSArray *descriptors=(id)descriptorsX;
  336. NSComparisonResult result=NSOrderedSame;
  337. NSInteger i,count=[descriptors count];
  338. for(i=0;i<count;i++){
  339. if((result=[[descriptors objectAtIndex:i++] compareObject:A toObject:B])!=NSOrderedSame)
  340. break;
  341. }
  342. return result;
  343. }
  344. - (void)sortUsingDescriptors:(NSArray *)descriptors {
  345. [self sortUsingFunction:compareObjectsUsingDescriptors context:descriptors];
  346. }
  347. -(NSUInteger)_insertObject:(id)obj inArraySortedByDescriptors:(NSArray*)descriptors {
  348. NSUInteger start=0;
  349. NSUInteger end=[self count];
  350. NSUInteger mid=0;
  351. // do a binary search to find an object NSOrderedSame
  352. while (mid = (start + end) / 2, start < end) {
  353. id other=[self objectAtIndex:mid];
  354. NSComparisonResult res=compareObjectsUsingDescriptors(obj, other, descriptors);
  355. if(res==NSOrderedAscending) {
  356. end = mid;
  357. }
  358. else if (res==NSOrderedDescending) {
  359. start = mid + 1;
  360. }
  361. else {
  362. [self insertObject:obj atIndex:mid];
  363. return mid;
  364. }
  365. }
  366. // none found; current position must be where we should be at
  367. [self insertObject:obj atIndex:mid];
  368. return mid;
  369. }
  370. -(void)filterUsingPredicate:(NSPredicate *)predicate {
  371. if(predicate==nil){
  372. [NSException raise:NSInvalidArgumentException format:@"-[%@ %s] predicate is nil",isa,_cmd];
  373. return;
  374. }
  375. NSInteger count=[self count];
  376. while(--count>=0){
  377. id check=[self objectAtIndex:count];
  378. if(![predicate evaluateWithObject:check])
  379. [self removeObjectAtIndex:count];
  380. }
  381. }
  382. @end