1 28 package org.jruby; 29 30 import java.util.Comparator ; 31 import java.util.List ; 32 import java.util.ArrayList ; 33 import java.util.Iterator ; 34 import java.util.Map ; 35 import java.util.HashMap ; 36 import java.util.Arrays ; 37 import java.util.Collections ; 38 39 import org.jruby.runtime.Arity; 40 import org.jruby.runtime.Block; 41 import org.jruby.runtime.CallBlock; 42 import org.jruby.runtime.BlockCallback; 43 import org.jruby.runtime.ThreadContext; 44 import org.jruby.runtime.Visibility; 45 import org.jruby.runtime.builtin.IRubyObject; 46 47 import org.jruby.internal.runtime.methods.MultiStub; 48 import org.jruby.internal.runtime.methods.MultiStubMethod; 49 50 53 public class RubyEnumerable { 54 private static class ListAddBlockCallback implements BlockCallback { 55 private final List arr = new ArrayList (); 56 private final Ruby runtime; 57 public ListAddBlockCallback(Ruby runtime) { 58 this.runtime = runtime; 59 } 60 public IRubyObject call(ThreadContext context, IRubyObject[] iargs, IRubyObject iself, Block block) { 61 if(iargs.length > 1) { 62 arr.add(runtime.newArrayNoCopy(iargs)); 63 } else { 64 arr.add(iargs[0]); 65 } 66 67 return runtime.getNil(); 68 } 69 public List getList() { 70 return arr; 71 } 72 } 73 74 private static class RubyFirstArrayComparator implements Comparator { 75 public int compare(Object o1, Object o2) { 76 IRubyObject obj1 = ((IRubyObject[])o1)[0]; 77 return RubyFixnum.fix2int((((IRubyObject[])o1)[0].callMethod(obj1.getRuntime().getCurrentContext(),"<=>", ((IRubyObject[])o2)[0]))); 78 } 79 } 80 private static class RubyYieldComparator implements Comparator { 81 private final ThreadContext context; 82 private final Ruby runtime; 83 private final Block block; 84 public RubyYieldComparator(ThreadContext context, Block block) { 85 this.context = context; 86 this.runtime = context.getRuntime(); 87 this.block = block; 88 } 89 public int compare(Object o1, Object o2) { 90 return RubyFixnum.fix2int(context.yield(runtime.newArray((IRubyObject)o1,(IRubyObject)o2), block)); 91 } 92 } 93 94 public static IRubyObject callEach(ThreadContext context, IRubyObject self, RubyModule module, BlockCallback bc) { 95 return self.callMethod(context, "each", new CallBlock(self,module,Arity.noArguments(),bc,context)); 96 } 97 98 public static List eachToList(ThreadContext context, IRubyObject self, RubyModule module) { 99 ListAddBlockCallback ladc = new ListAddBlockCallback(context.getRuntime()); 100 callEach(context,self,module,ladc); 101 return ladc.getList(); 102 } 103 104 105 106 public static class RubyEnumerableStub0 implements MultiStub { 107 public static RubyEnumerableStub0 createStub(final RubyModule recv) { 108 return new RubyEnumerableStub0(recv); 109 } 110 public final MultiStubMethod to_a; 111 public final MultiStubMethod sort; 112 public final MultiStubMethod sort_by; 113 public final MultiStubMethod grep; 114 public final MultiStubMethod detect; 115 public final MultiStubMethod select; 116 public final MultiStubMethod reject; 117 public final MultiStubMethod collect; 118 public final MultiStubMethod inject; 119 public final MultiStubMethod partition; 120 121 private final RubyModule module; 122 123 private RubyEnumerableStub0(final RubyModule recv) { 124 this.module = recv; 125 this.to_a = new MultiStubMethod(RubyEnumerableStub0.this,0,recv,Arity.noArguments(), Visibility.PUBLIC); 126 this.sort = new MultiStubMethod(RubyEnumerableStub0.this,1,recv,Arity.noArguments(), Visibility.PUBLIC); 127 this.sort_by = new MultiStubMethod(RubyEnumerableStub0.this,2,recv,Arity.noArguments(), Visibility.PUBLIC); 128 this.grep = new MultiStubMethod(RubyEnumerableStub0.this,3,recv,Arity.noArguments(), Visibility.PUBLIC); 129 this.detect = new MultiStubMethod(RubyEnumerableStub0.this,4,recv,Arity.noArguments(), Visibility.PUBLIC); 130 this.select = new MultiStubMethod(RubyEnumerableStub0.this,5,recv,Arity.noArguments(), Visibility.PUBLIC); 131 this.reject = new MultiStubMethod(RubyEnumerableStub0.this,6,recv,Arity.noArguments(), Visibility.PUBLIC); 132 this.collect = new MultiStubMethod(RubyEnumerableStub0.this,7,recv,Arity.noArguments(), Visibility.PUBLIC); 133 this.inject = new MultiStubMethod(RubyEnumerableStub0.this,8,recv,Arity.noArguments(), Visibility.PUBLIC); 134 this.partition = new MultiStubMethod(RubyEnumerableStub0.this,9,recv,Arity.noArguments(), Visibility.PUBLIC); 135 } 136 137 public IRubyObject method0(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 138 return context.getRuntime().newArray(eachToList(context,self,module)); 140 } 141 public IRubyObject method1(final ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 142 if (!block.isGiven()) return self.callMethod(context, "to_a").callMethod(context, "sort"); 144 145 final List arr = eachToList(context, self, module); 146 Collections.sort(arr, new RubyYieldComparator(context, block)); 147 148 return context.getRuntime().newArray(arr); 149 } 150 public IRubyObject method2(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 151 List result = eachToList(context,self,module); 153 IRubyObject[][] secResult = new IRubyObject[result.size()][2]; 154 int ix = 0; 155 for(Iterator iter = result.iterator();iter.hasNext();ix++) { 156 IRubyObject iro = (IRubyObject)iter.next(); 157 secResult[ix][0] = context.yield(iro, block); 158 secResult[ix][1] = iro; 159 } 160 Arrays.sort(secResult, new RubyFirstArrayComparator()); 161 IRubyObject[] result2 = new IRubyObject[secResult.length]; 162 for(int i=0,j=result2.length;i<j;i++) { 163 result2[i] = secResult[i][1]; 164 } 165 return context.getRuntime().newArrayNoCopy(result2); 166 } 167 public IRubyObject method3(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 168 self.checkArgumentCount(args,1,1); 170 List arr = eachToList(context,self,module); 171 List result = new ArrayList (); 172 IRubyObject pattern = args[0]; 173 if (!block.isGiven()) { 174 for (Iterator iter = arr.iterator();iter.hasNext();) { 175 IRubyObject item = (IRubyObject)iter.next(); 176 if (pattern.callMethod(context,"===", item).isTrue()) { 177 result.add(item); 178 } 179 } 180 } else { 181 for (Iterator iter = arr.iterator();iter.hasNext();) { 182 IRubyObject item = (IRubyObject)iter.next(); 183 if (pattern.callMethod(context,"===", item).isTrue()) { 184 result.add(context.yield(item, block)); 185 } 186 } 187 } 188 return context.getRuntime().newArray(result); 189 } 190 public IRubyObject method4(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 191 List arr = eachToList(context,self,module); 193 for(Iterator iter = arr.iterator();iter.hasNext();) { 194 IRubyObject element = (IRubyObject)iter.next(); 195 if(context.yield(element, block).isTrue()) { 196 return element; 197 } 198 } 199 if(args.length > 0 && args[0] instanceof RubyProc) { 200 return ((RubyProc)args[0]).call(new IRubyObject[0]); 201 } 202 return context.getRuntime().getNil(); 203 } 204 public IRubyObject method5(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 205 List arr = eachToList(context,self,module); 207 List result = new ArrayList (arr.size()); 208 for(Iterator iter = arr.iterator();iter.hasNext();) { 209 IRubyObject element = (IRubyObject)iter.next(); 210 if(context.yield(element, block).isTrue()) { 211 result.add(element); 212 } 213 } 214 return context.getRuntime().newArray(result); 215 } 216 public IRubyObject method6(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 217 List arr = eachToList(context,self,module); 219 List result = new ArrayList (arr.size()); 220 for(Iterator iter = arr.iterator();iter.hasNext();) { 221 IRubyObject element = (IRubyObject)iter.next(); 222 if(!context.yield(element, block).isTrue()) { 223 result.add(element); 224 } 225 } 226 return context.getRuntime().newArray(result); 227 } 228 public IRubyObject method7(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 229 List arr = eachToList(context,self,module); 231 IRubyObject[] result = new IRubyObject[arr.size()]; 232 if (block.isGiven()) { 233 int i=0; 234 for (Iterator iter = arr.iterator();iter.hasNext();) { 235 result[i++] = context.yield((IRubyObject)iter.next(), block); 236 } 237 } else { 238 int i=0; 239 for (Iterator iter = arr.iterator();iter.hasNext();) { 240 result[i++] = (IRubyObject)iter.next(); 241 } 242 } 243 return context.getRuntime().newArrayNoCopy(result); 244 } 245 public IRubyObject method8(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 246 IRubyObject result = null; 248 if(args.length > 0) { 249 result = args[0]; 250 } 251 List arr = eachToList(context,self,module); 252 for(Iterator iter = arr.iterator();iter.hasNext();) { 253 IRubyObject item = (IRubyObject)iter.next(); 254 if(result == null) { 255 result = item; 256 } else { 257 result = context.yield(context.getRuntime().newArray(result,item), block); 258 } 259 } 260 if(null == result) { 261 return context.getRuntime().getNil(); 262 } 263 return result; 264 } 265 public IRubyObject method9(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 266 List arr = eachToList(context,self,module); 268 List arr_true = new ArrayList (arr.size()/2); 269 List arr_false = new ArrayList (arr.size()/2); 270 for(Iterator iter = arr.iterator();iter.hasNext();) { 271 IRubyObject item = (IRubyObject)iter.next(); 272 if(context.yield(item, block).isTrue()) { 273 arr_true.add(item); 274 } else { 275 arr_false.add(item); 276 } 277 } 278 return context.getRuntime().newArray(context.getRuntime().newArray(arr_true),context.getRuntime().newArray(arr_false)); 279 } 280 } 281 282 public static class RubyEnumerableStub1 implements MultiStub { 283 public static RubyEnumerableStub1 createStub(final RubyModule recv) { 284 return new RubyEnumerableStub1(recv); 285 } 286 public final MultiStubMethod each_with_index; 287 public final MultiStubMethod include_p; 288 public final MultiStubMethod max; 289 public final MultiStubMethod min; 290 public final MultiStubMethod all_p; 291 public final MultiStubMethod any_p; 292 public final MultiStubMethod zip; 293 public final MultiStubMethod group_by; 294 295 private final RubyModule module; 296 297 private RubyEnumerableStub1(final RubyModule recv) { 298 this.module = recv; 299 this.each_with_index = new MultiStubMethod(RubyEnumerableStub1.this,0,recv,Arity.noArguments(), Visibility.PUBLIC); 300 this.include_p = new MultiStubMethod(RubyEnumerableStub1.this,1,recv,Arity.noArguments(), Visibility.PUBLIC); 301 this.max = new MultiStubMethod(RubyEnumerableStub1.this,2,recv,Arity.noArguments(), Visibility.PUBLIC); 302 this.min = new MultiStubMethod(RubyEnumerableStub1.this,3,recv,Arity.noArguments(), Visibility.PUBLIC); 303 this.all_p = new MultiStubMethod(RubyEnumerableStub1.this,4,recv,Arity.noArguments(), Visibility.PUBLIC); 304 this.any_p = new MultiStubMethod(RubyEnumerableStub1.this,5,recv,Arity.noArguments(), Visibility.PUBLIC); 305 this.zip = new MultiStubMethod(RubyEnumerableStub1.this,6,recv,Arity.noArguments(), Visibility.PUBLIC); 306 this.group_by = new MultiStubMethod(RubyEnumerableStub1.this,7,recv,Arity.noArguments(), Visibility.PUBLIC); 307 } 308 309 public IRubyObject method0(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 310 int index = 0; 312 List arr = eachToList(context,self,module); 313 Ruby rt = context.getRuntime(); 314 for(Iterator iter = arr.iterator();iter.hasNext();) { 315 context.yield(rt.newArray((IRubyObject)iter.next(),rt.newFixnum(index++)), block); 316 } 317 return self; 318 } 319 public IRubyObject method1(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 320 List arr = eachToList(context,self,module); 322 for(Iterator iter = arr.iterator();iter.hasNext();) { 323 if(args[0].callMethod(context,"==", (IRubyObject)iter.next()).isTrue()) { 324 return context.getRuntime().getTrue(); 325 } 326 } 327 return context.getRuntime().getFalse(); 328 } 329 public IRubyObject method2(final ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 330 IRubyObject result = null; 332 List arr = eachToList(context,self,module); 333 334 if(block.isGiven()) { 335 for(Iterator iter = arr.iterator();iter.hasNext();) { 336 IRubyObject item = (IRubyObject)iter.next(); 337 if(result == null || (context.yield(context.getRuntime().newArray(item,result), block).callMethod(context, ">", RubyFixnum.zero(context.getRuntime()))).isTrue()) { 338 result = item; 339 } 340 } 341 } else { 342 for(Iterator iter = arr.iterator();iter.hasNext();) { 343 IRubyObject item = (IRubyObject)iter.next(); 344 if(result == null || item.callMethod(context,"<=>", result).callMethod(context, ">", RubyFixnum.zero(context.getRuntime())).isTrue()) { 345 result = item; 346 } 347 } 348 } 349 if(null == result) { 350 return context.getRuntime().getNil(); 351 } 352 return result; 353 } 354 public IRubyObject method3(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 355 IRubyObject result = null; 357 List arr = eachToList(context,self,module); 358 359 if(block.isGiven()) { 360 for(Iterator iter = arr.iterator();iter.hasNext();) { 361 IRubyObject item = (IRubyObject)iter.next(); 362 if(result == null || (context.yield(context.getRuntime().newArray(item,result), block).callMethod(context, "<", RubyFixnum.zero(context.getRuntime()))).isTrue()) { 363 result = item; 364 } 365 } 366 } else { 367 for(Iterator iter = arr.iterator();iter.hasNext();) { 368 IRubyObject item = (IRubyObject)iter.next(); 369 if(result == null || item.callMethod(context,"<=>", result).callMethod(context, "<", RubyFixnum.zero(context.getRuntime())).isTrue()) { 370 result = item; 371 } 372 } 373 } 374 if(null == result) { 375 return context.getRuntime().getNil(); 376 } 377 return result; 378 } 379 public IRubyObject method4(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 380 boolean all = true; 382 List arr = eachToList(context,self,module); 383 384 if (block.isGiven()) { 385 for(Iterator iter = arr.iterator();iter.hasNext();) { 386 if(!context.yield((IRubyObject)iter.next(), block).isTrue()) { 387 all = false; 388 break; 389 } 390 } 391 } else { 392 for(Iterator iter = arr.iterator();iter.hasNext();) { 393 if(!((IRubyObject)iter.next()).isTrue()) { 394 all = false; 395 break; 396 } 397 } 398 } 399 return all ? context.getRuntime().getTrue() : context.getRuntime().getFalse(); 400 } 401 public IRubyObject method5(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 402 boolean any = false; 404 List arr = eachToList(context,self,module); 405 406 if (block.isGiven()) { 407 for(Iterator iter = arr.iterator();iter.hasNext();) { 408 if(context.yield((IRubyObject)iter.next(), block).isTrue()) { 409 any = true; 410 break; 411 } 412 } 413 } else { 414 for(Iterator iter = arr.iterator();iter.hasNext();) { 415 if(((IRubyObject)iter.next()).isTrue()) { 416 any = true; 417 break; 418 } 419 } 420 } 421 return any ? context.getRuntime().getTrue() : context.getRuntime().getFalse(); 422 } 423 public IRubyObject method6(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 424 List arr = eachToList(context,self,module); 426 int ix = 0; 427 List zip = new ArrayList (arr.size()); 428 int aLen = args.length+1; 429 if(block.isGiven()) { 430 for(Iterator iter = arr.iterator();iter.hasNext();) { 431 IRubyObject elem = (IRubyObject)iter.next(); 432 List array = new ArrayList (aLen); 433 array.add(elem); 434 for(int i=0,j=args.length;i<j;i++) { 435 array.add(args[i].callMethod(context,"[]", context.getRuntime().newFixnum(ix))); 436 } 437 context.yield(context.getRuntime().newArray(array), block); 438 ix++; 439 } 440 return context.getRuntime().getNil(); 441 } else { 442 for(Iterator iter = arr.iterator();iter.hasNext();) { 443 IRubyObject elem = (IRubyObject)iter.next(); 444 List array = new ArrayList (aLen); 445 array.add(elem); 446 for(int i=0,j=args.length;i<j;i++) { 447 array.add(args[i].callMethod(context,"[]", context.getRuntime().newFixnum(ix))); 448 } 449 zip.add(context.getRuntime().newArray(array)); 450 ix++; 451 } 452 } 453 return context.getRuntime().newArray(zip); 454 } 455 public IRubyObject method7(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 456 List arr = eachToList(context,self,module); 458 Map results = new HashMap (arr.size()); 459 for(Iterator iter = arr.iterator();iter.hasNext();) { 460 IRubyObject item = (IRubyObject)iter.next(); 461 IRubyObject key = context.yield(item, block); 462 IRubyObject curr = (IRubyObject)results.get(key); 463 if(curr == null) { 464 curr = context.getRuntime().newArray(); 465 results.put(key,curr); 466 } 467 curr.callMethod(context,"<<", item); 468 } 469 return new RubyHash(context.getRuntime(),results,context.getRuntime().getNil()); 470 } 471 public IRubyObject method8(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 472 return null; 473 } 474 public IRubyObject method9(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) { 475 return null; 476 } 477 } 478 479 public static RubyModule createEnumerableModule(Ruby runtime) { 480 RubyModule enm = runtime.defineModule("Enumerable"); 481 RubyEnumerableStub0 stub0 = RubyEnumerableStub0.createStub(enm); 482 RubyEnumerableStub1 stub1 = RubyEnumerableStub1.createStub(enm); 483 484 enm.addModuleFunction("to_a", stub0.to_a); 485 enm.addModuleFunction("entries", stub0.to_a); 486 enm.addModuleFunction("sort", stub0.sort); 487 enm.addModuleFunction("sort_by", stub0.sort_by); 488 enm.addModuleFunction("grep", stub0.grep); 489 enm.addModuleFunction("detect", stub0.detect); 490 enm.addModuleFunction("find", stub0.detect); 491 enm.addModuleFunction("select", stub0.select); 492 enm.addModuleFunction("find_all", stub0.select); 493 enm.addModuleFunction("reject", stub0.reject); 494 enm.addModuleFunction("collect", stub0.collect); 495 enm.addModuleFunction("map", stub0.collect); 496 enm.addModuleFunction("inject", stub0.inject); 497 enm.addModuleFunction("partition", stub0.partition); 498 499 enm.addModuleFunction("each_with_index", stub1.each_with_index); 500 enm.addModuleFunction("include?", stub1.include_p); 501 enm.addModuleFunction("member?", stub1.include_p); 502 enm.addModuleFunction("max", stub1.max); 503 enm.addModuleFunction("min", stub1.min); 504 enm.addModuleFunction("all?", stub1.all_p); 505 enm.addModuleFunction("any?", stub1.any_p); 506 enm.addModuleFunction("zip", stub1.zip); 507 enm.addModuleFunction("group_by", stub1.group_by); 508 509 return enm; 510 } 511 } 512 | Popular Tags |