/FScriptFramework/FSNSMutableArray.m

https://github.com/DottedGecko/F-Script · Objective C · 334 lines · 264 code · 66 blank · 4 comment · 163 complexity · 538d484933ac0028ac24ab35c2d9d80b MD5 · raw file

  1. /* FSNSMutableArray.m Copyright (c) 2003-2009 Philippe Mougin. */
  2. /* This software is open source. See the license. */
  3. #import "FSNSMutableArray.h"
  4. #import "FSBooleanPrivate.h"
  5. #import "FSArray.h"
  6. #import "FSMiscTools.h"
  7. #import "FScriptFunctions.h"
  8. #import "NumberPrivate.h"
  9. #import "FSNSArrayPrivate.h"
  10. @implementation NSMutableArray(FSNSMutableArray)
  11. - (void)add:(id)elem
  12. {
  13. [self addObject:elem];
  14. }
  15. - (id)at:(id)index put:(id)elem
  16. {
  17. double ind;
  18. NSUInteger count = [self count];
  19. if (!index) FSExecError(@"index of an array must not be nil");
  20. if ([index isKindOfClass:[NSIndexSet class]])
  21. {
  22. NSMutableArray *newIndex = [FSArray array];
  23. NSUInteger currentIndex = [index firstIndex];
  24. while (currentIndex != NSNotFound)
  25. {
  26. [newIndex addObject:[NSNumber numberWithDouble:currentIndex]];
  27. currentIndex = [index indexGreaterThanIndex:currentIndex];
  28. }
  29. index = newIndex;
  30. }
  31. if ([index isKindOfClass:[NSNumber class]])
  32. {
  33. ind = [index doubleValue];
  34. if (ind < 0) FSExecError(@"index of an array must be a number greater or equal to 0");
  35. if (ind >= count) FSExecError(@"index of an array must be a number less than the size of the array");
  36. [self replaceObjectAtIndex:ind withObject:elem];
  37. }
  38. else if ([index isKindOfClass:[NSArray class]])
  39. {
  40. id elem_index;
  41. NSUInteger i = 0;
  42. NSUInteger j = 0;
  43. NSUInteger nb = [index count];
  44. NSUInteger elem_count = 0; // elem_count is initialized in order to avoid a false warning "might be used uninitialized"
  45. BOOL elemIsArray = [elem isKindOfClass:[NSArray class]];
  46. //if (![elem isKindOfClass:[NSArray class]])
  47. // FSExecError(@"method \"at:put:\", argument 1 is an array, argument 2 must be an array too");
  48. if (elemIsArray) elem_count = [elem count];
  49. while (i < nb && ![index objectAtIndex:i]) i++; // ignore the nil value
  50. if (i == nb)
  51. {
  52. if ((nb == count || nb == 0) && (!elemIsArray || elem_count == 0)) return elem;
  53. else FSExecError(@"invalid index");
  54. }
  55. elem_index = [index objectAtIndex:i];
  56. if ([elem_index isKindOfClass:[FSBoolean class]])
  57. {
  58. NSUInteger k,trueCount;
  59. if (nb != count) FSExecError(@"indexing with an array of boolean of bad size");
  60. if (elemIsArray)
  61. {
  62. for (k=i, trueCount=0; k<nb; k++)
  63. {
  64. elem_index = [index objectAtIndex:k];
  65. if (elem_index == fsTrue || (elem_index != fsFalse && [elem_index isKindOfClass:[FSBoolean class]] && [elem_index isTrue]))
  66. trueCount++;
  67. }
  68. if (elem_count < trueCount) FSExecError(@"method \"at:put:\", not enough elements in argument 2");
  69. else if (elem_count > trueCount) FSExecError(@"method \"at:put:\", too many elements in argument 2");
  70. }
  71. while (i < nb)
  72. {
  73. elem_index = [index objectAtIndex:i];
  74. if (elem_index == fsTrue || (elem_index != fsFalse && [elem_index isKindOfClass:[FSBoolean class]] && [elem_index isTrue]) )
  75. {
  76. [self replaceObjectAtIndex:i withObject:elemIsArray ? [elem objectAtIndex:j] : elem];
  77. j++;
  78. }
  79. else if (elem_index != fsFalse && ![elem_index isKindOfClass:[FSBoolean class]]) FSExecError(@"indexing with a mixed array");
  80. i++;
  81. while (i < nb && ![index objectAtIndex:i]) i++; // ignore the nil value
  82. }
  83. return elem;
  84. }
  85. else if ([elem_index isKindOfClass:[NSNumber class]])
  86. {
  87. NSUInteger k;
  88. if (elemIsArray && nb != elem_count) FSExecError(@"method \"at:put:\", argument 1 and argument 2 must be arrays of same size");
  89. for (k=i; k<nb; k++)
  90. {
  91. elem_index = [index objectAtIndex:k];
  92. if (![elem_index isKindOfClass:[NSNumber class]]) FSExecError(@"array indexing by a mixed array");
  93. ind = [elem_index doubleValue];
  94. if (ind < 0) FSExecError(@"index of an array must be a number greater or equal to 0");
  95. else if (ind >= count) FSExecError(@"index of an array must be a number less than the size of the array");
  96. }
  97. while (i < nb)
  98. {
  99. elem_index = [index objectAtIndex:i];
  100. ind = [elem_index doubleValue];
  101. [self replaceObjectAtIndex:ind withObject:elemIsArray ? [elem objectAtIndex:i] : elem];
  102. i++;
  103. while (i < nb && ![index objectAtIndex:i]) i++; // ignore the nil value
  104. }
  105. }
  106. else // elem_index is neither an NSNumber nor a FSBoolean
  107. FSExecError([NSString stringWithFormat:@"array indexing by an array containing %@", descriptionForFSMessage(elem_index)]);
  108. }
  109. else
  110. FSExecError([NSString stringWithFormat:@"array indexing by %@, number, array or index set expected", descriptionForFSMessage(index)]);
  111. return elem;
  112. }
  113. -(void)insert:(id)obj at:(NSNumber *)index
  114. {
  115. double ind;
  116. FSVerifClassArgs(@"insert:at:",2,obj,(id)nil,(NSInteger)1,index,NSNumberClass,(NSInteger)0);
  117. ind = [index doubleValue];
  118. if (ind < 0) FSExecError(@"argument 2 of method \"insert:at:\" must be a number greater or equal to 0");
  119. if (ind > [self count]) FSExecError(@"argument 2 of method \"insert:at:\" must be a number less or equal to the size of the array");
  120. if (ind != (NSInteger)ind) FSExecError(@"argument 2 of method \"insert:at:\" must be an integer");
  121. [self insertObject:obj atIndex:(NSUInteger)ind];
  122. return;
  123. }
  124. - (void)removeAt:(id)index
  125. {
  126. NSUInteger count = [self count];
  127. id indexSet;
  128. if (!index) FSExecError(@"index of an array must not be nil");
  129. if ([index isKindOfClass:[NSNumber class]])
  130. {
  131. double ind = [index doubleValue];
  132. if (ind < 0) FSExecError(@"argument of method \"removeAt:\" must be a number greater or equal to 0");
  133. if (ind >= count) FSExecError(@"argument of method \"removeAt:\" must be a number less than the size of the array");
  134. if (ind != (NSInteger)ind) FSExecError(@"argument of method \"removeAt:\" must be an integer");
  135. [self removeObjectAtIndex:(NSUInteger)ind];
  136. return;
  137. }
  138. else if ([index isKindOfClass:[NSArray class]])
  139. {
  140. NSUInteger nb = [index count];
  141. NSUInteger i = 0;
  142. indexSet = [NSMutableIndexSet indexSet];
  143. while (i < nb && ![index objectAtIndex:i]) i++; // ignore the nil value
  144. if (i == nb)
  145. {
  146. if (nb == count || nb == 0) return;
  147. else FSExecError(@"invalid index");
  148. }
  149. id elem_index = [index objectAtIndex:i];
  150. if ([elem_index isKindOfClass:[FSBoolean class]])
  151. {
  152. if (nb != count) FSExecError(@"indexing with an array of boolean of bad size");
  153. while (i < nb)
  154. {
  155. elem_index = [index objectAtIndex:i];
  156. if (elem_index == fsTrue || (elem_index != fsFalse && [elem_index isKindOfClass:[FSBoolean class]] && [elem_index isTrue]) )
  157. [indexSet addIndex:i];
  158. else if (elem_index != fsFalse && ![elem_index isKindOfClass:[FSBoolean class]])
  159. FSExecError(@"indexing with a mixed array");
  160. i++;
  161. while (i < nb && ![index objectAtIndex:i]) i++; // ignore the nil value
  162. }
  163. }
  164. else if ([elem_index isKindOfClass:[NSNumber class]])
  165. {
  166. NSUInteger k;
  167. double ind;
  168. for (k=i; k<nb; k++)
  169. {
  170. elem_index = [index objectAtIndex:k];
  171. if (![elem_index isKindOfClass:[NSNumber class]]) FSExecError(@"indexing with a mixed array");
  172. ind = [elem_index doubleValue];
  173. if (ind < 0) FSExecError(@"index of an array must be a number greater or equal to 0");
  174. else if (ind >= count) FSExecError(@"index of an array must be a number less than the size of the array");
  175. }
  176. while (i < nb)
  177. {
  178. elem_index = [index objectAtIndex:i];
  179. ind = [elem_index doubleValue];
  180. [indexSet addIndex:ind];
  181. i++;
  182. while (i < nb && ![index objectAtIndex:i]) i++; // ignore the nil value
  183. }
  184. }
  185. else // elem_index is neither an NSNumber nor a FSBoolean
  186. FSExecError([NSString stringWithFormat:@"indexing with an array containing %@",descriptionForFSMessage(elem_index)]);
  187. }
  188. else if ([index isKindOfClass:[NSIndexSet class]])
  189. {
  190. indexSet = index;
  191. }
  192. else
  193. FSExecError([NSString stringWithFormat:@"indexing by %@, number, array or index set expected", descriptionForFSMessage(index)]);
  194. NSUInteger currentIndex = [indexSet lastIndex];
  195. while (currentIndex != NSNotFound)
  196. {
  197. [self removeObjectAtIndex:currentIndex];
  198. currentIndex = [indexSet indexLessThanIndex:currentIndex];
  199. }
  200. }
  201. - (void)removeWhere:(NSArray *)booleans
  202. {
  203. NSUInteger count = [self count];
  204. Class FSBooleanClass = [FSBoolean class];
  205. if (!booleans) FSExecError(@"argument of method \"removeWhere:\" must not be nil");
  206. if (![booleans isKindOfClass:[NSArray class]]) FSExecError([NSString stringWithFormat:@"argument of method \"removeWhere:\" is %@. An array was expected", descriptionForFSMessage(booleans)]);
  207. if (count != [booleans count]) FSExecError(@"receiver and argument of method \"removeWhere:\" must be arrays of same size");
  208. for (NSUInteger i = 0; i < count; i++)
  209. {
  210. id boolean = [booleans objectAtIndex:i];
  211. if (boolean != fsFalse && boolean != fsTrue && boolean != nil && ![boolean isKindOfClass:FSBooleanClass])
  212. FSExecError(@"argument of method \"removeWhere:\" must be an array of booleans");
  213. }
  214. for (NSUInteger i = count; i > 0; i--)
  215. {
  216. id boolean = [booleans objectAtIndex:i-1];
  217. if (boolean == fsFalse || boolean == nil)
  218. continue;
  219. else if (boolean == fsTrue || ([boolean isKindOfClass:FSBooleanClass] && [boolean isTrue]))
  220. [self removeObjectAtIndex:i-1];
  221. }
  222. }
  223. - (void)setValue:(NSArray *)operand
  224. {
  225. VERIF_OP_NSARRAY(@"setValue:");
  226. [self setArray:operand];
  227. }
  228. - (FSArray *)where:(NSArray *)booleans put:(id)elem
  229. {
  230. NSUInteger count = [self count];
  231. BOOL elemIsArray = [elem isKindOfClass:[NSArray class]];
  232. Class FSBooleanClass = [FSBoolean class];
  233. NSUInteger trueCount = 0;
  234. if (!booleans) FSExecError(@"argument 1 of method \"where:put:\" must not be nil");
  235. if (![booleans isKindOfClass:[NSArray class]]) FSExecError([NSString stringWithFormat:@"argument 1 of method \"where:put:\" is %@. An array was expected", descriptionForFSMessage(booleans)]);
  236. if (count != [booleans count]) FSExecError(@"receiver and argument 1 of method \"where:put:\" must be arrays of same size");
  237. for (NSUInteger i = 0; i < count; i++)
  238. {
  239. id boolean = [booleans objectAtIndex:i];
  240. if (boolean == fsFalse || boolean == nil)
  241. continue;
  242. else if (boolean == fsTrue )
  243. trueCount++;
  244. else if ([boolean isKindOfClass:FSBooleanClass])
  245. {
  246. if ([boolean isTrue])
  247. trueCount++;
  248. }
  249. else
  250. FSExecError(@"argument 1 of method \"where:put:\" must be an array of booleans");
  251. }
  252. if (elemIsArray)
  253. {
  254. if ([elem count] < trueCount) FSExecError(@"argument 2 of method \"where:put:\" has not enough elements");
  255. else if ([elem count] > trueCount) FSExecError(@"argument 2 of method \"where:put:\" has too many elements");
  256. }
  257. for (NSUInteger i = 0, j = 0; i < count; i++)
  258. {
  259. id boolean = [booleans objectAtIndex:i];
  260. if (boolean == fsTrue || (boolean != fsFalse && [boolean isKindOfClass:FSBooleanClass] && [boolean isTrue]))
  261. {
  262. [self replaceObjectAtIndex:i withObject:elemIsArray ? [elem objectAtIndex:j] : elem];
  263. j++;
  264. }
  265. }
  266. return elem;
  267. }
  268. @end